diff options
author | Barak A. Pearlmutter <bap@debian.org> | 2010-04-20 15:18:13 -0400 |
---|---|---|
committer | Barak A. Pearlmutter <bap@debian.org> | 2010-04-20 15:18:13 -0400 |
commit | 0960d4900c9bc749cd72e3d928e8cfbe081712ea (patch) | |
tree | a9e6d9f90ba35dd7f1fdb68a96f08808380bfbbe /bits |
Import bbdb_2.36.orig.tar.gz
[dgit import orig bbdb_2.36.orig.tar.gz]
Diffstat (limited to 'bits')
32 files changed, 9889 insertions, 0 deletions
diff --git a/bits/README b/bits/README new file mode 100644 index 0000000..cc941db --- /dev/null +++ b/bits/README @@ -0,0 +1,4 @@ +This is the collection of bits and pieces located on the net or mailed to me +by various folk that may or may not wind up in BBDB proper. They shouldn't +be considered part of the bbdb as-is, nor should you complain to me about +their failure to work. diff --git a/bits/bbdb-anniv.el b/bits/bbdb-anniv.el new file mode 100644 index 0000000..9e6205d --- /dev/null +++ b/bits/bbdb-anniv.el @@ -0,0 +1,206 @@ +;;; bbdb-anniv.el --- Get anniversaries from BBDB + +;; Copyright (C) 1998 Ivar Rummelhoff + +;; Author: Ivar Rummelhoff <ivarru@math.uio.no> +;; Maintainer: Ivar Rummelhoff <ivarru@math.uio.no> +;; Created: 11 March 1998 +;; Time-stamp: <00/08/07 10:52:12 ivarru> +;; Keywords: calendar + +;; 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 2, 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; If you have not received a copy of the GNU General Public License +;; along with this software, it can be obtained from the GNU Project's +;; World Wide Web server (http://www.gnu.org/copyleft/gpl.html), from +;; its FTP server (ftp://ftp.gnu.org/pub/gnu/GPL), by sending an electronic +;; mail to this program's maintainer or by writing to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; (require 'bbdb-anniv) +;; (add-hook 'list-diary-entries-hook #'bbdb-include-anniversaries) +;; +;; will include BBDB-anniversaries when the diary is displayed +;; (fancy). The anniversaries are stored in the field `anniversary' +;; in the format +;; +;; [YYYY-MM-DD CLASS-OR-FORMAT-STRING] +;; {\nYYYY-MM-DD CLASS-OR-FORMAT-STRING}* +;; +;; CLASS-OR-FORMAT-STRING is one of two things: +;; +;; * an identifier for a class of anniversaries (eg. birthday or +;; wedding) from `bbdb-anniversary-format-alist'. +;; * the (format) string displayed in the diary. +;; +;; It defaults to the value of `bbdb-default-anniversary-format' +;; ("birthday" by default). +;; +;; The substitutions in the format string are (in order): +;; * the name of the record containing this anniversary +;; * the number of years +;; * an ordinal suffix (st, nd, rd, th) for the year +;; +;; See the documentation of `bbdb-anniversary-format-alist' for +;; further options. +;; +;; Example (my own record): +;; +;; 1973-06-22 +;; 20??-??-?? wedding +;; 1998-03-12 %s created bbdb-anniv.el %d years ago +;; +;; If you use the hook `sort-diary-entries', you should make sure that +;; it is executed after `bbdb-include-anniversaries'. +;; + +(require 'bbdb) +(require 'diary-lib) +(eval-when-compile (require 'cl)) + +;;;###autoload +(defgroup bbdb-utilities-anniversaries nil + "Customizations for including diary anniversaries from BBDB." + :link '(emacs-library-link :tag "Lisp File" "bbdb-anniv.el") + :group 'bbdb-utilities) + +;;;###autoload +(defcustom bbdb-anniversaries nil + "Should BBDB anniversaries be included when the diary is displayed (fancy)? +You must modify via \\[customize] for this variable to have an effect." + :set #'(lambda (symbol value) + (if value + (add-hook 'list-diary-entries-hook + #'bbdb-include-anniversaries) + (remove-hook 'list-diary-entries-hook + #'bbdb-include-anniversaries))) + :type 'boolean + :group 'bbdb-utilities-anniversaries + :require 'bbdb-anniv) + +(defcustom bbdb-default-anniversary-format "birthday" + "Default anniversary class" + :type 'string + :group 'bbdb-utilities-anniversaries + :require 'bbdb) + +(defcustom bbdb-anniversary-format-alist + '( ("birthday" . "Birthday: %s (%d%s)") + ("wedding" . "%s's %d%s wedding anniversary") ) + "How different types of anniversaries should be formatted. +An alist of elements (STRING . FORMAT) where STRING is the name of an +anniversary class and format is either: +1) A format string with the following substitutions (in order): + * the name of the record containing this anniversary + * the number of years + * an ordinal suffix (st, nd, rd, th) for the year + +2) A function to be called with three arguments: NAME YEARS SUFFIX + (string int string) returning a string for the diary or nil. + +3) An emacs lisp form that should evaluate to a string (or nil) in the + scope of variables NAME, YEARS and SUFFIX (among others)." + :type 'sexp + :group 'bbdb-utilities-anniversaries + :require 'bbdb) + +(defcustom bbdb-anniversary-field 'anniversary + "Which BBDB field contains anniversaries." + :type 'symbol + :group 'bbdb-utilities-anniversaries + :require 'bbdb) + +(defcustom bbdb-extract-date-fun 'bbdb-anniv-extract-date + "How to retrieve `month date year' from the anniversary field." + :type 'function + :group 'bbdb-utilities-anniversaries + :require 'bbdb) + +(defcustom bbdb-anniversary-reminder-days 0 + "Number of days warning you are given of an impending anniversary. +Modify this to give yourself a n-day warning of those important +anniversaries. This works in a naive fashion, extending (forwards) the +range of days for which diary entries are being listed. When set to 0, +the behaviour is to only list anniversaries on the day." + :type 'integer + :group 'bbdb-utilities-anniversaries + :require 'bbdb) + +;; YYYY-MM-DD => (month date year) +(defun bbdb-anniv-extract-date (time-str) + (multiple-value-bind (y m d) (bbdb-split time-str "-") + (list (string-to-number m) + (string-to-number d) + (string-to-number y)))) + +(defun bbdb-anniv-split (str) + (let ((pos (string-match "[ \t]" str))) + (if pos (list (substring str 0 pos) + (bbdb-string-trim (substring str pos))) + (list str nil)))) + + +(defvar number) +(defvar original-date) + +;;;###autoload +(defun bbdb-include-anniversaries () + (let ((dates (loop repeat (+ number bbdb-anniversary-reminder-days) + for num from (calendar-absolute-from-gregorian + original-date) + for date = original-date + then (calendar-gregorian-from-absolute num) + ;; ((MM . DD) . YYYY) + collect (cons (cons (extract-calendar-month date) + (extract-calendar-day date)) + (extract-calendar-year date)))) + annivs date years + split class form) + (dolist (rec (bbdb-records)) + (when (setq annivs (bbdb-record-getprop + rec bbdb-anniversary-field)) + (setq annivs (bbdb-split annivs "\n")) + (while annivs + (setq split (bbdb-anniv-split (pop annivs))) + (multiple-value-bind (m d y) + (funcall bbdb-extract-date-fun (car split)) + + (when (and (or (setq date (assoc (cons m d) dates)) + (and (= d 29) + (= m 2) + (setq date (assoc '(3 . 1) dates)) + (not (calendar-leap-year-p (cdr date))))) + (< 0 (setq years (- (cdr date) y)))) + (let* ((class (or (cadr split) + bbdb-default-anniversary-format)) + (form (or (cdr (assoc class + bbdb-anniversary-format-alist)) + class)) ; (as format string) + (name (bbdb-record-name rec)) + (suffix (diary-ordinal-suffix years)) + (text (cond + ((functionp form) + (funcall form name years suffix)) + ((listp form) (eval form)) + (t (format form name years suffix))))) + (when text + (bbdb-anniv-add + (list (caar date) (cdar date) (cdr date)) ; MM DD YYYY + text)))))))))) + +(defun bbdb-anniv-add (a b) + (add-to-diary-list a b "")) + +(provide 'bbdb-anniv) + +;;; bbdb-anniv.el ends here diff --git a/bits/bbdb-canonicalize-lt.el b/bits/bbdb-canonicalize-lt.el new file mode 100644 index 0000000..bb3d9c0 --- /dev/null +++ b/bits/bbdb-canonicalize-lt.el @@ -0,0 +1,41 @@ +;;; As per email to bbdb-info list from Len Trigg <len@netvalue.net> +;;; http://sourceforge.net/mailarchive/message.php?msg_name=hbr60bfmvt.wl%25len@netvalue.net.nz + +;;; Useful name canonicalizer; consider inclusion in main package. + +(defun bbdb-canonicalize-name-hook-lt (name) + "Function used to canonicalize the full names of bbdb entries." + ;; (message (format "canonicalize name %s" name)) + (cond + ;; strip extra quotes (Some MS mailer likes "'full name'") + ((string-match "\\`[`'\"]\\(.*\\)[`'\"]\\'" name) + (bbdb-match-substring name 1)) + ;; replace multiple whitespace with single + ((string-match "[ \f\t\n\r\v]\\{2,\\}" name) + (replace-match " " nil t name)) + ;; remove anything in round brackets, e.g.: "Firstname Surname (E-mail)" + ((string-match "[ ]+(.*)" name) + (replace-match "" nil t name)) + ;; strip leading whitespace (this is a bug in std11 libs?) + ((string-match "\\`[ \t]+\\(.*\\)" name) + (bbdb-match-substring name 1)) + ;; strip trailing whitespace + ((string-match "\\(.*\\)[ ]+\\'" name) + (bbdb-match-substring name 1)) + ;; strip Dr pronoun + ((string-match "\\`Dr\\.? \\(.*\\)" name) + (bbdb-match-substring name 1)) + ;; person and person -> person & person + ((string-match "\\`\\(\\w+\\) and \\(\\w.+\\)\\'" name) + (concat (bbdb-match-substring name 1) " & " (bbdb-match-substring name 2))) + ;; Surname, Firstname -> Firstname Surname + ((string-match "\\`\\(\\w.+\\), \\(\\w.+\\)\\'" name) + (concat (bbdb-match-substring name 2) " " (bbdb-match-substring name 1))) + ;; Sometimes get an email address in the name part. Map the username to a name: <Name@domain> -> Name + ((string-match "\\`<\\(.*\\)@.*\\'" name) + (bbdb-match-substring name 1)) + ;; replace name without any whitespace with empty; I don't want bbdb names containing only a single name + ((string-match "\\`\\(\\w+\\)\\'" name) + ;;(message (format "Eliding name %s" name)) + "") + (t name))) diff --git a/bits/bbdb-edit.el b/bits/bbdb-edit.el new file mode 100644 index 0000000..b22f308 --- /dev/null +++ b/bits/bbdb-edit.el @@ -0,0 +1,139 @@ +;;; bbdb-edit.el --- BBDB field edit +;; Copyright (C) 1999, 2000, 2001 Shenghuo ZHU + +;; Author: Shenghuo ZHU <zsh@cs.rochester.edu> +;; Created: Fri Aug 27 17:45:25 EDT 1999 +;; Keywords: BBDB field edit + +;; This file is not a part of GNU Emacs. +;; +;; This file 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 2, or (at your +;; option) any later version. +;; +;; This file is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; bbdb-field-edit-add (`insert') and bbdb-field-edit-del (`delete') +;; add/del a item to/from a certain field of the bbdb record. These +;; keys also support `*'. + +;;; Code: + +(require 'bbdb) + +(defun bbdb-field-edit-get-values (record field) + (cond + ((eq field 'net) (bbdb-record-net record)) + ((eq field 'AKA) (bbdb-record-aka record)) + ((eq field 'address) (bbdb-record-addresses record)) + ((eq field 'phone) (bbdb-record-phones record)) + (t (bbdb-split (or (bbdb-record-getprop record field) "") + (or (get field 'field-separator) + bbdb-notes-default-separator))))) + +(defun bbdb-field-edit-put-values (record field values) + (if values + (cond + ((eq field 'net) (bbdb-record-set-net record values)) + ((eq field 'AKA) (bbdb-record-set-aka record values)) + ((eq field 'address) (bbdb-record-set-addresses record values)) + ((eq field 'phone) (bbdb-record-set-phones record values)) + (t (bbdb-record-putprop record field + (bbdb-join values + (or (get field 'field-separator) + bbdb-notes-default-separator))))) + (if (memq field '(net AKA address)) + (bbdb-record-store-field-internal record field nil) + (bbdb-record-putprop record field nil))) + (bbdb-change-record record t) + (bbdb-redisplay-one-record record)) + +;;;###autoload +(defun bbdb-field-edit-add (bbdb-record field value) + "Add VALUE to FIELD of bbdb-record(s)." + (interactive (list (if (bbdb-do-all-records-p) + (mapcar 'car bbdb-records) + (list (bbdb-current-record))) + (completing-read + "Field: " + (append '(("net")("notes")("AKA")) + (bbdb-propnames)) + nil nil + (symbol-name + (let ((on-field (bbdb-current-field t))) + (cond ((null on-field) 'mail-alias) + ((eq (car on-field) 'property) + (car (nth 1 on-field))) + (t (car on-field)))))) + (bbdb-read-string "Value: "))) + (if (stringp field) (setq field (intern field))) + (if (memq field '(name address phone)) + (error "Use `e' to edit this field.")) + (while bbdb-record + (let ((values (bbdb-field-edit-get-values (car bbdb-record) field))) + (if (member value values) nil + (bbdb-field-edit-put-values (car bbdb-record) field + (cons value values)))) + (setq bbdb-record (cdr bbdb-record)))) + +;;;###autoload +(defun bbdb-field-edit-del (bbdb-record field value) + "Delete VALUE to FIELD of bbdb-record(s). +If prefix arg exists, delete all existing field values matching VALUE(regexp)." + (interactive (list (if (bbdb-do-all-records-p) + (mapcar 'car bbdb-records) + (list (bbdb-current-record))) + (completing-read + "Field: " + (append '(("net")("notes")("AKA")) + (bbdb-propnames)) + nil nil (symbol-name + (let ((on-field (bbdb-current-field t))) + (cond ((null on-field) 'mail-alias) + ((eq (car on-field) 'property) + (car (nth 1 on-field))) + (t (car on-field)))))) + (bbdb-read-string (if current-prefix-arg + "Regexp: " + "Value: ")))) + (if (stringp field) (setq field (intern field))) + (if (memq field '(name address phone)) + (error "Use `e' to edit this field.")) + (while bbdb-record + (let ((values (bbdb-field-edit-get-values (car bbdb-record) field))) + (cond + (current-prefix-arg + (let (nvalues found) + (while values + (if (string-match value (car values)) + (setq found t) + (setq nvalues (cons (car values) nvalues))) + (setq values (cdr values))) + (if found + (bbdb-field-edit-put-values (car bbdb-record) field + (nreverse nvalues))))) + (t + (if (member value values) + (bbdb-field-edit-put-values (car bbdb-record) field + (delete value values)))))) + (setq bbdb-record (cdr bbdb-record)))) + +;;; The key binding might be moved to somewhere else. + +(define-key bbdb-mode-map [(insert)] 'bbdb-field-edit-add) +(define-key bbdb-mode-map [(delete)] 'bbdb-field-edit-del) + +(provide 'bbdb-edit) + +;; bbdb-edit.el ends here diff --git a/bits/bbdb-filters/COPYING.LIB b/bits/bbdb-filters/COPYING.LIB new file mode 100644 index 0000000..eb685a5 --- /dev/null +++ b/bits/bbdb-filters/COPYING.LIB @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/bits/bbdb-filters/README b/bits/bbdb-filters/README new file mode 100644 index 0000000..a88c2fc --- /dev/null +++ b/bits/bbdb-filters/README @@ -0,0 +1,64 @@ + +BBDB is a rolodex-like database program for GNU Emacs. +BBDB stands for Insidious Big Brother Database. BBDB is written by: +Jamie Zawinski <jwz@mcom.com>. My current version is 1.50. + +We have prepared a family of filters for BBDB. Currently the output +filters include: + + - bbdb --> emacs lisp exporting (for exchanging business cards) + - bbdb --> HP100/200 LX Phone Book + - bbdb --> PC Eudora Nicknames + - bbdb --> CC Mail Nicknames + - bbdb --> PH/QI + +There is presently only one input filter: + + - bbdb <-- UNIX passwd files + +We hope that over time a variety of other input and output filters +will be added to this collection. + + +bbdb-export in particular, can be very useful over the net. +It provides a convenient way for exchanging business cards. + + +This is a preliminary release. This stuff has not been tested much +outside of our office. We do use most of these filters on an going basis +and they work fine for us. + +To install, just edit the makefile and run "make install". + +To run them, read the comments on top of each filter file. + +There is very skimpy documentation in latexinfo format. It is just +meant to be a starting point. + +In addition to the attached shar file, +you can also ftp this package from: + //anonymous@ftp.neda.com:/pub/eoe/bbdbPlus/bbdb-filters-0.2.tar + URL = ftp://ftp.neda.com/pub/eoe/bbdbPlus/bbdb-filters-0.2.tar + +Many of the filters require bbdb-tex-print package by: +Boris Goldowsky <boris@prodigal.psych.rochester.edu>. + +The one that we use can be found in: + //anonymous@ftp.neda.com:/pub/eoe/bbdbPlus/bbdb-tex-3.0.tar + URL = ftp://ftp.neda.com/pub/eoe/bbdbPlus/bbdb-tex-3.0.tar + +You can checkout the overview of this package by +browsing the manual (latex/info/html) at: + URL = http://www.neda.com/eoe/bbdbFilters/bbdbFilters.html + + +Send bug-reports, comments and suggestions to: + Mohsen Banan-neda <mohsen@neda.com> +and refer to: + bbdb-filters RCS: README,v 1.2 1995/08/08 02:59:15 mohsen Exp + + +Hope you find this helpful. + +...Mohsen. + diff --git a/bits/bbdb-filters/bbdb-ccmail.el b/bits/bbdb-filters/bbdb-ccmail.el new file mode 100644 index 0000000..d8ce4d9 --- /dev/null +++ b/bits/bbdb-filters/bbdb-ccmail.el @@ -0,0 +1,118 @@ +;;; This file is part of the BBDB Filters Package. BBDB Filters Package is a +;;; collection of input and output filters for BBDB. +;;; +;;; Copyright (C) 1995 Neda Communications, Inc. +;;; Prepared by Mohsen Banan (mohsen@neda.com) +;;; +;;; This library is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU Library General Public License as +;;; published by the Free Software Foundation; either version 2 of the +;;; License, or (at your option) any later version. This library is +;;; distributed in the hope that it will be useful, but WITHOUT ANY +;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +;;; License for more details. You should have received a copy of the GNU +;;; Library General Public License along with this library; if not, write +;;; to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +;;; USA. +;;; +;;; This is bbdb-eudora.el +;;; +;;; +;;; RCS: bbdb-ccmail.el,v 1.1.1.1 1995/08/07 08:43:09 mohsen Exp +;;; +;;; a copy-and-edit job on bbdb-print.el + +;;; To use this, add the following to your .emacs +;;; and strip ";;;XXX" +;;; + +;;;XXX;; BBDB Filters +;;;XXX(load "bbdb-ccmail") + +;;;XXX(setq bbdb-ccmail-filename "~/privdir.ini") +;;;XXX;;; And then +;;;XXX;;; (bbdb-ccmail-output) + +;;; TODO +;;; Make the postoffice name optional as an argument +;;; + +(require 'bbdb-print) + +(defvar bbdb-ccmail-filename "~/privdir.ini" + "*Default file name for bbdb-output-ccmail printouts of BBDB database.") + +(defun bbdb-ccmail-output (to-file) + "Print the selected BBDB entries" + (interactive (list (read-file-name "Print To File: " bbdb-ccmail-filename))) + (setq bbdb-ccmail-filename (expand-file-name to-file)) + (let ((current-letter t) + (records (progn (set-buffer bbdb-buffer-name) + bbdb-records))) + (find-file bbdb-ccmail-filename) + (delete-region (point-min) (point-max)) + (let* ((ccmail-count 0)) + (while records + (setq current-letter + (boe-ccmail-format-record (car (car records)) + current-letter)) + (setq records (cdr records))) + (goto-char (point-min)) + (insert (format "[smtpgate]
\nEntryCount=%d
\n" ccmail-count)) + (goto-char (point-min))))) + +(defun boe-ccmail-output-this-record-p (name net) + "Examine NAME COMP NET PHONES ADDRS NOTES and return t if +the current record is to be output by bbdb-output-ccmail." + ;; if name is non-nil, output it + (cond ((and name net) t) + (t nil)) + ) + + +(defun boe-ccmail-format-record (record &optional current-letter brief) + "Insert the bbdb RECORD in Ccmail format. +Optional CURRENT-LETTER is the section we're in -- if this is non-nil and +the first letter of the sortkey of the record differs from it, a new section +heading will be output \(an arg of t will always produce a heading). +The new current-letter is the return value of this function. +Someday, optional third arg BRIEF will produce one-line format." + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "plus ungood: tex formatting deleted record"))) + + (let* ((bbdb-elided-display bbdb-print-elide) + (first-letter + (substring (concat (bbdb-record-sortkey record) "?") 0 1)) + (name (and (bbdb-field-shown-p 'name) + (or (bbdb-record-getprop record 'tex-name) + (bbdb-print-tex-quote + (bbdb-record-name record))))) + (net (and (bbdb-field-shown-p 'net) + (bbdb-record-net record))) + (begin (point)) + ) + + (if (and current-letter + (not (string-equal first-letter current-letter))) + (message "Now processing \"%s\" entries..." (upcase first-letter))) + + (if (boe-ccmail-output-this-record-p name net) + (progn + + ;; Email address -- just use their first address. + ;; Make all dots legal line-breaks. + ;; + ;; output in the following format: "<Pretty Name>" <email address> + (if net + (let ((net-addr (car net)) + (start 0)) + (setq ccmail-count (+ ccmail-count 1)) + (insert (format "Entry%d=" ccmail-count)) + (insert (format "\"%s\" <%s>
\n" name net-addr)))) + (setq current-letter first-letter)) + ) + + ;; return current letter + current-letter)) + diff --git a/bits/bbdb-filters/bbdb-eudora.el b/bits/bbdb-filters/bbdb-eudora.el new file mode 100644 index 0000000..2c2f848 --- /dev/null +++ b/bits/bbdb-filters/bbdb-eudora.el @@ -0,0 +1,284 @@ +;;; This file is part of the BBDB Filters Package. BBDB Filters Package is a +;;; collection of input and output filters for BBDB. +;;; +;;; Copyright (C) 1995 Neda Communications, Inc. +;;; Prepared by Mohsen Banan (mohsen@neda.com) +;;; +;;; This library is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU Library General Public License as +;;; published by the Free Software Foundation; either version 2 of the +;;; License, or (at your option) any later version. This library is +;;; distributed in the hope that it will be useful, but WITHOUT ANY +;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +;;; License for more details. You should have received a copy of the GNU +;;; Library General Public License along with this library; if not, write +;;; to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +;;; USA. +;;; +;;; This is bbdb-eudora.el +;;; +;;; +;;; RCS: bbdb-eudora.el,v 1.1.1.1 1995/08/07 08:43:09 mohsen Exp +;;; +;;; a copy-and-edit job on bbdb-print.el + +;;; To use this, add the following to your .emacs +;;; and strip ";;;XXX" +;;; + +;;;XXX;; BBDB Filters +;;;XXX(load "bbdb-eudora") + +;;;XXX(setq bbdb-eudora-nndbase-filename +;;;XXX (concat "/dos/m/eudora.mai/" (user-login-name) "/nndbase.txt")) +;;;XXX;;; And then +;;;XXX;; (bbdb-eudora-nndbase-output) + +;;;XXX(setq bbdb-eudora-rcpdbase-filename +;;;XXX (concat "/dos/m/eudora.mai/" (user-login-name) "/rcpdbase.txt")) +;;;XXX;;; And then +;;;XXX;; (bbdb-eudora-rcpdbase-output) + +(require 'bbdb-print) +(require 'basic-ext) + +(defvar bbdb-eudora-nndbase-filename "~/nndbase.txt" + "*Default file name for bbdb-output-eudora printouts of BBDB database.") + +(defun bbdb-eudora-nndbase-output (to-file) + "Print the selected BBDB entries" + (interactive (list (read-file-name "Print To File: " bbdb-eudora-nndbase-filename))) + (setq bbdb-eudora-nndbase-filename (expand-file-name to-file)) + (let ((current-letter t) + (records (progn (set-buffer bbdb-buffer-name) + bbdb-records))) + (find-file bbdb-eudora-nndbase-filename) + (delete-region (point-min) (point-max)) + (while records + (setq current-letter + (boe-format-record (car (car records)) current-letter)) + (setq records (cdr records))) + (goto-char (point-min)) + (message "Eudora nickname file %s generated." bbdb-eudora-nndbase-filename))) + +(defsubst boe-print-if-not-blank (string prepend-string &rest more) + "If STRING is not null, then return it with PREPEND-STRING in front and concatenated +with rest of arguments. If it is null, then all arguments are +ignored and the null string is returned." + (if (or (null string) (equal "" string)) + "" + (apply 'concat prepend-string string more))) + +(defun boe-output-this-record-p (name comp net phones addrs notes) + "Examine NAME COMP NET PHONES ADDRS NOTES and return t if +the current record is to be output by bbdb-output-eudora." + ;; if name is non-nil, output it + (cond ((and name net) t) + (t nil)) + ) + + +(defun boe-format-record (record &optional current-letter brief) + "Insert the bbdb RECORD in Eudora format. +Optional CURRENT-LETTER is the section we're in -- if this is non-nil and +the first letter of the sortkey of the record differs from it, a new section +heading will be output \(an arg of t will always produce a heading). +The new current-letter is the return value of this function. +Someday, optional third arg BRIEF will produce one-line format." + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "plus ungood: formatting deleted record"))) + + (let* ((bbdb-elided-display bbdb-print-elide) + (first-letter + (substring (concat (bbdb-record-sortkey record) "?") 0 1)) + (name (and (bbdb-field-shown-p 'name) + (or (bbdb-record-getprop record 'tex-name) + (bbdb-record-name record)))) + (comp (and (bbdb-field-shown-p 'company) + (bbdb-record-company record))) + (net (and (bbdb-field-shown-p 'net) + (bbdb-record-net record))) + (phones (and (bbdb-field-shown-p 'phone) + (bbdb-record-phones record))) + (addrs (and (bbdb-field-shown-p 'address) + (bbdb-record-addresses record))) + (notes (bbdb-record-raw-notes record)) + (begin (point)) + (bare t)) + + ;; Section header, if neccessary. + + (if (and current-letter (not (string-equal first-letter current-letter))) + (message "Now processing \"%s\" entries..." (upcase first-letter))) + + (if (boe-output-this-record-p name comp net phones addrs notes) + (progn + + ;; Eudora nickname in canonical form (e.g., mohsen.banan) + ;; + (if name + (insert (format "<%s>
\n" name))) + + ;; Email address -- just use their first address. + ;; Make all dots legal line-breaks. + ;; + ;; output in the following format: "<Pretty Name>" <email address> + (if net + (let ((net-addr (car net)) + (start 0)) + (insert (format ">\"%s\" <%s>
\n" name net-addr)))) + + ;; start a Eudora nndbase.txt notes section for this nickname + ;; by inserting the nickname again + + (if name + (insert (format "<%s>
\n" name))) + + ;; Company + ;; + (if comp + (insert (format "> Company: %s
\n" + (boe-mangle-if-multi-line comp)))) + + ;; Phone numbers + ;; + (while phones + (let ((place (aref (car phones) 0)) + (number (bbdb-phone-string (car phones)))) + (setq bare nil) + (insert (format "> Telephone: %s%s
\n" + (boe-print-if-not-blank place "" ": ") + number)) + (setq phones (cdr phones)))) + + ;; Addresses + ;; + (while addrs + (let ((addr (car addrs))) + (setq bare nil) + (insert + (format + "> Address:
\n%s" + (concat + (boe-print-if-not-blank (bbdb-address-street1 addr) "> " "
\n") + (boe-print-if-not-blank (bbdb-address-street2 addr) "> " "
\n") + (boe-print-if-not-blank (bbdb-address-street3 addr) "> ") + (boe-print-if-not-blank (bbdb-address-city addr) "> ") + (if (and (not (equal "" (bbdb-address-city addr))) + (not (equal "" (bbdb-address-state addr)))) + ", ") + (boe-print-if-not-blank (bbdb-address-state addr) "" " ") + (boe-print-if-not-blank (bbdb-address-zip-string addr) "" "
\n"))))) + (setq addrs (cdr addrs))) + + ;; BBDB Notes + + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + (while notes + (let ((thisnote (car notes))) + (if (bbdb-field-shown-p (car thisnote)) + (progn + (setq bare nil) + (if (eq 'notes (car thisnote)) + (insert (format "> Notes: %s
\n" + (boe-mangle-if-multi-line (cdr thisnote)))) + (insert (format "> Note [%s]: %s
\n" + (symbol-name (car thisnote)) + (boe-mangle-if-multi-line (cdr thisnote)))))))) + (setq notes (cdr notes))) + + ;; If record is bare, delete anything we may have inserted. + ;; otherwise, mark the end of this record. + + (if bare + (delete-region begin (point)) + + (setq current-letter first-letter)) + + )) + + ;; return current letter + current-letter)) + + +(defun boe-mangle-if-multi-line (string) + "If STRING is has multiple lines, mangle it for output to Eudora" + (if (string-match "\n" string) + (string-replace-regexp string "\n" "
\n> ") + string)) + + +;;;;;;;;;;;; Eudora Receipient DataBase (rcpdbase.txt) ;;;;;;;;;;; + +;;;(setq bbdb-eudora-rcpdbase-filename "/dos/m/eudora.mai/mohsen/rcpdbase.txt") +(defvar bbdb-eudora-rcpdbase-filename "~/rcpdbase.txt" + "*Default file name for bbdb-output-eudora printouts of BBDB database.") + +(defun bbdb-eudora-rcpdbase-output (to-file) + "Print the selected BBDB entries" + (interactive (list (read-file-name "Print To File: " bbdb-eudora-rcpdbase-filename))) + (setq bbdb-eudora-rcpdbase-filename (expand-file-name to-file)) + (let ((current-letter t) + (records (progn (set-buffer bbdb-buffer-name) + bbdb-records))) + (find-file bbdb-eudora-rcpdbase-filename) + (delete-region (point-min) (point-max)) + (while records + (setq current-letter + (boe-rcpdbase-format-record (car (car records)) current-letter)) + (setq records (cdr records))) + (goto-char (point-min)) + (message "Eudora rcpt. file %s generated." bbdb-eudora-nndbase-filename))) + + + +(defun boe-rcpdbase-format-record (record &optional current-letter brief) + "Insert the bbdb RECORD in Eudora format. +Optional CURRENT-LETTER is the section we're in -- if this is non-nil and +the first letter of the sortkey of the record differs from it, a new section +heading will be output \(an arg of t will always produce a heading). +The new current-letter is the return value of this function. +Someday, optional third arg BRIEF will produce one-line format." + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "plus ungood: formatting deleted record"))) + + (let* ((bbdb-elided-display bbdb-print-elide) + (first-letter + (substring (concat (bbdb-record-sortkey record) "?") 0 1)) + (name (and (bbdb-field-shown-p 'name) + (or (bbdb-record-getprop record 'tex-name) + (bbdb-record-name record)))) + (comp (and (bbdb-field-shown-p 'company) + (bbdb-record-company record))) + (net (and (bbdb-field-shown-p 'net) + (bbdb-record-net record))) + (phones (and (bbdb-field-shown-p 'phone) + (bbdb-record-phones record))) + (addrs (and (bbdb-field-shown-p 'address) + (bbdb-record-addresses record))) + (notes (bbdb-record-raw-notes record)) + (begin (point)) + (bare t)) + + ;; Section header, if neccessary. + + (if (and current-letter + (not (string-equal first-letter current-letter))) + (message "Now processing \"%s\" entries..." (upcase first-letter))) + + (if (boe-output-this-record-p name comp net phones addrs notes) + (progn + + ;; Eudora nickname in canonical form (e.g., mohsen.banan) + ;; + (if name + (insert (format "%s
\n" name))) + + (setq current-letter first-letter) + + )) + + ;; return current letter + current-letter)) diff --git a/bits/bbdb-filters/bbdb-export.el b/bits/bbdb-filters/bbdb-export.el new file mode 100644 index 0000000..279238a --- /dev/null +++ b/bits/bbdb-filters/bbdb-export.el @@ -0,0 +1,140 @@ +;;; This file is part of the BBDB Filters Package. BBDB Filters Package is a +;;; collection of input and output filters for BBDB. +;;; +;;; Copyright (C) 1995 Neda Communications, Inc. +;;; Prepared by Mohsen Banan (mohsen@neda.com) +;;; +;;; This library is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU Library General Public License as +;;; published by the Free Software Foundation; either version 2 of the +;;; License, or (at your option) any later version. This library is +;;; distributed in the hope that it will be useful, but WITHOUT ANY +;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +;;; License for more details. You should have received a copy of the GNU +;;; Library General Public License along with this library; if not, write +;;; to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +;;; USA. +;;; +;;; This is bbdb-export.el +;;; + +(defvar bbdb-export-buffer-name "*BBDB* Export" + "*Default buffer name for exporting the contents of the *BBDB* buffer.") + + +(defvar bbdb-export-compactly nil + "If nil, the exported records are compactly printed. +Otherwise the exported forms are indented for human-readability (at a +cost of somewhat longer processing time for exporting records. +The default value is nil.") + + +(defun bbdb-export () + "Print the selected BBDB entries" + (interactive) + (save-excursion + (let ((to-buffer (get-buffer-create bbdb-export-buffer-name)) + (records (progn (set-buffer bbdb-buffer-name) + bbdb-records)) + (current-letter "")) + ;; wipe to-buffer + (switch-to-buffer to-buffer) + (delete-region (point-min) (point-max)) + + ;; insert header, records, trailer + (bexp-buffer-insert-header) + (while records + (setq current-letter (bexp-do-record (car (car records)) current-letter)) + (setq records (cdr records))) + (bexp-buffer-insert-trailer) + + (goto-char (point-min)) + (search-forward "(progn") + (search-backward "(progn") + (indent-sexp) + )) + (message "BBDB export buffer %s generated." bbdb-export-buffer-name)) + + +(defun bexp-do-record (record current-letter) + "Insert the bbdb RECORD in export format." + (let* ((name (bbdb-record-name record)) + (comp (bbdb-record-company record)) + (net (bbdb-record-net record)) + (phones (bbdb-record-phones record)) + (addrs (bbdb-record-addresses record)) + (notes (bbdb-record-raw-notes record)) + (first-letter (upcase (substring (concat (bbdb-record-sortkey record) "?") 0 1)))) + + (if (not (string-equal first-letter current-letter)) + (progn (message "Now processing \"%s\" entries..." first-letter) + (sleep-for 1))) + (bexp-buffer-insert-record name comp net addrs phones notes) + first-letter)) + + +(defun bexp-buffer-insert-header() + (insert ";;; ======= Start of Exported BBDB Records =======\n") + (insert "(progn +(require 'bbdb-com) +(defun bbdb-maybe-create (name company net &optional addrs phones notes) + \"Try to add a record to BBDB if it does not already exist.\" + (condition-case err + (progn + (bbdb-create-internal name company net addrs phones notes) + (message \"%s %s added.\" name (if net (concat \"<\" net \">\") \"\")) + (sleep-for 1)) + (error (ding) + (message \"%s %s skipped. (%s)\" + name + (if net (concat \"<\" net \">\") \"\") + (car (cdr err))) + (sleep-for 1))))\n\n") + (normal-mode)) + + +(defun bexp-buffer-insert-trailer() + (insert ")\n") + (insert ";;; ======= End of Exported BBDB Records =======\n")) + + +(defun bexp-buffer-insert-record (name comp net addrs phones notes) + (let ((begin (point)) + end) + (message "Exporting %s" name) + (insert (format "(bbdb-maybe-create %s %s '%s '%s '%s '%s)\n" + (prin1-to-string (concat name "--IMPORTED")) + (prin1-to-string comp) + (prin1-to-string net) + (prin1-to-string addrs) + (prin1-to-string phones) + (prin1-to-string notes) + )) + (setq end (point)) + (if (not bbdb-export-compactly) + (progn + ;; format region + (narrow-to-region begin end) + (goto-char begin) + (replace-string " '(" "\n'(") + (goto-char begin) + (replace-string "\" \"" "\"\n\"") + (goto-char begin) + (replace-string "((" "(\n(") + (goto-char begin) + (replace-string "))" ")\n)") + (goto-char begin) + (replace-string "([" "(\n[") + (goto-char begin) + (replace-string "])" "]\n)") + (goto-char begin) + (replace-string ") (" ")\n(") + (goto-char begin) + (replace-string "] [" "]\n[") + (goto-char (point-max)) + (lisp-indent-region begin (point)) + (widen))) + )) + +(provide 'bbdb-export) diff --git a/bits/bbdb-filters/bbdb-hp200lx.el b/bits/bbdb-filters/bbdb-hp200lx.el new file mode 100644 index 0000000..fe3f00a --- /dev/null +++ b/bits/bbdb-filters/bbdb-hp200lx.el @@ -0,0 +1,348 @@ +;;; This file is part of the BBDB Filters Package. BBDB Filters Package is a +;;; collection of input and output filters for BBDB. +;;; +;;; Copyright (C) 1995 Neda Communications, Inc. +;;; Prepared by Mohsen Banan (mohsen@neda.com) +;;; +;;; This library is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU Library General Public License as +;;; published by the Free Software Foundation; either version 2 of the +;;; License, or (at your option) any later version. This library is +;;; distributed in the hope that it will be useful, but WITHOUT ANY +;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +;;; License for more details. You should have received a copy of the GNU +;;; Library General Public License along with this library; if not, write +;;; to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +;;; USA. +;;; +;;; This is bbdb-hp200lx.el +;;; +;;; +;;; RCS: bbdb-hp200lx.el,v 1.1.1.1 1995/08/07 08:43:09 mohsen Exp +;;; +;;; a copy-and-edit job on bbdb-print.el + + +;;; To use this, add the following to your .emacs +;;; and strip ";;;XXX" +;;; + +;;;XXX;; BBDB HP200LX Filter +;;;XXX(load "bbdb-hp200lx") + +;;;XXX(setq bbdb-hp200lx-filename +;;;XXX (concat "/dos/u/" (user-login-name) "/bb-phone.cdf")) +;;;XXX;;; - to output the *BBDB* buffer in HP200LX comma-delimited-file (.CDF) +;;;XXX;;; format, invoke M-x bbdb-hp200lx-output +;;;XXX;;; +;;;XXX;;; - you may also want to modify default values of the following (use +;;;XXX;;; M-x describe-variable for details): +;;;XXX;;; bbdb-hp200lx-output-elide +;;;XXX;;; bbdb-hp200lx-output-requires +;;;XXX;;; bbdb-hp200lx-output-no-bare-names + + +(require 'bbdb-print) +(require 'basic-ext) + + +(defvar bbdb-hp200lx-filename "~/bb-phone.cdf" + "*Default file name for bbdb-output-hp200lx printouts of BBDB database.") + + +(defvar bbdb-hp200lx-output-elide '(net creation-date timestamp mail-alias) + "*List of symbols denoting BBDB fields NOT to be output. +Valid symbols are: name comp net phones addrs. You can also use the +tags for notes (e.g., creation-date). + e.g.: '(net creation-date) +See also variable bbdb-hp200lx-output-requires.") + + +(defvar bbdb-hp200lx-output-requires '(or name comp) + "*A boolean expression of 'and' and 'or' to be evaluated to determine if +the current record should be output. Valid symbols for use +in the boolean expression are: name comp net phones addrs notes. + e.g.: (and name (or comp addrs)) +See also variable bbdb-hp200lx-output-elide. +") + + +(defvar bbdb-hp200lx-output-no-bare-names t + "*A bare name is one with no information other than +that in bbdb-hp200lx-output-requires. To avoid printing +these set this variable to t") + + +(defun bbdb-hp200lx-output (to-file) + "Print the selected BBDB entries" + (interactive (list (read-file-name "Print To File: " bbdb-hp200lx-filename))) + (setq bbdb-hp200lx-filename (expand-file-name to-file)) + (let ((current-letter t) + (records (progn (set-buffer bbdb-buffer-name) + bbdb-records))) + (find-file bbdb-hp200lx-filename) + (delete-region (point-min) (point-max)) + (while records + (setq current-letter + (boh-maybe-format-record (car (car records)) current-letter)) + (setq records (cdr records))) + (goto-char (point-min)) + (message "HP 200LX comma-delimited phonebook file %s generated." bbdb-hp200lx-filename))) + + +(defun boh-maybe-format-record (record &optional current-letter brief) + "Insert the bbdb RECORD in Hp200lx format. +Optional CURRENT-LETTER is the section we're in -- if this is non-nil and +the first letter of the sortkey of the record differs from it, a new section +heading will be output \(an arg of t will always produce a heading). +The new current-letter is the return value of this function. +Someday, optional third arg BRIEF will produce one-line format." + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "plus ungood: formatting deleted record"))) + + + (let* ((bbdb-elided-display bbdb-hp200lx-output-elide) + (first-letter + (substring (concat (bbdb-record-sortkey record) "?") 0 1)) + (name (and (bbdb-field-shown-p 'name) + (or (bbdb-record-getprop record 'tex-name) + (bbdb-record-name record)))) + (comp (and (bbdb-field-shown-p 'company) + (bbdb-record-company record))) + (net (and (bbdb-field-shown-p 'net) + (bbdb-record-net record))) + (phones (and (bbdb-field-shown-p 'phone) + (bbdb-record-phones record))) + (addrs (and (bbdb-field-shown-p 'address) + (bbdb-record-addresses record))) + (notes (bbdb-record-raw-notes record)) + (begin (point)) + (bare t)) + + + ;; Section header, if neccessary. + + + (if (and current-letter (not (string-equal first-letter current-letter))) + (message "Now processing \"%s\" entries..." (upcase first-letter))) + + + (if (eval bbdb-hp200lx-output-requires) + (let (more-phones) + + + ;; HP 200LX last name field (maxlen 86 ??) -- used for BBDB name + ;; + (insert (format "\"%s\"," (boh-maybe-truncate name 86))) + + + ;; HP 200LX first name field (maxlen ??) -- unused + (insert ",") + + + ;; HP 200LX middle name field (maxlen ??) -- unused + ;; + (insert ",") + + + ;; Phone numbers + ;; + (let (business-phone home-phone fax-phone saved-case-fold) + (setq saved-case-fold case-fold-search + case-fold-search t) + (while phones + (let ((place (aref (car phones) 0)) + (number (bbdb-phone-string (car phones)))) + (cond ((or (string-match place "office") + (string-match place "work")) + (if (null business-phone) + (setq business-phone (list place number)) + (setq more-phones (cons (list place number) more-phones)))) + ((string-match place "home") + (if (null home-phone) + (setq home-phone (list place number)) + (setq more-phones (cons (list place number) more-phones)))) + ((or (string-match place "fax") + (string-match place "facsimile")) + (if (null fax-phone) + (setq fax-phone (list place number)) + (setq more-phones (cons (list place number) more-phones)))) + (t + (setq more-phones (cons (list place number) more-phones))))) + (setq phones (cdr phones))) + + + (setq case-fold-search saved-case-fold) + + + ;; HP 200LX business phone field (maxlen 29) + (if business-phone + (progn + (insert (format "\"%s\"," (boh-maybe-truncate + (format "%s" (car (cdr business-phone))) + 29))) + (setq bare nil)) + (insert ",")) + + + ;; HP 200LX home phone field (maxlen 29) + (if home-phone + (progn + (insert (format "\"%s\"," (boh-maybe-truncate + (format "%s" (car (cdr home-phone))) + 29))) + (setq bare nil)) + (insert ",")) + + + ;; HP 200LX alternate phone field (maxlen 29) -- unused + (insert ",") + + + ;; HP 200LX fax phone field (maxlen 29) + (if fax-phone + (progn + (insert (format "\"%s\"," (boh-maybe-truncate + (format "%s" (car (cdr fax-phone))) ; the description + 29))) + (setq bare nil)) + (insert ",")) + ) + + + ;; HP 200LX title field (maxlen 38) -- unused + (insert ",") + + + ;; HP 200LX category field (maxlen 127) -- unused + (insert ",") + + + ;; HP 200LX company field (maxlen 82) -- used for BBDB company + (if comp + (insert (format "\"%s\"," (boh-maybe-truncate comp 82))) + (insert ",")) + + + ;; Addresses + ;; + (let ((addr (car addrs)) ;just take the first bbdb address + hp-addr1 hp-addr2 hp-city hp-state hp-zip) + + (if addr + (progn + (setq hp-addr1 (bbdb-address-street1 addr)) + (setq hp-addr2 (concat (bbdb-address-street2 addr) + (if (and (> (length (bbdb-address-street2 addr)) 0) + (> (length (bbdb-address-street3 addr)) 0)) + ", " "") + (bbdb-address-street3 addr))) + (setq hp-city (bbdb-address-city addr)) + (setq hp-state (bbdb-address-state addr)) + (setq hp-zip (bbdb-address-zip-string addr)))) + + ;; HP 200LX address 1 field (maxlen 82) + (if hp-addr1 + (progn + (insert (format "\"%s\"," (boh-maybe-truncate hp-addr1 82))) + (setq bare nil)) + (insert ",")) + + ;; HP 200LX address 2 field (maxlen 82) + (if hp-addr2 + (progn + (insert (format "\"%s\"," (boh-maybe-truncate hp-addr2 82))) + (setq bare nil)) + (insert ",")) + + ;; HP 200LX city field (maxlen 34) + (if hp-city + (progn + (insert (format "\"%s\"," (boh-maybe-truncate hp-city 34))) + (setq bare nil)) + (insert ",")) + + ;; HP 200LX state field (maxlen 39) + (if hp-state + (progn + (insert (format "\"%s\"," (boh-maybe-truncate hp-state 39))) + (setq bare nil)) + (insert ",")) + + ;; HP 200LX zip field (maxlen 16) + (if hp-zip + (progn + (insert (format "\"%s\"," (boh-maybe-truncate hp-zip 16))) + (setq bare nil)) + (insert ",")) + ) + + ;; BBDB Notes + + (let (hp-note) + (save-excursion + (set-buffer (get-buffer-create " *boh-scratch*")) + (kill-region (point-min) (point-max)) + + (while more-phones + (insert (format "%s: %s\t" + (car (car more-phones)) ; the tag + (car (cdr (car more-phones)))) ; the number + ) + (setq bare nil) + (setq more-phones (cdr more-phones))) + + ;; output BBDB email-addresses + (while net + (insert (format "%s\t" (car net))) + (setq bare nil) + (setq net (cdr net))) + + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + + (while notes + (let ((thisnote (car notes))) + (if (bbdb-field-shown-p (car thisnote)) + (progn + (setq bare nil) + (if (eq 'notes (car thisnote)) + (insert (format "Notes: %s\t" (boh-mangle-if-multi-line (cdr thisnote)))) + (insert (format "Note [%s]: %s\t" + (symbol-name (car thisnote)) + (boh-mangle-if-multi-line (cdr thisnote)))))))) + (setq notes (cdr notes))) + + (setq hp-note (buffer-string))) + + ;; HP 200LX notes field (32K for the entire record) + (if (> (length hp-note) 0) + (progn + (insert (format "\"%s\"" hp-note)) + (setq bare nil))) + ) + + ;; If record is bare, delete anything we may have inserted. + ;; otherwise, mark the end of this record. + (if (and bare bbdb-hp200lx-output-no-bare-names) + (delete-region begin (point)) + (insert "
\n")) ; HP 200LX end of record + )) + + ;; return current letter + current-letter)) + + +(defun boh-maybe-truncate (string maxlen) + "If STRING is longer than MAXLEN, returns a truncated version." + (if (> (length string) maxlen) + (substring string 0 maxlen) + string)) + + +(defun boh-mangle-if-multi-line (string) + "If STRING is has multiple lines, mangle it for output to HP200LX" + (if (string-match "\n" string) + (string-replace-regexp string "\n" "\t") ; tabs are used to denote new lines in the .cdf file + string)) diff --git a/bits/bbdb-filters/bbdb-passwd.el b/bits/bbdb-filters/bbdb-passwd.el new file mode 100644 index 0000000..74dc8fd --- /dev/null +++ b/bits/bbdb-filters/bbdb-passwd.el @@ -0,0 +1,192 @@ +;;; This file is part of the BBDB Filters Package. BBDB Filters Package is a +;;; collection of input and output filters for BBDB. +;;; +;;; Copyright (C) 1995 Neda Communications, Inc. +;;; Prepared by Mohsen Banan (mohsen@neda.com) +;;; +;;; This library is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU Library General Public License as +;;; published by the Free Software Foundation; either version 2 of the +;;; License, or (at your option) any later version. This library is +;;; distributed in the hope that it will be useful, but WITHOUT ANY +;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +;;; License for more details. You should have received a copy of the GNU +;;; Library General Public License along with this library; if not, write +;;; to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +;;; USA. + +;;; This is bbdb-passwd.el + +;;; This file is a bbdb filter. It converts passwd files to the +;;; canonical bbdb input filter format (i.e., a file of +;;; bif-create-record expressions + + +(defvar bpf-default-bif-file "~/passwd-bif.el" + "*Default file name for bbdb-passwd-input.") + + +(defvar bpf-default-domain-name (if (boundp '*eoe-site-name*) *eoe-site-name*) + "*Default domain name for bbdb-passwd-input.") + + +(defvar bpf-default-org-name (if (boundp 'gnus-local-organization) gnus-local-organization + bpf-default-domain-name) + "*Default organization name for bbdb-passwd-input.") + + +(defvar bpf-omit-uid-limit 100 + "Skip UIDs below this value. Default is 100.") + +(defvar bpf-omit-user-name-regexp "\\(sl-\\\|guest\\)" + "Skip usernames that match this regular expression. +E.g., \"\\\\(sl-\\\\\\|guest\\\\)\" +") + +(defvar bpf-omit-user-name-list '("nobody" "noaccess") + "Skip usernames in this list. +E.g., '(\"noaccess\" \"nobody\") +") + +(defvar bpf-omit-pretty-name-regexp "\\(Slip \\\|Listserv\\\|PPP\\)" + "Skip pretty names that match this regular expression. +E.g., \"\\\\(Slip \\\\\\|Listserv\\\\\\|PPP\\\\)\" +") + +(defvar bpf-omit-pretty-name-list '() + "Skip pretty names that match this regular expression. +E.g., '(\"John Q. Public\") +") + + +(defun bbdb-passwd-input (domain-name org-name to-file) + "Parse current buffer which contains a UNIX passwd file to generate a .bif format file" + (interactive (list (setq bpf-default-domain-name (read-string "Domain name: " + bpf-default-domain-name)) + (setq bpf-default-org-name (read-string "Organization name: " + bpf-default-org-name)) + (setq bpf-default-bif-file + (read-file-name "Output To File: " + (concat + (file-name-directory bpf-default-bif-file) + (concat "bif-" bpf-default-domain-name ".el")) + (concat + (file-name-directory bpf-default-bif-file) + (concat "bif-" bpf-default-domain-name ".el")))))) + (let (to-buffer) + (save-excursion + (message (expand-file-name to-file)) + (set-buffer (find-file (expand-file-name to-file))) + (delete-region (point-min) (point-max)) + (bif-buffer-insert-header) + (setq to-buffer (current-buffer))) + + ;; walk the passwd file in the current buffer + (goto-char (point-min)) + (while (not (eobp)) + (beginning-of-line) + (bpf-parse-line domain-name org-name to-buffer) + (forward-line 1)) + + (message "Done.") + (set-buffer to-buffer) + )) + + +(defun bif-buffer-insert-header () + (insert "(require 'bbdb-passwd)\n\n")) + + +(defun bif-buffer-insert-record (pretty-name org-name email) + (insert (format "(bif-create-record")) + + (insert (format " \"%s\"" pretty-name)) ; NAME string + + (insert (format " \"%s\"" org-name)) ; COMPANY is a string or nil + + (insert (format " \"%s\"" email)) ; NET is a comma-separated list of email address, + ; or a list of strings + + ;; (insert " nil") ; ADDRS is a list of address objects. + ; An address is a vector of the form + ; ["location" "line1" "line2" "line3" "City" "State" zip] + + ;; (insert " nil") ; PHONES is a list of phone-number objects. + ; A phone-number is a vector of the form + ; ["location" areacode prefix suffix extension-or-nil] + ; or + ; ["location" "phone-number"] + + ;; (insert " nil") ; NOTES is a string, or an alist associating symbols with + ; strings. + + (insert ")\n") + ) + +(defun bpf-parse-line (domain-name org-name to-buffer) + "Parse the passwd file line. Point is assumed to be at the beginning of line." + (let (record-string uid user-name pretty-name email) + (setq record-string (buffer-substring (point) + (progn (end-of-line) (point)))) + + (message "Processing record: %s" record-string) + + ;; (setq record-string "mohsen:x:100:10:Mohsen Banan:/home/arash/mohsen:/bin/csh") + + ;; check for a valid and qualifying uid on line, else skip + (cond ((and + ;; + ;; extract and test uid + ;; + (string-match "^\\w*:\\w*:\\([0-9]+\\):" record-string) + (setq uid (read (substring record-string + (match-beginning 1) + (match-end 1)))) + (>= uid bpf-omit-uid-limit) + ;; + ;; extract and test user name + ;; + (string-match "^\\([^:]+\\):" record-string) + (setq user-name (substring record-string (match-beginning 1) (match-end 1))) + (or (null bpf-omit-user-name-regexp) + (not (string-match bpf-omit-user-name-regexp user-name))) + (or (null bpf-omit-user-name-list) + (not (member user-name bpf-omit-user-name-list))) + ;; + ;; extract and test pretty name + ;; + (string-match "^[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]+\\):" record-string) + (setq pretty-name (substring record-string (match-beginning 1) (match-end 1))) + (or (null bpf-omit-pretty-name-regexp) + (not (string-match bpf-omit-pretty-name-regexp pretty-name))) + (or (null bpf-omit-pretty-name-list) + (not (member pretty-name bpf-omit-pretty-name-list))) + ) + + ;; synthesize email address + (setq email (concat user-name "@" domain-name)) + + ;; output bif record + (save-excursion + (set-buffer to-buffer) + (bif-buffer-insert-record pretty-name org-name email) + ) + ) + (t + ;; not a valid line, skip + nil)) + )) + +(defun bif-create-record (name company net &optional addrs phones notes) + "Try to add a record to BBDB; if one does not already exist." + (condition-case err + (progn + (bbdb-create-internal name company net addrs phones notes) + (message "%s <%s> added." name net)) + (error (message "%s" (car (cdr err))) + (sleep-for 1)))) + + +(provide 'bbdb-passwd) + diff --git a/bits/bbdb-filters/bbdb-ph.el b/bits/bbdb-filters/bbdb-ph.el new file mode 100644 index 0000000..fc21502 --- /dev/null +++ b/bits/bbdb-filters/bbdb-ph.el @@ -0,0 +1,253 @@ +;;; This file is part of the BBDB Filters Package. BBDB Filters Package is a +;;; collection of input and output filters for BBDB. +;;; +;;; Copyright (C) 1995 Neda Communications, Inc. +;;; Prepared by Mohsen Banan (mohsen@neda.com) +;;; +;;; This library is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU Library General Public License as +;;; published by the Free Software Foundation; either version 2 of the +;;; License, or (at your option) any later version. This library is +;;; distributed in the hope that it will be useful, but WITHOUT ANY +;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +;;; License for more details. You should have received a copy of the GNU +;;; Library General Public License along with this library; if not, write +;;; to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +;;; USA. +;;; +;;; This is bbdb-ph.el +;;; +;;; +;;; RCS: bbdb-ph.el,v 1.1.1.1 1995/08/07 08:43:08 mohsen Exp +;;; +;;; a copy-and-edit job on bbdb-print.el + + +;;; To use this, add the following to your .emacs +;;; and strip ";;;XXX" +;;; + +;;;XXX;; BBDB PH Filter +;;;XXX(load "bbdb-ph") + +;;;XXX(setq bbdb-ph-filename +;;;XXX (concat "/dos/u/" (user-login-name) "/bb-phone.cdf")) +;;;XXX;;; - to output the *BBDB* buffer in PH tab-delimited-file (.CDF) +;;;XXX;;; format, invoke M-x bbdb-ph-output +;;;XXX;;; +;;;XXX;;; - you may also want to modify default values of the following (use +;;;XXX;;; M-x describe-variable for details): +;;;XXX;;; bbdb-ph-output-elide +;;;XXX;;; bbdb-ph-output-requires +;;;XXX;;; bbdb-ph-output-no-bare-names + + +(require 'bbdb-print) +(require 'basic-ext) + + +(defvar bbdb-ph-filename "~/data.out" + "*Default file name for bbdb-output-ph printouts of BBDB database.") + + +(defvar bbdb-ph-output-elide '(creation-date timestamp mail-alias) + "*List of symbols denoting BBDB fields NOT to be output. +Valid symbols are: name comp net phones addrs. You can also use the +tags for notes (e.g., creation-date). + e.g.: '(net creation-date) +See also variable bbdb-ph-output-requires.") + + +(defvar bbdb-ph-output-requires '(and name net) + "*A boolean expression of 'and' and 'or' to be evaluated to determine if +the current record should be output. Valid symbols for use +in the boolean expression are: name comp net phones addrs notes. + e.g.: (and name (or comp addrs)) +See also variable bbdb-ph-output-elide. +") + + +(defvar bbdb-ph-output-no-bare-names t + "*A bare name is one with no information other than +that in bbdb-ph-output-requires. To avoid printing +these set this variable to t") + + +(defun bbdb-ph-output (to-file) + "Print the selected BBDB entries" + (interactive (list (read-file-name "Print To File: " bbdb-ph-filename))) + (setq bbdb-ph-filename (expand-file-name to-file)) + (let ((current-letter t) + (records (progn (set-buffer bbdb-buffer-name) + bbdb-records))) + (find-file bbdb-ph-filename) + (delete-region (point-min) (point-max)) + (while records + (setq current-letter + (boph-maybe-format-record (car (car records)) current-letter)) + (setq records (cdr records))) + (goto-char (point-min)) + (message "PH tag and tab-delimited file %s generated." bbdb-ph-filename))) + + +(defun boph-maybe-format-record (record &optional current-letter brief) + "Insert the bbdb RECORD in Ph format. +Optional CURRENT-LETTER is the section we're in -- if this is non-nil and +the first letter of the sortkey of the record differs from it, a new section +heading will be output \(an arg of t will always produce a heading). +The new current-letter is the return value of this function. +Someday, optional third arg BRIEF will produce one-line format." + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "plus ungood: formatting deleted record"))) + + (let* ((bbdb-elided-display bbdb-ph-output-elide) + (first-letter + (substring (concat (bbdb-record-sortkey record) "?") 0 1)) + (name (and (bbdb-field-shown-p 'name) + (or (bbdb-record-getprop record 'tex-name) + (bbdb-record-name record)))) + (comp (and (bbdb-field-shown-p 'company) + (bbdb-record-company record))) + (net (and (bbdb-field-shown-p 'net) + (bbdb-record-net record))) + (phones (and (bbdb-field-shown-p 'phone) + (bbdb-record-phones record))) + (addrs (and (bbdb-field-shown-p 'address) + (bbdb-record-addresses record))) + (notes (bbdb-record-raw-notes record)) + (begin (point)) + (bare t) + ph-name ph-email ph-office-phone ph-skypager ph-portable + ph-title-notes-part + saved-case-fold) + + + ;; Section header, if neccessary. + + (if (and current-letter (not (string-equal first-letter current-letter))) + (message "Now processing \"%s\" entries..." (upcase first-letter))) + + + (if (eval bbdb-ph-output-requires) + (progn + + ;; ============================================================= + ;; grovel through BBDB record collecting ph-relevant information + ;; ============================================================= + + ;; grovel through name + ;; + (setq ph-name name) + + ;; grovel through phone numbers + ;; + (progn + (setq saved-case-fold case-fold-search + case-fold-search t) + (while phones + (let ((place (aref (car phones) 0)) + (number (bbdb-phone-string (car phones)))) + (cond ((or (string-match place "office") + (string-match place "work")) + (if (null ph-office-phone) + (setq ph-office-phone number))) + ((or (string-match place "mobile") + (string-match place "cellular")) + (if (null ph-portable) + (setq ph-portable number))) + (t nil))) + (setq phones (cdr phones))) + + + (setq case-fold-search saved-case-fold) + ) + + ;; grovel through BBDB email-addresses + ;; + (if net + (setq ph-email (car net))) + + ;; grovel through BBDB Notes + ;; + (progn + + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + + (while notes + (let ((curr-note (car notes))) + (if (bbdb-field-shown-p (car curr-note)) + (cond ((member (car curr-note) '(skypage pager)) + (setq ph-skypager (boph-mangle-if-multi-line (cdr curr-note)))) + ((equal (car curr-note) 'mobile) + (setq ph-portable (boph-mangle-if-multi-line (cdr curr-note)))) + ((equal (car curr-note) 'notes) + (setq ph-title-notes-part (boph-mangle-if-multi-line (cdr curr-note)))) + (t nil)) + )) + (setq notes (cdr notes))) + ) + + ;; grovel through comp + ;; + (setq ph-title-coname-part comp) + (setq ph-title (concat (or ph-title-coname-part "") + (if (and ph-title-coname-part ph-title-notes-part) " " "") + (if ph-title-notes-part (concat "[" ph-title-notes-part "]") ""))) + + ;; ==================== + ;; now output PH record + ;; ==================== + + ;; PH 'name' field (maxlen 256) + ;; + (insert (format "3:%s\t" (boph-maybe-truncate (or name "") 256))) + + ;; PH 'email' field (maxlen 25) (should be 128?) ** NOT YET ** + (if ph-email (setq bare nil)) + (insert (format "2:%s\t" (boph-maybe-truncate (or ph-email "") 25))) + + ;; PH 'office_phone' field (max len 60) + ;; + (if ph-office-phone (setq bare nil)) + (insert (format "32:%s\t" (boph-maybe-truncate (or ph-office-phone "") 60))) + + ;; PH 'title' field (maxlen 120) + (insert (format "98:%s\t" (boph-maybe-truncate ph-title 120))) + + ;; PH 'portable' field (maxlen 60) + (if ph-portable (setq bare nil)) + (insert (format "97:%s\t" (boph-maybe-truncate (or ph-portable "") 60))) + + ;; PH 'skypager' field (maxlen 64) + (if ph-skypager (setq bare nil)) + (insert (format "27:%s\t" (boph-maybe-truncate (or ph-skypager "") 64))) + + ;; ========== + ;; bare check + ;; ========== + + ;; If record is bare, delete anything we may have inserted. + ;; otherwise, mark the end of this record. + (if (and bare bbdb-ph-output-no-bare-names) + (delete-region begin (point)) + (insert "\n")) ; PH end of record + )) + + ;; return current letter + current-letter)) + + +(defun boph-maybe-truncate (string maxlen) + "If STRING is longer than MAXLEN, returns a truncated version." + (if (> (length string) maxlen) + (substring string 0 maxlen) + string)) + + +(defun boph-mangle-if-multi-line (string) + "If STRING is has multiple lines, mangle it for output to PH" + (if (string-match "\n" string) + (string-replace-regexp string "\n" "\t") ; tabs are used to denote new lines in the .cdf file + string)) diff --git a/bits/bbdb-filters/doc/formatted/bbdb-filters.info b/bits/bbdb-filters/doc/formatted/bbdb-filters.info new file mode 100644 index 0000000..c66edef --- /dev/null +++ b/bits/bbdb-filters/doc/formatted/bbdb-filters.info @@ -0,0 +1,1101 @@ +Info file: bbdb-filters.info, -*-Text-*- +produced by latexinfo-format-buffer +from file: main.tex + + + +File: bbdb-filters.info Node: Top, Prev: (dir), Up: (dir), Next: Introduction + +{BBDB Filters} + +{6} + +Copyright (C)1995 NEDA COMMUNICATIONS, INC. + + +* Menu: + +* Introduction:: +* Output Filters:: +* Input Filters:: +* Miscellany:: +* GNU LIBRARY GENERAL PUBLIC LICENSE:: +* Concept Index:: +* Command Index:: + + --- The Detailed Node Listing --- + +Introduction + +* About This Package:: +* About This Manual:: + +Output Filters + +* HP 200LX Phone Book:: +* PC Eudora:: +* Lotus cc:Mail Nicknames:: +* PH:: +* Emacs Lisp Export:: + +PC Eudora + +* PC Eudora Nickname Database:: +* PC Eudora Recipient Database:: + +Input Filters + +* General Facilities for Input Filtering:: +* UNIX Password Files:: + +Miscellany + +* TODO List:: +* Credits:: + +GNU LIBRARY GENERAL PUBLIC LICENSE + +* Preamble:: +* TERMS AND CONDITIONS FOR COPYING:: * +* NO WARRANTY:: +* END OF TERMS AND CONDITIONS:: +* How to Apply These Terms to Your New Libraries:: + + + +File: bbdb-filters.info Node: Introduction, Prev: Top, Up: Top, Next: Output Filters + +Introduction +************ + + +Over time much valuable data has been gathered in BBDB database files. +Many wish to share parts or all of this information with others. They +also wish to have access to this same information from other systems +(like personal digital assistants) lacking straightforward BBDB +access. + +For these reasons, we have prepared a family of filters that convert +the information in BBDB to and from a variety of other +formats. "Output filters" export BBDB information to other formats +while "input filters" import information from other formats into +BBDB. + +Our hope is that over time this collection of BBDB filters will grow +through contributed code. + + +* Menu: + +* About This Package:: +* About This Manual:: + + + +File: bbdb-filters.info Node: About This Package, Prev: Introduction, Up: Introduction, Next: About This Manual + +About This Package +================== + + +This package is a collection of filters and is called "BBDB Input and +Output Filters". It has been somewhat tested with BBDB version 1.50. +The present state of the software is still preliminary although it has +proved useful. + + +File: bbdb-filters.info Node: About This Manual, Prev: About This Package, Up: Introduction + +About This Manual +================= + + +This documentation applies to Version 0.2 of the "BBDB Input and +Output Filters" package. The documentation is presently skeletal and +very preliminary. It mostly provides the user with instructions for +use, and very little background is included. Familiarity with Emacs +Lisp is assumed for some sections. + + +File: bbdb-filters.info Node: Output Filters, Prev: Introduction, Up: Top, Next: Input Filters + +Output Filters +************** + + +"Output filters" are used to export BBDB information into formats +used by other systems. + +In general, an output filter uses the contents of your +`*BBDB*' buffer as input. Note that output filters do not use +BBDB files (typically ``~/.bbdb'') directly. + +An output filter is invoked by executing its associated lisp function. +The name of the function is conventionally named `bbdb-<system>-output' +(e.g., `M-x bbdb-hp200lx-output'). + +The result of running an output filter is to create a new buffer that +contains the `*BBDB*' information appropriately transformed into a +format suitable for use by the target system. The new buffer is given +a file name that you specify. + + +* Menu: + +* HP 200LX Phone Book:: +* PC Eudora:: +* Lotus cc:Mail Nicknames:: +* PH:: +* Emacs Lisp Export:: + + + +File: bbdb-filters.info Node: HP 200LX Phone Book, Prev: Output Filters, Up: Output Filters, Next: PC Eudora + +HP 200LX Phone Book +=================== + + +This package has only been tested on HP 200LX palmtop systems. It +also requires the "HP 200LX Connectivity Pack" for converting +comma-delimited ASCII files into binary .PDB files which are read by +the HP 200LX Phone Book application. Version 1.00 of the "HP 200LX +Connectivty Pack" was used for testing. + +The HP 200LX output filter is in file `bbdb-hp200lx.el'. + + + + 1. Invoke `M-x bbdb' to populate the `*BBDB*' buffer + with the contents you wish to export. + + 2. Invoke ` bbdb-hp200lx-output' to create an ASCII .CDF + (Comma Delimited File). + + 3. Using Xlate/Merge option of HP Connectivity Pack convert the + .CDF file into a binary .PDB file used by the Phone Book program. + + 4. Download the .PDB file to your palmtop's internal disk and + ensure that the Phone Book program is set use the newly downloaded + .PDB file. + + + + +File: bbdb-filters.info Node: PC Eudora, Prev: HP 200LX Phone Book, Up: Output Filters, Next: Lotus cc:Mail Nicknames + +PC Eudora +========= + + +BBDB information can be exported to PC Eudora in two formats--as a +nickname database file and as a recipients database file. + +The PC Eudora output filter is in file `bbdb-eudora.el'. + +* Menu: + +* PC Eudora Nickname Database:: +* PC Eudora Recipient Database:: + + + +File: bbdb-filters.info Node: PC Eudora Nickname Database, Prev: PC Eudora, Up: PC Eudora, Next: PC Eudora Recipient Database + +PC Eudora Nickname Database +--------------------------- + + + + 1. Invoke `M-x bbdb' to populate the `*BBDB*' buffer + with the contents you wish to export. + + 2. Invoke `bbdb-eudora-nndbase-output' to create a PC Eudora + Nickname database file. + + 3. Make the file accessible to PC Eudora. + + + + +File: bbdb-filters.info Node: PC Eudora Recipient Database, Prev: PC Eudora Nickname Database, Up: PC Eudora + +PC Eudora Recipient Database +---------------------------- + + + + 1. Invoke `M-x bbdb' to populate the `*BBDB*' buffer + with the contents you wish to export. + + 2. Invoke `bbdb-eudora-rcpdbase-output' to create a PC Eudora + recipient's database file. + + 3. Make the file accessible to PC Eudora. + + + + +File: bbdb-filters.info Node: Lotus cc:Mail Nicknames, Prev: PC Eudora, Up: Output Filters, Next: PH + +Lotus cc:Mail Nicknames +======================= + + +The Lotus cc:Mail output filter is in file `bbdb-ccmail.el'. + + + 1. Invoke `M-x bbdb' to populate the `*BBDB*' buffer + with the contents you wish to export. + + 2. Invoke ` bbdb-ccmail-output' to create a cc:Mail Nicknames file. + + 3. Make the file accessible to cc:Mail. + + + + +File: bbdb-filters.info Node: PH, Prev: Lotus cc:Mail Nicknames, Up: Output Filters, Next: Emacs Lisp Export + +PH +== + + +The PH output filter is in file `bbdb-ph.el'. + + + 1. Invoke `M-x bbdb' to populate the `*BBDB*' buffer + with the contents you wish to export. + + 2. Invoke `bbdb-ph-output' to create a `ph' data file for + use with the `maked' program. + + 3. Make the file accessible to `ph'. + + + + +File: bbdb-filters.info Node: Emacs Lisp Export, Prev: PH, Up: Output Filters + +Emacs Lisp Export +================= + + +The Emacs Lisp Export output filter is in file `bbdb-export.el'. + +This output filter uses the current contents of your +`*BBDB*' buffer to generate a new buffer (`*BBDB* Export') +that contains a single lisp `(progn ...)' expression. For +example, a `*BBDB*' buffer containing two records would result in +the following `*BBDB* Export' buffer: + + + ;;; ======= Start of Exported BBDB Records ======= + (progn + (require 'bbdb-com) + (defun bbdb-maybe-create (name company net &optional addrs phones notes) + "Try to add a record to BBDB if it does not already exist." + (condition-case err + (progn + (bbdb-create-internal name company net addrs phones notes) + (message "%s %s added." name (if net (concat "<" net ">") "")) + (sleep-for 1)) + (error (ding) + (message "%s %s skipped. (%s)" + name + (if net (concat "<" net ">") "") + (car (cdr err))) + (sleep-for 1)))) + + (bbdb-maybe-create "Jill Doe--IMPORTED" + "CBS Corporation" + '("jilld@cbs.com") + '( + ["Home" + "368 222ND PL" + "" + "" + "Springfield" + "MA" 2117] + ) + '( + ["Office" 617 555 9983 0] + ) '"Movie Mogul") + (bbdb-maybe-create "John Doe--IMPORTED" + "ABC Incorporated" + '("jdoe@abc.com") + '( + ["Office" + "123 Any Street" + "" + "" + "Any Town" + "WA" (98027 7758)] + ) + '( + ["Office" 206 555 1234 0] + ) '"TV Producer") + ) + ;;; ======= End of Exported BBDB Records ======= + + +This lisp expression can then be sent via email or some other +text-based messaging facility to another user who can then evaluate +the expression which will add the `BBDB' records to the +recipient's +`BBDB' database. + +Only new records are added. A record with the same name or net +address as one already existing in the `BBDB' is skipped +entirely. + +In the sample contents of a `*BBDB* Export' buffer presented, two +records are being exported--one for "John Doe" and the other for +"Jill Doe". Notice that their names have been appended with +`--IMPORTED'. This string can be used to quick locate each record +that is added to the database using this mechanism. + +The following steps are for exporting BBDB records into Emacs Lisp: + + + 1. Invoke `M-x bbdb' to populate the `*BBDB*' buffer + with the contents you wish to export. + + 2. Invoke `bbdb-export' to create a `*BBDB* Export' buffer which contains a + single `(progn ...)' can be evaluated to add the records to the + existing `BBDB' database (if the records do not already exist). + + 3. Use the contents of `*BBDB* Export' in email and other messaging systems. + + + +The following steps are for a user wishing to import the contents of a +`*BBDB* Export' buffer's expression into his or her own database: + + + 1. Evaluate the region bounded by the lines + `;;; ======= Start of Exported BBDB Records =======' + and + `;;; ======= End of Exported BBDB Records ======='. + You can use such commands as + `M-x eval-region' or `M-x eval-last-sexp'. + + 2. Review the newly imported entries. To see them, invoke `M-x + bbdb' and specify `--IMPORTED' at the `Regular Expression' + prompt. + + 3. After reviewing the contents of the imported records, you may + wish to remove the `--IMPORTED' that is appended to the name by + `bbdb-export'. + + + + +File: bbdb-filters.info Node: Input Filters, Prev: Output Filters, Up: Top, Next: Miscellany + +Input Filters +************* + + +"Input filters" are used to import into BBDB information from a +foreign system's data file. + +The name of the function is conventionally named +`bbdb-<system>-input' (e.g., `bbdb-passwd-input' is the name +of the Emacs Lisp function for the UNIX password file input filter). + +In general, an "input filter" expects the foreign system's data to +be in the current buffer. The contents of the current buffer are used +to create an Emacs Lisp file which when loaded will add new records +into your BBDB database if they don't yet exist--existing BBDB records +will not be modified. + + +* Menu: + +* General Facilities for Input Filtering:: +* UNIX Password Files:: + + + +File: bbdb-filters.info Node: General Facilities for Input Filtering, Prev: Input Filters, Up: Input Filters, Next: UNIX Password Files + +General Facilities for Input Filtering +====================================== + + +The result of running an input filter is to produce a new buffer a +series of `bif-create-record' +expressions, each corresponding to a single user's record. Notice +that input filters do not directly modify the contents of the BBDB +files (typically ``~/.bbdb''). + +To actually modify the contents of the BBDB database, you must +evaluated the expressions in the resultant buffer created by the input +filter. One way to do so is simply to invoke `M-x eval-buffer'. +Another way is to simply save the buffer to disk and load its contents +into Emacs Lisp using `M-x load-file'. + + +File: bbdb-filters.info Node: UNIX Password Files, Prev: General Facilities for Input Filtering, Up: Input Filters + +UNIX Password Files +=================== + + +The UNIX password file input filter is in file `bbdb-passwd.el'. + + + 1. Use `M-x find-file' to visit the UNIX password file you wish to import. + + 2. With the password file in the current buffer, invoke the input + filter `M-x bbdb-passwd-input'. You will be prompted for the + domain name associated with that host's password file; an organization + name; as well as the file name to be associated with the buffer of + `bif-create-record' expressions. + + 3. Evaluate the contents of the input filter's buffer to add records + into your BBDB database file. + + + + +File: bbdb-filters.info Node: Miscellany, Prev: Input Filters, Up: Top, Next: GNU LIBRARY GENERAL PUBLIC LICENSE + +Miscellany +********** + + + +* Menu: + +* TODO List:: +* Credits:: + + + +File: bbdb-filters.info Node: TODO List, Prev: Miscellany, Up: Miscellany, Next: Credits + +TODO List +========= + + + + * Move generic input filter functionality out of + `bbdb-passwd.el' and into, say, `bbdb-ifilt.el'. + The generic functionality code has names typically prefixed with `bif-'. + + * Add support for `gdbload' (as an alternative to the + Xlate/Merge application provided in the HP 200LX Connectivity Pack) + into the HP 200LX output filter. This is based on input from Robert + Nicholson `<robert@steffi.dircon.co.uk>'. + + * Add documentation for variables in the various input and output filters. + + * Check and document all dependencies on other packages. + + + + +File: bbdb-filters.info Node: Credits, Prev: TODO List, Up: Miscellany + +Credits +======= + + +Pean Lim `<pean@neda.com>' wrote most of this package. Mohsen +Banan `<mohsen@neda.com>' put it all together and guided the +work. Neda Communications, Inc. sponsored the work. The output +filters code is based on `bbdb-print' by Boris Goldowsky +`<boris@prodigal.psych.rochester.edu>'. + + + +File: bbdb-filters.info Node: GNU LIBRARY GENERAL PUBLIC LICENSE, Prev: Miscellany, Up: Top, Next: Concept Index + +GNU LIBRARY GENERAL PUBLIC LICENSE +********************************** + + + Version 2, June 1991 + + + + Copyright (C) 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + [This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + + +* Menu: + +* Preamble:: +* TERMS AND CONDITIONS FOR COPYING:: * +* NO WARRANTY:: +* END OF TERMS AND CONDITIONS:: +* How to Apply These Terms to Your New Libraries:: + + + +File: bbdb-filters.info Node: Preamble, Prev: GNU LIBRARY GENERAL PUBLIC LICENSE, Up: GNU LIBRARY GENERAL PUBLIC LICENSE, Next: TERMS AND CONDITIONS FOR COPYING + +Preamble +======== + + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software---to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + + + 1. This License Agreement applies to any software library which + contains a notice placed by the copyright holder or other authorized + party saying it may be distributed under the terms of this Library + General Public License (also called "this License"). Each licensee is + addressed as "you". + + A "library" means a collection of software functions and/or data + prepared so as to be conveniently linked with application programs + (which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work + which has been distributed under these terms. A "work based on the + Library" means either the Library or any derivative work under + copyright law: that is to say, a work containing the Library or a + portion of it, either verbatim or with modifications and/or translated + straightforwardly into another language. (Hereinafter, translation is + included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for + making modifications to it. For a library, complete source code means + all the source code for all modules it contains, plus any associated + interface definition files, plus the scripts used to control compilation + and installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running a program using the Library is not restricted, and output from + such a program is covered only if its contents constitute a work based + on the Library (independent of the use of the Library in a tool for + writing it). Whether that is true depends on what the Library does + and what the program that uses the Library does. + + 2. You may copy and distribute verbatim copies of the Library's + complete source code as you receive it, in any medium, provided that + you conspicuously and appropriately publish on each copy an + appropriate copyright notice and disclaimer of warranty; keep intact + all the notices that refer to this License and to the absence of any + warranty; and distribute a copy of this License along with the + Library. + + You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange for a + fee. + + 3. You may modify your copy or copies of the Library or any portion + of it, thus forming a work based on the Library, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + 1. The modified work must itself be a software library. + + 2. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + 3. You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + 4. If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Library, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote + it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 4. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so + that they refer to the ordinary GNU General Public License, version 2, + instead of to this License. (If a newer version than version 2 of the + ordinary GNU General Public License has appeared, then you can specify + that version instead if you wish.) Do not make any other change in + these notices. + + Once this change is made in a given copy, it is irreversible for + that copy, so the ordinary GNU General Public License applies to all + subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of + the Library into a program that is not a library. + + 5. You may copy and distribute the Library (or a portion or + derivative of it, under Section 2) in object code or executable form + under the terms of Sections 1 and 2 above provided that you accompany + it with the complete corresponding machine-readable source code, which + must be distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy + from a designated place, then offering equivalent access to copy the + source code from the same place satisfies the requirement to + distribute the source code, even though third parties are not + compelled to copy the source along with the object code. + + 6. A program that contains no derivative of any portion of the + Library, but is designed to work with the Library by being compiled or + linked with it, is called a "work that uses the Library". Such a + work, in isolation, is not a derivative work of the Library, and + therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library + creates an executable that is a derivative of the Library (because it + contains portions of the Library), rather than a "work that uses the + library". The executable is therefore covered by this License. + Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file + that is part of the Library, the object code for the work may be a + derivative work of the Library even though the source code is not. + Whether this is true is especially significant if the work can be + linked without the Library, or if the work is itself a library. The + threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data + structure layouts and accessors, and small macros and small inline + functions (ten lines or less in length), then the use of the object + file is unrestricted, regardless of whether it is legally a derivative + work. (Executables containing this object code plus portions of the + Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may + distribute the object code for the work under the terms of Section 6. + Any executables containing that work also fall under Section 6, + whether or not they are linked directly with the Library itself. + + 7. As an exception to the Sections above, you may also compile or + link a "work that uses the Library" with the Library to produce a + work containing portions of the Library, and distribute that work + under terms of your choice, provided that the terms permit + modification of the work for the customer's own use and reverse + engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the + Library is used in it and that the Library and its use are covered by + this License. You must supply a copy of this License. If the work + during execution displays copyright notices, you must include the + copyright notice for the Library among them, as well as a reference + directing the user to the copy of this License. Also, you must do one + of these things: + + 1. Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + 2. Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + 3. If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + 4. Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + + For an executable, the required form of the "work that uses the + Library" must include any data and utility programs needed for + reproducing the executable from it. However, as a special exception, + the source code distributed need not include anything that is normally + distributed (in either source or binary form) with the major + components (compiler, kernel, and so on) of the operating system on + which the executable runs, unless that component itself accompanies + the executable. + + It may happen that this requirement contradicts the license + restrictions of other proprietary libraries that do not normally + accompany the operating system. Such a contradiction means you cannot + use both them and the Library together in an executable that you + distribute. + + 8. You may place library facilities that are a work based on the + Library side-by-side in a single library together with other library + facilities not covered by this License, and distribute such a combined + library, provided that the separate distribution of the work based on + the Library and of the other library facilities is otherwise + permitted, and provided that you do these two things: + + 1. Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + 2. Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + + 9. You may not copy, modify, sublicense, link with, or distribute + the Library except as expressly provided under this License. Any + attempt otherwise to copy, modify, sublicense, link with, or + distribute the Library is void, and will automatically terminate your + rights under this License. However, parties who have received copies, + or rights, from you under this License will not have their licenses + terminated so long as such parties remain in full compliance. + + 10. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Library or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Library (or any work based on the + Library), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Library or works based on it. + + 11. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the + original licensor to copy, distribute, link with or modify the Library + subject to these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 12. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Library at all. For example, if a patent + license would not permit royalty-free redistribution of the Library by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Library. + + If any portion of this section is held invalid or unenforceable under any + particular circumstance, the balance of the section is intended to apply, + and the section as a whole is intended to apply in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 13. If the distribution and/or use of the Library is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Library under this License may add + an explicit geographical distribution limitation excluding those countries, + so that distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation as if + written in the body of this License. + + 14. The Free Software Foundation may publish revised and/or new + versions of the Library General Public License from time to time. + Such new versions will be similar in spirit to the present version, + but may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and + "any later version", you have the option of following the terms and + conditions either of that version or of any later version published by + the Free Software Foundation. If the Library does not specify a + license version number, you may choose any version ever published by + the Free Software Foundation. + + 15. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, + write to the author to ask for permission. For software which is + copyrighted by the Free Software Foundation, write to the Free + Software Foundation; we sometimes make exceptions for this. Our + decision will be guided by the two goals of preserving the free status + of all derivatives of our free software and of promoting the sharing + and reuse of software generally. + + + NO WARRANTY + + + + 16. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO + WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR + OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE + LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME + THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 17. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY + AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU + FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE + LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING + RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A + FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF + SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + DAMAGES. + + + + END OF TERMS AND CONDITIONS + + + + + +File: bbdb-filters.info Node: How to Apply These Terms to Your New Libraries, Prev: END OF TERMS AND CONDITIONS, Up: GNU LIBRARY GENERAL PUBLIC LICENSE + +How to Apply These Terms to Your New Libraries +============================================== + + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + ONE LINE TO GIVE THE LIBRARY'S NAME AND AN IDEA OF WHAT IT DOES. + Copyright (C) YEAR NAME OF AUTHOR + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + MA 02139, USA. + + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + + Yoyodyne, Inc., hereby disclaims all copyright interest in + the library `Frob' (a library for tweaking knobs) written + by James Random Hacker. + + SIGNATURE OF TY COON, 1 April 1990 + Ty Coon, President of Vice + + +That's all there is to it! + + + + +File: bbdb-filters.info Node: Concept Index, Prev: GNU LIBRARY GENERAL PUBLIC LICENSE, Up: Top, Next: Command Index + +Concept Index +************* + + + +* Menu: + +* About This Manual: About This Manual. +* About This Package: About This Package. +* .CDF file, HP 200LX Phone Book: HP 200LX Phone Book. +* Credits: Credits. +* Emacs Lisp Export: Emacs Lisp Export. +* General Facilities for Input Filtering: General Facilities for Input Filtering. +* GNU LIBRARY GENERAL PUBLIC LICENSE: GNU LIBRARY GENERAL PUBLIC LICENSE. +* How to Apply These Terms to Your New Libraries: How to Apply These Terms to Your New Libraries. +* HP 200LX Connectivity Pack: HP 200LX Phone Book. +* HP 200LX Phone Book: HP 200LX Phone Book. +* Input Filters: Input Filters. +* Introduction: Introduction. +* Lotus cc:Mail Nicknames: Lotus cc:Mail Nicknames. +* Miscellany: Miscellany. +* Output Filters: Output Filters. +* PC Eudora Nickname Database: PC Eudora Nickname Database. +* PC Eudora: PC Eudora. +* PC Eudora Recipient Database: PC Eudora Recipient Database. +* .PDF file, HP 200LX Phone Book: HP 200LX Phone Book. +* PH: PH. +* Preamble: Preamble. +* Sending BBDB records via email: Emacs Lisp Export. +* TODO List: TODO List. +* UNIX Password Files: UNIX Password Files. + + + + +File: bbdb-filters.info Node: Command Index, Prev: Concept Index, Up: Top + +Command Index +************* + + + +* Menu: + +* bbdb-ccmail-output: Lotus cc:Mail Nicknames. +* bbdb-eudora-nndbase-output: PC Eudora Nickname Database. +* bbdb-eudora-rcpdbase-output: PC Eudora Recipient Database. +* bbdb-export: Emacs Lisp Export. +* bbdb-hp200lx-output: HP 200LX Phone Book. +* bbdb-passwd-input: UNIX Password Files. +* bbdb-ph-output: PH. +* bif-create-record: General Facilities for Input Filtering. + + diff --git a/bits/bbdb-filters/doc/lgpl.tex b/bits/bbdb-filters/doc/lgpl.tex new file mode 100644 index 0000000..7427570 --- /dev/null +++ b/bits/bbdb-filters/doc/lgpl.tex @@ -0,0 +1,552 @@ +\c This LGPL is meant to be included from other files. +\c To format a standalone LGPL, use liblic.texi. + +\chapter{GNU LIBRARY GENERAL PUBLIC LICENSE} + +\begin{center} +Version 2, June 1991 +\end{center} + +\begin{example} +Copyright \copyright{} 1991 Free Software Foundation, Inc. +675 Mass Ave, Cambridge, MA 02139, USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] +\end{example} + +\section*{Preamble} + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software---to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +``work based on the library'' and a ``work that uses the library''. The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + +\begin{iftex} +\section*{TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION} +\end{iftex} +\begin{ifinfo} +\begin{center} +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +\end{center} +\end{ifinfo} + +\begin{enumerate} +\item +This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called ``this License''). Each licensee is +addressed as ``you''. + + A ``library'' means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The ``Library'', below, refers to any such software library or work +which has been distributed under these terms. A ``work based on the +Library'' means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term ``modification''.) + + ``Source code'' for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + +\item +You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + +\item +You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +\begin{enumerate} +\item +The modified work must itself be a software library. + +\item +You must cause the files modified to carry prominent notices +stating that you changed the files and the date of any change. + +\item +You must cause the whole of the work to be licensed at no +charge to all third parties under the terms of this License. + +\item +If a facility in the modified Library refers to a function or a +table of data to be supplied by an application program that uses +the facility, other than as an argument passed when the facility +is invoked, then you must make a good faith effort to ensure that, +in the event an application does not supply such function or +table, the facility still operates, and performs whatever part of +its purpose remains meaningful. + +(For example, a function in a library to compute square roots has +a purpose that is entirely well-defined independent of the +application. Therefore, Subsection 2d requires that any +application-supplied function or table used by this function must +be optional: if the application does not supply it, the square +root function must still compute square roots.) +\end{enumerate} + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +\item +You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + +\item +You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + +\item +A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a ``work that uses the Library''. Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a ``work that uses the Library'' with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a ``work that uses the +library''. The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a ``work that uses the Library'' uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +\item +As an exception to the Sections above, you may also compile or +link a ``work that uses the Library'' with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + +\begin{enumerate} +\item +Accompany the work with the complete corresponding +machine-readable source code for the Library including whatever +changes were used in the work (which must be distributed under +Sections 1 and 2 above); and, if the work is an executable linked +with the Library, with the complete machine-readable ``work that +uses the Library'', as object code and/or source code, so that the +user can modify the Library and then relink to produce a modified +executable containing the modified Library. (It is understood +that the user who changes the contents of definitions files in the +Library will not necessarily be able to recompile the application +to use the modified definitions.) + +\item +Accompany the work with a written offer, valid for at +least three years, to give the same user the materials +specified in Subsection 6a, above, for a charge no more +than the cost of performing this distribution. + +\item +If distribution of the work is made by offering access to copy +from a designated place, offer equivalent access to copy the above +specified materials from the same place. + +\item +Verify that the user has already received a copy of these +materials or that you have already sent this user a copy. +\end{enumerate} + + For an executable, the required form of the ``work that uses the +Library'' must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + +\item +You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + +\begin{enumerate} +\item +Accompany the combined library with a copy of the same work +based on the Library, uncombined with any other library +facilities. This must be distributed under the terms of the +Sections above. + +\item +Give prominent notice with the combined library of the fact +that part of it is a work based on the Library, and explaining +where to find the accompanying uncombined form of the same work. +\end{enumerate} + +\item +You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +\item +You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +\item +Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +\item +If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +\item +If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + +\item +The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +``any later version'', you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + +\item +If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +\begin{iftex} +\section*{NO WARRANTY} +\end{iftex} +\begin{ifinfo} +\begin{center} +NO WARRANTY +\end{center} +\end{ifinfo} + +\item +BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY ``AS IS'' WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +\item +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. +\end{enumerate} + +\begin{iftex} +\section*{END OF TERMS AND CONDITIONS} +\end{iftex} +\begin{ifinfo} +\begin{center} +END OF TERMS AND CONDITIONS +\end{center} +\end{ifinfo} + +\clearpage + +\section*{How to Apply These Terms to Your New Libraries} + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +``copyright'' line and a pointer to where the full notice is found. + +\begin{smallexample} +\var{one line to give the library's name and an idea of what it does.} +Copyright (C) \var{year} \var{name of author} + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the +Free Software Foundation, Inc., 675 Mass Ave, Cambridge, +MA 02139, USA. +\end{smallexample} + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a ``copyright disclaimer'' for the library, if +necessary. Here is a sample; alter the names: + +\begin{example} +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +\var{signature of Ty Coon}, 1 April 1990 +Ty Coon, President of Vice +\end{example} + +That's all there is to it! diff --git a/bits/bbdb-filters/doc/main.texinfo b/bits/bbdb-filters/doc/main.texinfo new file mode 100644 index 0000000..7edb948 --- /dev/null +++ b/bits/bbdb-filters/doc/main.texinfo @@ -0,0 +1,492 @@ +% This is really LaTeXInfo, but some time LaTeX mode is more useful -*- LaTeX -*- +% This is really LaTeXInfo, but some time LaTeX mode is more useful -*- Latexinfo -*- +% +% Revision: main.texinfo,v 1.1.1.1 1995/08/07 08:43:10 mohsen Exp +% +%\documentstyle[12pt,latexinfo,format,smallverb,tabular]{book} +%\documentstyle[12pt,latexinfo,format]{book} +\documentstyle[12pt,format,hyperlatex,latexinfo]{book} +%\documentstyle[12pt,times,latexinfo,format]{book} +%\documentstyle[12pt,avantgarde,latexinfo,format]{book} +%\documentstyle[12pt,palatino,latexinfo,format]{book} +%\documentstyle[10pt,avantgarde,latexinfo,format]{book} + +\pagestyle{empty} + +\c \input{transfig} \c Used with eepic -- not needed when using psfig. +\input{epsf} + +\begin{document} + +\c \bibliographystyle{alpha} \c [banan92] +\c \bibliographystyle{plain} \c Numbers [1] + +\c \textwidth 5.2in \c for .tty generation + +\htmldirectory{bbdbFilters} +\htmlname{bbdbFilters} +\htmltitle{BBDB Filters} +\htmlmathitalics +\htmladdress{\htmlrule{}info@neda.com} + +\c Declare which indices you want to make use of. +\newindex{cp} +\newindex{fn} + +\title{BBDB Input and Output Filters\\ + \vspace{0.25in} {\large DRAFT}\\ + {\normalsize Version 0.2}} + +\author{{\normalsize Prepared by}\\ + Mohsen Banan \\ + \code{mohsen@neda.com}\\ + Neda Communications, Inc.\\ + 17005 SE 31st Place\\ + Bellevue, WA 98008} + +\c (current-time-string) +\date{July 26, 1995} +\c \date{\today} + +\maketitle + +\c The following commands start the copyright page for the printed manual. +\clearpage +\vspace*{0pt plus 1filll} + + +\bigskip +\bigskip +\bigskip + + +This document describes the ``BBDB Input and Output Filters'' package, +a utility which translates BBDB information to and from various other +formats. + +\begin{display} + +Copyright \copyright 1995 Neda Communications, Inc. + +Published by: +Neda Communications, Inc. +17005 SE 31st Place, +Bellevue, WA 98008 USA + +\end{display} + + +Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + +Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be stated in a +translation approved by the Foundation. + +\bigskip +\bigskip + +\clearpage +\pagestyle{headings} + +\c Use roman numerals for the page numbers and Insert the Table of Contents. +\pagenumbering{roman} +\tableofcontents + +\c \listoftables +\c \listoffigures + +\c End the Table of Contents and start numbering from 1 with Arabic numbers + +\clearpage +\pagenumbering{arabic} + +\c Anything before the setfilename will not appear in the Info file. +\setfilename{INFOFILE} + +\topnode{BBDB Filters} + +\htmlmenu{6} + +\begin{ifinfo} +Copyright \copyright \var{1995} \var{Neda Communications, Inc.} +\end{ifinfo} + +\c The Top node contains the master menu for the Info file. +\c This appears only in the Info file, not the printed manual. + +\chapter{Introduction} + +Over time much valuable data has been gathered in BBDB database files. +Many wish to share parts or all of this information with others. They +also wish to have access to this same information from other systems +(like personal digital assistants) lacking straightforward BBDB +access. + +For these reasons, we have prepared a family of filters that convert +the information in BBDB to and from a variety of other +formats. ``Output filters'' export BBDB information to other formats +while ``input filters'' import information from other formats into +BBDB. + +Our hope is that over time this collection of BBDB filters will grow +through contributed code. + +\section{About This Package} + +This package is a collection of filters and is called ``BBDB Input and +Output Filters''. It has been somewhat tested with BBDB version 1.50. +The present state of the software is still preliminary although it has +proved useful. + +\section{About This Manual} + +This documentation applies to Version 0.2 of the ``BBDB Input and +Output Filters'' package. The documentation is presently skeletal and +very preliminary. It mostly provides the user with instructions for +use, and very little background is included. Familiarity with Emacs +Lisp is assumed for some sections. + +\chapter{Output Filters} + +``Output filters'' are used to export BBDB information into formats +used by other systems. + +In general, an output filter uses the contents of your +\code{*BBDB*} buffer as input. Note that output filters do not use +BBDB files (typically `\code{~/.bbdb}') directly. + +An output filter is invoked by executing its associated lisp function. +The name of the function is conventionally named \code{bbdb-<system>-output} +(e.g., \code{M-x bbdb-hp200lx-output}). + +The result of running an output filter is to create a new buffer that +contains the \code{*BBDB*} information appropriately transformed into a +format suitable for use by the target system. The new buffer is given +a file name that you specify. + +\section{HP 200LX Phone Book} + +\cindex{HP 200LX Connectivity Pack} +This package has only been tested on HP 200LX palmtop systems. It +also requires the ``HP 200LX Connectivity Pack'' for converting +comma-delimited ASCII files into binary .PDB files which are read by +the HP 200LX Phone Book application. Version 1.00 of the ``HP 200LX +Connectivty Pack'' was used for testing. + +The HP 200LX output filter is in file \code{bbdb-hp200lx.el}. + +\begin{enumerate} + +\findex{bbdb-hp200lx-output} + +\item Invoke \code{M-x bbdb} to populate the \code{*BBDB*} buffer +with the contents you wish to export. + +\item Invoke \code{ bbdb-hp200lx-output} to create an ASCII .CDF +(Comma Delimited File). \cindex{.CDF file, HP 200LX Phone Book} + +\item Using Xlate/Merge option of HP Connectivity Pack convert the +.CDF file into a binary .PDB file used by the Phone Book program. +\cindex{.PDF file, HP 200LX Phone Book} + +\item Download the .PDB file to your palmtop's internal disk and +ensure that the Phone Book program is set use the newly downloaded +.PDB file. + +\end{enumerate} + +\section{PC Eudora} + +BBDB information can be exported to PC Eudora in two formats--as a +nickname database file and as a recipients database file. + +The PC Eudora output filter is in file \code{bbdb-eudora.el}. + +\subsection{PC Eudora Nickname Database} + +\begin{enumerate} + +\item Invoke \code{M-x bbdb} to populate the \code{*BBDB*} buffer +with the contents you wish to export. + +\findex{bbdb-eudora-nndbase-output} +\item Invoke \code{bbdb-eudora-nndbase-output} to create a PC Eudora +Nickname database file. + +\item Make the file accessible to PC Eudora. + +\end{enumerate} + +\subsection{PC Eudora Recipient Database} + +\begin{enumerate} + +\item Invoke \code{M-x bbdb} to populate the \code{*BBDB*} buffer +with the contents you wish to export. + +\findex{bbdb-eudora-rcpdbase-output} +\item Invoke \code{bbdb-eudora-rcpdbase-output} to create a PC Eudora +recipient's database file. + +\item Make the file accessible to PC Eudora. + +\end{enumerate} + +\section{Lotus cc:Mail Nicknames} + +The Lotus cc:Mail output filter is in file \code{bbdb-ccmail.el}. + +\begin{enumerate} + +\item Invoke \code{M-x bbdb} to populate the \code{*BBDB*} buffer +with the contents you wish to export. + +\findex{bbdb-ccmail-output} +\item Invoke \code{ bbdb-ccmail-output} to create a cc:Mail Nicknames file. + +\item Make the file accessible to cc:Mail. + +\end{enumerate} + +\section{PH} + +The PH output filter is in file \code{bbdb-ph.el}. + +\begin{enumerate} + +\item Invoke \code{M-x bbdb} to populate the \code{*BBDB*} buffer +with the contents you wish to export. + +\findex{bbdb-ph-output} +\item Invoke \code{bbdb-ph-output} to create a \code{ph} data file for +use with the \code{maked} program. + +\item Make the file accessible to \code{ph}. + +\end{enumerate} + +\section{Emacs Lisp Export} + +The Emacs Lisp Export output filter is in file \code{bbdb-export.el}. + +This output filter uses the current contents of your +\code{*BBDB*} buffer to generate a new buffer (\code{*BBDB* Export}) +that contains a single lisp \code{(progn ...)} expression. For +example, a \code{*BBDB*} buffer containing two records would result in +the following \code{*BBDB* Export} buffer: + +\begin{example} +;;; ======= Start of Exported BBDB Records ======= +(progn + (require 'bbdb-com) + (defun bbdb-maybe-create (name company net &optional addrs phones notes) + "Try to add a record to BBDB if it does not already exist." + (condition-case err + (progn + (bbdb-create-internal name company net addrs phones notes) + (message "%s %s added." name (if net (concat "<" net ">") "")) + (sleep-for 1)) + (error (ding) + (message "%s %s skipped. (%s)" + name + (if net (concat "<" net ">") "") + (car (cdr err))) + (sleep-for 1)))) + + (bbdb-maybe-create "Jill Doe--IMPORTED" + "CBS Corporation" + '("jilld@cbs.com") + '( + ["Home" + "368 222ND PL" + "" + "" + "Springfield" + "MA" 2117] + ) + '( + ["Office" 617 555 9983 0] + ) '"Movie Mogul") + (bbdb-maybe-create "John Doe--IMPORTED" + "ABC Incorporated" + '("jdoe@abc.com") + '( + ["Office" + "123 Any Street" + "" + "" + "Any Town" + "WA" (98027 7758)] + ) + '( + ["Office" 206 555 1234 0] + ) '"TV Producer") + ) +;;; ======= End of Exported BBDB Records ======= +\end{example} + +\cindex{Sending BBDB records via email} +This lisp expression can then be sent via email or some other +text-based messaging facility to another user who can then evaluate +the expression which will add the \code{BBDB} records to the +recipient's +\code{BBDB} database. + +Only new records are added. A record with the same name or net +address as one already existing in the \code{BBDB} is skipped +entirely. + +In the sample contents of a \code{*BBDB* Export} buffer presented, two +records are being exported--one for ``John Doe'' and the other for +``Jill Doe''. Notice that their names have been appended with +\code{--IMPORTED}. This string can be used to quick locate each record +that is added to the database using this mechanism. + +The following steps are for exporting BBDB records into Emacs Lisp: + +\begin{enumerate} + +\item Invoke \code{M-x bbdb} to populate the \code{*BBDB*} buffer +with the contents you wish to export. + +\findex{bbdb-export} +\item Invoke \code{bbdb-export} to create a \code{*BBDB* Export} buffer which contains a +single \code{(progn ...)} can be evaluated to add the records to the +existing \code{BBDB} database (if the records do not already exist). + +\item Use the contents of \code{*BBDB* Export} in email and other messaging systems. + +\end{enumerate} + +The following steps are for a user wishing to import the contents of a +\code{*BBDB* Export} buffer's expression into his or her own database: + +\begin{enumerate} + +\item Evaluate the region bounded by the lines \\ + \code{;;; ======= Start of Exported BBDB Records =======} \\ +and \\ + \code{;;; ======= End of Exported BBDB Records =======}. \\ +You can use such commands as +\code{M-x eval-region} or \code{M-x eval-last-sexp}. + +\item Review the newly imported entries. To see them, invoke \code{M-x +bbdb} and specify \code{--IMPORTED} at the \code{Regular Expression} +prompt. + +\item After reviewing the contents of the imported records, you may +wish to remove the \code{--IMPORTED} that is appended to the name by +\code{bbdb-export}. + +\end{enumerate} + +\chapter{Input Filters} + +``Input filters'' are used to import into BBDB information from a +foreign system's data file. + +The name of the function is conventionally named +\code{bbdb-<system>-input} (e.g., \code{bbdb-passwd-input} is the name +of the Emacs Lisp function for the UNIX password file input filter). + +In general, an ``input filter'' expects the foreign system's data to +be in the current buffer. The contents of the current buffer are used +to create an Emacs Lisp file which when loaded will add new records +into your BBDB database if they don't yet exist--existing BBDB records +will not be modified. + +\section{General Facilities for Input Filtering} + +The result of running an input filter is to produce a new buffer a +series of \code{bif-create-record} \findex{bif-create-record} +expressions, each corresponding to a single user's record. Notice +that input filters do not directly modify the contents of the BBDB +files (typically `\code{~/.bbdb}'). + +To actually modify the contents of the BBDB database, you must +evaluated the expressions in the resultant buffer created by the input +filter. One way to do so is simply to invoke \code{M-x eval-buffer}. +Another way is to simply save the buffer to disk and load its contents +into Emacs Lisp using \code{M-x load-file}. + +\section{UNIX Password Files} + +The UNIX password file input filter is in file \code{bbdb-passwd.el}. + +\begin{enumerate} + +\item Use \code{M-x find-file} to visit the UNIX password file you wish to import. + +\findex{bbdb-passwd-input} +\item With the password file in the current buffer, invoke the input +filter \code{M-x bbdb-passwd-input}. You will be prompted for the +domain name associated with that host's password file; an organization +name; as well as the file name to be associated with the buffer of +\code{bif-create-record} expressions. + +\item Evaluate the contents of the input filter's buffer to add records +into your BBDB database file. + +\end{enumerate} + +\chapter{Miscellany} + +\section{TODO List} + +\begin{itemize} + +\item Move generic input filter functionality out of +\code{bbdb-passwd.el} and into, say, \code{bbdb-ifilt.el}. +The generic functionality code has names typically prefixed with \code{bif-}. + +\item Add support for \code{gdbload} (as an alternative to the +Xlate/Merge application provided in the HP 200LX Connectivity Pack) +into the HP 200LX output filter. This is based on input from Robert +Nicholson \code{<robert@steffi.dircon.co.uk>}. + +\item Add documentation for variables in the various input and output filters. + +\item Check and document all dependencies on other packages. + +\end{itemize} + +\section{Credits} + +Pean Lim \code{<pean@neda.com>} wrote most of this package. Mohsen +Banan \code{<mohsen@neda.com>} put it all together and guided the +work. Neda Communications, Inc. sponsored the work. The output +filters code is based on \code{bbdb-print} by Boris Goldowsky\\ +\code{<boris@prodigal.psych.rochester.edu>}. + +\c ;;;;;;;;;;;;;;;; Appendix Starts Here ;;;;;;;;;;;;; +\appendix + +\mbinput{lgpl.tex} + +\begin{tex} +%\bibliography{/usr/local/lib/bib/gnu,/usr/local/lib/bib/networking,/usr/local/lib/bib/directory,/usr/local/lib/bib/rfcs} +\end{tex} + +\c \twocolumn +\node Concept Index, Top, First Chapter, Top +\unnumbered{Concept Index} + +\printindex{cp} + +\H \htmlprintindex + +\node Command Index, Top, First Chapter, Top +\unnumbered{Command Index} + +\printindex{fn} + +\end{document} + diff --git a/bits/bbdb-filters/doc/makefile b/bits/bbdb-filters/doc/makefile new file mode 100644 index 0000000..3feac99 --- /dev/null +++ b/bits/bbdb-filters/doc/makefile @@ -0,0 +1,159 @@ +# +# RCS makefile,v 1.1.1.1 1995/08/07 08:43:10 mohsen Exp +# + +# The name of the file +MANUAL=main +INFOFILE= bbdb-filters.info + +TEXPARTS = + +EPSFIGS = + +TGRINDS = + +EOEBASE = /usr/public/eoe/lisp/public/bbdbPlus +EOEINFO = /usr/public/eoe/info + +# The name of your DVI to PS filter +DVIPS=dvips -f + +# The name of your GNU Emacs +EMACS= xemacs + +LATEXINFO= /usr/public/tex/latexinfo1.7 + +### +### SHOUL NOT HAVE TO TOUCH ANYTHING BELOW HERE +### +SHELL=/bin/sh + +.SUFFIXES: +.SUFFIXES: .lpr .ps .tty .xdvi .dvi .tex .ptex .eps .fig .c + +.fig.eps: + fig2dev -L ps $< > $@ + +.c.tex: + tgrind -f $< > $@ + + +# DEFAULT TARGET +#all: $(INFOFILE) $(MANUAL).ps +all: fast.ps + +$(INFOFILE): $(MANUAL).tex $(TEXPARTS) + rm -f makeinfo.el + sed -e "s+MANUAL+$(MANUAL)+" \ + -e "s+LATEXINFO+$(LATEXINFO)+" $(LATEXINFO)/local/makeinfo.tmplt > makeinfo.el + $(EMACS) -batch -q -l makeinfo.el + #cp $(INFOFILE) /usr/public/eoe/info + +$(MANUAL).tex: $(MANUAL).texinfo $(TEXPARTS) + sed -e "s+INFOFILE+$(INFOFILE)+" $(MANUAL).texinfo | expand > $(MANUAL).tex + -rm -f maketex.el + sed -e "s+MANUAL+$(MANUAL)+" \ + -e "s+LATEXINFO+$(LATEXINFO)+" $(LATEXINFO)/local/maketex.tmplt > maketex.el + $(EMACS) -batch -q -l maketex.el + +$(MANUAL).hyperlatex: $(MANUAL).texinfo $(TEXPARTS) + sed -e "s+INFOFILE+$(INFOFILE)+" $(MANUAL).texinfo | expand > $(MANUAL).hyperlatex + -rm -f makehyperlatex.el + sed -e "s+MANUAL+$(MANUAL)+" \ + -e "s+LATEXINFO+$(LATEXINFO)+" $(LATEXINFO)/local/makehyperlatex.tmplt > makehyperlatex.el + $(EMACS) -batch -q -l makehyperlatex.el + +$(MANUAL).dvi: $(MANUAL).tex $(EPSFIGS) $(TGRINDS) + latex2dvi $(MANUAL).tex + +$(MANUAL).bbl: + latex $(MANUAL) + -bibtex $(MANUAL) + latex $(MANUAL) + +$(MANUAL).xdvi: $(MANUAL).dvi + xdvi $(MANUAL).dvi & + +$(MANUAL).ps: $(MANUAL).dvi + $(DVIPS) $(MANUAL) > $(MANUAL).ps + +$(MANUAL).lpr: $(MANUAL).ps + lpr $(MANUAL).ps + +info: $(INFOFILE) + -echo Built $(INFOFILE) + +$(MANUAL).html: $(MANUAL)/$(MANUAL).html + -echo Building $(MANUAL)/$(MANUAL).html + +$(MANUAL)/$(MANUAL).html: $(MANUAL).dvi $(MANUAL).htmlTex + /usr/public/src/Sol-2/networking/www/latex2html-95.1/latex2html $(MANUAL).tex + +EMACSBASE = /opt/public/networking/www/hyperlatex-1.3/emacs + +html: $(MANUAL).hyperlatex # $(MANUAL).dvi + -mkdir bbdbFilters + $(EMACS) -batch -no-init-file -no-site-file \ + -l $(EMACSBASE)/hyperlatex1.el -funcall batch-hyperlatex-format $(MANUAL).hyperlatex + echo latex \'\\def\\makegifs{}\\input{$(MANUAL).hyperlatex}\' > dolatex.sh + #sh dolatex.sh ; /bin/rm dolatex.sh + #sh $(MANUAL).makegif + +install: $(INFOFILE) + cp $(INFOFILE) $(EOEINFO)/$(INFOFILE) + +# +# Fast Processing +# + +fast.tex: $(MANUAL).texinfo $(TEXPARTS) + sed -e "s+INFOFILE+$(INFOFILE)+" -e "s+mbinput+input+" $(MANUAL).texinfo | expand > fast.tex + +fast.dvi: fast.tex $(EPSFIGS) $(TGRINDS) + latex fast.tex + +fast.xdvi: fast.dvi + xdvi fast.dvi & + +fast.ps: fast.dvi + $(DVIPS) fast > fast.ps + +fast.xps: fast.ps + pageview fast.ps & + +fast.lpr: fast.ps + lpr fast.ps + + +# TeX Figures for when dvi files are needed. Just an example +#XX.tex YY.tex: XX.fig YY.fig +# transfig -m 1.00 -L eepic -M fig.make XX.fig YY.fig +# make -f fig.make + +# Encapsulated PostScript figures -- Done by the Suffix rules +#XX.eps: XX.fig +# fig2dev -L ps -m 1.0 $< > $@ + +# Src Code +#cot-calling.tex: cot-calling.c +# tgrind -f $< > $@ + + +shar:: + split $(MANUAL).tex $(MANUAL)- + +clean: + rm -f $(MANUAL).log $(MANUAL).blg makeinfo.el maketex.el *~ #~ + +veryclean: clean + rm -f $(MANUAL).ps $(MANUAL).dvi $(MANUAL).dlog $(MANUAL).info + +realclean: veryclean + rm -f $(MANUAL).aux $(MANUAL).bbl $(MANUAL).blg $(MANUAL).cp \ + $(MANUAL).toc $(MANUAL).cps $(MANUAL).lot $(MANUAL).lof fig.make \ + $(MANUAL).auxO $(MANUAL).fn $(MANUAL).fns \ + transfig.tex $(MANUAL).tex $(INFOFILE) \ + $(MANUAL).hyperlatex makehyperlatex.el dolatex.sh \ + fast.aux fast.dvi fast.log fast.ps fast.tex fast.toc fast.cp fast.fn \ + $(EPSFIGS) $(TGRINDS) + diff --git a/bits/bbdb-filters/makefile b/bits/bbdb-filters/makefile new file mode 100644 index 0000000..9959f0e --- /dev/null +++ b/bits/bbdb-filters/makefile @@ -0,0 +1,67 @@ +# This file is part of the BBDB Filters Package. BBDB Filters Package is a +# collection of input and output filters for BBDB. +# +# Copyright (C) 1995 Neda Communications, Inc. +# Prepared by Mohsen Banan (mohsen@neda.com) +# +# This library is free software; you can redistribute it and/or modify +# it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. This library is +# distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +# License for more details. You should have received a copy of the GNU +# Library General Public License along with this library; if not, write +# to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, +# USA. +# +# + +# Makefile for the Insidious Big Brother Database -- Input and Output Filters +# +# RCS makefile,v 1.2 1995/08/08 01:20:32 mohsen Exp +# + +EOEBASE = /usr/public/eoe/lisp/public/bbdbPlus +EOEINFO = /usr/public/eoe/info +EMACS = xemacs + + +# You shouldn't need to change anything after this point. + +SRCS = bbdb-ccmail.el bbdb-eudora.el bbdb-export.el bbdb-hp200lx.el bbdb-ph.el bbdb-passwd.el + +SHELL=/bin/sh + +.SUFFIXES: +.SUFFIXES: .elc .el + +.el.elc: + $(EMACS) -batch -q -f batch-byte-compile $(@:.elc=.el) + +default: + @echo Targets: install clean shar + +install: + cp $(SRCS) $(EOEBASE) + cd doc; make EOEBASE=$(EOEBASE) EOEINFO=$(EOEINFO) install + +clean: + -/bin/rm *.elc package.shar + cd doc; make EOEBASE=$(EOEBASE) EOEINFO=$(EOEINFO) clean + + +shar: $(SRCS) makefile + shar -o package.shar $(SRCS) makefile COPYING.LIB README \ + doc doc/main.texinfo doc/lgpl.tex doc/makefile \ + doc/formatted doc/formatted/bbdb-filters.info + + +FORFTPING = /h8/var/ftp/pub/eoe/bbdbPlus/bbdb-filters-0.2.tar + +tar: $(SRCS) makefile + tar cvf $(FORFTPING) . + + + diff --git a/bits/bbdb-funcs.txt b/bits/bbdb-funcs.txt new file mode 100644 index 0000000..14a8180 --- /dev/null +++ b/bits/bbdb-funcs.txt @@ -0,0 +1,383 @@ +Navigation: Table of Contents, Index, next: .emacs file by Alex, prev: Emacs + +BBDB Elisp Code + +Overview: + + * Unmigrating from file format 4 + * Writing a .mailrc from BBDB + * Writing a Pine addressbook from BBDB, by Matt McClure + * Editing and formatting addresses with the country patch + o A new address editing function + o Adding a new formatting function + + The identifying function + + The formatting function + + Print formatting of addresses + +Unmigrating from file format 4 + +(defun bbdb-unmigrate-stuff (&optional new-version) + "Create a buffer with unmigrated BBDB data. +Usefull if you fooled around with BBDB file format 4 by Alex and want to +start using the official BBDB 2.00.06 again. In order to do that, you +have to save your .bbdb in BBDB file format 3 instead of the file format 4 +introduced by Alex. This function will create a *BBDB Version 3* buffer +for you, which you can examine and save as your new .bbdb. The unmigration +will strip the country fields of all entries in your BBDB as such a field +did not exist in the BBDB file format 3 used in BBDB 2.00.06." + (interactive "nUnmigrate to version (I recommend version 3): ") + (if (null new-version) + (setq new-version 3)) + (if (>= new-version bbdb-file-format) + (error "Current BBDB file format is version %d" bbdb-file-format) + (let* ((records (bbdb-records)) + (propnames (bbdb-with-db-buffer bbdb-propnames)) + (rec) + (bbdb-file-format-migration (cons bbdb-file-format new-version)) + (buf (get-buffer-create (format "*BBDB Version %d*" (cdr bbdb-file-format-migration))))) + (message "Unconverting the BBDB database...") + (set-buffer buf) + (erase-buffer) + (insert (format (concat ";;; file-version: %d\n" + ";;; user-fields: %S\n") + new-version (mapcar (function (lambda (x) (intern (car x)))) + propnames))) + (while records + (setq rec (copy-sequence (car records))) + (bbdb-unmigrate-record rec) + (aset rec 8 nil) + (insert (format "%S\n" rec)) + (setq records (cdr records))) + (pop-to-buffer buf) + (message "Unconverting the BBDB database...done")))) + +Writing a .mailrc from BBDB + +The following will export a very primitive version of your BBDB information +into a .mailrc file which is used for normal mail(1) and Emacs Rmail. + +Usually the main problem when exporting BBDB to other formats is the +creation of an ALIAS name. In my example below I just use LASTNAME. The +following function tries to write your BBDB into a .mailrc file, like this: + +alias LASTNAME "FULL_NAME <NETADDRESS>" + +mail-groups defined via the mail-alias field are not supported, but see Matt +McClure's code further down the page for an example on how to do this. + +I used the same code as bbdb-print for the file-name. Unfortunately this +very simple code must have a bug somewhere. It only occurs if you test it a +lot: When you are prompted for a file-name, "~/bbdb.tex" or "~/.mailrc" is +the default. Press RET. Sometimes this will find-file the correct file, and +sometimes you will overwrite your selected buffer instead. I haven't looked +into this, however. :( + +(defvar bbdb-mailrc-file-name ".mailrc" + "Filename to write mail aliases to.") + +(defun bbdb-write-mailrc (visible-records to-file) + (interactive (list (bbdb-do-all-records-p) + (read-file-name "Export To File: " bbdb-mailrc-file-name))) + (setq bbdb-mailrc-file-name (expand-file-name to-file)) + ;; `good' are people with netaddresses, `bad' are people without. The + ;; people are taken of the list records and put on either the good or + ;; the bad list. + (let ((good '()) (bad '()) + (records (if (not visible-records) + (bbdb-records) + (set-buffer bbdb-buffer-name) + (mapcar 'car bbdb-records)))) + ;; Open .mailrc file + (find-file bbdb-mailrc-file-name) + (widen) + (erase-buffer) + ;; Loop through records to print. + (while records + (if (bbdb-record-net (car records)) + (setq good (cons (car records) good)) + (setq bad (cons (car records) bad))) + (setq records (cdr records))) + ;; write all net-addresses into .mailrc + (insert (mapconcat (function (lambda (x) + (let ((name (bbdb-dwim-net-address x)) + (alias (bbdb-record-lastname x))) + (concat "alias " + alias + " \"" + (if (string-match "\"\\(.*\\)\"\\(.*\\)" name) + (format "%s%s" (match-string 1 name) + (match-string 2 name)) + name) + "\"")))) + (nreverse good) + "\n")) + ;; Mail groups + + ;; not implemented, yet + + ;; Feedback on the output quality. + (if bad + (message "There were %d people with bad or missing net addresses." + (length bad)) + (message "Done.")))) + +Writing a Pine addressbook from BBDB, by Matt McClure + +From: Matt McClure <matthew.mcclure.es.99@aya.yale.edu> +Subject: Re: conversion to pine addressbook? +Date: Wed, 25 Aug 1999 10:12:50 -0400 (EDT) + +It isn't pretty, but this will create a pine addressbook. +It also supports the mail-alias field (inefficiently, but it works). +I don't think it should be too difficult to modify to create mailrc +files instead. + +Thanks to Alex for the start. + +Matt + +;;;;; + +(defvar bbdb-mailrc-file-name "~/.addressbook" + "Filename to write mail aliases to.") + +(defun bbdb-write-dot-addressbook (to-file) + (interactive (list (read-file-name "Export To File: " "" nil nil bbdb-mailrc-file-name))) + (setq bbdb-mailrc-file-name (expand-file-name to-file)) + ;; `good' are people with netaddresses, `bad' are people without. The + ;; people are taken of the list records and put on either the good or + ;; the bad list. + (let ((good '()) (bad '()) + (records (bbdb-records)) + (grouped-good '()) (grouped-bad '()) + (grouped-records (bbdb-records)) + (mail-groups-alist '())) + ;; Open .mailrc file + (find-file bbdb-mailrc-file-name) + (widen) + (erase-buffer) + ;; Loop through records to print. + (while records + (if (bbdb-record-net (car records)) + (setq good (cons (car records) good)) + (setq bad (cons (car records) bad))) + (setq records (cdr records))) + ;; write all net-addresses into .mailrc + (insert (mapconcat + (function (lambda (x) + (let ((alias (concat (bbdb-record-firstname x) + " " + (bbdb-record-lastname x))) + (name (concat (bbdb-record-lastname x) + ", " + (bbdb-record-firstname x))) + (email (car (bbdb-record-net x))) + ) + (concat alias + "\t" + name + "\t" + email + ) + ))) + (nreverse good) + "\n")) + ;; Mail groups + ;; get the mail-aliases + (while grouped-records + (if (and + (bbdb-record-net (car grouped-records)) + (assoc 'mail-alias (bbdb-record-raw-notes (car grouped-records)))) + (setq grouped-good (cons (car grouped-records) grouped-good)) + (setq grouped-bad (cons (car grouped-records) grouped-bad))) + (setq grouped-records (cdr grouped-records))) + + (while grouped-good + (let ((aliases (split-string + (cdr (assoc 'mail-alias + (bbdb-record-raw-notes (car grouped-good)))) + "[, \f\t\n\r\v]+"))) + (while aliases + ;; store the name associated with alias somehow + (setq mail-groups-alist + (cons (cons (car aliases) + (concat "\"" + (bbdb-record-firstname (car grouped-good)) + " " + (bbdb-record-lastname (car grouped-good)) + "\"")) + mail-groups-alist)) + (setq aliases (cdr aliases)))) + (setq grouped-good (cdr grouped-good))) + + (setq mail-groups-alist (sort mail-groups-alist + (lambda (x y) + (string< (car x) (car y))))) + + ;; put each name from mail-groups-alist into the appropriate mail aliases + (setq assn '("" . "")) + (while mail-groups-alist + (let ((assn-new (car mail-groups-alist))) + (if (string= (car assn) "") + (insert (concat "\n" (car assn-new) "\t\t(")) + (if (not (string= (car assn) (car assn-new))) + (insert (concat ")\n" (car assn-new) "\t\t(")))) + (insert (concat (cdr assn-new) ",")) + (setq mail-groups-alist (cdr mail-groups-alist)) + (setq assn assn-new))) + + (if (not (string= (car assn) "")) + (insert ")\n")) + + ;; Feedback on the output quality. + (if bad + (message "There were %d people with bad or missing net addresses." + (length bad)) + (message "Done.")))) + +Editing and formatting addresses with the country patch + +If you are using my country patch to BBDB, you might want to use a different +address editing function or add new address formating functions. The +following shows you how to go about doing that. + +A new address editing function + +You can only have one active input function at the time. The name of the +active input function is stored in the variable +`bbdb-address-editing-function'. Therefore, you will have to write a new +address editing function and you will have to set +`bbdb-address-editing-function'. + +The easiest way to go about this, is using paste and copy: use +`bbdb-address-edit-default' as a starting point. + +(defun bbdb-address-edit-continental-german (addr) + "Function to use for address editing. +The sub-fields are queried using the continental order and using German +prompts. This is an alternate value for `bbdb-address-editing-function'. +It is used by German speaking users. + +The sub-fields and the prompts used are: +Strasse, Zeile 1: street1 +Strasse, Zeile 2: street2 +Strasse, Zeile 3: street3 +PLZ: zip +Stadt: city +Region/Staat: state +Land: country" + (let* ((st1 (bbdb-read-string "Strasse, Zeile 1: " (bbdb-address-street1 addr))) + (st2 (if (string= st1 "") "" + (bbdb-read-string "Strasse, Zeile 2: " (bbdb-address-street2 addr)))) + (st3 (if (string= st2 "") "" + (bbdb-read-string "Strasse, Zeile 3: " (bbdb-address-street3 addr)))) + (zip (bbdb-error-retry + (bbdb-parse-zip-string + (bbdb-read-string "PLZ: " (bbdb-address-zip-string addr))))) + (cty (bbdb-read-string "Stadt: " (bbdb-address-city addr))) + (ste (bbdb-read-string "Region/Staat: " (bbdb-address-state addr))) + (country (bbdb-read-string "Land: " (bbdb-address-country addr)))) + (bbdb-address-set-street1 addr st1) + (bbdb-address-set-street2 addr st2) + (bbdb-address-set-street3 addr st3) + (bbdb-address-set-city addr cty) + (bbdb-address-set-state addr ste) + (bbdb-address-set-zip addr zip) + (bbdb-address-set-country addr country) + nil)) +(setq bbdb-address-editing-function 'bbdb-address-edit-continental-german) + +Adding a new formatting function + +You will have to add a new entry to `bbdb-address-formatting-alist'. The new +entry must be a cons cell consisting of an identifying function and a +formatting function. + +I'll use a Japanese format as an example. Please note that I don't really +know how Japanese mail is formatted in Japan. The following reflects +international standards for mail from outside Japan being sent to a Japanese +address. + +First we'll start by adding the identifying function and the formatting +function to `bbdb-address-formatting-alist'. This will controll address +formatting in the *BBDB* buffer. + +(add-to-list 'bbdb-address-formatting-alist + '(bbdb-address-is-japanese . bbdb-format-address-japanese)) + +The identifying function + +The function can do any testing it likes with the address received. In this +case we just test for the country name "Japan". + +(defun bbdb-address-is-japanese (addr) + "Return non-nil if the address ADDR is a japanese address. + +This is a possible identifying function for +`bbdb-address-formatting-alist' and +`bbdb-address-print-formatting-alist'." + (and (string= (upcase (bbdb-address-country addr)) "JAPAN"))) + +The formatting function + +Another paste and copy event: use `bbdb-format-address-default' as a +starting point. + +(defun bbdb-format-address-japanese (addr) + "Insert formated Japanese address ADDR in current buffer. + +This is what it looks like: + location: street1 + street2 + street3 + city + state + zip country" + (insert (format " %14s: " (bbdb-address-location addr))) + (bbdb-format-streets addr) + (let ((c (bbdb-address-city addr)) + (s (bbdb-address-state addr)) + (z (bbdb-address-zip-string addr)) + (y (bbdb-address-country addr))) + (if (or (> (length c) 0) + (> (length s) 0) + (> (length z) 0) + (> (length y) 0)) + (progn + (if (> (length c) 0) + (progn + (indent-to 17) + (insert c "\n"))) + (if (> (length s) 0) + (progn + (indent-to 17) + (insert s "\n"))) + (if (or (> (length z) 0) + (> (length y) 0)) + (progn + (indent-to 17) + (if (> (length z) 0) + (insert z (if (> (length y) 0) " " ""))) + (if (> (length y) 0) + (insert y)) + (insert "\n" ""))))))) + +Print formatting of addresses + +This works just like the example above. Instead of adding the identifying +and formatting functions to `bbdb-address-formatting-alist', you add the two +functions to `bbdb-address-print-formatting-alist'. You can use the same +identifying function that you used in `bbdb-address-formatting-alist'. The +only thing you will have to code up is a print formatting function. It will +be very similar to the normal formatting function. Use +`bbdb-print-format-address-default' as a starting point. The details are +left as an exercise to the reader. +---------------------------------------------------------------------------- + +Navigation: Top, Table of Contents, Index, next: .emacs file by Alex, prev: +Emacs +---------------------------------------------------------------------------- +http://hammer.prohosting.com/~gumbart/bbdb-funcs.html / Alex Schroeder +<a.schroeder@bsiag.ch> / updated: 2000-03-10 / significant changes: +2000-02-11 +---------------------------------------------------------------------------- diff --git a/bits/bbdb-gnokii.el b/bits/bbdb-gnokii.el new file mode 100644 index 0000000..a730b2e --- /dev/null +++ b/bits/bbdb-gnokii.el @@ -0,0 +1,865 @@ +;; bbdb-gnokii.el --- Export phone entries from BBDB to gnokii contacts file. + +;; +;; Copyright (C) 2000, 2003, 2004, 2005, 2006 +;; Martin Schwenke, Reiner Steib, Len Trigg +;; Authors: Martin Schwenke <martin@meltin.net>, +;; Reiner Steib <Reiner.Steib@gmx.de>, +;; Len Trigg <len@reeltwo.com> +;; Maintainer: Martin Schwenke <martin@meltin.net> +;; Created: 23 August 2000 +;; $Id: bbdb-gnokii.el,v 1.16 2006/04/19 13:02:09 martins Exp $ +;; Keywords: BBDB, Nokia, gnokii +;; X-URL: http://meltin.net/hacks/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 2, 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; If you have not received a copy of the GNU General Public License +;; along with this software, it can be obtained from the GNU Project's +;; World Wide Web server (http://www.gnu.org/copyleft/gpl.html), from +;; its FTP server (ftp://ftp.gnu.org/pub/gnu/GPL), by sending an electronic +;; mail to this program's maintainer or by writing to the Free Software +;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +;;; Commentary: +;; +;; Exports BBDB phone entries to a contacts file that can be used by +;; gnokii to write them to a Nokia mobile phone. +;; +;; No responsibility for blowing up your phone... blah, blah, blah... +;; I recommend dumping your phone book to a file (using xgnokii, say) +;; and keeping it in a safe place until you are sure that +;; bbdb-gnokii.el doesn't do anything stupid. +;; +;; The latest version of this file is available via: +;; +;; http://meltin.net/hacks/emacs/ +;; +;; The gnokii web site is +;; +;; http://www.gnokii.org/ +;; +;; bbdb-gnokii.el is loosely based on JWZ's bbdb-pilot-jwz.el. +;; +;; gnokii expects a file with the following format: +;; +;; name;number;memory_type;entry_location;caller_group_number;\ +;; subentry_type;subentry_number_type;subentry_id;subentry_text +;; +;; The length and syntax of "name" and "number" are limited, so some +;; munging goes on. You can adjust the munging to your needs by +;; customizing the variables `bbdb-gnokii-firstname-transform', +;; `bbdb-gnokii-lastname-transform' and +;; `bbdb-gnokii-location-transform'. +;; +;; The default settings of these variables reflect Martin's preferences. +;; Here is a combination of alternative settings used by Reiner: +;; +;; (setq +;; ;; Use long firstnames and lastnames and a short location: +;; bbdb-gnokii-firstname-transform 'bbdb-gnokii-transform-word +;; bbdb-gnokii-lastname-transform 12 +;; bbdb-gnokii-location-transform 'bbdb-gnokii-transform-location +;; bbdb-gnokii-max-name-length 16) +;; +;; The memory_type specifies where to write the contacts (phone memory +;; or SIM card). See variable `bbdb-gnokii-default-memory-type' and +;; it's documentation for details. + +;; Configuration: +;; +;; Add this to your ~/.emacs or equivalent: +;; +;; (autoload +;; 'bbdb-gnokii-export +;; "bbdb-gnokii" +;; "Export phone entries from BBDB to a Gnokii contacts file." +;; t) +;; +;; If you want to add some standard entries to your phone, you can put +;; them in a file and set the following variable: +;; +;; (setq bbdb-gnokii-extras-file +;; (expand-file-name "~/.bbdb-gnokii-extras.txt")) +;; +;; The contents of the specified file get appended to the file +;; generated from the BBDB (cf. `bbdb-gnokii-extras-file-position'). +;; My phone vendor preloads a bunch of their numbers into the SIM +;; card, and I'm keeping them until I'm sure they're not useful! +;; +;; Entries are only extracted from the BBDB for entries that have a +;; gnokii field. In general, if this field is present, then all of +;; the phone numbers (except those that have locations listed in +;; `bbdb-gnokii-exclude-locations') will be exported. +;; +;; For example: +;; +;; Fred Smith - Widget, Inc. +;; mobile: (04) 1234 5678 +;; home: (02) 1234 5678 +;; gnokii: t +;; +;; will have 2 items exported: +;; +;; Fred S mobile;0412345678;... +;; Fred S home;0212345678;... +;; +;; For entries with a name, the default generated name is the first +;; word of firstname, space, first letter of lastname. +;; +;; For entries without a name, but with a company, the default +;; generated name is the first word of the company name. +;; +;; The phone number locations are only appended if there is more than +;; 1 phone entry exported. +;; +;; If the gnokii field contains a string in double-quotes, then it +;; will be used as the name. +;; +;; If the gnokii field contains something like location=X then the +;; number for location will be put into speed-dial location X. All +;; other entries are put between `bbdb-gnokii-general-min-location' +;; and `bbdb-gnokii-general-max-location'. +;; +;; If the gnokii field contains something like (Y) then the entry will +;; belong to caller group Y, otherwise +;; `bbdb-gnokii-default-caller-group' is used. +;; +;; So, +;; +;; Fred Smith - Widget, Inc. +;; mobile: (04) 1234 5678 +;; home: (02) 1234 5678 +;; fax: (02) 8765 4321 +;; gnokii: "Freddy" (0) mobile=2 home=3 +;; +;; will have 2 items exported: +;; +;; Freddy mobile;0412345678;...;0; +;; Freddy home;0212345678;...;0; +;; +;; No item is exported for the fax number because it is a member of +;; `bbdb-gnokii-exclude-locations'. +;; +;; If the gnokii field contains "skip=foo", the phone number corresponding to +;; the location "foo" will not be exported. +;; +;; You can also export a whole BBDB record to a single gnokii entry by +;; setting `bbdb-gnokii-phonebook-style' to `multi' or `mega'. In +;; this style the default phone number can be set by specifying the +;; associated location in the BBDB gnokii field. For example, if the +;; gnokii field contains "[work]" then the phone number with location +;; "work" will be the default one. If no default location is +;; specified in the gnokii field, then the order of preference is +;; determined by `bbdb-gnokii-preferred-phone-locations'. If +;; `bbdb-gnokii-phonebook-style' is set to `mega', an email address +;; and postal address are also added to the gnokii entry, when +;; available. + +;; See the variables and code below for more details. You may check all +;; customizable variables using `M-x customize-group RET bbdb-gnokii RET'. + + + +;;; History: + +;; $Log: bbdb-gnokii.el,v $ +;; Revision 1.16 2006/04/19 13:02:09 martins +;; Function bbdb-gnokii-do-name now just uses firstname if lastname is +;; not set. Suggested by Magnus Henoch <mange@freemail.hu>. +;; +;; Revision 1.15 2005/06/06 09:52:49 martins +;; Added support for gnokii entries with multiple phone numbers using +;; subentries, implemented using a variation and subset of code by Len +;; Trigg: new variables bbdb-gnokii-phonebook-style and +;; bbdb-gnokii-preferred-phone-locations; removed variable +;; bbdb-gnokii-insert-extra-fields (replaced by +;; bbdb-gnokii-phonebook-style); removed defstruct bbdb-gnokii; replaced +;; functions bbdb-gnokii-convert and bbdb-gnokii-format with new function +;; bbdb-gnokii-format-record, which has most of the implementation +;; details for this feature; new functions bbdb-gnokii-format-address, +;; bbdb-gnokii-phones-find-location, bbdb-gnokii-get-default-phone; +;; retain '+' in phone number in function bbdb-gnokii-fix-phone; +;; bbdb-gnokii-export just calls bbdb-gnokii-format-record for each +;; record, instead of converting and then formatting; added Len Trigg to +;; to copyright and authors. +;; +;; Revision 1.14 2004/03/30 12:01:29 martins +;; After discussion with Reiner, changed the names of the following +;; variables: +;; +;; bbdb-gnokii-default-group -> bbdb-gnokii-default-caller-group +;; bbdb-gnokii-default-memtype -> bbdb-gnokii-default-memory-type +;; bbdb-gnokii-general-maxpos -> bbdb-gnokii-general-max-location +;; bbdb-gnokii-general-minpos -> bbdb-gnokii-general-min-location +;; bbdb-gnokii-speed-maxpos -> bbdb-gnokii-speed-dial-max-location +;; bbdb-gnokii-speed-minpos -> bbdb-gnokii-speed-dial-min-location +;; +;; for consistency with gnokii documentation, and changed associated +;; documentation accordingly. In struct bbdb-gnokii- changed name of +;; member `mempos' to `location'. Also changed function names: +;; +;; bbdb-gnokii-do-mempos -> bbdb-gnokii-do-location +;; bbdb-gnokii-do-group -> bbdb-gnokii-do-caller-group +;; +;; Revision 1.13 2004/03/02 00:50:53 martins +;; Documentation cleanups by Reiner Steib <Reiner.Steib@gmx.de>. +;; +;; Revision 1.12 2004/02/27 03:40:59 martins +;; bbdb-gnokii-default-memtype now has default value of "SM" (for +;; compatibility with xgnokii >= 0.6) - documentation and customisation +;; choices have also been improved. bbdb-gnokii-default-group's +;; documentation and customisation choices have also been improved. +;; Changes implemented by Reiner Steib <Reiner.Steib@gmx.de>. +;; +;; Revision 1.11 2004/02/25 01:16:08 martins +;; Added RCS Log section in History and imported previous entries. +;; Thanks again to Reiner. +;; +;; Revision 1.10 2004/02/07 11:47:04 martins +;; Replaced uses of bbdb-gnokii-extra-tag with bbdb-gnokii-extra-tags. +;; Oops. + +;; Revision 1.9 2004/02/07 11:40:31 martins +;; `bbdb-gnokii-extra-tags': New variable for Siemens C35 used in +;; `bbdb-gnokii-export'. Exchanged defun and defalias: +;; bbdb-gnokii-export vs. bbdb-to-gnokii-file. Changed documentation +;; section to mention bbdb-gnokii-export, not bbdb-to-gnokii. Renamed +;; function bbdb-record-to-gnokii-records to bbdb-gnokii-convert. Minor +;; cosmetic fixes. Thanks to Reiner Steib <Reiner.Steib@gmx.de>. + +;; Revision 1.8 2004/02/06 03:07:33 martins +;; Merged changes from Reiner Steib <reiner.steib@gmx.de>: Made +;; variables customizable. Did some checkdoc fixes. Made many things +;; more flexible, especially the shortening of firstname, lastname and +;; location strings. Added `bbdb-gnokii-add-field'. Also replaced +;; variable `bbdb-gnokii-maxpos' with `bbdb-gnokii-general-minpos' and +;; `bbdb-gnokii-general-maxpos'. Added information about where to get +;; latest version. Various documentation fixes. Added variable +;; `bbdb-gnokii-insert-extra-fields'. Various documentation fixes. +;; Removed declarations of variables `bbdb-gnokii-mempos' and +;; `bbdb-gnokii-speed-done' (since they are bound in a `let'). + +;; Revision 1.7 2003/07/01 01:44:29 martins +;; Added extra fields to output, which seem to be required for newer +;; phones/gnokiis. + +;; Revision 1.6 2003/06/30 01:58:10 martins +;; (bbdb-gnokii-do-name): Handle case where lastname is empty. + +;; Revision 1.5 2001/02/12 00:10:45 martin +;; Changed e-mail address. + +;; Revision 1.4 2000/10/04 00:41:58 martins +;; Changed default-memtype back to "A". + +;; Revision 1.3 2000/08/25 02:58:15 martins +;; - Added documentation and stuff at top. +;; - Changed spelling from Gnokii to gnokii. +;; - Changed default memory type to work with command-line gnokii. +;; - Reduced allowable length of names. +;; - Added bbdb-gnokii-exclude-locations and associated filtering. +;; Thanks to Chris Yeoh. +;; - Added various comments. + +;; Revision 1.2 2000/08/24 11:52:57 martins +;; Fixed RCS Id string. + +;; Revision 1.1 2000/08/24 11:52:39 martins +;; Initial revision + + +;;; Code: +(require 'bbdb) + +;; Only for `bbdb-gnokii-add-field': +(autoload 'bbdb-merge-interactively "bbdb-snarf" nil nil) +(autoload 'bbdb-add-new-field "bbdb-com" nil nil) + +(defgroup bbdb-gnokii nil + "Sync BBDB and gnokii." + :group 'bbdb) + +(defcustom bbdb-gnokii-transform-word-regexp + (if (string-match "[[:word:]]" "x") + "[^-[:word:]]" + ;; old Emacsen (e.g. Emacs 20) don't support character classes. + "[^-A-Za-z]") + "Regexp used to shorten names in `bbdb-gnokii-transform-word'." + :group 'bbdb-gnokii + :type '(choice (const :tag "first word" "[^-[:word:]]") + (const :tag "ascii" "[^-A-Za-z]") + (regexp :tag "Other"))) + +(defun bbdb-gnokii-transform-max (name &optional limit) + "Limit NAME to LIMIT characters." + (if (> (length name) limit) + (substring name 0 limit) + name)) + +(defun bbdb-gnokii-transform-word (name &optional regexp) + "Shorten NAME to first word. +`bbdb-gnokii-transform-word-regexp' is used unless REGEXP is given." + (substring name + 0 (string-match (or regexp bbdb-gnokii-transform-word-regexp) name))) + +(defun bbdb-gnokii-transform-location (location) + "Shorten LOCATION field." + ;; The default BBDB location "Office" and "Other" both give "O" + (if (string= name "Other") + "o" + (bbdb-gnokii-transform-max location 1))) + +(defcustom bbdb-gnokii-firstname-transform 'bbdb-gnokii-transform-word + "How to transform the lastname field to short variant. +If a function, call it with the name as it's argument. If a number, use +substring with maximal length number." + :group 'bbdb-gnokii + :type '(choice (const bbdb-gnokii-transform-word) + (function) + (integer))) + +(defcustom bbdb-gnokii-lastname-transform 1 + "How to transform the lastname field to short variant. +If a function, call it with the name as it's argument. If a number, use +substring with maximal length number." + :group 'bbdb-gnokii + :type '(choice (const bbdb-gnokii-transform-word) + (function) + (integer))) + +(defcustom bbdb-gnokii-location-transform 10 + "Transform the location field to short variant. +If a function, call it with the name as it's argument. If a number, use +substring with maximal length number." + :group 'bbdb-gnokii + :type '(choice (const bbdb-gnokii-transform-location) + (function) + (integer))) + +(defun bbdb-gnokii-apply-transform (transform name) + "Apply transformation TRANSFORM to NAME and return a shortened name." + (cond + ((functionp transform) + (funcall transform name)) + ((natnump transform) + (bbdb-gnokii-transform-max name transform)) + (t name))) + +(defcustom bbdb-gnokii-extras-file nil + "Name of file containing extra entries to add to gnokii." + :group 'bbdb-gnokii + :type '(choice (const :tag "None" nil) + (file))) + +(defcustom bbdb-gnokii-extra-tags nil + "List of two string elements: \"\(\"tag\" \"indicator\"\)\" or nil. +For each occurance of the form \"location=tag\" in the BBDB gnokii field, the +gnokii string \"indicator\" will be appended to the generated name in the +gnokii file. In some Siemens phones \(C35 and possibly others\), the +indicator \"!\" is used to specify a \"VIP entry\"." + :group 'bbdb-gnokii + :type '(choice (const :tag "Siemens C35 style" ("vip" "!")) + (list (symbol :tag "BBDB tag") + (symbol :tag "Gnokii string")))) + +(defcustom bbdb-gnokii-default-output-file nil + "Name of the default output file. +If the filename contains the string \"%s\", it will be replaced +with the current date in ISO format (YYYY-MM-DD)." + :group 'bbdb-gnokii + :type '(choice (const :tag "None" nil) + (file))) + +(defcustom bbdb-gnokii-extras-file-position 'bottom + "Where to insert `bbdb-gnokii-extras-file'." + :group 'bbdb-gnokii + :type '(choice (const :tag "Top" top) + (const :tag "Bottom" bottom))) + +(defcustom bbdb-gnokii-inserted-hook nil + "Hook run after all records from BBDB were inserted into the output buffer. +The hook is called in the output buffer immediately before saving the buffer." + :group 'bbdb-gnokii + :type 'hook) + +(defcustom bbdb-gnokii-confirm-kill nil + "Ask for confirmation before killing the output buffer." + :group 'bbdb-gnokii + :type 'boolean) + +(defcustom bbdb-gnokii-phonebook-style 'single + "Style for phonebook entries. +This affects the number of phone numbers per gnokii entry and the way +the name is constructed. `single' (the default) allows only a single +phone number per gnokii entry, and also generates a subentry for that +phone number. `ancient' also allows only a single phone number per +gnokii entry, but generates no subentry - older versions of gnokii +seem to work like this. `multiple' causes all phone numbers for a +BBDB entry to be put into a single gnokki entry, using multiple +subentries - in this case the location is also never appended to the +name. `mega' is like multiple but causes the 1st email address and +postal address to also be put into the gnokii entry. Note that +`multiple' and `mega' probably won't work well with +`bbdb-gnokii-default-memory-type' set to \"SM\"." + :type '(choice (const :tag "Single with subentry" single) + (const :tag "Single without subentry" ancient) + (const :tag "Multiple subentries" multiple) + (const :tag "Subentries, email, postal" mega))) + +(defcustom bbdb-gnokii-speed-dial-min-location 1 + "Minimum memory location allowed for speed dial entries. +See also `bbdb-gnokii-general-min-location', +`bbdb-gnokii-general-max-location' and +`bbdb-gnokii-speed-dial-max-location'. The range for speed dial +entries should not overlap with the range for general entries, or +entries found in `bbdb-gnokii-extras-file'." + :group 'bbdb-gnokii + :type 'integer) + +(defcustom bbdb-gnokii-speed-dial-max-location 9 + "Maximum memory location allowed for speed dial entries. +See also `bbdb-gnokii-general-min-location', +`bbdb-gnokii-general-max-location' and +`bbdb-gnokii-speed-dial-min-location'. The range for speed dial +entries should not overlap with the range for general entries, or +entries found in `bbdb-gnokii-extras-file'." + :group 'bbdb-gnokii + :type 'integer) + +(defcustom bbdb-gnokii-general-min-location 10 + "Minimum memory location allowed for general BBDB to gnokii entries. +See also `bbdb-gnokii-general-max-location', +`bbdb-gnokii-speed-dial-min-location' and +`bbdb-gnokii-speed-dial-max-location'. The range for speed dial +entries should not overlap with the range for general entries, or +entries found in `bbdb-gnokii-extras-file'." + :group 'bbdb-gnokii + :type 'integer) + +(defcustom bbdb-gnokii-general-max-location 89 + "Maximum memory location allowed for general BBDB to gnokii entries. +See also `bbdb-gnokii-general-min-location', +`bbdb-gnokii-speed-dial-min-location' and +`bbdb-gnokii-speed-dial-max-location'. The range for speed dial +entries should not overlap with the range for general entries, or +entries found in `bbdb-gnokii-extras-file'." + :group 'bbdb-gnokii + :type 'integer) + +(defcustom bbdb-gnokii-default-memory-type "SM" + "Default type of phone memory to use for BBDB to gnokii entries. +\"SM\" is for SIM card, \"ME\" for the phone memory. In versions prior to +0.6, `xgnokii' used \"A\" is for SIM card and \"B\" for the phone memory. +Please see the documentation of gnokii and xgnokii for valid values." + :group 'bbdb-gnokii + :type '(choice (const :tag "SIM card" "SM") + (const :tag "phone memory" "ME") + (const :tag "SIM card (for old xgnokii)" "A") + (const :tag "phone memory (for old xgnokii)" "B") + ;; Other valid memory types probably aren't writable. + (string :tag "Other"))) + +(defcustom bbdb-gnokii-default-caller-group 5 + "Default caller group to put BBDB to gnokii entries into. + +If the gnokii field contains something like \"\(N\)\" then the entry will +belong to caller group N, otherwise `bbdb-gnokii-default-caller-group' +is used. Possible values are 0 \(Family\), 1 \(VIP\), 2 \(Friends\), +3 \(Colleagues\), 4 \(Other group\), 5 \(No group\). Note that these +are defaults, you are able to change these manually in your phone. +See also \"caller_group_number\" in the documentation of gnokii." + :group 'bbdb-gnokii + :type '(choice (const :tag "0 (Family)" 0) + (const :tag "1 (VIP)" 1) + (const :tag "2 (Friends)" 2) + (const :tag "3 (Colleagues)" 3) + (const :tag "4 (Other group)" 4) + (const :tag "5 (No group)" 5) + (integer :tag "Other"))) + +(defcustom bbdb-gnokii-max-name-length 17 + "Maximum allowable length of name field." + :group 'bbdb-gnokii + :type 'integer) + +(defcustom bbdb-gnokii-exclude-locations '("fax") + "List of locations for phone numbers to exclude." + :group 'bbdb-gnokii + :type '(choice (const :tag "None" nil) + (const :tag "Fax" '("fax")) + (repeat (string :tag "Field")))) + +(defcustom bbdb-gnokii-preferred-phone-locations '("mobile" "home" "work") + "List of locations for choosing default phone number in multi-phone entries. +The phone number associated with earliest location in this list is used. +Otherwise, the first phone number is used." + :group 'bbdb-gnokii + :type '(choice (repeat (string :tag "Field")))) + +(defconst bbdb-gnokii-label-type-alist + '(("home" . 2) + ("mobile" . 3) + ("fax" . 4) + ("office" . 6) + ("work" . 6) + ("." . 10)) + "Alist mapping BBDB phones labels to gnokii phone number types.") + +(defun bbdb-gnokii-format-record (record) + "Convert a BBDB RECORD to text in the current buffer." + + (let ((allphones (bbdb-record-phones record)) + (allnet (bbdb-record-net record)) + (alladdresses (bbdb-record-addresses record)) + (stuff (if (listp (bbdb-record-raw-notes record)) + (cdr (assq 'gnokii (bbdb-record-raw-notes record))))) + (subentry-id 0) + name useloc phones default-phone print-escape-newlines) + + (setq name (bbdb-gnokii-do-name (bbdb-record-lastname record) + (bbdb-record-firstname record) + (bbdb-record-company record) + stuff)) + + ;; Filter out unwanted phone locations and find default phone number. + (while allphones + (let ((p (car allphones))) + (if (not (or (member (bbdb-phone-location p) + bbdb-gnokii-exclude-locations) + (string-match (concat "\\<skip=\\(" + (bbdb-phone-location p) + "\\)\\>") + (or stuff "")))) + (add-to-list 'phones p))) + (setq allphones (cdr allphones))) + + (if (memq bbdb-gnokii-phonebook-style '(multiple mega)) + (setq default-phone (bbdb-gnokii-get-default-phone phones stuff))) + + ;; Only continue if they have a name, a gnokii field and some + ;; phone numbers. + (if (and name stuff phones) + (progn + ;; Only add the location to name if there is >1 phone number + ;; and we're not doing multiple-subentries. + (setq useloc (and (> (length phones) 1) + (memq bbdb-gnokii-phonebook-style + '(ancient single)))) + ;; Create records. + (while phones + (let* ((location (bbdb-phone-location (car phones))) + (loc (bbdb-gnokii-apply-transform + bbdb-gnokii-location-transform + location)) + (num (bbdb-gnokii-fix-phone + (bbdb-phone-string (car phones)))) + (default-loc (or (and default-phone + (bbdb-gnokii-apply-transform + bbdb-gnokii-location-transform + (bbdb-phone-location default-phone))) + loc)) + (default-num (or (and default-phone + (bbdb-gnokii-fix-phone + (bbdb-phone-string default-phone))) + num)) + (name (if useloc (concat name " " loc) name))) + (if (> (length name) bbdb-gnokii-max-name-length) + ;; Don't error out on long entries, truncate them instead. + (progn + (message + (concat + "Name \"%s\" is too long. " + "Maybe you want to edit gnokii field.") + name) + (setq + name + (cond + ;; Make sure we don't strip location: + (useloc + (concat + (bbdb-gnokii-transform-max + name (- bbdb-gnokii-max-name-length + (1+ (length loc)))) + " " loc)) + (t + (bbdb-gnokii-transform-max + name bbdb-gnokii-max-name-length)))))) + ;; Checking for bbdb-gnokii-extra-tags: + (when (and (car bbdb-gnokii-extra-tags) + (cadr bbdb-gnokii-extra-tags) + location + (string-match + (concat + "\\<" location + "=" + (regexp-quote (car bbdb-gnokii-extra-tags)) + "\\>") + stuff)) + ;; extra entry found, changing label: + (setq name + (concat (bbdb-gnokii-transform-max + name (- bbdb-gnokii-max-name-length 1)) + (cadr bbdb-gnokii-extra-tags)))) + + (if (= subentry-id 0) + (insert (format "%s;%s;%s;%s;%s" + name + default-num + bbdb-gnokii-default-memory-type + (bbdb-gnokii-do-location stuff default-loc) + (bbdb-gnokii-do-caller-group stuff)))) + (if (not (eq bbdb-gnokii-phonebook-style 'ancient)) + (insert (format ";11;%d;%d;%s" + (assoc-default location + bbdb-gnokii-label-type-alist + 'string-match nil) + subentry-id + num))) + + ;; Continute along list of phone numbers. + (setq phones (cdr phones)) + ;; If doing multiple per entry, increment subentry-id count. + (if (memq bbdb-gnokii-phonebook-style '(multiple mega)) + (setq subentry-id (1+ subentry-id)) + (insert "\n")))) + + (when (eq bbdb-gnokii-phonebook-style 'mega) + ;; First email address? + (when allnet + (insert (format ";8;0;%d;%s" subentry-id (car allnet))) + (setq subentry-id (1+ subentry-id))) + ;; First postal address? + (when alladdresses + (insert (format ";9;0;%d;%s" subentry-id + (bbdb-gnokii-format-address (car alladdresses)))) + (setq subentry-id (1+ subentry-id)))) + (if (memq bbdb-gnokii-phonebook-style '(multiple mega)) + (insert "\n")) + )))) + +(defun bbdb-gnokii-format-address (address) + "Generates a single-line representation of an address." + (let (st field) + (cond ((>= bbdb-file-format 6) + (setq st (bbdb-join (bbdb-address-streets address) "\\n"))) + (t + (setq st (bbdb-address-street1 address)) + (if (> (length (bbdb-address-street2 address)) 0) + (setq st (concat st "\\n" (bbdb-address-street2 address)))) + (if (> (length (bbdb-address-street3 address)) 0) + (setq st (concat st "\\n" (bbdb-address-street3 address)))))) + (setq field (bbdb-address-city address)) + (if (> (length field) 0) (setq st (concat st "\\n" field))) + (setq field (bbdb-address-state address)) + (if (> (length field) 0) (setq st (concat st "\\n" field))) + (setq field (bbdb-address-zip-string address)) + (if (> (length field) 0) (setq st (concat st "\\n" field))) + (setq field (bbdb-address-country address)) + (if (> (length field) 0) (setq st (concat st "\\n" field))) + st)) + +(defun bbdb-gnokii-do-name (lastname firstname company stuff) + "Construct a name from the given arguments." + + (let (name) + + (cond + + ((and stuff + (string-match "\"\\([^\"]+\\)\"" stuff)) + (setq name (substring stuff (match-beginning 1) (match-end 1)))) + + (firstname + ;; Yay, they have a name! Default is first word of firstname, + ;; space, first letter of lastname. + (setq name + (bbdb-gnokii-apply-transform + bbdb-gnokii-firstname-transform firstname)) + (when (> (length lastname) 0) + (setq name + (concat name + " " + (setq name + (bbdb-gnokii-apply-transform + bbdb-gnokii-lastname-transform lastname)))))) + (company + ;; Yay, first word of company name! + ;; Maybe this should be made customizable, too (Reiner Steib). + (setq name (substring company 0 (string-match " " company))))) + name)) + + +(defun bbdb-gnokii-do-location (stuff loc) + "Calculate the `location' field for a gnokii record. +The field content STUFF and the location LOC are used." + + (let (num) + (if (and stuff + (string-match (concat "\\<" loc "=\\([0-9]+\\)") stuff)) + (progn + (setq num (string-to-number + (substring stuff (match-beginning 1) (match-end 1)))) + (if (or (< num bbdb-gnokii-speed-dial-min-location) + (> num bbdb-gnokii-speed-dial-max-location) + (member num bbdb-gnokii-speed-done)) + (error + "Speed dial location %d out of range or duplicate for %s" + num name) + (add-to-list 'bbdb-gnokii-speed-done num))) + (if (> bbdb-gnokii-location bbdb-gnokii-general-max-location) + (error "Too many records to fit in SIM card!")) + (setq num bbdb-gnokii-location) + (setq bbdb-gnokii-location (+ bbdb-gnokii-location 1))) + num)) + +(defun bbdb-gnokii-do-caller-group (bbdb-field) + "Calculate the caller `group' field for given BBDB-FIELD." + + (let (group) + (if (and bbdb-field + (string-match "(\\([0-9]+\\))" bbdb-field)) + (setq group (string-to-number + (substring bbdb-field (match-beginning 1) (match-end 1)))) + (setq group bbdb-gnokii-default-caller-group)) + group)) + +(defun bbdb-gnokii-phones-find-location (location phones) + "Return the phone element in PHONES with given LOCATION, nil if not found." + (let ((ps phones) + ret) + (while (and (not ret) ps) + (if (string= location (bbdb-phone-location (car ps))) + (setq ret (car ps))) + (setq ps (cdr ps))) + ret)) + +(defun bbdb-gnokii-get-default-phone (phones stuff) + "Get the default phone entry for a record." + + (let* ((loc (and stuff + (string-match "\\[\\([^]]+\\)\\]" stuff) + (substring stuff (match-beginning 1) (match-end 1)))) + (locs bbdb-gnokii-preferred-phone-locations) + ret) + + (if loc + (setq ret (bbdb-gnokii-phones-find-location loc phones))) + + (while (and (not ret) locs) + (setq ret (bbdb-gnokii-phones-find-location (car locs) phones)) + (setq locs (cdr locs))) + (or ret (car phones)))) + +(defun bbdb-gnokii-fix-phone (phone) + "Change phone number PHONE to gnokii compatible form." + + (let ((chars phone) + out) + (while (> (length chars) 0) + (let ((h (substring chars 0 1))) + (if (string-match "[+0-9]" h) + (setq out (concat out h))) + (setq chars (substring chars 1)))) + out)) + +;;;###autoload +(defalias 'bbdb-to-gnokii-file 'bbdb-gnokii-export) + +;;;###autoload +(defun bbdb-gnokii-export (filename &optional records) + "Export phone entries from BBDB to a gnokii contacts file FILENAME. +Unless RECORDS is given, all BBDB entries are processed." + (interactive + (list (let ((default (if (stringp bbdb-gnokii-default-output-file) + (format bbdb-gnokii-default-output-file + (format-time-string "%Y-%m-%d" (current-time))) + default-directory))) + (read-file-name "Output file: " + (file-name-directory default) + default + nil + (file-name-nondirectory default))))) + (or records (setq records (bbdb-records))) + (save-excursion + (set-buffer (find-file-noselect filename)) + (erase-buffer) + (let ((len (length records)) + (i 0) + (bbdb-gnokii-location bbdb-gnokii-general-min-location) + bbdb-gnokii-speed-done) + (while records + (message "%d%%..." (/ (* 100 i) len)) + (bbdb-gnokii-format-record (car records)) + (setq records (cdr records) + i (1+ i)))) + (when (and bbdb-gnokii-extras-file + (file-readable-p bbdb-gnokii-extras-file)) + (cond ((eq bbdb-gnokii-extras-file-position 'top) + (goto-char (point-min))) + ((eq bbdb-gnokii-extras-file-position 'bottom) + (goto-char (point-max)))) + (insert-file-contents bbdb-gnokii-extras-file)) + (run-hooks 'bbdb-gnokii-inserted-hook) + (save-buffer) + ;; Useful especially when testing. + (when (or (not bbdb-gnokii-confirm-kill) + (y-or-n-p "Kill output buffer? ")) + (kill-buffer (current-buffer)))) + filename) + +;;;###autoload +(defun bbdb-gnokii-add-field (&optional records) + "Go through all RECORDS and ask for adding a gnokii field. +If RECORDS is nil, go thru all records. If a BBDB record has an +expire field in YYYY-MM-DD format \(e.g. \"expire=2003-12-31\"\), +the record is skipped if it is older than today." + (interactive) + (or records (setq records (bbdb-records))) + (bbdb-add-new-field 'gnokii) + (dolist (record records) + ;; Go thru all records, check if we have a phone and no gnokii field. + (if (bbdb-record-phones record) + (let* ((have-gnokii + (and (listp (bbdb-record-raw-notes record)) + (cdr (assq 'gnokii (bbdb-record-raw-notes record))))) + (expire + (and (listp (bbdb-record-raw-notes record)) + (cdr (assq 'expire (bbdb-record-raw-notes record))))) + (name (bbdb-record-name record)) + (is-expired (and + expire + (string-lessp expire + (format-time-string + "%Y-%m-%d" (current-time)))))) + (message "In record `%s': gnokii=`%s', expire=`%s', is-exp=`%s'" + name have-gnokii expire is-expired) + (cond + (is-expired + (message "In record `%s': is expired." name)) + (have-gnokii + (message "In record `%s': already has gnokii field." name)) + ((y-or-n-p (format "Add gnokii field to `%s'? " name)) + (bbdb-merge-interactively name;; name + nil ;; company + nil ;; net + nil ;; addrs + nil ;; phones + '((gnokii . "t"))) + (message "In record `%s': gnokii field added." name)) + (t + (message "In record `%s': gnokii refused interactively." name)))) + (message "In record `%s': no phone found." (bbdb-record-name record))))) + +(provide 'bbdb-gnokii) + +;;; bbdb-gnokii.el ends here diff --git a/bits/bbdb-ldif.el b/bits/bbdb-ldif.el new file mode 100644 index 0000000..7f6df8c --- /dev/null +++ b/bits/bbdb-ldif.el @@ -0,0 +1,821 @@ +;;; Copyright (C) 1998,2000 by Niels Elgaard Larsen <elgaard@diku.dk> + +;;; $Log: bbdb-ldif.el,v $ +;;; Revision 1.1 2006/02/04 15:35:15 joerg +;;; Added +;;; +;;; Revision 1.1 2005/02/13 14:16:03 waider +;;; * added new file, with minor abuse to make it work with current BBDB +;;; +;;; Revision 1.7 2000/03/15 14:16:44 elgaard +;;; Fixed problem with concatenation of strings/integers +;;; Changed mobiletelephonenumber to cellphone to follow Netscape :-( +;;; Added support for pagerphone +;;; +;;; Revision 1.6 1998/09/08 12:35:27 elgaard +;;; Works with xemacs, emacs, emacs-19.34, bbdb-2 and bbdb-1.51 +;;; Bugfixes +;;; +;; Rev 0.3 +;; Can export mail-alias'es and .mailrc aliases to Netscape Mailing List +;;Bugfix. +;; + +;; Rev. 0.2.1 +;; Compiles without MEL + +;; Rev. 0.2 +;; Notes work better now +;; added 'bbdb-elided-export-ldif' +;; Fixed base64 bug + +;; 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 2 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;; Niels Elgaard Larsen, <URL:mailto:elgaard@diku.dk> +;; July 18, 1998 + +;; bbdb-import-ldif imports LDIF entries +;; bbdb-to-ldif export bbdb to LDIF. + +;; Both functions are somewhat specialized for Netscape Communicator (and Mozilla) + + + +;;; Installation: + +;;; Put (add-hook 'bbdb-load-hook (function (lambda () (require 'bbdb-ldif)))) +;;; into your .emacs, or autoload it. + + +;; If you use non-ASCII characters recode the output file from emacs: +;; "recode ..UTF-8 output.ldif" +;; and the input file from Netscape: +;; "recode UTF-8.. i2.ldif " +;;;;;; Does not work for base-64 encoded text. + +(require 'bbdb) + +;; WAIDER MOD FEB 2005 +;; deprecated functions. I should fix the code rather than do this, but. +(defun bbdb-address-street1(addr) + (nth 0 (bbdb-address-streets addr))) +(defun bbdb-address-street2(addr) + (nth 1 (bbdb-address-streets addr))) +(defun bbdb-address-street3(addr) + (nth 2 (bbdb-address-streets addr))) + +(if (locate-library "mel") (require 'mel) + (message "We try without MEL (base64 operation), multiline fields will not work" + ) + ) + +(if (fboundp 'split-string) nil + (defun split-string (string &optional pattern) + "Return a list of substrings of STRING which are separated by PATTERN. +If PATTERN is omitted, it defaults to \"[ \\f\\t\\n\\r\\v]+\"." + (or pattern + (setq pattern "[ \f\t\n\r\v]+")) + ;; The FSF version of this function takes care not to cons in case + ;; of infloop. Maybe we should synch? + (let (parts (start 0)) + (while (string-match pattern string start) + (setq parts (cons (substring string start (match-beginning 0)) parts) + start (match-end 0))) + (nreverse (cons (substring string start) parts)))) + ) + +(if (fboundp 'caadr) nil (defun caadr (foo) (car (car (cdr foo))))) + + + +(defvar bbdb-ldif-nsnil "?" "Null name for Netscape") + +(defun tnsnil (st) + (if (equal st bbdb-ldif-nsnil) + nil + st)) + +(defvar bbdb-elided-export-ldif nil "Set this to a list of some +of the symbols '(address phone net notes) to select those fields to be left +out when exporting to LDIF format" +) + +;(require 'bbdb-snarf) +(require 'bbdb-com) + + +(defvar bbdb-ldif-prefix "xbbdb") +(defvar bbdb-ldif-prefixh "xhbbdb") + +;;;; From bbdb-snarf with bugfix: +(defun bbdb-merge-internally-ldif (old-record new-record) + "Merge two records. NEW-RECORDS wins over OLD in cases of ties." + (if (and (null (bbdb-record-firstname new-record)) + (bbdb-record-firstname old-record)) + (bbdb-record-set-firstname new-record (bbdb-record-firstname old-record))) + (if (and (null (bbdb-record-lastname new-record)) + (bbdb-record-lastname old-record)) + (bbdb-record-set-lastname new-record (bbdb-record-lastname old-record))) + (if (and (null (bbdb-record-company new-record)) + (bbdb-record-company old-record)) + (bbdb-record-set-company new-record (bbdb-record-company old-record))) + ;; nets + (let ((old-nets (bbdb-record-net old-record)) + (new-nets (bbdb-record-net new-record))) + (while old-nets + (if (not (member (car old-nets) new-nets)) + (setq new-nets (append new-nets (list (car old-nets))))) + (setq old-nets (cdr old-nets))) + (bbdb-record-set-net new-record new-nets)) + ;; addrs + (let ((old-addresses (bbdb-record-addresses old-record)) + (new-addresses (bbdb-record-addresses new-record))) + (while old-addresses + (if (not (member (car old-addresses) new-addresses)) + (setq new-addresses (append new-addresses (list (car old-addresses))))) + (setq old-addresses (cdr old-addresses))) + (bbdb-record-set-addresses new-record new-addresses)) + ;; phones + (let ((old-phones (bbdb-record-phones old-record)) + (new-phones (bbdb-record-phones new-record))) + (while old-phones + (if (not (member (car old-phones) new-phones)) + (setq new-phones (append new-phones (list (car old-phones))))) + (setq old-phones (cdr old-phones))) + (bbdb-record-set-phones new-record new-phones)) + ;; notes + (let ((old-notes (bbdb-ensure-list (bbdb-record-raw-notes old-record))) + (new-notes (bbdb-ensure-list (bbdb-record-raw-notes new-record)))) + (while old-notes + (if (not (member (car old-notes) new-notes)) + (setq new-notes (append new-notes (list (car old-notes))))) + (setq old-notes (cdr old-notes))) + (bbdb-record-set-raw-notes new-record new-notes)) + ;; return + new-record) + +(defun bbdb-ensure-list (foo) + (if (lisp foo) foo + (list foo) + ) + ) + +(defun bbdb-zulu (date) + (if (fboundp 'bbdb-time-convert) + (bbdb-time-convert date "%Y%m%d%H%Mz") + date ;; bbdb1.51 does not use it anyway. + ) +) + +(defun bbdb-unzulu (date) + (if (eq (length date) 13) + (format "%s-%s-%s" (substring date 0 4) (substring date 4 6) (substring date 6 8)) + date) +) +(defun bbdb-ldif-indent (str) + (if (> (length str) 70) + (concat (substring str 0 65) "\n " (bbdb-ldif-indent (substring str 65))) + str) +) + +(defun addnote (nrec nname note) + (bbdb-record-set-raw-notes + nrec (cons (cons nname note) (bbdb-record-raw-notes nrec) ) + ) + ) + +(defmacro alias-update () + (if (fboundp 'bbdb-define-all-aliases) (list 'bbdb-define-all-aliases)) +) + +(defmacro alias-setup () + (if (fboundp 'mail-aliases-setup) (list 'mail-aliases-setup)) +) + +(defmacro domailaliases () + (fboundp 'mail-aliases-setup) +) + + +(defmacro dodenote (st) + (if (fboundp 'base64-decode-string) + (list 'base64-decode-string st) + "?" + ) +) + +(defun addtonote (ton str) + (cond + ((and ton str) (concat ton "\n" str)) + (str (concat "--bbdb--\n" str)) + (ton) + ) + ) + +(defun setaddr (nrec afun val) + (if (not (bbdb-record-addresses nrec)) + (let ((addr(make-vector bbdb-address-length ""))) + (bbdb-record-set-addresses nrec (list addr)) + (bbdb-address-set-location addr "address") + ) + ) + (eval (list afun (car (bbdb-record-addresses nrec)) val)) + ) + + +(defun setphone (nrec iloc pno np) + (let ((nov (bbdb-parse-phone-number pno)) + (pv (make-vector bbdb-phone-length "")) + (ploc iloc) + ) + (if (and np (equal (car np) (concat bbdb-ldif-prefixh "PhoneLoc"))) + (setq ploc (cdr np)) + ) + + (if (and nov bbdb-north-american-phone-numbers-p) + (progn + (bbdb-phone-set-location pv ploc) + (bbdb-phone-set-area pv (nth 0 nov)) + (bbdb-phone-set-exchange pv (nth 1 nov)) + (bbdb-phone-set-suffix pv (nth 2 nov)) + (bbdb-phone-set-extension pv (or (nth 3 nov) 0)) + ) + (setq pv (vector ploc pno)) + ) + (bbdb-record-set-phones nrec(append (bbdb-record-phones nrec)(list pv))) + ) + ) + +(defun bbdb-string-fetch (key mls) + (let ((tmls (car mls)) res) + (while (and (not res) (car tmls)) + (if (string-match (format "%s= *\\(.+\\)" key) (car tmls)) + (setq res (match-string 1 (car tmls)))) + (setq tmls (cdr tmls))) + res + ) + ) + +(defun bbdb-ldif-get-phone (atts df) + (if (and (cdr atts) (equal (concat bbdb-ldif-prefixh "phoneloc") (caadr atts))) + (cdr (cadr atts)) + df) +) + +(defun bbdb-import-ldif () + "import LDIF entries for current buffer +Mailinglists \(groupOfNames\) are imported as entries in bbdb mail-alias fields." + (interactive) +; (message (concat (/(* 100 (point)) (point-max)) " pct\n")) +;; (message (concat "\nnew rec at" (point))) + (let ((reclist (split-string (buffer-substring 1 (point-max)) "\n[ \t\r]*\n")) + (numr 0) maxr (opct 0) pct mailinglists (emptyrec (make-vector bbdb-record-length nil)) + ) + (setq maxr (length reclist)) + (mapcar + (lambda (rec) + (if (not (equal "" rec)) + (let ( + (atts (mapcar (lambda (at) + (if (equal (string-to-char at) ?\ ) + (cons 'continuation (substring at 1)) + (let ( (cpos (string-match ":" at))) + (if cpos + (let ((cpos2 ( string-match "[^ \t]" at (1+ cpos)))) + (if cpos2 + (cons (substring at 0 cpos) (substring at cpos2)) + ) + ) + ) + ) + ) + ) + (split-string rec "[\n\r]+")) + ) + ) + (setq pct (/ (* 100 numr) maxr)) + (if (/= opct pct) + (progn + (setq opct pct) + (message (concat pct " pct")) + ) + ) + (setq numr (1+ numr)) + + (if (member '("objectclass" . "groupOfNames") atts) + (let (mlcn lmlist) + (while atts + (if (car atts) + (let ((attName (downcase (caar atts))) + (attVal (cdar atts)) + ) + (while (and (cdr atts) (equal (caadr atts) 'continuation)) + (setq atts (cdr atts)) + (setq attVal (concat attVal (cdar atts))) + ) + (if (equal (string-to-char attVal) ?:) + (setq attVal (dodenote (substring attVal (string-match "[^: \t]" attVal))))) + + (cond + ((or (equal attName "cn") (equal attName "commonname")) (setq mlcn attVal)) + ((equal attName "member") + (setq lmlist (cons (bbdb-split attVal ",") lmlist)) + ) + ) + ) + ) + (setq atts (cdr atts)) + ) ; while + (setq mailinglists (cons (cons mlcn lmlist) mailinglists)) + ) + (let ( + (new-record (make-vector bbdb-record-length nil))) + (while atts + (if (stringp (car-safe (car-safe atts))) + (let ( + (attName (downcase (caar atts))) + (attVal (cdar atts)) + (nextAtt (car-safe (cdr-safe atts))) + ) + + (while (and (cdr atts) (equal (caadr atts) 'continuation)) + (setq atts (cdr atts)) + (setq attVal (concat attVal (cdar atts))) + ) + (if (equal (string-to-char attVal) ?:) + (setq attVal + (dodenote (substring attVal (string-match "[^: \t]" attVal)))) + ) + (cond + ;((or (equal attName "cn") (equal attName "commonname")) hmm) + ((or (equal attName "sn") (equal attName "surname")) (bbdb-record-set-lastname new-record attVal)) + ((equal attName "givenname") (bbdb-record-set-firstname new-record attVal)) + ((equal attName "o") (bbdb-record-set-company new-record attVal)) + ((equal attName "locality") (setaddr new-record 'bbdb-address-set-city attVal)) + ((equal attName "postalcode") (setaddr new-record 'bbdb-address-set-zip attVal)) + ((equal attName "st") (setaddr new-record 'bbdb-address-set-state attVal)) + ((equal attName (concat bbdb-ldif-prefixh "mainaddrloc")) + (setaddr new-record 'bbdb-address-set-location attVal)) + + ;; This is ugly. But is it the only way Netscape understands. + ((equal attName "postofficebox") (setaddr new-record 'bbdb-address-set-street1 attVal)) + ((equal attName "streetaddress") (setaddr new-record 'bbdb-address-set-street2 attVal)) + + ((equal attName "mail") + (bbdb-record-set-net new-record (cons attVal (bbdb-record-net new-record)))) + + ((equal attName "mailalternateaddress") + (bbdb-record-set-net new-record (append (bbdb-record-net new-record) + (list attVal))) + ) + + ((equal attName "postaladdress") + (let ( + (alines (split-string (concat (bbdb-ldif-renl attVal) "\n")"[\n\r]")) + (addr (make-vector bbdb-address-length ""))) + (if (and (string-match "^bbdb=" (nth 0 alines )) + (> (length alines) 6)) + (progn + (bbdb-address-set-location addr (substring (nth 0 alines) 5)) + (bbdb-address-set-street1 addr (nth 1 alines)) + (bbdb-address-set-street2 addr (nth 2 alines)) + (bbdb-address-set-street3 addr (nth 3 alines)) + (bbdb-address-set-zip addr (nth 4 alines)) + (bbdb-address-set-city addr (nth 5 alines)) + (bbdb-address-set-state addr (nth 6 alines)) + (bbdb-record-set-addresses + new-record + (append (bbdb-record-addresses new-record) (list addr)) + ) + ) + ) + ) + ) + + + ((equal attName "homephone") + (setphone new-record (bbdb-ldif-get-phone atts "Private") attVal nextAtt) ) + ((equal attName "facsimiletelephonenumber") + (setphone new-record (bbdb-ldif-get-phone atts "Fax") attVal nextAtt)) + ((equal attName "pagerphone") + (setphone new-record (bbdb-ldif-get-phone atts "pagerphone") attVal nextAtt)) + ((equal attName "cellphone") + (setphone new-record (bbdb-ldif-get-phone atts "cellphone") attVal nextAtt)) + ((equal attName "mobiletelephonenumber") + (setphone new-record (bbdb-ldif-get-phone atts "cellphone") attVal nextAtt)) + ((equal attName "telephonenumber") + (setphone new-record (bbdb-ldif-get-phone atts "Work") attVal nextAtt)) + ((equal attName "xmozillanickname") (bbdb-record-set-aka new-record (list attVal))) + ((or (equal attName "description") (equal attName "multilinedescription")) + (if (equal attName "multilinedescription") + (setq attVal (bbdb-ldif-renl attVal))) + (let ((thenote (substring attVal 0 (string-match "\n?--bbdb--\n" attVal)))) + (if (not (equal "" thenote)) + (addnote new-record 'notes thenote) + ) + ) + ) + + ((equal attName "createTimestamp") + (addnote new-record 'creation-date (bbdb-unzulu attVal))) + ((equal attName "modifyTimestamp") + (addnote new-record 'timestamp (bbdb-unzulu attVal))) + ((eq (string-match bbdb-ldif-prefix attName) 0) + (let ( + (bbdb-ldif-note (make-symbol (substring attName (length bbdb-ldif-prefix))))) + (bbdb-record-set-raw-notes new-record + (cons (cons bbdb-ldif-note attVal) + (bbdb-record-raw-notes new-record))) + ) + ) + ) + ) + ) + (setq atts (cdr atts)) + ) + ; (print new-record) + (if (not (equal new-record emptyrec)) + (progn + (bbdb-record-set-cache new-record (make-vector bbdb-cache-length nil)) + (let ((old-record +;; (and (bbdb-record-net new-record) + (bbdb-search-simple (tnsnil (bbdb-record-name new-record)) + (car (bbdb-record-net new-record))) +;; ) + ) + ) + (if old-record + (progn + (setq new-record (bbdb-merge-internally-ldif old-record new-record)) + (bbdb-delete-record-internal old-record))) + ;; create new record + (bbdb-invoke-hook 'bbdb-create-hook new-record) + (bbdb-change-record new-record t) + (bbdb-hash-record new-record) + ) + ) + ) + ) + ) + + ) + ) ; if + ) ; lambda + reclist + ) + (mapcar + (lambda (mlist) + (let ( + (mlcn (car mlist)) (lmlist (cdr mlist))) + (if mlcn + (while lmlist + (let ( + (mnet (bbdb-string-fetch"mail" lmlist)) + (mname (bbdb-string-fetch"cn" lmlist)) + (mcomp (bbdb-string-fetch"o" lmlist)) +;; (mou (bbdb-string-fetch"ou" lmlist)) + (therecs (bbdb-records)) + therec + mal + ) + (if mnet (setq therecs (bbdb-search therecs nil nil mnet nil))) + (if mname (setq therecs (bbdb-search therecs mname nil nil nil ))) + (if mcomp (setq therecs (bbdb-search therecs nil mcomp nil nil nil ))) + + (cond ((not therecs) + (message (concat "Mailing list member not found: " mname " " mnet))) + ((= (length therecs) 1) + (setq therec (car therecs)) + (setq mal (assq 'mail-alias (bbdb-record-raw-notes therec))) + (if (not mal) + (progn + (setq mal (cons 'mail-alias "")) + (bbdb-record-set-raw-notes therec (cons mal (bbdb-record-raw-notes therec)))) + (bbdb-change-record therec nil) + (bbdb-hash-record therec) + ) + (if (not (member mlcn (split-string (cdr mal) "[, ]"))) + (setcdr mal (concat mlcn (if (> (length (cdr-safe mal)) 0) "," "") (cdr mal) ))) + ) + (t (message "Mailing List member not unique %s, %s" mname mnet)) + ) + ) + (setq lmlist (cdr lmlist)) + ) + ; (define-mail-alias cn lmlist) + ) + ) + ) + mailinglists + ) + ) +(message nil) +) + + + +(defun rmspace (str) + (apply 'concat (bbdb-split str "\n\r"))) + +(defun bbdb-ldif-replace-string (str frs tos) + (let ((start 0)) + (while (string-match frs str start) + (setq str + (concat (substring str 0 (match-beginning 0)) + tos + (substring str (match-end 0)))) + (setq start (+ (length tos) (match-beginning 0)))) + ) +str +) + + +(defun bbase64-encode-string (st) + (concat ":" (bbdb-ldif-indent (rmspace st)) + ) + ) + +(defun bbdb-ldif-rmnl (str) + (bbdb-ldif-replace-string (bbdb-ldif-replace-string str "\\$" "\\24") "\n" "$") +) + +(defun bbdb-ldif-renl (str) + (bbdb-ldif-replace-string (bbdb-ldif-replace-string str "\\$" "\n") "\\\\24" "$") +) + +(defmacro donote (st) + (if (fboundp 'base64-encode-string) + (list 'bbase64-encode-string (list 'base64-encode-string st)) + (list 'bbdb-ldif-rmnl st) + ) +) + +(defun base64IfMulti (st) + (if (string-match "\n" st) + (donote st) + (concat " " (bbdb-ldif-indent st)) + ) +) + +(defun nsloc (pl) "Guess mapping from userdefined bbdb locations to NS Work/Home/Fax" + (let ( + (pld (and pl (downcase pl))) + (fc (and pl (not (equal pl "")) (string-to-char (downcase pl)))) + ) + (cond ( (not fc) "telephonenumber") + ((or (= fc ?a) (= fc ?w)) "telephonenumber") + ( (= fc ?h) "homephone") +;; ( (= fc ?m) "mobileTelephoneNumber") + ( (equal pld "private") "homephone") + ( (= fc ?m) "cellphone") + ( (and (= fc ?p) (> (length pld) 1) (= (aref pld 1) ?a)) "pagerphone") + ( (equal pld "fax") "facsimiletelephonenumber") + ( t "telephonenumber") + ) + ) +) + +(defun tnil(tt) + (if tt tt "?")) + +(defvar ldifbuffer "*LDIF*" "Name of buffer for LDIF output") + +(defun bbdb-to-ldif (visible-records) "Converts BBDB to LDIF format. Can be used to export bbdb to Netscape +Communicator Address book.\\<bbdb-mode-map> +If \"\\[bbdb-apply-next-command-to-all-records]\\[bbdb2ldif]\" is \ +used instead of simply \"\\[bbdb2ldif]\", then includes only the +people currently in the *BBDB* buffer. +The result is placed in a buffer name \"*LDIF*\" +If MEL is installed Multiline notes/descriptions work with Netscape address book. +Mail-aliases from mailrc file or bbdb mail-aliases fields are exported as mainglists +\(GroupOfNames\) +" + (interactive (list + (bbdb-do-all-records-p) + ) + ) + (let* ( + (target (cons bbdb-define-all-aliases-field ".")) + (ldif-records + (bbdb-search + (if (not visible-records) + (bbdb-records) + (mapcar 'car bbdb-records) + ) + nil nil nil target) + ) + tmps + record + ) + + + (setq ldif-records + (if (not visible-records) + (bbdb-records) + (mapcar 'car bbdb-records) + ) + ) + + (set-buffer (get-buffer-create ldifbuffer)) + (setq fill-column 1000) + (erase-buffer) + + (while ldif-records + (setq record (car ldif-records)) + (insert "\nxmozillausehtmlmail: FALSE\n") + (let ( + (net (car (bbdb-record-net record))) + (rnet (bbdb-record-net record)) + ) + (insert (format "dn: cn=%s" (tnil (bbdb-record-name record)))) + (if net + (insert (format ",mail=%s" net)) + ) + (insert "\n") + + (setq tmps (bbdb-record-firstname record)) (insert "givenname: " (tnil tmps) "\n") + (setq tmps (bbdb-record-lastname record)) (if tmps (insert "sn: " tmps "\n")) + (insert "objectclass: top\nobjectclass: person\n") + (setq tmps (bbdb-record-company record)) (if tmps (insert "o: " tmps "\n")) + (setq tmps (bbdb-record-name record)) (if tmps (insert "cn: " tmps "\n")) + + (if net (insert "mail: " net "\n")) + (while (cdr rnet) + (insert "mailAlternateAddress: " (cadr rnet) "\n") + (setq rnet (cdr rnet)) + ) + ) + (let ( + (phones (bbdb-record-phones record)) + (addrs (bbdb-record-addresses record)) + (aka (bbdb-record-aka record)) + (firstaddr t) + tonote + phone + (elide nil) + ) + + (while phones + (setq phone (car phones)) + (if (equal (nsloc (bbdb-phone-location phone))"cellphone") + (setq tonote (addtonote tonote (concat "M:" (bbdb-phone-string phone) ))) + ) + (if (equal (nsloc (bbdb-phone-location phone))"pagerphone") + (setq tonote (addtonote tonote (concat "P:" (bbdb-phone-string phone) ))) + ) + (insert (format "%s: " (nsloc (bbdb-phone-location phone))) (bbdb-phone-string phone) "\n") + (insert bbdb-ldif-prefixh "PhoneLoc:" (bbdb-phone-location phone)"\n") + (setq phones (cdr phones))) + + (let (addr tmps) + (while addrs + (setq addr (car addrs)) + (if firstaddr (progn + (if (= 0 (length (setq tmps (bbdb-address-street1 addr)))) nil (insert "postOfficeBox: " tmps "\n")) + (if (= 0 (length (setq tmps (bbdb-address-street2 addr)))) nil (insert "streetaddress: " tmps "\n")) + (if (= 0 (length (setq tmps (bbdb-address-street3 addr)))) nil (insert "streetaddress: " tmps "\n" )) + + ; This does not work with Netscape + ; (if (= 0 (length (setq tmps (bbdb-address-street1 addr)))) nil (insert "homePostalAddress:" tmps )) + ; (if (= 0 (length (setq tmps (bbdb-address-street2 addr)))) nil (insert "$" tmps)) + ; (if (= 0 (length (setq tmps (bbdb-address-street3 addr)))) nil (insert "$" tmps )) + ; (insert "\n") + + (insert "locality:" (bbdb-address-city addr) "\n") + (setq tmps (bbdb-address-state addr)) + (if (and tmps (not (equal tmps ""))) (insert "st:" tmps "\n")) + (if (bbdb-address-zip-string addr) + (insert "postalcode:" (bbdb-address-zip-string addr) "\n")) + (setq firstaddr nil) + ) + (progn + (setq tonote (addtonote tonote (concat (bbdb-address-street1 addr)))) + (setq tonote (addtonote tonote (concat (bbdb-address-street2 addr)))) + (setq tonote (addtonote tonote (concat (bbdb-address-street3 addr)))) + (setq tonote (addtonote tonote (concat (bbdb-address-zip-string addr) " " (bbdb-address-city addr) ))) + (insert (concat "postalAddress: " + (base64IfMulti (concat "bbdb=" (bbdb-address-location addr) "\n" + (bbdb-address-street1 addr) "\n" + (bbdb-address-street2 addr) "\n" + (bbdb-address-street3 addr) "\n" + (bbdb-address-zip-string addr) "\n" + (bbdb-address-city addr) "\n" + (bbdb-address-state addr) + ) + ) + "\n" + ) + ) + ) + ) + (setq addrs (cdr addrs))) + ) + (cond (aka + (insert (format "%s: %s\n" "xmozillanickname" + (mapconcat (function identity) aka ", "))) + )) + (let ((notes (bbdb-record-raw-notes record))) + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + (while notes + (setq elide nil) + (cond + ((member (caar notes) bbdb-elided-export-ldif) (setq elide t)) + ((eq (car (car notes)) 'creation-date) + (insert "createTimestamp: " (bbdb-zulu (cdar notes))"\n") + (setq elide t) + ) + ((eq (car (car notes)) 'timestamp) + (setq elide t) + (insert "modifyTimestamp: "(bbdb-zulu (cdar notes))"\n") + ) + ((eq (car (car notes)) 'notes) (setq elide t)) + ((eq (car (car notes)) 'mail-alias) (setq elide t)) + (t + ;; Netscape cannot display this. So we also put it in the notes field. + (setq tonote (addtonote tonote (format "%s:%s" (caar notes) (cdar notes)))) + (insert (format "%s%s:" bbdb-ldif-prefix (car (car notes)))) + ) + ) + (if (eq (caar notes) 'notes) + (if tonote + (setq tonote (concat (cdar notes) "\n" tonote)) + (setq tonote (cdar notes))) + (if (not elide) + (insert (base64IfMulti (tnil (cdar notes))) "\n")) + ) + (setq notes (cdr notes)) + ) + (if tonote + (if (and (string-match "\n" tonote) (not (fboundp 'base64-encode-string))) + (insert "multilineDescription:" (bbdb-ldif-rmnl tonote ) "\n") + (insert "description:" (base64IfMulti tonote ) "\n") + ) + ) + ) + (if (bbdb-record-addresses record) + (insert bbdb-ldif-prefixh "mainAddrLoc:" (bbdb-address-location (car (bbdb-record-addresses record)))"\n") + ) + + ) + (setq ldif-records (cdr ldif-records)) + ) + ) + (if (and (not visible-records) (domailaliases)) + (progn + (alias-update) + (alias-setup) + ;; (bbdb-define-all-aliases) + (let ((mai 0) mae alist (malen (length mail-aliases) + )) + (while (< mai malen) + (setq mae (aref mail-aliases mai) ) + (if (and mae (symbolp mae )) + (progn + (insert (format "\ndn: cn=%s\n" mae)) + (insert (format "cn: %s\n" mae)) + (insert "objectclass: top\n") + (insert "objectclass: groupOfNames\n") + (setq alist (symbol-value mae )) + (if alist + (mapcar + (lambda (an) + (let ((trec (bbdb-search-simple nil an)) + ) + (if trec + (insert (format "member: cn=%s,mail=%s\n" + (tnil (bbdb-record-name trec)) + (tnil (car (bbdb-record-net trec))) + ) + ) + ) + ) + ) + (split-string alist ", ") + ) + ) + ) + ) + (setq mai (1+ mai)) + ) + ) + ) + (alias-update) + ) + (set-window-buffer (get-lru-window) ldifbuffer ) +) +;;(add-hook 'bbdb-load-hook (lambda () (define-key bbdb-mode-map "L" 'bbdb-to-ldif))) +(define-key bbdb-mode-map "L" 'bbdb-to-ldif) +(provide 'bbdb-ldif) diff --git a/bits/bbdb-mail-folders.el b/bits/bbdb-mail-folders.el new file mode 100644 index 0000000..701a2c9 --- /dev/null +++ b/bits/bbdb-mail-folders.el @@ -0,0 +1,122 @@ +;;; From: Geoffroy Ville <ville@isr.umd.edu> +;;; Subject: bbdb/mail-folders +;;; Date: 20 Nov 1998 00:00:00 GMT +;;; Message-ID: <6azlnl56h9v.fsf@einstein.isr.umd.edu> +;;; Sender: ville@einstein.isr.umd.edu +;;; Organization: University of Maryland, College Park +;;; X-Url: http://www.cenaath.cena.dgac.fr/~ville/ +;;; Newsgroups: gnu.emacs.sources,gnu.emacs.vm.info + + +;;; Just thought I would repost this piece of code after today's +;;; improvement. Cengiz told me he does not use it hence does not maintain it +;;; anymore. + +;;; I do not remember where I got it from originally, thus this post in sources +;;; and vm.info. + +;;; For BBDB users, this code allows you to have several mail-folder by default +;;; for a given author. Saving one mail creates automaically the entry if none, or +;;; allows you to select which among the existing one you want, or add a new one. +;;; Very useful when several people you know are involved in many different +;;; projects. After a while, a typical entry would look like this: + +;;; mail-folders: ("~/Mail/project1" "~/Mail/project2" "~/Mail/personal") + +;;; My 2 cts addition is an expand file-name to get rid of possible duplicate +;;; paths to the same file and a file-name-abbrevation to keep it ~/Mail for +;;; example (very useful for me because I changed sites twice in the recent years +;;; and had different home directories). + +;;; I'm just *sharing* the code and will not have time to maintain it further. But +;;; if it's buggy or outdated by some new feature of I_do_not_know_what, please +;;; tell me :-) + +;;; --- bbdb-mail-folders.el --- + +;A while back Roland posted advices to enable a mail-folder +;property. This property was used as the default folder name while +;saving messages in vm. + +;I have improved that in two ways: +;1. It is now a list of folder names, the first one on this list +; becomes the default folder name and the other names are pushed to +; the file-name history so that one can scroll through them using the +; history mechanisms. This is useful if you are saving mail from a +; person to more than one folder. +;2. This property is created and updated automatically when a message +; is saved to a folder so that the list is in MRU (most recently +; used) order. This is useful, because I am lazy to set the +; mail-folder property by hand. + +;I renamed the property to mail-folders so that it does not break with +;the existing mail-folder property. + +;Enjoy. Bug fixes are welcome. + +;Cengiz + +;-- +;Cengiz Alaettinoglu Information Sciences Institute +;(310) 822-1511 University of Southern California +;http://www.isi.edu/div7/people/cengiz.home + +;$Modified: Fri Nov 20 11:41:56 1998 by ville@isr.umd.edu $ +; GV: - always expand filename to avoid duplicate similar path +; - use abbreviation alist for home directory (comes from mode-line) + +(defvar bbdb/vm-mail-folders-file-name-history nil "") + +(defvar bbdb/file-name-abbreviation-alist + (list + (cons (concat "^" (expand-file-name "~") "/") "~/") + ) +) + +(defadvice vm-save-message (around bbdb/vm-mail-folders activate compile) + "cache" + (let* ((folder-name "") + (record (bbdb/vm-update-record nil)) + (mail-folders (and record (bbdb-record-getprop record 'mail-folders))) + (folder-list (and mail-folders (car (read-from-string mail-folders))))) + ad-do-it + (setq folder-name (ad-get-arg 0)) + (setq folder-name (expand-file-name folder-name vm-folder-directory)) + (setq folder-name (string-replace-regexp-alist + folder-name bbdb/file-name-abbreviation-alist)) + (setq file-name-history + (append (list folder-name) bbdb/vm-mail-folders-file-name-history)) + (and record + (progn + (setq folder-list (delete folder-name folder-list)) + (setq folder-list (append (list folder-name) folder-list)) + (bbdb-record-putprop record 'mail-folders + (prin1-to-string folder-list)) + ) + ) + ) + ) + +(defadvice vm-auto-select-folder (around bbdb/vm-mail-folders activate compile) + "If the message sender's BBDB entry has a `mail-folder' property, use that." + (let* ((record (bbdb/vm-update-record nil)) + (mail-folders (and record (bbdb-record-getprop record 'mail-folders))) + (folder-list (and mail-folders (car (read-from-string mail-folders)))) + (folder-name (and folder-list (car folder-list)))) + (setq bbdb/vm-mail-folders-file-name-history file-name-history) + (and (cdr folder-list) + (setq file-name-history + (append (cdr folder-list) file-name-history))) + (if folder-name + (setq ad-return-value (file-name-nondirectory folder-name)) + ad-do-it) + ) + ) + +(provide 'bbdb-mail-folders) + +;;; --- end --- + +;;; Enjoy, + +;;; -- Geoffroy diff --git a/bits/bbdb-mew.el b/bits/bbdb-mew.el new file mode 100644 index 0000000..5f8b63b --- /dev/null +++ b/bits/bbdb-mew.el @@ -0,0 +1,248 @@ +;;; bbdb-mew.el --- BBDB interface to Mew + +;; Copyright (C) 1991, 1992 Jamie Zawinski +;; Copyright (C) 1996 Shuhei KOBAYASHI +;; Copyright (C) 1996 Daisuke Kanda +;; Copyright (C) 1999 Mitsuo Nishizawa + +;; Author: Jamie Zawinski <jwz@netscape.com> +;; Shuhei KOBAYASHI <shuhei-k@jaist.ac.jp> +;; Daisuke Kanda <small@first.tsukuba.ac.jp> +;; Mitsuo Nishizawa <mitsuo@phys2.med.osaka-u.ac.jp> +;; Maintenance: Chris Beggy +;; Created: 1996/11/04 +;; Version: $Id: bbdb-mew.el,v 1.5 2001/12/29 16:12:20 chrisb Exp $ + +;; Keywords: mail, BBDB + +;; This file is not part of BBDB (Insidious Big Brother Database). + +;; 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 2, 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to the +;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;;; Commentary: +;; +;; 2002-12-28 checked and edited for bbdb CVS version + mew 3.0.51 + emacs 21.1 + +;; Installation: +;; +;; Put bbdb-mew.el in your load path, so that emacs can find it. +;; +;; Run a patched bbdb-com.el to allow mew to be the mailer bbdb +;; uses if bbdb-send-mail-style is set to 'mew +;; +;; Insert the following lines in your ~/.emacs: +;; (other BBDB stuff comes here) +;; : +;; (autoload 'bbdb-insinuate-mew "bbdb-mew" "Hook BBDB into Mew") +;; (add-hook 'mew-init-hook 'bbdb-insinuate-mew) +;; (setq bbdb-send-mail-style 'mew) +;; +;; To use BBDB name at From: field of header in citation, please set +;; (setq mew-cite-bbdb-header t) +;; +;; Chris Beggy started doing some maintenance. + +;;; Codes: + +(require 'bbdb) +(require 'mew) + +(defvar mew-cite-bbdb-header nil) +(defvar mew-cite-bbdb-enable nil) + +(or (fboundp 'mew-header-get-value) + (fset 'mew-header-get-value (symbol-function 'mew-field-get-value)) + ) + +(defun bbdb/mew-update-record (&optional offer-to-create) + "Returns the record corresponding to the current mew message, +creating or modifying it as necessary. A record will be created if +bbdb/mail-auto-create-p is non-nil, or if OFFER-TO-CREATE is true and +the user confirms the creation." + (save-excursion + (set-buffer (mew-buffer-message)) + (if bbdb-use-pop-up + (bbdb/mew-pop-up-bbdb-buffer offer-to-create) + (let* ((from (mew-header-get-value mew-from:)) + (addr (and from + (car (cdr (mail-extract-address-components from)))))) + (if (or (null from) + (null addr) + (string-match (bbdb-user-mail-names) addr)) + (setq from (or (mew-header-get-value mew-to:) from))) + (if from + (bbdb-annotate-message-sender + from t + (or (bbdb-invoke-hook-for-value + bbdb/mail-auto-create-p) + offer-to-create) + offer-to-create)))))) + +(defun bbdb/mew-annotate-sender (string) + "Add a line to the end of the Notes field of the BBDB record +corresponding to the sender of this message." + (interactive + (list (if bbdb-readonly-p + (error "The Insidious Big Brother Database is read-only.") + (read-string "Comments: ")))) + (bbdb-annotate-notes (bbdb/mew-update-record t) string)) + +(defun bbdb/mew-edit-notes (&optional arg) + "Edit the notes field or (with a prefix arg) a user-defined field +of the BBDB record corresponding to the sender of this message." + (interactive "P") + (let ((record (or (bbdb/mew-update-record t) (error "")))) + (bbdb-display-records (list record)) + (if arg + (bbdb-record-edit-property record nil t) + (bbdb-record-edit-notes record t)))) + +(defun bbdb/mew-show-sender () + "Display the contents of the BBDB for the sender of this message. +This buffer will be in bbdb-mode, with associated keybindings." + (interactive) + (let ((record (bbdb/mew-update-record t))) + (if record + (bbdb-display-records (list record)) + (error "unperson")))) + +(defun bbdb/mew-pop-up-bbdb-buffer (&optional offer-to-create) + "Make the *BBDB* buffer be displayed along with the mew windows, +displaying the record corresponding to the sender of the current message." + (let ((framepop (eq temp-buffer-show-function 'framepop-display-buffer))) + (or framepop + (bbdb-pop-up-bbdb-buffer + (function + (lambda (w) + (let ((b (current-buffer))) + (set-buffer (window-buffer w)) + (prog1 (eq major-mode 'mew-message-mode) + (set-buffer b))))))) + (let ((bbdb-gag-messages t) + (bbdb-use-pop-up nil) + (bbdb-electric-p nil)) + (let ((record (bbdb/mew-update-record offer-to-create)) + (bbdb-display-layout bbdb-pop-up-display-layout) + (b (current-buffer))) + (if framepop + (if record + (bbdb-display-records (list record)) + (framepop-banish)) + (bbdb-display-records (if record (list record) nil))) + (set-buffer b) + record)))) + +;;; Utilities +;;; + +(defun bbdb-record-field (record field) + (cond + ((eq field 'firstname) (bbdb-record-firstname record)) + ((eq field 'lastname) (bbdb-record-lastname record)) + ((eq field 'aka) (bbdb-record-aka record)) + ((eq field 'company) (bbdb-record-company record)) + ((eq field 'phones) (bbdb-record-phones record)) + ((eq field 'addresses) (bbdb-record-addresses record)) + ((eq field 'net) (bbdb-record-net record)) + ((eq field 'raw-notes) (bbdb-record-raw-notes record)) + ((eq field 'cache) (bbdb-record-cache record)) + (t + (and (consp (bbdb-record-raw-notes record)) + (cdr (assq field (bbdb-record-raw-notes record))) + )))) + +(defun bbdb-record-fields (record fields) + (let (value) + (while (and fields (null value)) + (setq value (bbdb-record-field record (car fields))) + (setq fields (cdr fields))) + value)) + +;;; Register citation attribution in BBDB +;;; + +(defvar mew-cite-bbdb-fields '(attribution lastname firstname)) + +(defun mew-cite-prefix-bbdb () + (if mew-cite-bbdb-enable + (let (from petname prefix) + (setq from (mew-header-get-bbdb-name)) + (if (and mew-use-petname mew-petname-alist + (setq petname + (cdr (mew-assoc-case-equal from mew-petname-alist 0)))) + (setq prefix petname) + (setq prefix (mew-addrstr-extract-user from))) + (if mew-ask-cite-prefix + (setq prefix (read-string "Citation prefix: " prefix))) + (format "%s> " prefix) + ))) + +(defun mew-header-get-bbdb-name () + (if mew-cite-bbdb-enable + (let* ((from (mew-header-parse-address mew-from:)) + (addr from) + (name nil) + (net addr) + (record (and addr + (bbdb-search-simple name + (if (and net bbdb-canonicalize-net-hook) + (bbdb-canonicalize-address net) + net))))) + (or (and record + (bbdb-record-fields record mew-cite-bbdb-fields)) + net)))) + +(or (fboundp 'bbdb:mew-cite-strings) + (fset 'bbdb:mew-cite-strings (symbol-function 'mew-cite-strings))) + +(defun mew-cite-strings-bbdb () + (if mew-cite-bbdb-enable + (let (fields) + (if mew-cite-bbdb-header + (setq fields + (mapcar + (function + (lambda (x) + (or (if (string= x mew-from:) + (mew-header-get-bbdb-name) + (mew-header-get-value x)) + ""))) + mew-cite-fields)) + (setq fields + (mapcar (function mew-header-get-value) mew-cite-fields))) + (setq fields (mapcar (lambda (x) (or x "")) fields)) + (if mew-use-petname + (setq fields (mew-cite-strings-with-petname fields mew-cite-fields)) + ) + (if mew-use-bbdb + (apply (function format) mew-cite-format fields) + (bbdb:mew-cite-strings))))) + +;;; Installation +;;; + +(defun bbdb-insinuate-mew () + "Call this function to hook BBDB into Mew." + (if (string-match "2.3" (bbdb-version)) + (add-hook 'mew-message-hook 'bbdb/mew-update-record) + (bbdb-add-hook 'mew-message-hook 'bbdb/mew-update-record)) + (define-key mew-summary-mode-map ":" 'bbdb/mew-show-sender) + (define-key mew-summary-mode-map ";" 'bbdb/mew-edit-notes) + ) + +(provide 'bbdb-mew) + +;;; bbdb-mew.el ends here. diff --git a/bits/bbdb-obsolete.el b/bits/bbdb-obsolete.el new file mode 100644 index 0000000..18ac88c --- /dev/null +++ b/bits/bbdb-obsolete.el @@ -0,0 +1,67 @@ +;;; bbdb-obsolete-net.el -- Handle obsolete-net addresses. + +;; Copyright (C) 2001 Colin Rafferty + +;; Author: Colin Rafferty <colin@xemacs.org> +;; Keywords: bbdb, net, obsolete +;; Version: $Id: bbdb-obsolete.el,v 1.3 2006/02/04 15:34:30 joerg Exp $ + +;; 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 2, 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; A copy of the GNU General Public License can be obtained from this +;; program's author (send electronic mail to colin@xemacs.org) or from +;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; Send bug reports to colin@xemacs.org + +;;; Commentary: + +;; My ~/.bbdb is seven years old. People change jobs, change ISPs, +;; and change nyms. Their email addresses change. + +;; While I no longer want to send someone email at an old address, I +;; still have old messages with the old addresses, and I want to match +;; up. + +;; Move the old addresses into the field `obsolete-net', and: + +;; (setq 'bbdb-obsolete-net-canonicalize-net-hook 'bbdb-canonicalize-net-hook) + +;; If you already have a `bbdb-obsolete-net-canonicalize-net-hook', +;; then call `bbdb-canonicalize-net-hook' from within your function. + +;;; Code: + +(require 'bbdb-com) + +(defgroup bbdb-obsolete-net nil + "Customizations for setting up obsolete network addresses." + :group 'bbdb) + +(defcustom bbdb-obsolete-net-field 'obsolete-net + "*Field in which to add the obsolete net addresses." + :group 'bbdb-obsolete-net + :type 'symbol) + +;;;###autoload +(defun bbdb-obsolete-net-canonicalize-net-hook (addr) + "Return user's current net address given obsolete ADDR. + +Return ADDR if it is not obsolete anywhere, or there is no net address +in the matching record. The field is set in `bbdb-obsolete-net-field'." + (let* ((notes (cons bbdb-obsolete-net-field (concat "\\<" (regexp-quote addr) "\\>"))) + (records (bbdb-search (bbdb-records) nil nil nil notes))) + (or (and (not (null records)) (car (bbdb-record-net (car records)))) addr))) + +(provide 'bbdb-obsolete-net) + +;;; bbdb-obsolete-net.el ends here diff --git a/bits/bbdb-pgp.el b/bits/bbdb-pgp.el new file mode 100644 index 0000000..f6558f7 --- /dev/null +++ b/bits/bbdb-pgp.el @@ -0,0 +1,217 @@ +;;; bbdb-pgp.el --- use BBDB to store PGP preferences + +;; Copyright (C) 1997,1999 Kevin Davidson + +;; Author: Kevin Davidson tkld@quadstone.com +;; Maintainer: Kevin Davidson tkld@quadstone.com +;; Created: 10 Nov 1997 +;; Version: $Revision: 1.6 $ +;; Keywords: PGP BBDB message mailcrypt + + +;; 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 2, 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; A copy of the GNU General Public License can be obtained from this +;; program's author (send electronic mail to tkld@quadstone.com) or +;; from the Free Software Foundation, Inc.,59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. + +;; LCD Archive Entry: +;; bbdb-pgp|Kevin Davidson|tkld@quadstone.com +;; |Use BBDB to store PGP preferences +;; |$Date: 2003/08/11 08:54:35 $|$Revision: 1.6 $|~/packages/bbdb-pgp.el + +;;; Commentary: +;; +;; It is believed that encrypted mail works best if all mail between +;; individuals is encrypted - even concerning matters that are not +;; confidential. The reasoning is that confidential messages cannot +;; then be easily spotted and decryption efforts concentrated on them. +;; Some people therefore prefer to have all their email encrypted. +;; This package allows you to mark the BBDB entries for those +;; individuals so that messages will be encrypted when they are sent. +;; +;; These packages are required: BBDB, mailcrypt, message +;; +;; message.el is included with recent versions of Emacs. +;; You can use mail-mode as well as message-mode to send mail. + +;;; Usage: +;; (require 'bbdb-pgp) +;; +;; Then for all users who you want to send encrypted mail to, add the field +;; pgp-mail with the value `encrypt'. Alternatively you can add the value +;; `sign' if you just want to send signed messages. +;; +;; and possibly (if you do not want the PGP field printed out) +;; (add-hook 'bbdb-print-elide bbdb-pgp-field) +;; +;; The variable bbdb/pgp-default-action defines what to do if the recipient +;; is not in the BBDB. + +;;; TODO +;; Spot incoming PGP mail by hooking into mc-verify/decrypt and adding pgp-mail +;; field to BBDB entry (creating one if necessary); like bbdb-sc.el maintains +;; attribution prefs. + +;;; PGP Public Key +;; The author's public key is available from any public PGP keyserver +;; eg http://www.pgp.net/pgpnet/ +;; Fingerprint: 1F A9 3F 3E 90 F7 85 64 55 35 32 C8 75 91 3A E3 + + +;;; Code: + +(require 'message) +(require 'bbdb) +(condition-case nil (require 'mailcrypt) (error nil)) + +(defconst bbdb/pgp-version (substring "$Revision: 1.6 $" 11 -2) + "$Id: bbdb-pgp.el,v 1.6 2003/08/11 08:54:35 waider Exp $ + +Report bugs to: Kevin Davidson tkld@quadstone.com") + +;;;###autoload +(defgroup bbdb-utilities-pgp nil + "Automatically sign and/or encrypt outgoing messages." + :link '(emacs-library-link :tag "Lisp Source File" "bbdb-pgp.el") + :group 'bbdb-utilities) + + +(defcustom bbdb/pgp-field 'pgp-mail + "*Field to use in BBDB to store PGP preferences. + +If this field's value in a record is \"encrypt\" then messages are +encrypted. If it is \"sign\" then messages are signed." + :type 'symbol + :tag "BBDB Field" + :require 'bbdb + :group 'bbdb-utilities-pgp) + +(defcustom bbdb/pgp-method 'mailcrypt + "*How to sign or encrypt messages. + +'mailcrypt means use Mailcrypt. +'mml-pgp means add MML tags for Message to use old PGP format +'mml-pgpmime means add MML tags for Message to use PGP/MIME +'mml-smime means add MML tags for Message to use S/MIME" + :type '(choice + (const :tag "Mailcrypt" mailcrypt :require 'mailcrypt) + (const :tag "MML PGP" mml-pgp :require 'mml) + (const :tag "MML PGP/MIME" mml-pgpmime :require 'mml) + (const :tag "MML S/MIME" mml-smime :require 'mml)) + :tag "Signing/Encryption Method" + :group 'bbdb-utilities-pgp) + +(defcustom bbdb/pgp-default-action nil + "*Default action when sending a message and the recipient is not in BBDB. + +nil means do nothing. +'encrypt means encrypt message. +'sign means sign message." + :type '(choice + (const :tag "Do Nothing") + (const :tag "Encrypt" encrypt) + (const :tag "Sign" sign)) + :tag "Default Action" + :group 'bbdb-utilities-pgp) + +(defcustom bbdb/pgp-quiet nil + "*Do not ask for confirmation on pgp-action. + +nil means normal messages/questions. +'t means to be quiet." + :type '(choice + (const :tag "normal") + (const :tag "quiet" t)) + :tag "Quietness" + :group 'bbdb-utilities-pgp) + +(defun bbdb/pgp-get-pgp (name address) + "Look up user NAME and ADDRESS in BBDB and return the PGP preference." + (let* ((record (bbdb-search-simple name address)) + (pgp (and record + (bbdb-record-getprop record bbdb/pgp-field)))) + pgp)) + +(defun bbdb/pgp-sign () + "Sign a message. +bbdb/pgp-method controls the method used." + (cond + ((eq bbdb/pgp-method 'mailcrypt) + (mc-sign 0)) + ((eq bbdb/pgp-method 'mml-pgp) + (mml-secure-message-sign-pgp)) + ((eq bbdb/pgp-method 'mml-pgpmime) + (mml-secure-message-sign-pgpmime)) + ((eq bbdb/pgp-method 'mml-smime) + (mml-secure-message-sign-smime)) + (t + (error 'invalid-state "bbdb/pgp-method")))) + +(defun bbdb/pgp-encrypt () + "Encrypt and sign a message. +bbdb/pgp-method controls the method used." + (cond + ((eq bbdb/pgp-method 'mailcrypt) + (mc-encrypt 0)) + ((eq bbdb/pgp-method 'mml-pgp) + (mml-secure-message-encrypt-pgp)) + ((eq bbdb/pgp-method 'mml-pgpmime) + (mml-secure-message-encrypt-pgpmime)) + ((eq bbdb/pgp-method 'mml-smime) + (mml-secure-message-encrypt-smime)) + (t + (error 'invalid-state "bbdb/pgp-method")))) + +(defun bbdb/pgp-hook-fun () + "Function to be added to message-send-hook +Uses PGP to encrypt messages to users marked in the BBDB with the +field `bbdb/pgp-field'. +The user is prompted before encryption or signing." + (save-restriction + (save-excursion + (message-narrow-to-headers) + (and (featurep 'mailalias) + (not (featurep 'mailabbrev)) + mail-aliases + (expand-mail-aliases (point-min) (point-max))) + (let* ((to-field (mail-fetch-field "To" nil t)) + (address (mail-extract-address-components (or to-field "")))) + (widen) + (if (not (equal address '(nil nil))) + (let ((pgp-p (bbdb/pgp-get-pgp (car address) (car (cdr address))))) + (cond + ((string= "encrypt" pgp-p) + (and (or bbdb/pgp-quiet + (y-or-n-p "Encrypt message? ")) + (bbdb/pgp-encrypt))) + ((string= "sign" pgp-p) + (and (or bbdb/pgp-quiet + (y-or-n-p "Sign message? ")) + (bbdb/pgp-sign))) + (t + (cond + ((eq bbdb/pgp-default-action 'encrypt) + (and (y-or-n-p "Encrypt message? ") + (bbdb/pgp-encrypt))) + ((eq bbdb/pgp-default-action 'sign) + (and (y-or-n-p "Sign message? ") + (bbdb/pgp-sign))) + (t + nil)))))))))) + +(add-hook 'message-send-hook 'bbdb/pgp-hook-fun) +(add-hook 'mail-send-hook 'bbdb/pgp-hook-fun) + +(provide 'bbdb-pgp) + +;;; bbdb-pgp.el ends here diff --git a/bits/bbdb-signature.el b/bits/bbdb-signature.el new file mode 100644 index 0000000..f229063 --- /dev/null +++ b/bits/bbdb-signature.el @@ -0,0 +1,193 @@ +;;; MAIL-SIGNATURE.EL - Add context sensitive signature +;;; Copyright (C) 1997 Kevin Davidson +;;; Copyright (C) 1985, 1986, 1992 Free Software Foundation, Inc + +;;; Maintainer: tkld@quadstone.com +;;; Keywords: mail + +;;; 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 2, 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 +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. + +;;; A copy of the GNU General Public License can be obtained from this +;;; program's author (send electronic mail to <tkld@quadstone.com>) +;;; or from the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +;;; Boston, MA 02111-1307, USA. + +;;; LCD Archive Entry: +;;; mail-signature|Kevin Davidson|<tkld@quadstone.com> +;;; |Add context sensitive signature +;;; |$Date: 2001/03/01 15:38:31 $|$Revision: 1.1 $|~/packages/mail-signature.el + +;;; Commentary: + +;;; This is a reworking of the function mail-signature in sendmail.el +;;; (part of the Emacs distribution) to insert a context sensitive signature. +;;; Using regular expressions, appropriate signatures can be inserted +;;; for different audiences. +;;; Repeated calls removes the current signature from the message and cycles +;;; through all applicable signatures. +;;; Use with something like this in .emacs: +;;; (eval-after-load "sendmail" +;;; (progn +;;; (load "mail-signature") +;;; (setq mail-signature-alist +;;; (append '((bbdb) +;;; ("Newsgroups" "^sci" "-scientific") +;;; ("To" "^[^@]+$" "-local") +;;; ("To" "friend" "-friendly")) mail-signature-alist)))) +;;; And create a file called ~/.signature-friendly that has a +;;; signature appropriate for the user `friend' to receive, a +;;; ~/.signature-local for users at the same site and a +;;; ~/.signature-scientific that contains a signature suitable for sci.* +;;; newsgroups. +;;; Any users in your BBDB that have a `signature' property will get that +;;; signature. Obviously you need to have installed the Insidious Big Brother +;;; Database (BBDB) for this to work. +;;; If using message-mode (included with Emacs 19.34/GNUS 5.3 or later) +;;; (setq message-signature 'mail-signature) + +;;; Change log: +;; $Log: bbdb-signature.el,v $ +;; Revision 1.1 2001/03/01 15:38:31 waider +;; More bits, possibly incompatible with 2.00.06. Use at own risk. +;; +;; Revision 1.11 1997/11/11 11:18:29 tkld +;; Updated email address. +;; +;; Revision 1.10 1997/10/22 14:44:33 tkld +;; Remove dependency on cl. More sanity checking. Checked out on emacs +;; -q. +;; +;; Revision 1.9 1997/10/22 12:42:49 tkld +;; Use bbdb-signature if magic entry 'bbdb is present in +;; mail-signature-alist +;; +;; Revision 1.8 1997/10/21 13:16:04 tkld +;; Off by one error caused first entry in alist to be ignored. +;; +; Revision 1.7 1997/04/18 09:14:51 tkld +; Add change log. Update GPL version and FSF address. Cycle through all +; possible signatures, not just toggle between two. +; + +;;; Code: + +(defconst mail-signature-version (substring "$Revision: 1.1 $" 11 -2) + "$Id: bbdb-signature.el,v 1.1 2001/03/01 15:38:31 waider Exp $ + +Report bugs to: Kevin Davidson <tkld@quadstone.com>") + + +(defvar bbdb-signature-field 'signature + "*BBDB field used to store signature for") + +(defvar mail-signature-last-signature -1 + "Record index of last signature used for repeated calls of mail-signature +Buffer local") +(make-variable-buffer-local 'mail-signature-last-signature) + +(defvar mail-signature-base "~/.signature" + "*The base part of signature filename. +Entries from mail-signature-alist will be added to this.") + +(defvar mail-signature-alist + '(("" "" "")) + "*List of extensions to add to mail-signature-base to form name of sig file. +Format is: (HEADER REGEX EXTENSION), where REGEX is a regular expression +that should match the contents of the mail or news header HEADER. +The first to match is used. In REGEX, ^ and $ mark the beginning and end +of just the text in the header, not the whole line. +If HEADER is the symbol 'bbdb then search for a matching entry and use the +field specified by bbdb-signature-field as the suffix.") + +(defun mail-signature (&optional atpoint) + "Sign letter with context sensitive signature, based on mail-signature-alist. +Argument ATPOINT says whether to insert signature at point, or at end of +buffer." + (interactive "P") + (save-excursion + (or atpoint + (goto-char (point-max))) + ;; First search for previous signature to delete + ;; or delete trailing whitespace + (if (null (search-backward "\n-- \n" (point-min) t)) + (progn + (skip-chars-backward " \t\n") + (end-of-line)) + (skip-chars-backward " \t\n")) + (or atpoint + (delete-region (point) (point-max))) + (insert "\n\n-- \n") + (let ((sig-file (expand-file-name (mail-find-signature)))) + (if (file-exists-p sig-file) + (insert-file-contents sig-file) + (error "Signature file %s does not exist. Check mail-signature-alist." + sig-file))))) + +(defun mail-find-signature () + "Find an appropriate signature file." + (let* ((elist mail-signature-alist) + (found nil) + (sind 0) + (entry (car elist)) + (header (car entry)) + (regex (car (cdr entry))) + (file (car (cdr (cdr entry))))) + (save-excursion + (if (>= mail-signature-last-signature (length mail-signature-alist)) + (setq mail-signature-last-signature -1)) + (while (and (not found) elist) + (if (equal header 'bbdb) + (if (and (> sind mail-signature-last-signature) + (setq file (bbdb-frob-signature))) + (setq found t) + (setq elist (cdr elist) + entry (car elist) + header (car entry) + sind (1+ sind) + regex (car (cdr entry)) + file (car (cdr (cdr entry))))) + (if (and (> sind mail-signature-last-signature) + (mail-position-on-field header 'soft) + (re-search-backward (concat "^" header ":[ \t]*\\(.*\\)$") + (point-min) t) + (string-match regex (buffer-substring-no-properties + (match-beginning 1) (match-end 1)))) + (setq found t) + (setq elist (cdr elist) + entry (car elist) + header (car entry) + sind (1+ sind) + regex (car (cdr entry)) + file (car (cdr (cdr entry)))))))) + (setq mail-signature-last-signature sind) + (concat mail-signature-base file))) + +(defun bbdb-find-signature (name address) + "Look up user NAME and ADDRESS in BBDB and return the appropriate signature." + (let* ((record (bbdb-search-simple name address)) + (sig (and record + (bbdb-record-getprop record bbdb-signature-field)))) + sig)) + +(defun bbdb-frob-signature () + "Parse current message to get recipients and generate signature" + (save-restriction + (save-excursion + (message-narrow-to-headers) + (let* ((to-field (mail-fetch-field "To" nil t)) + (address (mail-extract-address-components (or to-field "")))) + (if (not (equal address '(nil nil))) + (bbdb-find-signature (car address) (car (cdr address))) + nil))))) + +(provide 'mail-signature) + +;; mail-signature.el ends here diff --git a/bits/bbdb-sort-mailrc.el b/bits/bbdb-sort-mailrc.el new file mode 100644 index 0000000..c465f14 --- /dev/null +++ b/bits/bbdb-sort-mailrc.el @@ -0,0 +1,322 @@ +;;; >>>>> Ronan Waide writes: + +;;; >> * birthdays/anniversaries + +;;; RW> This /is/ venturing into calendar land. Still, go to yer bbdb buffer +;;; RW> and create a field with C-o. Again, I prefer not to add baggage to the +;;; RW> file format unless it's absolutely necessary. Also, you should be able +;;; RW> to attach bbdb to calendar.el using the bbdb record-dinking hooks so +;;; RW> that it auto-fills your calendar with goop for you. And maybe get +;;; RW> working on calendar-pilot.el... + +;;; Well, this isn't really release-ready -- but since someone asks, it +;;; could be a good starting point for someone. Feel free to +;;; redistribute, or chop up and use the useful bits. + +;;; Bng + +;;; BBDB-BNG +;;; Various functions I have added to enhance the big brother database. +;;; Boris Goldowsky, <boris@cs.rochester.edu> +;;; $Revision: 1.1 $ $Date: 2001/01/24 21:19:08 $ +;;; +;;; This file allows you to do the following things: +;;; * Sort by firstname or company rather than last name. +;;; * Mark people's birthdays in emacs's calendar and diary displays. +;;; * Maintains a file of mail aliases, for use by other mailers, +;;; automatically updated when the information changes in your database. +;;; * Make sure that everyone has their username defined as an alias +;;; for their complete net addresses. +;;; +;;; INSTALLATION: +;;; Put this file in emacs's load-path, and make sure it gets loaded whenever +;;; you load BBDB. +;;; * To use alternate sorting, evaluate (bbdb-sort-by ...) whenever you load +;;; bbdb. YOU MUST EITHER ALWAYS DO THIS, OR NEVER DO IT. When you switch +;;; over, evaluate (bbdb-resort-database). +;;; * To make a file of mail-aliases, set bbdb-mail-alias-file to a filename, +;;; and source that file from your .mailrc. +;;; * Username-aliases are enabled by default. Set +;;; `bbdb-auto-username-alias' to nil if you don't want them. +;;; You can also use the function `bbdb-add-user-name-as-alias' to +;;; add such aliases manually. +;;; * The bbdb/calendar stuff is under development, and may not work. +;;; +;;; EXAMPLE: +;;; The following code could go in your .emacs: +;;; (add-hook 'bbdb-load-hook +;;; (function (lambda () +;;; (setq bbdb-mail-alias-file +;;; (expand-file-name "~/.mail_aliases") +;;; (require 'bbdb-bng) +;;; (bbdb-sort-by 'firstname)))) + +;;; USE: +;;; If installed as above, these functions operate automatically. + +;;; DEPENDENCIES: +;;; BBDB, of course. +;;; calendar.el and diary-lib.el are built into recent emacs versions. +;;; dates.el is available from me. + +(provide 'bbdb-bng) + +;;; +;;; New birthday stuff. +;;; + +(require 'calendar) +(require 'dates) + +(if (not (featurep 'diary)) ; the library of many names. + (or (load "diary-lib" t) + (load "diary"))) + +(defvar bbdb/calendar-marker + (if (not window-system) + "^" + (require 'faces) + 'bold-italic) + "*How to mark birthdays in calendar. +Can be either a single-character string or a face.") + +(add-hook 'list-diary-entries-hook 'bbdb/calendar-list-entries) +(add-hook 'mark-diary-entries-hook 'bbdb/calendar-mark-entries) + +(defun bbdb/calendar-mark-entries () + (save-excursion + (set-buffer calendar-buffer) + (let ((month displayed-month) + (year displayed-year)) + (bbdb/calendar-mark-month month year) + (increment-calendar-month month year -1) + (bbdb/calendar-mark-month month year) + (increment-calendar-month month year 2) + (bbdb/calendar-mark-month month year)))) + +(defun bbdb/calendar-mark-month (month year) + (message "Marking birthdays..." + (let ((days (aref (bbdb/calendar-birthdays) month))) + (while days + (mark-visible-calendar-date (list month (car (car days)) year) + bbdb/calendar-marker) + (setq days (cdr days)))) + (message nil))) + +(defun bbdb/calendar-list-entries () + (message "Listing birthdays..." + (let* ((bdays (bbdb/calendar-birthdays)) + (start-date (calendar-absolute-from-gregorian original-date)) + (end-date (+ number start-date))) + (calendar-for-loop abs-date from start-date to end-date do + (let* ((date (calendar-gregorian-from-absolute abs-date)) + (entries (cdr (assoc (extract-calendar-day date) + (aref bdays + (extract-calendar-month date)))))) + (while entries + (add-to-diary-list date (car entries)) + (setq entries (cdr entries)))))) + (message nil))) + +(defvar bbdb/calendar-birthdays nil + "Used by function of the same name, which see.") + +(defun bbdb/calendar-birthdays () + "Returns a vector containing the birthdays in your BBDB. +This is a vector with one element per month: + [birthdays ; identifier in spot 0 + ((4 \"Isaac Newton's birthday\")) ; Newton's birthday is Jan 4. + ((11 \"Thomas Edison's birthday\") ; Edison's is Feb 11. + (15 \"Galileo's birthday\" \"Susan B. Anthony's birthday\")) ; Both Feb 15. + ...march through dec... + ]" + (or bbdb/calendar-birthdays + (setq bbdb/calendar-birthdays + (let ((cal (make-vector 13 nil)) + (recs (bbdb-records)) + birthday-string) + (aset cal 0 'birthdays) + (while recs + (if (setq birthday-string + (bbdb-record-getprop (car recs) 'birthday)) + (let ((events (bbdb-split birthday-string ",")) + (name (bbdb-record-name (car recs)))) + (while events + (let ((bday (date-parse (car events)))) + (if (null bday) + (message "Unparsable birthday: %s" (car events)) + (let* ((date-end (parse-string-end)) + (eventname (if (eq t date-end) + "birthday" + (substring (car events) + date-end))) + (event (concat name "'s " + (if (equal "" eventname) + "birthday" + eventname))) + (month (extract-calendar-month bday)) + (day (extract-calendar-day bday)) + (monthlist (aref cal month)) + (daylist (assoc day monthlist))) + (if daylist + (setcdr daylist (cons event (cdr daylist))) + (aset cal month (cons (list day event) + monthlist)))))) + (setq events (cdr events))))) + (setq recs (cdr recs))) + cal)))) + +;;; +;;; Mail alias code +;;; + +(defvar bbdb-mail-alias-file nil + "*File to save mail-aliases into. +Aliases are also kept in the database proper; this is just for the convenience +of other programs that are interested in mail aliases. For example, you can +use your bbdb mail aliases with ucb mail by including the line +source ~/.mail_aliases +in your .mailrc file. +Set this to nil to avoid storing mail aliases in a file.") + +(defvar bbdb-auto-username-alias t + "*If t, always have a person's username as a mail-alias for them.") + +(if bbdb-mail-alias-file + (add-hook 'bbdb-after-change-hook (function bbdb-check-mail-alias))) + +(defun bbdb-add-user-name-as-alias () + (interactive) + (let ((bbdb-auto-username-alias t) + (this(bbdb-current-record))) + (bbdb-check-mail-alias this) + (bbdb-redisplay-one-record this))) + +(defun bbdb-record-username (record) + "Return just the username part of RECORD's first net address, +if it looks like a well-formed internet address; nil otherwise." + (let ((addr (car (bbdb-record-net record)))) + (if (and addr (string-match "^[a-zA-z0-9]+@" addr)) + (substring addr 0 (1- (match-end 0)))))) + +(defun bbdb-record-mail-aliases (record) + (let ((all (bbdb-record-getprop record bbdb-define-all-aliases-field))) + (if all (bbdb-split all ",")))) + +(defun bbdb-check-mail-alias (record) + "Makes sure the person's username is defined as a mail abbrev +for them, and makes sure all their mail abbreves are ready for use." + (let ((username (bbdb-record-username record)) + (current (bbdb-record-getprop record bbdb-define-all-aliases-field))) + (if (and current (string-match "\\(,\\)? *\n" current)) + (setq current (replace-match ", " nil nil current))) + (if (and bbdb-auto-username-alias + username + (not (and (boundp 'mail-abbrevs) + (intern-soft username mail-abbrevs))) + (not (member username (bbdb-record-mail-aliases record)))) + (setq current + (if current (concat current ", " username) + username))) + (if current + (bbdb-record-putprop record bbdb-define-all-aliases-field current)) + + ;; And make sure aliases are all defined (if any are) + (if (boundp 'mail-abbrevs) + (mapcar (function + (lambda (alias) + (if (not (intern-soft alias mail-abbrevs)) + (my-define-mail-abbrev + alias (bbdb-dwim-net-address record))))) + (bbdb-record-mail-aliases record))))) + +(defun my-define-mail-abbrev (abbrev address) + "Defines abbrev, and marks bbdb-mail-alias-file as modified." + (define-mail-abbrev abbrev address) + (save-excursion + (set-buffer (find-file-noselect bbdb-mail-alias-file)) + (setq buffer-read-only t) + (set-buffer-modified-p t) + (make-variable-buffer-local 'local-write-file-hooks) + (if (not (memq 'bbdb-mail-alias-file-write-hook + local-write-file-hooks)) + (setq local-write-file-hooks '(bbdb-mail-alias-file-write-hook))))) + +(defun bbdb-insert-mail-aliases () + (let ((begin (point))) + (if (not (boundp 'mail-abbrevs)) + (bbdb-define-all-aliases)) + (insert-abbrev-table-description 'mail-abbrevs nil) + (goto-char begin) + (let ((abbrevs (nth 1 (nth 2 (read (current-buffer)))))) + (setq abbrevs (sort abbrevs (function + (lambda (x y) + (string-lessp (car x) (car y)))))) + (delete-region begin (point)) + (mapcar (function + (lambda (abbrev) + (let ((alias (car abbrev)) + (addr (mapconcat (function simplify-address) + (bbdb-split (nth 1 abbrev) ",") " "))) + (if (not (string-equal alias addr)) + (insert (format "alias %s\t%s\n" alias addr)))))) + abbrevs)))) + +(defun simplify-address (addr) + (let ((addr (car (cdr (mail-extract-address-components addr))))) + (if (string-match (concat "@" (system-name) "$") addr) + (substring addr 0 (match-beginning 0)) + addr))) + +(defun bbdb-mail-alias-file-write-hook () + "Regenerate mail-aliases if necc. +Call from local-write-file-hooks." + (let ((buffer-read-only nil)) + (message "Writing aliases...") + (delete-region (point-min) (point-max)) + (bbdb-insert-mail-aliases) + (message "Writing aliases...done") + nil)) + +;;; +;;; sorting frobnification. +;;; + +(defun bbdb-sort-by (field) + "Tell BBDB which field is the primary sort key. +Currently FIELD must be one of 'firstname 'lastname or 'company. +The first time you use this, use bbdb-resort-database immediately +afterwards. Then put \(bbdb-sort-by 'firstname), or whichever field is +your choice, on your bbdb-after-load-db-hook." + (cond ((eq field 'lastname) + (defun bbdb-record-sortkey (record) + (or (bbdb-cache-sortkey (bbdb-record-cache record)) + (bbdb-cache-set-sortkey + (bbdb-record-cache record) + (downcase + (concat (bbdb-record-lastname record) + (bbdb-record-firstname record) + (bbdb-record-company record))))))) + ((eq field 'firstname) + (defun bbdb-record-sortkey (record) + (or (bbdb-cache-sortkey (bbdb-record-cache record)) + (bbdb-cache-set-sortkey + (bbdb-record-cache record) + (downcase + (concat (bbdb-record-firstname record) + (bbdb-record-lastname record) + (bbdb-record-company record))))))) + ((eq field 'company) + (defun bbdb-record-sortkey (record) + (or (bbdb-cache-sortkey (bbdb-record-cache record)) + (bbdb-cache-set-sortkey + (bbdb-record-cache record) + (downcase + (concat (bbdb-record-company record) + (bbdb-record-lastname record) + (bbdb-record-firstname record))))))) + (t (error "Can only sort by firstname lastname or company!")))) + +;;; Local Variables: +;;; eval:(put 'calendar-for-loop 'lisp-indent-hook 6) +;;; End: diff --git a/bits/bbdb-to-outlook.el b/bits/bbdb-to-outlook.el new file mode 100644 index 0000000..a8dd6bf --- /dev/null +++ b/bits/bbdb-to-outlook.el @@ -0,0 +1,261 @@ +;;; This is bbdb-to-outlook.el, version 0.11 +;;; +;;; Author: Bin Mu <mubin@cs.uchicago.edu> +;;; <http://www.cs.uchicago.edu/~mubin> +;;; Created: 30 Oct 1997 +;;; Version: 0.11 +;;; +;;; Updated: 26 May 2004 +;;; Frank J. Christophersen <FJC@control.ee.ethz.ch> +;;; <http://www.control.ee.ethz.ch/~christop/> +;;; +;;; The Insidious Big Brother Database 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 1, or (at your +;;; option) any later version. +;;; +;;; BBDB is distributed in the hope that it will be useful, but WITHOUT ANY +;;; WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +;;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +;;; details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Emacs; see the file COPYING. If not, write to +;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;;; +;;; This module is for exporting BBDB databases into a comma delimited +;;; text file, which can be imported into microsoft outlook contact forms and +;;; ms address book. +;;; +;;; USE: In the *BBDB* buffer, type O to convert the listing to text format. +;;; It will prompt you for a filename. And then you can import the file +;;; into Microsoft outlook contacts and outlook express address boook +;;; etc. +;;; +;;; INSTALLATION: Put this file somewhere on your load-path. +;;; Put (require 'bbdb-to-outlook) in your .emacs, or autoload it. +;;; +;;; + +(require 'bbdb) +(require 'bbdb-com) + +(define-key bbdb-mode-map "O" 'bbdb-to-outlook) + +(autoload 'bbdb-print-field-shown-p "bbdb-print") +(defalias 'bbdb-field-shown-p 'bbdb-print-field-shown-p) + +;;; +;;; Variables +;;; + +(defvar bbdb-to-outlook-file-name "~/bbdb.txt" + "*Default file name for printouts of BBDB database.") + +(defvar bbdb-to-outlook-prolog + (concat "\"First Name\"" + ",\"Last Name\"" + ",\"Company\"" + + ;; phones + ",\"Business Phone\"" + ",\"Home Phone\"" + ",\"Business Fax\"" + ",\"Mobile Phone\"" + ",\"Pager\"" + + ;; EMAIL + ",\"E-mail Address\"" + ",\"E-mail 2 Address\"" + ",\"E-mail 3 Address\"" + + ;; addresses + ",\"Business Street\"" + ",\"\"Business Street 2\"" + ",\"\"Business Street 3\"" + ",\"Business City\"" + ",\"Business State\"" + ",\"Business Postal Code\"" + ",\"Business Country\"" + + ",\"Home Street\"" + ",\"\"Home Street 2\"" + ",\"\"Home Street 3\"" + ",\"Home City\"" + ",\"Home State\"" + ",\"Home Postal Code\"" + ",\"Home Country\"" + + ;; notes + ; ",\"Nickname\"" doesn't work + ",\"Notes\"" + + ;; end of prolog + "\n" + ) + "*TeX statements to include at the beginning of the bbdb-to-outlook file.") + +(defvar bbdb-to-outlook-epilog "" + "*TeX statements to include at the end of the bbdb-to-outlook file.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun bbdb-to-outlook (to-file) + "Outlook the selected BBDB entries" + (interactive (list (read-file-name "To File: " bbdb-to-outlook-file-name))) + (setq bbdb-to-outlook-file-name (expand-file-name to-file)) + (let ((current-letter t) + (records (progn (set-buffer bbdb-buffer-name) + bbdb-records))) + (find-file bbdb-to-outlook-file-name) + (erase-buffer) + (while records + (setq current-letter + (bbdb-to-outlook-format-record (car (car records)) current-letter)) + (setq records (cdr records))) + (goto-char (point-min)) (insert bbdb-to-outlook-prolog) + (goto-char (point-max)) (insert bbdb-to-outlook-epilog) + (goto-char (point-min)))) + +(defun bbdb-to-outlook-format-record (record &optional current-letter brief) + "Insert the bbdb RECORD in TeX format. +Optional CURRENT-LETTER is the section we're in -- if this is non-nil and +the first letter of the sortkey of the record differs from it, a new section +heading will be outlook \(an arg of t will always produce a heading). +The new current-letter is the return value of this function. +Someday, optional third arg BRIEF will produce one-line format." + (bbdb-debug (if (bbdb-record-deleted-p record) + (error "plus ungood: tex formatting deleted record"))) + + (let* ((first-letter + (substring (concat (bbdb-record-sortkey record) "?") 0 1)) + (lname (and (bbdb-field-shown-p 'name) + (bbdb-record-lastname record))) + (fname (and (bbdb-field-shown-p 'name) + (bbdb-record-firstname record))) + (comp (and (bbdb-field-shown-p 'company) + (bbdb-record-company record))) + (net (and (bbdb-field-shown-p 'net) + (bbdb-record-net record))) + (phones (and (bbdb-field-shown-p 'phone) + (bbdb-record-phones record))) + (addrs (and (bbdb-field-shown-p 'address) + (bbdb-record-addresses record))) + (aka (and (bbdb-field-shown-p 'aka) + (bbdb-record-aka record))) + (notes (bbdb-record-raw-notes record)) +;; notes;; skip notes + (begin (point))) + + ;; Section header, if neccessary. + + ;; name + (insert (format "\"%s\"" (bbdb-to-outlook-if-not-blank fname))) + (insert (format ",\"%s\"" (bbdb-to-outlook-if-not-blank lname))) + (insert (format ",\"%s\"" (bbdb-to-outlook-if-not-blank comp))) + + ;; Phone numbers + (insert (bbdb-to-outlook-phone phones "work\\|office")) + (insert (bbdb-to-outlook-phone phones "home")) + (insert (bbdb-to-outlook-phone phones "fax")) + (insert (bbdb-to-outlook-phone phones "car\\|mobile")) + (insert (bbdb-to-outlook-phone phones "page")) + + ;; Email address + ;; at most three email address + (insert (format ",\"%s\"" (bbdb-to-outlook-if-not-blank (car net)))) + (setq net (cdr net)) + (insert (format ",\"%s\"" (bbdb-to-outlook-if-not-blank (car net)))) + (setq net (cdr net)) + (insert (format ",\"%s\"" (bbdb-to-outlook-if-not-blank (car net)))) + (setq net (cdr net)) + + ;; Addresses + (insert (bbdb-to-outlook-address addrs "work\\|office")) + (insert (bbdb-to-outlook-address addrs "home")) + + ;; Notes + (if (stringp notes) + (setq notes (list (cons 'notes notes)))) + +; (if aka +; (insert (format ",\"%s\"" +; (mapconcat (function identity) aka ", "))) +; (insert ",\"\"")) +; + (insert ",\"") + (while notes + (let ((thisnote (car notes))) + (if (bbdb-field-shown-p (car thisnote)) + (progn + (if (eq 'notes (car thisnote)) + (insert (format "Note: %s\n" + (bbdb-print-outlook-quote (cdr thisnote)))) + (if (not (eq 'mail-folders (car thisnote))) + (insert (format "%s: %s\n" + (bbdb-print-outlook-quote + (symbol-name (car thisnote))) + (bbdb-print-outlook-quote + (cdr thisnote))))))))) + (setq notes (cdr notes))) + + (if aka (insert (format "AKA: %s\n" + (mapconcat (function identity) aka ", ")))) + + (insert "\"") + + ;; end of everything + (insert "\n") + ;; If record is bare, delete anything we may have inserted. + ;; otherwise, mark the end of this record. + current-letter)) + +(defun bbdb-to-outlook-if-not-blank (string &rest more) + "If STRING is not null, then return it concatenated +with rest of arguments. If it is null, then all arguments are +ignored and the null string is returned." + (if (or (null string) (equal "" string)) + "" + (apply 'concat string more))) + +(defun bbdb-print-outlook-quote (string) + "replace \" with \' in the string" + (let (i) + (while (setq i (string-match "\"" string i)) + (setq string (concat (substring string 0 i) "\'" (substring string (1+ i)))))) + string) + +(defun bbdb-to-outlook-phone (phones pattern) + (let ((found nil) + (result ",\"\"")) + (while (and phones (not found)) + (let ((place (downcase (aref (car phones) 0))) + (number (bbdb-phone-string (car phones)))) + (if (setq found (string-match pattern place)) + (setq result (format ",\"%s\"" number))) + (setq phones (cdr phones)))) + result)) + + +(defun bbdb-to-outlook-address (addrs pattern) + (let ((found nil) + (result ",\"\",\"\",\"\",\"\",\"\",\"\",\"\"")) + (while addrs + (let ((place (downcase (aref (car addrs) 0))) + (addr (car addrs))) + (if (setq found (string-match pattern place)) + (setq result + (format + ",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"" + (bbdb-to-outlook-if-not-blank (nth 0 (bbdb-address-streets addr))) + (bbdb-to-outlook-if-not-blank (nth 1 (bbdb-address-streets addr))) + (bbdb-to-outlook-if-not-blank (nth 2 (bbdb-address-streets addr))) + (bbdb-to-outlook-if-not-blank (bbdb-address-city addr)) + (bbdb-to-outlook-if-not-blank (bbdb-address-state addr)) + (bbdb-to-outlook-if-not-blank (bbdb-address-zip-string addr)) + (bbdb-to-outlook-if-not-blank (bbdb-address-country addr)) + ))) + (setq addrs (cdr addrs)))) + result)) + +(provide 'bbdb-to-outlook)
\ No newline at end of file diff --git a/bits/bbdb-vcard-export.el b/bits/bbdb-vcard-export.el new file mode 100644 index 0000000..9d77024 --- /dev/null +++ b/bits/bbdb-vcard-export.el @@ -0,0 +1,239 @@ +;;; bbdb-vcard-export.el -- export BBDB as vCard files +;; +;; Copyright (c) 2002 Jim Hourihan +;; Copyright (c) 2005 Alex Schroeder +;; +;; bbdb-vcard-export.el 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 2, or (at +;; your option) any later version. +;; +;; This software is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;; Author: Jim Hourihan <jimh@panix.com> +;; Created: 2002-08-08 +;; Version: $Id: bbdb-vcard-export.el,v 1.3 2006/03/14 00:00:00 malcolmp Exp $ +;; Keywords: vcard ipod + +;;; Commentary + +;; I use this code to sync my ipod with bbdb under OS X. To do so: +;; +;; M-x bbdb-vcard-export-update-all +;; +;; and enter `/Volumes/IPOD_NAME/Contacts/' at the prompt +;; +;; vCard documentated in RFC 2426 <http://www.faqs.org/rfcs/rfc2426.html> +;; Value types documented in RFC 2425 <http://www.faqs.org/rfcs/rfc2425.html> + +;; The coding system used for writing the files is UTF-16 by default. +;; To use anything else, use a prefix argument: C-u M-x +;; bbdb-vcard-export-update-all. You will be prompted for another +;; coding system to use. Latin-1 is probably a good choice. +;; bbdb-file-coding-system's default value is iso-2022-7bit, which is +;; probably useless for vCard exports. + +;;; Code: + +(require 'bbdb) + +; XEmacs prior to 21.5 is not dumped with replace-regexp-in-string. In those +; cases it can be found in the xemacs-base package. +(eval-and-compile + (if (and (not (fboundp 'replace-regexp-in-string)) (featurep 'xemacs)) + (require 'easy-mmode))) + +(defvar bbdb-translation-table + '(("Mobile" . "Cell")) + "Translations of text items, typically for labels.") + +(defun bbdb-translate (str) + "Translate STR into some other string based on `bbdb-translation-table'." + (let ((translation (assoc str bbdb-translation-table))) + (if translation + (cdr translation) + str))) + +;; 2.3 Predefined VALUE Type Usage + +;; The predefined data type values specified in [MIME-DIR] MUST NOT be +;; repeated in COMMA separated value lists except within the N, +;; NICKNAME, ADR and CATEGORIES value types. + +;; The text value type defined in [MIME-DIR] is further restricted such +;; that any SEMI-COLON character (ASCII decimal 59) in the value MUST be +;; escaped with the BACKSLASH character (ASCII decimal 92). + +(defun bbdb-vcard-export-escape (str) + "Return a copy of STR with ; , and newlines escaped." + (setq str (bbdb-translate str) + str (or str ""); get rid of nil values + str (replace-regexp-in-string "\\(;\\|,\\|\\\\\\)" "\\\\\\1" str) + str (replace-regexp-in-string "\n" "\\\\n" str))) + +;; (insert (bbdb-vcard-export-escape "this is, not \\ or \n true")) + +(defun bbdb-vcard-export-several (list) + "Return a comma-separated list of escaped unique elements in LIST." + (let ((hash (make-hash-table :test 'equal)) + result) + (dolist (item list) + (puthash (bbdb-vcard-export-escape item) t hash)) + (maphash (lambda (key val) + (setq result (cons key result))) + hash) + (bbdb-join result ","))) + +;; The component values MUST be specified in +;; their corresponding position. The structured type value corresponds, +;; in sequence, to the post office box; the extended address; the street +;; address; the locality (e.g., city); the region (e.g., state or +;; province); the postal code; the country name. When a component value +;; is missing, the associated component separator MUST still be +;; specified. + +;; The text components are separated by the SEMI-COLON character (ASCII +;; decimal 59). Where it makes semantic sense, individual text +;; components can include multiple text values (e.g., a "street" +;; component with multiple lines) separated by the COMMA character +;; (ASCII decimal 44). +(defun bbdb-vcard-export-address-string (address) + "Return the address string" + (let ((streets (bbdb-address-streets address)) + (city (bbdb-address-city address)) + (state (bbdb-address-state address)) + (country (bbdb-address-country address)) + (zip (bbdb-address-zip address))) + (concat + "adr;type=" (bbdb-vcard-export-escape (bbdb-address-location address)) ":" + ";;" ;; no post office box, no extended address + (bbdb-vcard-export-several streets) ";" + (bbdb-vcard-export-escape city) ";" + (bbdb-vcard-export-escape state) ";" + (bbdb-vcard-export-escape zip) ";" + (bbdb-vcard-export-escape country)))) + +(defun bbdb-vcard-export-record-insert-vcard (record) + "Insert a vcard formatted version of RECORD into the current buffer" + (let ((name (bbdb-record-name record)) + (first-name (bbdb-record-firstname record)) + (last-name (bbdb-record-lastname record)) + (aka (bbdb-record-aka record)) + (company (bbdb-record-company record)) + (notes (bbdb-record-notes record)) + (phones (bbdb-record-phones record)) + (addresses (bbdb-record-addresses record)) + (net (bbdb-record-net record)) + (categories (bbdb-record-getprop + record + bbdb-define-all-aliases-field))) + (insert "begin:vcard\n" + "version:3.0\n") + ;; Specify the formatted text corresponding to the name of the + ;; object the vCard represents. The property MUST be present in + ;; the vCard object. + (insert "fn:" (bbdb-vcard-export-escape name) "\n") + ;; Family Name, Given Name, Additional Names, Honorific + ;; Prefixes, and Honorific Suffixes + (when (or last-name first-name) + (insert "n:" + (bbdb-vcard-export-escape last-name) ";" + (bbdb-vcard-export-escape first-name) ";;;\n")) + ;; Nickname of the object the vCard represents. One or more text + ;; values separated by a COMMA character (ASCII decimal 44). + (when aka + (insert "nickname:" (bbdb-vcard-export-several aka) "\n")) + ;; FIXME: use face attribute for this one. + ;; PHOTO;ENCODING=b;TYPE=JPEG:MIICajCCAdOgAwIBAgICBEUwDQYJKoZIhvcN + ;; AQEEBQAwdzELMAkGA1UEBhMCVVMxLDAqBgNVBAoTI05ldHNjYXBlIENvbW11bm + ;; ljYXRpb25zIENvcnBvcmF0aW9uMRwwGgYDVQQLExNJbmZvcm1hdGlvbiBTeXN0 + + ;; FIXME: use birthday attribute if there is one. + ;; BDAY:1996-04-15 + ;; BDAY:1953-10-15T23:10:00Z + ;; BDAY:1987-09-27T08:30:00-06:00 + + ;; A single structured text value consisting of components + ;; separated the SEMI-COLON character (ASCII decimal 59). But + ;; BBDB doesn't use this. So there's just one level: + (when company + (insert "org:" (bbdb-vcard-export-escape company) "\n")) + (when notes + (insert "note:" (bbdb-vcard-export-escape notes) "\n")) + (dolist (phone phones) + (insert "tel;type=" (bbdb-vcard-export-escape (bbdb-phone-location phone)) ":" + (bbdb-vcard-export-escape (bbdb-phone-string phone)) "\n")) + (dolist (address addresses) + (insert (bbdb-vcard-export-address-string address) "\n")) + (dolist (mail net) + (insert "email;type=internet:" (bbdb-vcard-export-escape mail) "\n")) + ;; Use CATEGORIES based on mail-alias. One or more text values + ;; separated by a COMMA character (ASCII decimal 44). + (when categories + (insert "categories:" + (bbdb-join (mapcar 'bbdb-vcard-export-escape + (bbdb-split categories ",")) ",") "\n")) + (insert "end:vcard\n"))) + +(defun bbdb-vcard-export-vcard-name-from-record (record) + "Come up with a vcard name given a record" + (let ((name (bbdb-record-name record)) + (first-name (elt record 0)) + (last-name (elt record 1))) + (concat first-name "_" last-name ".vcf"))) + +(defun bbdb-vcard-export-make-vcard (record vcard-name) + "Make a record buffer and write it" + (let ((buffer (get-buffer-create "*bbdb-vcard-export*"))) + (save-excursion + (set-buffer buffer) + (kill-region (point-min) (point-max)) + (bbdb-vcard-export-record-insert-vcard record) + (write-region (point-min) (point-max) vcard-name)) + (kill-buffer buffer))) + +(defun bbdb-vcard-do-record (record output-dir coding-system) + "Update the vcard of one bbdb record" + (setq coding-system (or coding-system 'utf-16)) + (let ((coding-system-for-write coding-system)) + (message "Updating %s" (bbdb-record-name record)) + (bbdb-vcard-export-make-vcard + record + (concat output-dir + (bbdb-vcard-export-vcard-name-from-record record))))) + +(defun bbdb-vcard-export-update-all (output-dir coding-system) + "Update the vcard Contacts directory from the bbdb database" + (interactive "DDirectory to update: \nZCoding system: ") + (bbdb ".*" nil) + (dolist (record (bbdb-records)) + (bbdb-vcard-do-record record output-dir coding-system))) + +(defun bbdb-vcard-export (regexp output-dir coding-system) + "Update the vcard Contacts directory from records matching REGEXP" + (interactive "sExport records matching: \nDDirectory to update: \nZCoding system: ") + (bbdb regexp nil) + (let ((notes (cons '* regexp))) + (dolist (record (bbdb-search (bbdb-records) regexp regexp regexp notes nil)) + (message "Updating %s" (bbdb-record-name record)) + (bbdb-vcard-do-record record output-dir coding-system)))) + +(defun bbdb-vcard-export-current (output-dir coding-system) + "Update the vcard of the current record" + (interactive "DDirectory to update: \nZCoding system: ") + (let ((record (bbdb-current-record nil))) + (bbdb-vcard-do-record record output-dir coding-system))) + +(define-key bbdb-mode-map [(v)] 'bbdb-vcard-export-current) + + +(provide 'bbdb-vcard-export) + +;;; bbdb-vcard-export.el ends here diff --git a/bits/bbdb-vcard-import.el b/bits/bbdb-vcard-import.el new file mode 100644 index 0000000..27f592d --- /dev/null +++ b/bits/bbdb-vcard-import.el @@ -0,0 +1,199 @@ +;;; bbdb-vcard-import.el -- import vCards into BBDB +;; +;; Copyright (c) 2008 Marcus Crestani +;; +;; bbdb-vcard-import.el 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 2, or (at +;; your option) any later version. +;; +;; This software is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +;; +;; Author: Marcus Crestani <crestani@informatik.uni-tuebingen.de> +;; Created: 2008-01-03 +;; Version: $Id: bbdb-vcard-import.el,v 1.6 2008/01/31 16:19:15 cvs Exp $ +;; Keywords: vcard bbdb +;; +;; This requires vcard.el by NoahFriedman for the importer to work. +;; +;; http://www.splode.com/~friedman/software/emacs-lisp/src/vcard.el +;; +;; The implementation is based on Christopher Smiths very simple +;; version of `bbdb-vcard-snarf-buffer': +;; +;; http://www.emacswiki.org/cgi-bin/wiki/BbdbImporters#toc3 +;; + +;;; Commentary + +;; +;; To import all vCards that are in the file ~/vCards.vcf do: +;; +;; M-x bbdb-vcard-import RET ~/vCards.vcf RET +;; + +;;; Todo + +;; +;; STREET ADDRESSES and PHONE NUMBERS are not yet imported. See +;; comment in `bbdb-vcard-merge'. +;; + +;;; ChangeLog + +;; +;; 2008-01-31 Marcus Crestani <crestani@informatik.uni-tuebingen.de> +;; - Do not enforce (type . "internet") for email addresses. +;; +;; 2008-01-03 Marcus Crestani <crestani@informatik.uni-tuebingen.de> +;; - Initial version. +;; + +;;; Code: + +(require 'vcard) +(require 'bbdb) + +(defvar bbdb-vcard-merged-records nil) + +(defun bbdb-vcard-filter-empty-values (values) + "Filter out empty values." + (if (consp values) + (if (string= "" (car values)) + (bbdb-vcard-filter-empty-values (cdr values)) + (cons (car values) (bbdb-vcard-filter-empty-values (cdr values)))))) + +(defun bbdb-vcard-values (record field) + "Return the values of an RECORD's FIELD; empty string entries are filtered out." + (let ((values (vcard-values record (list field)))) + (if values + (mapconcat 'identity + (bbdb-vcard-filter-empty-values (car values)) + ", ") + ""))) + +(defun bbdb-vcard-get-emails (record) + "Return a list of email addresses." + (let ((pref (vcard-ref record '("email" ("type" . "pref")))) + (rest (vcard-ref record '("email") '(("type" . "pref"))))) + (mapcar (lambda (entry) (car (cdr entry))) + (if pref + (cons (car pref) rest) + rest)))) + +(defun bbdb-vcard-get-phones (record) + "Return a list of phone number objects." + (let ((pref (vcard-ref record '("tel" ("type" . "pref")))) + (rest (vcard-ref record '("tel") '(("type" . "pref"))))) + (mapcar (lambda (entry) + (let ((proplist (car entry)) + (phone (car (cdr entry)))) + (vector + (vcard-get-property proplist "type") + phone))) + (if pref + (cons (car pref) rest) + rest)))) + +(defun bbdb-vcard-get-addresses (record) + "Return a list of adress objects." + (let ((pref (vcard-ref record '("adr" ("type" . "pref")))) + (rest (vcard-ref record '("adr") '(("type" . "pref"))))) + (mapcar (lambda (entry) + (let ((proplist (car entry)) + (phone (car (cdr entry)))) + (vector + (vcard-get-property proplist "type") + phone))) + (if pref + (cons (car pref) rest) + rest)))) + +(defun bbdb-vcard-merge-interactively (name company nets addrs phones notes) + "Interactively add a new record; see \\[bbdb-merge-interactively]." + (let* + ((f-l-name (bbdb-divide-name name)) + (firstname (car f-l-name)) + (lastname (nth 1 f-l-name)) + (aka nil) + (new-record + (vector firstname lastname aka company phones addrs + (if (listp nets) nets (list nets)) notes + (make-vector bbdb-cache-length nil))) + (old-record (bbdb-search-simple name nets))) + (if old-record + (progn + (setq new-record (bbdb-merge-internally old-record new-record)) + (bbdb-delete-record-internal old-record))) + ;; create new record + (bbdb-invoke-hook 'bbdb-create-hook new-record) + (bbdb-change-record new-record t) + (bbdb-hash-record new-record) + new-record)) + +(defun 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 and phones are not yet imported. To do this + ;; right, figure out a way to map the several labels to + ;; `bbdb-default-label-list'. Also, some phone number + ;; conversion may break the format of numbers. + (new-record (bbdb-vcard-merge-interactively name company net nil nil notes))) + (setq bbdb-vcard-merged-records (append bbdb-vcard-merged-records + (list new-record))))) + +(defun bbdb-vcard-snarf-region (begin end) + "Bbdb-snarf each match." + (let ((record (vcard-parse-region begin end))) + (bbdb-vcard-merge record))) + +(defun bbdb-vcard-snarf-buffer (buf) + "Traverse BUF via regex. Bbdb-snarf against each match." + (setq bbdb-vcard-merged-records nil) + (let ((bbdb-current-buffer (current-buffer)) + (bbdb-current-point (point-min)) + (bbdb-next-point (point-min))) + (switch-to-buffer buf) + (goto-char bbdb-current-point) + (while (re-search-forward "END:VCARD" nil (message "%s done" buf)) + (setq bbdb-next-point (point)) + (bbdb-vcard-snarf-region bbdb-current-point (point)) + (switch-to-buffer buf) + (goto-char bbdb-next-point) + (setq bbdb-current-point (point))) + (switch-to-buffer bbdb-current-buffer) + (bbdb-display-records bbdb-vcard-merged-records))) + +(defun bbdb-vcard-snarf-current-buffer () + "Snarf the vcards in the current buffer." + (interactive) + (bbdb-vcard-snarf-buffer (current-buffer))) + +(defun bbdb-vcard-import-current-buffer () + "Import the vcards in the current buffer into your bbdb." + (interactive) + (bbdb-vcard-snarf-current-buffer)) + +(defun bbdb-vcard-import (file) + "Import the vcards in FILE into your bbdb." + (interactive "FvCard file to read from: ") + (let ((buffer (find-file file))) + (bbdb-vcard-snarf-buffer buffer) + (revert-buffer buffer) + (kill-buffer buffer))) + +(provide 'bbdb-vcard-import) diff --git a/bits/bbdbpalm.el b/bits/bbdbpalm.el new file mode 100644 index 0000000..4a308fb --- /dev/null +++ b/bits/bbdbpalm.el @@ -0,0 +1,501 @@ +;;; bbdbpalm.el -- BBDBpalm exporter of BBDB database to Palm(R) address book + +;; Copyright (C) 1999,2002,2006 Neil W. Van Dyke + +;; Author: Neil W. Van Dyke <neil@neilvandyke.org> +;; Version: 0.3 +;; X-URL: http://www.neilvandyke.org/bbdbpalm/ +;; X-CVS: $Id: bbdbpalm.el,v 1.26 2006-11-12 04:46:58 neil Exp $ + +;; This 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 2, or (at your option) any later version. This +;; is distributed in the hope that it will be useful, but without any warranty; +;; without even the implied warranty of merchantability or fitness for a +;; particular purpose. See the GNU General Public License for more details. +;; You should have received a copy of the GNU General Public License along with +;; Emacs; see the file `COPYING'. If not, write to the Free Software +;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.") + +;;; Commentary: + +;; ABOUT: +;; +;; BBDBpalm exports your BBDB address database to your Palm/USR/3Com +;; Pilot/PalmPilot/Palm-Connected-Organizer (hereinafter simply "Palm"). +;; BBDB is a sort of electronic address book written by Jamie Zawinsky +;; <jwz@jwz.org> that integrates nicely with Emacs-based E-mail and Usenet +;; clients. BBDBpalm lets you bring that address book with you if you +;; don't have the luxury of 24/7 network access to a remote Emacs session +;; from your Palm. +;; +;; The Web page is `http://www.neilvandyke.org/bbdbpalm/'. +;; +;; This package is no longer being maintained. + +;; REQUIREMENTS: +;; +;; BBDBpalm was developed with BBDB 1.51, which is available at +;; `http://www.jwz.org/bbdb/' if you don't already have it. It has also +;; been reported to work with BBDB 2.00.02. +;; +;; BBDBpalm uses the `pilot-addresses' program, which is part of the +;; Pilot-Link package. Pilot-Link is freely available on the 'net, and is +;; included with some GNU/Linux distributions. The master sources are +;; available at `ftp://ryeham.ee.ryerson.ca/pub/PalmOS/', although you may +;; wish to instead find a pre-compiled distribution for your operating +;; system. BBDBpalm was tested with version 0.9.0. +;; +;; BBDBpalm was developed under GNU Emacs 20.3 running atop the GNU/Linux +;; platform. It will probably work with Emacs 19 and has been reported to +;; work under XEmacs 21.2b17. It will probably work under Emacs on other +;; Unix variants. Please let me know if you encounter any problems with +;; other Emacsen or Unixen. + +;; INSTALLATION: +;; +;; If you're Emacs-savvy enough to be using BBDB, then you probably don't +;; need much install instructions. The only three non-obvious things you +;; need to do are: +;; +;; 1. On your Palm, add an Address List category called "BBDB", in all +;; caps. (Reason: Unfortunately, `pilot-addresses' does not presently +;; create categories on your Palm, or overwrite duplicate entries. +;; So, every time we upload to the Palm, we blast everything in the +;; "BBDB" category and put all the BBDB-exported records into that +;; category.) If you change entries on the Palm side of things, +;; change their category so that you remember to manually propagate +;; the change to BBDB. +;; +;; 2. If you don't want to export everything in your BBDB to the Palm, +;; then do both of: +;; +;; a. Put the following your `.emacs' file or wherever you put your +;; Emacs customizations: +;; +;; (setq bbdbpalm-export-all-p nil) +;; +;; b. Add a field called `palm' to each BBDB record that you wish to +;; export (by pressing `C-o' in the `*BBDB*' buffer with the +;; point on the desired record). Give each `palm' field a value +;; of `yes' for now. Note that a later version of BBDBpalm might +;; put something else in that field. +;; +;; 3. If you wish to have titles for people be exported to the Palm, add +;; a field called `title' to BBDB and use it. + +;; ALTERNATIVES: +;; +;; Tom Fawcett <fawcett@basit.com> wrote `bbdb-pilot', which is available +;; at `ftp://ftp.croftj.net/usr/fawcett/bbdb-pilot.el'. The version I +;; found, dated 1998, didn't seem to do what I wanted (I'm so picky) but +;; you may prefer it. +;; +;; Neale Picket <zephyr@roguetrader.com> hacked up a small convertor in +;; Feb-1998. See `http://acm.rpi.edu/~albert/pilot/Feb98/0039.html'. + +;; THINGS TO DO: +;; +;; * Add support for custom fields. +;; +;; * Add special support for `Web' custom field. +;; +;; * Maybe someday do bidirectional sync-ing. For now, users should just +;; keep all the BBDB-exported records in the `BBDB' category on their +;; Palm, and manually change those records on the BBDB end rather than on +;; the Palm end. +;; +;; * Maybe I should make it fix certain family names that BBDB has +;; mis-parsed, such as, well... I dunno... how about... "Van Dyke"? +;; Better yet, I should move to BBDB 2.x and make sure it's fixed there. +;; +;; * Make it be smarter about which address it picks if there are multiple +;; ones. +;; +;; * Add BBDB extension so that it prompts you for `palm' field. +;; +;; * Make it reformat phone numbers. +;; +;; * Add completion-percentage indicator for file-exporting and uploading. +;; +;; * Check for error from `pilot-addresses' and maybe do something with it. +;; +;; * ``I think it would be nice if the order of phone numbers as they +;; appear in the BBDB was preserved in the Pilot. Same thing for multiple +;; email addresses; they are now listed in reverse order.'' [Mark Moll +;; <mmoll@cs.cmu.edu>, 24-Jun-1999] +;; +;; * ``Maybe it's a good idea to put in a message "Please press the HotSync +;; button" at the appropiate time.'' [Mark Moll <mmoll@cs.cmu.edu>, +;; 24-Jun-1999] + +;;; Change Log: + +;; [Version 0.3, 2006-11-12] Made `bbdbpalm-format-record' work with newer BBDB +;; versions by use of `bbdb-address-streets'. Thanks to Christoph Conrad for +;; the patch. Note that I do not have access to a Palm and cannot test this +;; myself. +;; +;; [Version 0.2, 2002-10-15] I no longer have access to a Palm, so I am not +;; maintaining this package. This release is a snapshot of my last modified +;; version, which fixes a typo in jwz's name (writes one observant BBDBpalm +;; user: ``jwz's spelling of his last name differs a bit from yours. If +;; "Zawinksy" an in-joke, it's probably funny.''), and updates my email +;; address. +;; +;; [Version 0.1, 1999-06-23] Initial release. + +;;; Code: + +(defconst bbdbpalm-name "BBDBpalm") +(defconst bbdbpalm-version "0.3") + +;; Package Dependencies: + +(require 'bbdb) +(require 'cl) + +;; Options: + +(defvar bbdbpalm-category + "BBDB" + "*Name of the category under which the exported address records are to be +filed. Note that all addresses in this category will be removed from the Palm +when the new addresses are uploaded by `pilot-addresses'.") + +(defvar bbdbpalm-export-all-p + t + "*If non-nil, export all records, rather than exporting only those records +that that have a `palm' field.") + +(defvar bbdbpalm-export-file + (expand-file-name ".bbdbpalm-export" "~") + "*Filename of the file into which BBDB-Palm puts the exported address data +for `pilot-addresses'.") + +(defvar bbdbpalm-leave-work-field-p + t + "*If non-nil, never put anything in the first contact field (which defaults +to the Work phone number) except Work.") + +(defvar bbdbpalm-pilot-addresses-program + "pilot-addresses" + "*Command to invoke the `pilot-addresses' program. The program should either +be in the executable search path, or this variable should be set to a +fully-qualified pathname to the program file.") + +;; Constants: + +(defconst bbdbpalm-contactcode-strings + '((email . "E-Mail") + (fax . "Fax") + (home . "Home") + (mail . "Main") + (mobile . "Mobile") + (other . "Other") + (pager . "Pager") + (work . "Work"))) + +(defconst bbdbpalm-octal-700 448) + +;; Macros: + +(defmacro bbdbpalm-assq-del (key alist) + (assert (symbolp alist)) + (let ((cell (gensym)) + (eval-key (gensym)) + (head (gensym)) + (lasthead (gensym))) + `(let ((,eval-key ,key) + (,cell nil) + (,head ,alist) + (,lasthead nil)) + (while (and ,head (not ,cell)) + (setq ,cell (car ,head)) + (if (eq (car ,cell) ,eval-key) + (if ,lasthead + (setcdr ,lasthead (cdr ,head)) + (setq ,alist (cdr ,head))) + (setq ,cell nil) + (setq ,lasthead ,head) + (setq ,head (cdr ,head)))) + ,cell))) + +(defmacro bbdbpalm-log-activity (what &rest body) + ;; Note: This function was adapted from `jomtool-log-activity' in Neil's + ;; Jomtool package. + (let ((eval-what (gensym))) + `(let ((,eval-what ,what)) + (bbdbpalm-log (concat ,eval-what "...")) + (prog1 (progn ,@body) + (bbdbpalm-log (concat ,eval-what "...done")))))) + +;; Functions: + +(defun bbdbpalm () + (interactive) + (bbdbpalm-log-activity + "Exporting BBDB data to the Palm" + (bbdbpalm-export-to-file bbdbpalm-export-file) + (bbdbpalm-upload-export-file bbdbpalm-export-file))) + +(defun bbdbpalm-contactcode-string (contactcode) + (cdr (assq contactcode bbdbpalm-contactcode-strings))) + +(defun bbdbpalm-export-to-file (export-file) + (let (buf + old-default-file-modes + record) + (bbdbpalm-log-activity + (format "Exporting to file \"%s\"" export-file) + (unwind-protect + (progn + ;; Make sure created files are only readable by user. + (setq old-default-file-modes (default-file-modes)) + (set-default-file-modes bbdbpalm-octal-700) + ;; Find the file and empty it. + (setq buf (find-file-noselect export-file)) + (set-buffer buf) + (goto-char (point-min)) + (delete-region (point-min) (point-max)) + ;; Write the records. + (mapc (function + (lambda (record) + (let ((notes (bbdb-record-raw-notes record))) + (if (or bbdbpalm-export-all-p + (and (listp notes) (assq 'palm notes))) + (insert (bbdbpalm-format-record record)))))) + (bbdb-records)) + ;; Save the file and get rid of the buffer. + (save-buffer buf) + (kill-buffer buf)) + ;; unwind-protect cleanup: Restore default-file-modes. + (set-default-file-modes old-default-file-modes))))) + +(defun bbdbpalm-format-contact-field (contact-field) + (if contact-field + (list (bbdbpalm-contactcode-string (car contact-field)) + (cdr contact-field)) + nil)) + +(defun bbdbpalm-format-field (field) + (cond ((null field) "\"\"") + ((stringp field) (bbdbpalm-format-field-string field)) + ((listp field) (mapconcat 'bbdbpalm-format-field-string + field + ";")) + (t (error "Can't handle type of this field: " + field)))) + +(defun bbdbpalm-format-field-list (list) + (concat (mapconcat 'bbdbpalm-format-field + list + ",") + "\n")) + +(defun bbdbpalm-format-field-string (field) + (if field + ;; Note: This is a grossly slow way to do it. + (concat "\"" + (mapconcat (function + (lambda (c) + (cond ((= c 34) "\"\"") + ((and (> c 31) (< c 128)) (char-to-string c)) + ((= c 9) "\\t") + ((= c 10) "\\n") + (t "")))) + field + "") + "\"") + "\"\"")) + +(defun bbdbpalm-format-record (record) + (let ((city nil) + (contact-fields nil) + (country nil) + (custom-1 nil) + (custom-2 nil) + (custom-3 nil) + (custom-4 nil) + (group nil) + (show-field nil) + (state nil) + (street nil) + (title nil) + (zip nil)) + + ;; Prepare the contact fields. + (let ((contact-cands '())) + + ;; Add phone numbers to contact-cands. + (mapcar + (function + (lambda (phone) + (let ((code (bbdbpalm-location-to-contactcode + (bbdb-phone-location phone)))) + (if code + (setq contact-cands + (nconc contact-cands + (list (cons code + (bbdb-phone-string phone))))))))) + (bbdb-record-phones record)) + + ;; Add E-mail addresses to contact-cands (note that we want these + ;; added after the phone numbers, so that phone numbers get higher + ;; priority when we're filling up extra contact fields). + (mapcar (function (lambda (net) + (setq contact-cands + (nconc contact-cands + (list (cons 'email net)))))) + (bbdb-record-net record)) + + ;; Set the contact fields, giving preference to one of each and to the + ;; Palm default ordering. Fill the remaining empty contact fields with + ;; other contact info. + (setq contact-fields (list (bbdbpalm-assq-del 'work contact-cands) + (bbdbpalm-assq-del 'home contact-cands) + (bbdbpalm-assq-del 'fax contact-cands) + (bbdbpalm-assq-del 'other contact-cands) + (bbdbpalm-assq-del 'email contact-cands))) + (let ((probe contact-fields)) + (if bbdbpalm-leave-work-field-p + (setq probe (cdr probe))) + (while (and probe contact-cands) + (if (not (car probe)) + (progn + (setcar probe (car contact-cands)) + (setq contact-cands (cdr contact-cands)))) + (setq probe (cdr probe)))) + + ;; Set show-field. + (setq show-field (if (and (not (assq 'work contact-fields)) + (assq 'home contact-fields)) + "Home" + "Work"))) + + ;; Prepare address fields. + (let ((addr nil) + (addrs (bbdb-record-addresses record))) + (setq addr (car addrs)) + (if addr + (setq street (mapconcat + 'identity + (delq nil + (mapcar (function + (lambda (s) + (if (= (length s) 0) nil s))) + (bbdb-address-streets addr) + ;; Note: Old code. Replaced by above + ;; line for newer BBDB. + ;; + ;; (list (bbdb-address-street1 addr) + ;; (bbdb-address-street2 addr) + ;; (bbdb-address-street3 addr)) + )) + ", ") + city (bbdb-address-city addr) + state (bbdb-address-state addr) + zip (bbdb-address-zip-string addr) + country nil))) + + ;; Get information from the raw notes fields. + (mapcar (function (lambda (field) + (if (consp field) + (case (car field) + ('title (setq title (cdr field))) + ('group (setq group (cdr field))))))) + (bbdb-record-raw-notes record)) + + ;; Return the formatted record. + (bbdbpalm-format-field-list + (list + ;; 1. <FileCategory> SEMI <DisplayField> SEMI <LastName> + ;; "Unfiled";"Fax";"ALastName", + (list bbdbpalm-category show-field (bbdb-record-lastname record)) + ;; 2. <FirstName> + ;; "AFirstName", + (bbdb-record-firstname record) + ;; 3. <Title> + ;; "ATitle", + title + ;; 3. <Company> + ;; "ACompany", + (bbdb-record-company record) + ;; 4-8. ( <ContactAttr> SEMI <ContactValue> ) | ( <emptystring> ) + ;; "","","Fax";"zFax","Other";"zOther, with ""quotes""", + ;; "E-mail";"zEmail", + (bbdbpalm-format-contact-field (nth 0 contact-fields)) + (bbdbpalm-format-contact-field (nth 1 contact-fields)) + (bbdbpalm-format-contact-field (nth 2 contact-fields)) + (bbdbpalm-format-contact-field (nth 3 contact-fields)) + (bbdbpalm-format-contact-field (nth 4 contact-fields)) + ;; 9. <Street> + ;; "zAddress", + street + ;; 10. <City> + ;; "zCity", + city + ;; 11. "zState", + state + ;; 12. "zZip", + zip + ;; 13. "zCountry", + country + ;; 14. "zGroup", + custom-1 + ;; 15. "zWeb", + custom-2 + ;; 16. "zIrc", + custom-3 + ;; 17. "zC4", + custom-4 + ;; 18. <Notes> + ;; "", + (bbdb-record-notes record) + ;; 19. <Unknown2> + ;; "0" + "0")))) + +(defun bbdbpalm-location-to-contactcode (loc) + (let ((s (assoc (downcase loc) + '(("cell" . mobile) + ("fax" . fax) + ("home" . home) + ("main" . main) + ("mobile" . mobile) + ("office" . work) + ("pad" . home) + ("work" . work))))) + (if s (cdr s) 'other))) + +(defun bbdbpalm-log (format &rest args) + (apply 'message (concat bbdbpalm-name ": " format) args)) + +(defun bbdbpalm-upload-export-file (export-file) + (bbdbpalm-log-activity + (format "Uploading file \"%s\" to Palm" export-file) + (save-excursion + (save-window-excursion + (let ((buf (get-buffer-create "*BBDBpalm*"))) + (set-buffer buf) + (setq buffer-read-only nil) + (delete-region (point-min) (point-max)) + (insert bbdbpalm-name + " will now run \"" + bbdbpalm-pilot-addresses-program + "\" to upload the data to your Palm.\n\n") + (or (getenv "PILOTRATE") + (insert "You may be able to speed up uploads by setting your" + " \"PILOTRATE\" environment\n" + "variable. See your Pilot-Link documentation for" + " details.\n\n")) + (pop-to-buffer buf) + (call-process bbdbpalm-pilot-addresses-program + nil buf t + "-d" bbdbpalm-category + "-r" bbdbpalm-export-file) + (setq buffer-read-only t)))))) + +(provide 'bbdbpalm) + +;;; bbdbpalm.el ends here diff --git a/bits/make.bat b/bits/make.bat new file mode 100644 index 0000000..0e5248d --- /dev/null +++ b/bits/make.bat @@ -0,0 +1,106 @@ +@echo off + +rem Written by Yair Friedman (yair@MailAndNews.com) +rem Based upon the gnus make.bat by David Charlap (shamino@writeme.com) +rem +rem There are two possible problems with this batch file. The emacs.bat batch +rem file may not exist in all distributions. It is part of the GNU build of +rem Emacs 20.4 (http://www.gnu.org/softare/emacs/windows.ntemacs.html) If you +rem install BBDB with some other build, you may have to replace calls to +rem %1\emacs.bat with something else. +rem +rem Also, the emacs.bat file that comes with Emacs does not accept more than 9 +rem parameters, so the attempts to compile the .texi files will fail. To +rem fix that (at least on NT. I don't know about Win95), the following +rem change should be made to emacs.bat: +rem +rem %emacs_dir%\bin\emacs.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 +rem +rem should become +rem +rem %emacs_dir%\bin\emacs.exe %* +rem +rem which will allow the batch file to accept an unlimited number of +rem parameters. + +rem For the meaning of these look at the Makefile. +rem Notice that you have to double any backslashes in the path. +set GNUSDIR=E:\\emacs-20.7\\lisp\\gnus +set MHEDIR= +set VMDIR= +set OTHERDIR= +rem give it any value if you want to use rmail with bbdb +set RMAIL= +rem This is where you bbdb lisp is going +set BBDBDIR=D:\\emacs-20.7\\site-lisp\\bbdb-2.2\\lisp + +rem Clear PWD so emacs doesn't get confused +set BBDB_PWD_SAVE=%PWD% +set PWD= + +if "%1" == "" goto usage + +rem Emacs 20.7 no longer includes emacs.bat. Use emacs.exe if the batch file is +rem not present -- this also fixes the problem about too many parameters on Win9x. +set emacs=emacs.exe +if exist %1\bin\emacs.bat set emacs=emacs.bat + +set VM=-eval "(progn (if (not (string-match \"%VMDIR%\" \"\")) (setq load-path (cons \"%VMDIR%\" load-path))) (if (load \"vm-version\" t) (cond ((> (string-to-number vm-version) 5.31) (load \"vm\")) (t (load \"vm-vars\") (load \"vm\")))))" +set GNUS=-eval "(if (not (string-match \"%GNUSDIR%\" \"\")) (setq load-path (cons \"%GNUSDIR%\" load-path)))" +set MHE=-eval "(progn (if (not (string-match \"%MHEDIR%\" \"\")) (setq load-path (cons \"%MHEDIR%\" load-path))) (load \"mh-e\"))" +set PUSHPATH=-eval "(setq load-path (delete \"\" (append (list \".\" \"%OTHERDIR%\") load-path)))" + +cd lisp + +call %1\bin\%emacs% -batch -q -no-site-file -f batch-byte-compile ./bbdb.el +call %1\bin\%emacs% -batch -q -no-site-file %PUSHPATH% -l ./bbdb.elc -f batch-byte-compile bbdb-com.el bbdb-hooks.el bbdb-print.el bbdb-ftp.el bbdb-whois.el bbdb-srv.el bbdb-reportmail.el bbdb-snarf.el bbdb-w3.el bbdb-sc.el bbdb-merge.el bbdb-migrate.el + +IF "%RMAIL%" == "" goto afterrmail +call %1\bin\%emacs% -batch -q -no-site-file %PUSHPATH% -l ./bbdb.elc -f batch-byte-compile bbdb-rmail.el +:afterrmail + +IF "%GNUSDIR%" == "" goto aftergnus +call %1\bin\%emacs% -batch -q -no-site-file %PUSHPATH% -l ./bbdb.elc %GNUS% -f batch-byte-compile bbdb-gnus.el +:aftergnus + +IF "%VMDIR%"=="" goto aftervm +call %1\bin\%emacs% -batch -q -no-site-file %PUSHPATH% -l ./bbdb.elc %VM% -f batch-byte-compile bbdb-vm.el +:aftervm + +IF "%MHEDIR%"=="" goto aftermhe +call %1\bin\%emacs% -batch -q -no-site-file %PUSHPATH% -l ./bbdb.elc %MHE% -f batch-byte-compile bbdb-mhe.el +:aftermhe + +echo home is where the heart is. + +rem echo > bbdb-autoloads.el +rem call %1\bin\%emacs% -batch -q -no-site-file -l autoload -eval "(setq generated-autoload-file \"%BBDBDIR%\\bbdb-autoloads.el\")" -eval "(setq make-backup-files nil)" -eval "(setq autoload-package-name \"bbdb\")" -f batch-update-autoloads %BBDBDIR% +call %1\bin\%emacs% -batch -q -no-site-file -f batch-byte-compile bbdb-autoloads.el + +if not "%2%"=="copy" goto info +attrib -r %1\lisp\bbdb\* +copy *.el* %1\lisp\bbdb + +:info +set EMACSINFOHACK="(while (re-search-forward \"@\\(end \\)?ifnottex\" nil t) (replace-match \"\"))" +cd ..\texinfo +call %1\bin\%emacs% -batch -q -no-site-file bbdb.texinfo -eval %EMACSINFOHACK% -eval "(setq max-lisp-eval-depth 600)" -f texinfo-every-node-update -f texinfo-format-buffer -f save-buffer +if not "%2" == "copy" goto done +copy bbdb.info %1\info + +:done +cd .. +goto end + +:usage +echo Usage: make :emacs-dir: [copy] +echo. +echo where: :emacs-dir: is the directory you installed emacs in +echo eg. d:\emacs\20.4 +echo copy indicates that the compiled files should be copied to your +echo emacs lisp, info, and etc directories + +rem Restore PWD so whoever called this batch file doesn't get confused +set PWD=%BBDB_PWD_SAVE% +set BBDB_PWD_SAVE= +:end diff --git a/bits/vcard.el b/bits/vcard.el new file mode 100644 index 0000000..27eb3df --- /dev/null +++ b/bits/vcard.el @@ -0,0 +1,704 @@ +;;; vcard.el --- vcard parsing and display routines + +;; Copyright (C) 1997, 1999, 2000 Noah S. Friedman + +;; Author: Noah Friedman <friedman@splode.com> +;; Maintainer: friedman@splode.com +;; Keywords: vcard, mail, news +;; Created: 1997-09-27 + +;; $Id: vcard.el,v 1.11 2000/06/29 17:07:55 friedman Exp $ + +;; 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 2, 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, you can either send email to this +;; program's maintainer or write to: The Free Software Foundation, +;; Inc.; 59 Temple Place, Suite 330; Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; Unformatted vcards are just plain ugly. But if you live in the MIME +;; world, they are a better way of exchanging contact information than +;; freeform signatures since the former can be automatically parsed and +;; stored in a searchable index. +;; +;; This library of routines provides the back end necessary for parsing +;; vcards so that they can eventually go into an address book like BBDB +;; (although this library does not implement that itself). Also included +;; is a sample pretty-printer which MUAs can use which do not provide their +;; own vcard formatters. + +;; This library does not interface directly with any mail user agents. For +;; an example of bindings for the VM MUA, see vm-vcard.el available from +;; +;; http://www.splode.com/~friedman/software/emacs-lisp/index.html#mail +;; +;; Updates to vcard.el should be available there too. + +;; The main entry point to this package is `vcard-pretty-print' although +;; any documented variable or function is considered part of the API for +;; operating on vcard data. + +;; The vcard 2.1 format is defined by the versit consortium. +;; See http://www.imc.org/pdi/vcard-21.ps +;; +;; RFC 2426 defines the vcard 3.0 format. +;; See ftp://ftp.rfc-editor.org/in-notes/rfc2426.txt + +;; A parsed vcard is a list of attributes of the form +;; +;; (proplist value1 value2 ...) +;; +;; Where proplist is a list of property names and parameters, e.g. +;; +;; (property1 (property2 . parameter2) ...) +;; +;; Each property has an associated implicit or explicit parameter value +;; (not to be confused with attribute values; in general this API uses +;; `parameter' to refer to property values and `value' to refer to attribute +;; values to avoid confusion). If a property has no explicit parameter value, +;; the parameter value is considered to be `t'. Any property which does not +;; exist for an attribute is considered to have a nil parameter. + +;; TODO: +;; * Finish supporting the 3.0 extensions. +;; Currently, only the 2.1 standard is supported. +;; * Handle nested vcards and grouped attributes? +;; (I've never actually seen one of these in use.) +;; * Handle multibyte charsets. +;; * Inverse of vcard-parse-string: write .VCF files from alist +;; * Implement a vcard address book? Or is using BBDB preferable? +;; * Improve the sample formatter. + +;;; Code: + +(defgroup vcard nil + "Support for the vCard electronic business card format." + :group 'vcard + :group 'mail + :group 'news) + +;;;###autoload +(defcustom vcard-pretty-print-function 'vcard-format-sample-box + "*Formatting function used by `vcard-pretty-print'." + :type 'function + :group 'vcard) + +;;;###autoload +(defcustom vcard-standard-filters + '(vcard-filter-html + vcard-filter-adr-newlines + vcard-filter-tel-normalize + vcard-filter-textprop-cr) + "*Standard list of filters to apply to parsed vcard data. +These filters are applied sequentially to vcard attributes when +the function `vcard-standard-filter' is supplied as the second argument to +`vcard-parse'." + :type 'hook + :group 'vcard) + + +;;; No user-settable options below. + +;; XEmacs 21 ints and chars are disjoint types. +;; For all else, treat them as the same. +(defalias 'vcard-char-to-int + (if (fboundp 'char-to-int) 'char-to-int 'identity)) + +;; This is just the version number for this package; it does not refer to +;; the vcard format specification. Currently, this package does not yet +;; support the full vcard 3.0 specification. +;; +;; Whenever any part of the API defined in this package change in a way +;; that is not backward-compatible, the major version number here should be +;; incremented. Backward-compatible additions to the API should be +;; indicated by increasing the minor version number. +(defconst vcard-api-version "2.0") + +;; The vcard standards allow specifying the encoding for an attribute using +;; these values as immediate property names, rather than parameters of the +;; `encoding' property. If these are encountered while parsing, associate +;; them as parameters of the `encoding' property in the returned structure. +(defvar vcard-encoding-tags + '("quoted-printable" "base64" "8bit" "7bit")) + +;; The vcard parser will auto-decode these encodings when they are +;; encountered. These methods are invoked via vcard-parse-region-value. +(defvar vcard-region-decoder-methods + '(("quoted-printable" . vcard-region-decode-quoted-printable) + ("base64" . vcard-region-decode-base64))) + +;; This is used by vcard-region-decode-base64 +(defvar vcard-region-decode-base64-table + (let* ((a "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") + (len (length a)) + (tbl (make-vector 123 nil)) + (i 0)) + (while (< i len) + (aset tbl (vcard-char-to-int (aref a i)) i) + (setq i (1+ i))) + tbl)) + + +;;; This function can be used generically by applications to obtain +;;; a printable representation of a vcard. + +;;;###autoload +(defun vcard-pretty-print (vcard) + "Format VCARD into a string suitable for display to user. +VCARD can be an unparsed string containing raw VCF vcard data +or a parsed vcard alist as returned by `vcard-parse-string'. + +The result is a string with formatted vcard information suitable for +insertion into a mime presentation buffer. + +The function specified by the variable `vcard-pretty-print-function' +actually performs the formatting. That function will always receive a +parsed vcard alist." + (and (stringp vcard) + (setq vcard (vcard-parse-string vcard))) + (funcall vcard-pretty-print-function vcard)) + + +;;; Parsing routines + +;;;###autoload +(defun vcard-parse-string (raw &optional filter) + "Parse RAW vcard data as a string, and return an alist representing data. + +If the optional function FILTER is specified, apply that filter to each +attribute. If no filter is specified, `vcard-standard-filter' is used. + +Filters should accept two arguments: the property list and the value list. +Modifying in place the property or value list will affect the resulting +attribute in the vcard alist. + +Vcard data is normally in the form + + begin: vcard + prop1a: value1a + prop2a;prop2b;prop2c=param2c: value2a + prop3a;prop3b: value3a;value3b;value3c + end: vcard + +\(Whitespace around the `:' separating properties and values is optional.\) +If supplied to this function an alist of the form + + \(\(\(\"prop1a\"\) \"value1a\"\) + \(\(\"prop2a\" \"prop2b\" \(\"prop2c\" . \"param2c\"\)\) \"value2a\"\) + \(\(\"prop3a\" \"prop3b\"\) \"value3a\" \"value3b\" \"value3c\"\)\) + +would be returned." + (let ((vcard nil) + (buf (generate-new-buffer " *vcard parser work*"))) + (unwind-protect + (save-excursion + (set-buffer buf) + ;; Make sure last line is newline-terminated. + ;; An extra trailing newline is harmless. + (insert raw "\n") + (setq vcard (vcard-parse-region (point-min) (point-max) filter))) + (kill-buffer buf)) + vcard)) + +;;;###autoload +(defun vcard-parse-region (beg end &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 "[ \t]*\n") + (set-marker newpos (match-end 0)) + (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))) + +(defun vcard-parse-region-properties (beg end) + (downcase-region beg end) + (let* ((proplist (vcard-split-string (buffer-substring beg end) ";")) + (props proplist) + split) + (save-match-data + (while props + (cond ((string-match "=" (car props)) + (setq split (vcard-split-string (car props) "=" 2)) + (setcar props (cons (car split) (car (cdr split))))) + ((member (car props) vcard-encoding-tags) + (setcar props (cons "encoding" (car props))))) + (setq props (cdr props)))) + proplist)) + +(defun vcard-parse-region-value (proplist beg end) + (let* ((encoding (vcard-get-property proplist "encoding")) + (decoder (cdr (assoc encoding vcard-region-decoder-methods))) + result pos match-beg match-end) + (save-restriction + (narrow-to-region beg end) + (cond (decoder + ;; Each `;'-separated field needs to be decoded and saved + ;; separately; if the entire region were decoded at once, we + ;; would not be able to distinguish between the original `;' + ;; chars and those which were encoded in order to quote them + ;; against being treated as field separators. + (goto-char beg) + (setq pos (set-marker (make-marker) (point))) + (setq match-beg (make-marker)) + (setq match-end (make-marker)) + (save-match-data + (while (< pos (point-max)) + (cond ((search-forward ";" nil t) + (set-marker match-beg (match-beginning 0)) + (set-marker match-end (match-end 0))) + (t + (set-marker match-beg (point-max)) + (set-marker match-end (point-max)))) + (funcall decoder pos match-beg) + (setq result (cons (buffer-substring pos match-beg) result)) + (set-marker pos (marker-position match-end)))) + (setq result (nreverse result)) + (vcard-set-property proplist "encoding" nil)) + (t + (setq result (vcard-split-string (buffer-string) ";"))))) + (goto-char (point-max)) + result)) + + +;;; Functions for retrieving property or value information from parsed +;;; vcard attributes. + +(defun vcard-values (vcard have-props &optional non-props limit) + "Return the values in VCARD. +This function is like `vcard-ref' and takes the same arguments, but return +only the values, not the associated property lists." + (mapcar 'cdr (vcard-ref vcard have-props non-props limit))) + +(defun vcard-ref (vcard have-props &optional non-props limit) + "Return the attributes in VCARD with HAVE-PROPS properties. +Optional arg NON-PROPS is a list of properties which candidate attributes +must not have. +Optional arg LIMIT means return no more than that many attributes. + +The attributes in VCARD which have all properties specified by HAVE-PROPS +but not having any specified by NON-PROPS are returned. The first element +of each attribute is the actual property list; the remaining elements are +the values. + +If a specific property has an associated parameter \(e.g. an encoding\), +use the syntax \(\"property\" . \"parameter\"\) to specify it. If property +parameter is not important or it has no specific parameter, just specify +the property name as a string." + (let ((attrs vcard) + (result nil) + (count 0)) + (while (and attrs (or (null limit) (< count limit))) + (and (vcard-proplist-all-properties (car (car attrs)) have-props) + (not (vcard-proplist-any-properties (car (car attrs)) non-props)) + (setq result (cons (car attrs) result) + count (1+ count))) + (setq attrs (cdr attrs))) + (nreverse result))) + +(defun vcard-proplist-all-properties (proplist props) + "Returns nil unless PROPLIST contains all properties specified in PROPS." + (let ((result t)) + (while (and result props) + (or (vcard-get-property proplist (car props)) + (setq result nil)) + (setq props (cdr props))) + result)) + +(defun vcard-proplist-any-properties (proplist props) + "Returns `t' if PROPLIST contains any of the properties specified in PROPS." + (let ((result nil)) + (while (and (not result) props) + (and (vcard-get-property proplist (car props)) + (setq result t)) + (setq props (cdr props))) + result)) + +(defun vcard-get-property (proplist property) + "Return the value from PROPLIST of PROPERTY. +PROPLIST is a vcard attribute property list, which is normally the first +element of each attribute entry in a vcard." + (or (and (member property proplist) t) + (cdr (assoc property proplist)))) + +(defun vcard-set-property (proplist property value) + "In PROPLIST, set PROPERTY to VALUE. +PROPLIST is a vcard attribute property list. +If VALUE is nil, PROPERTY is deleted." + (let (elt) + (cond ((null value) + (vcard-delete-property proplist property)) + ((setq elt (member property proplist)) + (and value (not (eq value t)) + (setcar elt (cons property value)))) + ((setq elt (assoc property proplist)) + (cond ((eq value t) + (setq elt (memq elt proplist)) + (setcar elt property)) + (t + (setcdr elt value)))) + ((eq value t) + (nconc proplist (cons property nil))) + (t + (nconc proplist (cons (cons property value) nil)))))) + +(defun vcard-delete-property (proplist property) + "Delete from PROPLIST the specified property PROPERTY. +This will not succeed in deleting the first member of the proplist, but +that element should never be deleted since it is the primary key." + (let (elt) + (cond ((setq elt (member property proplist)) + (delq (car elt) proplist)) + ((setq elt (assoc property proplist)) + (delq (car (memq elt proplist)) proplist))))) + + +;;; Vcard data filters. +;;; +;;; Filters receive both the property list and value list and may modify +;;; either in-place. The return value from the filters are ignored. +;;; +;;; These filters can be used for purposes such as removing HTML tags or +;;; normalizing phone numbers into a standard form. + +(defun vcard-standard-filter (proplist values) + "Apply filters in `vcard-standard-filters' to attributes." + (vcard-filter-apply-filter-list vcard-standard-filters proplist values)) + +;; This function could be used to dispatch other filter lists. +(defun vcard-filter-apply-filter-list (filter-list proplist values) + (while filter-list + (funcall (car filter-list) proplist values) + (setq filter-list (cdr filter-list)))) + +;; Some lusers put HTML (or even javascript!) in their vcards under the +;; misguided notion that it's a standard feature of vcards just because +;; Netscape supports this feature. That is wrong; the vcard specification +;; does not define any html content semantics and most MUAs cannot do +;; anything with html text except display them unparsed, which is ugly. +;; +;; Thank Netscape for abusing the standard and damned near rendering it +;; useless for interoperability between MUAs. +;; +;; This filter does a very rudimentary job. +(defun vcard-filter-html (proplist values) + "Remove HTML tags from attribute values." + (save-match-data + (while values + (while (string-match "<[^<>\n]+>" (car values)) + (setcar values (replace-match "" t t (car values)))) + (setq values (cdr values))))) + +(defun vcard-filter-adr-newlines (proplist values) + "Replace newlines with \"; \" in `adr' values." + (and (vcard-get-property proplist "adr") + (save-match-data + (while values + (while (string-match "[\r\n]+" (car values)) + (setcar values (replace-match "; " t t (car values)))) + (setq values (cdr values)))))) + +(defun vcard-filter-tel-normalize (proplist values) + "Normalize telephone numbers in `tel' values. +Spaces and hyphens are replaced with `.'. +US domestic telephone numbers are replaced with international format." + (and (vcard-get-property proplist "tel") + (save-match-data + (while values + (while (string-match "[\t._-]+" (car values)) + (setcar values (replace-match " " t t (car values)))) + (and (string-match "^(?\\(\\S-\\S-\\S-\\))? ?\ +\\(\\S-\\S-\\S- \\S-\\S-\\S-\\S-\\)" + (car values)) + (setcar values + (replace-match "+1 \\1 \\2" t nil (car values)))) + (setq values (cdr values)))))) + +(defun vcard-filter-textprop-cr (proplist values) + "Strip carriage returns from text values." + (and (vcard-proplist-any-properties + proplist '("adr" "email" "fn" "label" "n" "org" "tel" "title" "url")) + (save-match-data + (while values + (while (string-match "\r+" (car values)) + (setcar values (replace-match "" t t (car values)))) + (setq values (cdr values)))))) + + +;;; Decoding methods. + +(defmacro vcard-hexstring-to-ascii (s) + (if (string-lessp emacs-version "20") + `(format "%c" (car (read-from-string (format "?\\x%s" ,s)))) + `(format "%c" (string-to-number ,s 16)))) + +(defun vcard-region-decode-quoted-printable (&optional beg end) + (save-excursion + (save-restriction + (save-match-data + (narrow-to-region (or beg (point-min)) (or end (point-max))) + (goto-char (point-min)) + (while (re-search-forward "=\n" nil t) + (delete-region (match-beginning 0) (match-end 0))) + (goto-char (point-min)) + (while (re-search-forward "=[0-9A-Za-z][0-9A-Za-z]" nil t) + (let ((s (buffer-substring (1+ (match-beginning 0)) (match-end 0)))) + (replace-match (vcard-hexstring-to-ascii s) t t))))))) + +(defun vcard-region-decode-base64 (&optional beg end) + (save-restriction + (narrow-to-region (or beg (point-min)) (or end (point-max))) + (save-match-data + (goto-char (point-min)) + (while (re-search-forward "[ \t\r\n]+" nil t) + (delete-region (match-beginning 0) (match-end 0)))) + (goto-char (point-min)) + (let ((count 0) + (n 0) + (c nil)) + (while (not (eobp)) + (setq c (char-after (point))) + (delete-char 1) + (cond ((char-equal c ?=) + (if (= count 2) + (insert (lsh n -10)) + ;; count must be 3 + (insert (lsh n -16) (logand 255 (lsh n -8)))) + (delete-region (point) (point-max))) + (t + (setq n (+ n (aref vcard-region-decode-base64-table + (vcard-char-to-int c)))) + (setq count (1+ count)) + (cond ((= count 4) + (insert (logand 255 (lsh n -16)) + (logand 255 (lsh n -8)) + (logand 255 n)) + (setq n 0 count 0)) + (t + (setq n (lsh n 6)))))))))) + + +(defun vcard-split-string (string &optional separator limit) + "Split STRING at occurences of SEPARATOR. Return a list of substrings. +Optional argument SEPARATOR can be any regexp, but anything matching the + separator will never appear in any of the returned substrings. + If not specified, SEPARATOR defaults to \"[ \\f\\t\\n\\r\\v]+\". +If optional arg LIMIT is specified, split into no more than that many + fields \(though it may split into fewer\)." + (or separator (setq separator "[ \f\t\n\r\v]+")) + (let ((string-list nil) + (len (length string)) + (pos 0) + (splits 0) + str) + (save-match-data + (while (<= pos len) + (setq splits (1+ splits)) + (cond ((and limit + (>= splits limit)) + (setq str (substring string pos)) + (setq pos (1+ len))) + ((string-match separator string pos) + (setq str (substring string pos (match-beginning 0))) + (setq pos (match-end 0))) + (t + (setq str (substring string pos)) + (setq pos (1+ len)))) + (setq string-list (cons str string-list)))) + (nreverse string-list))) + +(defun vcard-copy-tree (tree) + "Make a deep copy of nested conses." + (cond + ((consp tree) + (cons (vcard-copy-tree (car tree)) + (vcard-copy-tree (cdr tree)))) + (t tree))) + +(defun vcard-flatten (l) + (if (consp l) + (apply 'nconc (mapcar 'vcard-flatten l)) + (list l))) + + +;;; Sample formatting routines. + +(defun vcard-format-sample-box (vcard) + "Like `vcard-format-sample-string', but put an ascii box around text." + (let* ((lines (vcard-format-sample-lines vcard)) + (len (vcard-format-sample-max-length lines)) + (edge (concat "\n+" (make-string (+ len 2) ?-) "+\n")) + (line-fmt (format "| %%-%ds |" len)) + (formatted-lines + (mapconcat (function (lambda (s) (format line-fmt s))) lines "\n"))) + (if (string= formatted-lines "") + formatted-lines + (concat edge formatted-lines edge)))) + +(defun vcard-format-sample-string (vcard) + "Format VCARD into a string suitable for display to user. +VCARD should be a parsed vcard alist. The result is a string +with formatted vcard information which can be inserted into a mime +presentation buffer." + (mapconcat 'identity (vcard-format-sample-lines vcard) "\n")) + +(defun vcard-format-sample-lines (vcard) + (let* ((name (vcard-format-sample-get-name vcard)) + (title (vcard-format-sample-values-concat vcard '("title") 1 "; ")) + (org (vcard-format-sample-values-concat vcard '("org") 1 "; ")) + (addr (vcard-format-sample-get-address vcard)) + (tel (vcard-format-sample-get-telephone vcard)) + (lines (delete nil (vcard-flatten (list name title org addr)))) + (col-template (format "%%-%ds%%s" + (vcard-format-sample-offset lines tel))) + (l lines)) + (while tel + (setcar l (format col-template (car l) (car tel))) + ;; If we stripped away too many nil slots from l, add empty strings + ;; back in so setcar above will work on next iteration. + (and (cdr tel) + (null (cdr l)) + (setcdr l (cons "" nil))) + (setq l (cdr l)) + (setq tel (cdr tel))) + lines)) + +(defun vcard-format-sample-get-name (vcard) + (let ((name (car (car (vcard-values vcard '("fn") nil 1)))) + (email (car (vcard-format-sample-values + vcard '((("email" "pref")) + (("email" "internet")) + (("email"))) 1)))) + (cond ((and name email) + (format "%s <%s>" name email)) + (email) + (name) + ("")))) + +(defun vcard-format-sample-get-telephone (vcard) + (let ((fields '(("Work: " + (("tel" "work" "pref") . ("fax" "pager" "cell")) + (("tel" "work" "voice") . ("fax" "pager" "cell")) + (("tel" "work") . ("fax" "pager" "cell"))) + ("Home: " + (("tel" "home" "pref") . ("fax" "pager" "cell")) + (("tel" "home" "voice") . ("fax" "pager" "cell")) + (("tel" "home") . ("fax" "pager" "cell")) + (("tel") . ("fax" "pager" "cell" "work"))) + ("Cell: " + (("tel" "cell" "pref")) + (("tel" "cell"))) + ("Fax: " + (("tel" "pref" "fax")) + (("tel" "work" "fax")) + (("tel" "home" "fax")) + (("tel" "fax"))))) + (phones nil) + result) + (while fields + (setq result (vcard-format-sample-values vcard (cdr (car fields)))) + (while result + (setq phones + (cons (concat (car (car fields)) (car (car result))) phones)) + (setq result (cdr result))) + (setq fields (cdr fields))) + (nreverse phones))) + +(defun vcard-format-sample-get-address (vcard) + (let* ((addr (vcard-format-sample-values vcard '((("adr" "pref" "work")) + (("adr" "pref")) + (("adr" "work")) + (("adr"))) 1)) + (street (delete "" (list (nth 0 addr) (nth 1 addr) (nth 2 addr)))) + (city-list (delete "" (nthcdr 3 addr))) + (city (cond ((null (car city-list)) nil) + ((cdr city-list) + (format "%s, %s" + (car city-list) + (mapconcat 'identity (cdr city-list) " "))) + (t (car city-list))))) + (delete nil (if city + (append street (list city)) + street)))) + +(defun vcard-format-sample-values-concat (vcard have-props limit sep) + (let ((l (car (vcard-values vcard have-props nil limit)))) + (and l (mapconcat 'identity (delete "" (vcard-copy-tree l)) sep)))) + +(defun vcard-format-sample-values (vcard proplists &optional limit) + (let ((result (vcard-format-sample-ref vcard proplists limit))) + (if (equal limit 1) + (cdr result) + (mapcar 'cdr result)))) + +(defun vcard-format-sample-ref (vcard proplists &optional limit) + (let ((result nil)) + (while (and (null result) proplists) + (setq result (vcard-ref vcard + (car (car proplists)) + (cdr (car proplists)) + limit)) + (setq proplists (cdr proplists))) + (if (equal limit 1) + (vcard-copy-tree (car result)) + (vcard-copy-tree result)))) + +(defun vcard-format-sample-offset (row1 row2 &optional maxwidth) + (or maxwidth (setq maxwidth (frame-width))) + (let ((max1 (vcard-format-sample-max-length row1)) + (max2 (vcard-format-sample-max-length row2))) + (if (zerop max1) + 0 + (+ max1 (min 5 (max 1 (- maxwidth (+ max1 max2)))))))) + +(defun vcard-format-sample-max-length (strings) + (let ((maxlen 0)) + (while strings + (setq maxlen (max maxlen (length (car strings)))) + (setq strings (cdr strings))) + maxlen)) + +(provide 'vcard) + +;;; vcard.el ends here. |