Abstract: I don't type in phone numbers any more. A spare
analog modem, connected in parallel to my phone, does the whole job. I
type M-d
into my address book, the Big Brother Database,
and it will dial the stored number, using the cheapest provider.
Get isdn4k-utils
from isdn4linux.de; don't worry, you
don't actually need to have ISDN, we just need the
isdnrate
utility for finding the best provider. The
"stable" versions won't work, so get some CVS snapshot instead.
Get recent provider data from rates4linux.sourceforge.net.
Fix /etc/isdn/rates.conf
to list the providers of your
choice.
Get BBDB, the Insidious Big Brother Database, by Jamie Zawinski, version 2.00.06. Put all addresses and phone numbers into the database, and get rid of your old address book.
Connect a modem to the same telephone line as your phone. If you have a TAE socket as is usual in Germany, plug the modem into an "N" socket. This way, when the modem is off-hook, the phone plugged into the "F" socket gets disconnected, so you won't have to listen to the DTMF tones.
Try
dialing with it via minicom
, then write a chat script
like this, /usr/local/etc/dial-chat
:
SAY "Dialing \T...\n" ABORT 'BLACKLISTED' ABORT 'NO DIALTONE' ECHO ON '' ATM0X1DT\T; OK ath0
The trick is to have the modem return to command mode after
dialing, instead of waiting for a modem carrier. This is accomplished
by typing a semicolon after the number in the ATD
command. When the modem returns to command mode, we hang up
immediately, so the off-hooked phone gets the line again.
Here are a few trivial scripts that I use:
/usr/local/bin/do-dial-number
:
#! /bin/sh exec /usr/sbin/chat -S -T "$1" -f /usr/local/etc/dial-chat < /dev/ttyS1 > /dev/ttyS1
/usr/local/bin/dial-number
:
#! /bin/sh exec sudo /usr/local/bin/do-dial-number "$1"
/usr/local/bin/fast-isdnrate
first tries to connect
to a running isdnrate
daemon process, starting one on
failure. (isdnrate
has a fairly long setup time.)
#! /bin/sh # Start daemon if needed if ! isdnrate -C 0391 2>&1 > /dev/null ; then isdnrate -D2 2> /dev/null sleep 3 fi exec isdnrate -C $*
bbdb-phone.el
, which does some nice things
with European phone numbers. It also provides the M-x
dial
command.
;;; bbdb-phone.el --- BBDB/Isdnlog/ESTIC integration ;; Copyright (C) 1999 by Free Software Foundation, Inc. ;; Author: Matthias Koeppe <mkoeppe@moose.boerde.de> ;; Keywords: local ;; This file is NOT part of GNU Emacs. ;; This program is free software; you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation; either version 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: ;; BBDB & phone integration ;;; Code: (require 'bbdb) (require 'bbdb-com) (defvar phone-area-prefix "391") (defvar phone-area-internal-prefix "ISTEC") (defvar dialout-prefix "0,") (defun my-canonicalize-phone-number (number) "Canonicalize phone number NUMBER, which must be a string." (cond ((= (aref number 0) ?+) number) ; already has international prefix ((= (aref number 0) ?0) (concat "+49 " (substring number 1))) (t (concat "+49 " phone-area-prefix number)))) (defun my-localize-phone-number (number) "Make NUMBER ready for dialing from local site." (cond ((string-match (concat "^\\(\\++49[^0-9]*\\|0\\)" phone-area-prefix "[^0-9]*") number) ; make local number (substring number (match-end 0))) ((string-match "^\\++49[^0-9]*" number) ; make long-distance number (concat "0" (substring number (match-end 0)))) ((string-match "^\\++" number) ; make international number (concat "00" (substring number (match-end 0)))) (t number))) ; number is ok (defun my-strip-nondigits (string) "Return STRING stripped of all non-digits." (while (string-match "[^0-9]+" string) (setq string (replace-match "" t t string))) string) (defun my-strip-nondigitsplus (string) "Return STRING stripped of all non-digit non-plus characters." (while (string-match "[^0-9+]+" string) (setq string (replace-match "" t t string))) string) (defun my-extract-phone-aliases-from-bbdb () "Extract phone aliases from BBDB." (let ((records (bbdb-records)) (isdnlog-alias-buffer (get-buffer-create " *isdnlog-alias*")) (estic-alias-buffer (get-buffer-create " *estic-alias*"))) (while (not (null records)) (let* ((record (car records)) (phones (bbdb-record-phones record)) (name (bbdb-record-name record)) (comp (bbdb-record-company record)) (name-comp (cond ((and name comp) (concat name " - " comp)) ((or name comp)) (t "???")))) (while phones (let* ((phone (car phones)) (location (aref phone 0)) (number (aref phone 1)) (name-comp-loc (concat name-comp " (" location ")"))) (set-buffer isdnlog-alias-buffer) (insert "[number]\n" "NUMBER = " (my-canonicalize-phone-number number) "\n" "SI = 1\n" ; service indicator is voice "ZONE = 1\n" ; this is incorrect but who cares? "ALIAS = " name-comp-loc "\n\n") (set-buffer estic-alias-buffer) (insert (my-strip-nondigits (my-localize-phone-number number)) " \"" name-comp-loc "\"\n")) (setq phones (cdr phones)))) (setq records (cdr records))) (set-buffer isdnlog-alias-buffer) (set-buffer-file-coding-system 'latin-1-unix) (write-file "~/.isdnlog-alias") (kill-buffer isdnlog-alias-buffer) (set-buffer estic-alias-buffer) (set-buffer-file-coding-system 'latin-1-unix) (write-file "~/.estic-alias") (kill-buffer estic-alias-buffer))) (defvar incoming-phone-messages-file "/var/log/messages") (defun last-unnamed-caller (output-to-buffer-p) "Show the phone number of the last unnamed caller. With prefix argument, insert in current buffer." (interactive "P") (let ((buffer (get-buffer-create " *last-caller*")) (old-buffer (current-buffer))) (set-buffer buffer) (let ((len (nth 7 (file-attributes incoming-phone-messages-file)))) (insert-file-contents incoming-phone-messages-file nil (max 0 (- len 20000)) len)) (goto-char (point-max)) (if (search-backward-regexp "Call from \\(\\+[0-9]+ [0-9]+/[0-9]+\\).*RING" nil t) (if output-to-buffer-p (progn (set-buffer old-buffer) (insert-buffer-substring buffer (match-beginning 1) (match-end 1))) (message "Last unnamed caller: %s" (buffer-substring (match-beginning 1) (match-end 1)))) (error "No unnamed caller.")) (set-buffer old-buffer) (kill-buffer buffer))) (defvar outgoing-phone-messages-file "/var/log/estic-outgoing.log") (defun last-unnamed-destination (output-to-buffer-p) "Show the phone number of the last unnamed call destination. With prefix argument, insert in current buffer." (interactive "P") (let ((buffer (get-buffer-create " *last-caller*")) (old-buffer (current-buffer))) (set-buffer buffer) (let ((len (nth 7 (file-attributes outgoing-phone-messages-file)))) (insert-file-contents outgoing-phone-messages-file nil (max 0 (- len 20000)) len)) (goto-char (point-max)) (if (search-backward-regexp "Called \\([0-9]+\\) with" nil t) (if output-to-buffer-p (progn (set-buffer old-buffer) (insert-buffer-substring buffer (match-beginning 1) (match-end 1))) (message "Last unnamed call destination: %s" (buffer-substring (match-beginning 1) (match-end 1)))) (error "No unnamed call destination.")) (set-buffer old-buffer) (kill-buffer buffer))) (defun provider-prefix (number) "Return a provider prefix for dialing canonical NUMBER." "") (defun my-localize-phone-number (number) "Make canonical NUMBER ready for dialing from local site." (let ((num (my-strip-nondigitsplus number)) (provider-prefix (provider-prefix number))) (cond ((string-match (concat "^\\(\\++49[^0-9]*\\|0\\)" phone-area-prefix phone-area-internal-prefix "[^0-9]*") num) ; make internal number (substring num (match-end 0))) ((and (string= provider-prefix "") (string-match (concat "^\\(\\++49[^0-9]*\\|0\\)" phone-area-prefix "[^0-9]*") num)) ; make local number (concat dialout-prefix (substring num (match-end 0)))) ((string-match "^\\++49[^0-9]*" num) ; make long-distance number (concat dialout-prefix provider-prefix "0" (substring num (match-end 0)))) ((string-match "^\\++" num) ; make international number (concat dialout-prefix provider-prefix "00" (substring num (match-end 0))))))) ; My own version (defun bbdb-dial (phone force-area-code) "On a Sun SparcStation, play the appropriate tones on the builtin speaker to dial the phone number corresponding to the current line. If the point is at the beginning of a record, dial the first phone number." (interactive (list (bbdb-current-field) current-prefix-arg)) (if (eq (car-safe phone) 'name) (setq phone (car (bbdb-record-phones (car (cdr phone)))))) (if (eq (car-safe phone) 'phone) (setq phone (car (cdr phone)))) (or (vectorp phone) (error "not on a phone field")) (or window-system (error "You're not under window system.")) (or (file-exists-p bbdb-sound-player) (error "no sound player program")) (let* ((str (my-localize-phone-number (my-canonicalize-phone-number (bbdb-phone-string phone))))) (bbdb-dial-string str))) (defun dial (phone) "Dial the given phone number." (interactive "sNumber: ") (let* ((str (my-localize-phone-number (my-canonicalize-phone-number phone)))) (bbdb-dial-string str))) (provide 'bbdb-phone) ;;; bbdb-phone.el ends here
.emacs
:
;;; Dialling (require 'bbdb-phone) (defun bbdb-dial-string (s) (message "Dialing %s..." s) (call-process "dial-number" nil nil nil s) (message "Dialing %s...done." s)) (defvar my-provider "01033") ;; DTAG (defun provider-prefix (number) "Return a provider prefix for dialing canonical NUMBER." (interactive "sShow best providers for number: ") (set-buffer (get-buffer-create "*Best providers*")) (erase-buffer) (call-process "fast-isdnrate" nil t nil "-o" ; only those listed in rate.conf (my-strip-nondigitsplus number)) (pop-to-buffer (current-buffer)) (shrink-window-if-larger-than-buffer) (sit-for 0) (goto-char (point-min)) (if (re-search-forward (concat "^" my-provider "_[0-9]*:.*") nil t) (put-text-property (match-beginning 0) (match-end 0) 'face 'bold)) (goto-char (point-min)) (if (looking-at "\\([0-9]*\\)_[0-9]*:") (if (string= (match-string 1) my-provider) "" (concat (match-string 1) ",")) (error "Huh? Didn't find provider?"))) (setq bbdb-sound-player "/bin/true")
M-x dial RET number RET
.M-x bbdb RET regexp
to view a list of
people matching regexp, put the point in one phone field,
pick up the phone and type M-d
.M-x
provider-prefix RET number RET
.