
THE GOAL
Back in 2000 I has no ringers on my home phone line. People who knew me
could call my cell phone and people that didn't know my cell phone could just
left a voice mail message. There existed, however, a small class of people
whose calls I wanted to take but whom I did not want to have my cell phone
number. Freshmeat has a lot of caller id
software, but none of it did what I wanted, so I wrote my own. My
requirements were:
- Multiple types of alerts to include:
- Something visual
(for when I'm awake)
- Something audible (for when I'm asleep/not-looking)
- Something persistent (for historical reasons)
- Cell phone notification (for when I'm not home)
- Integration with my existing address book, abook
- A language I'm willing to modify (not C/C++)
- Works with Linux and the modem I already had
Maybe there was something that met my requirements and I just didn't find
it, but whatever it didn't take too long as was mostly fun.
THE DESIGN
I planned for a two part system implemented in Perl. The less interesting
of the two components was to be the cidlistener.pl script. It
should be a daemon program that initializes the modem and listens for caller
id entries. These it would turn into simple information string of this
format:
DATE=0119 TIME=0136 NMBR=6125557352 NAME='SOME
ONE'
The second component, cidfilter.pl would be the more
interesting of the two. It would take as its command line arguments a string
of the format produced by cidlistener.pl and would handle the
incoming call as configured internally and by two external configuration
files. The configuration files would create the following mappings:
- one phone number maps to one name and one or more classes
- one class maps to zero or more actions
- one action maps to one Perl subroutine
The idea being that one's acquaintances can be sorted into categories (classes)
and that call notification for a caller would be determined by their classes.
The mappings would be work as follows:
Number to Name and Classes
The phone number to name and classes mappings are to be defined in the
~/.cidfilter/phonebook file. This file will actually be the
source code for a single Perl hash variable. Within this hash phone number
strings will be mapped to internal hash objects. These hashes are to contain
keys named name and classes. The value of name is
to be a string. The value of classes will be an array of class names
to which the phone number belongs. An optional note will also be
allowed for each number.
Class to Actions
The ~/.cidfilter/classlist file will map each class used as a
value for the classes attribute in the previous configuration file to
zero or more actions. Like the phonebook, this file will also be the Perl
source for a single hash variable. The keys are the names of the classes and
the values will be arrays of actions to taken when a caller in that class
calls. As numbers can belong to multiple classes, when a number rings
all off the actions associated with all of the classes to which
that number belongs will be invoked. There will exist a special class named
default which is used when a number does not have a corresponding
entry in the phonebook file.
Actions to Subroutines
There will also be a hash that maps action names as found in the classes to
actions mapping to Perl subroutines. Each action subroutine will receive as
its parameter the call information originally passed to the
cidfilter.pl script.
THE RESULT
Things pretty much came out as planned. I think the resulting cidfilter.pl and cidlistener.pl
scripts show that Perl code can be clear and easily maintainable. They rely on
the configuration files detailed in the previous section. Samples of these
configuration files are available within the downloadable archive
file. The action string to subroutine mappings ended up in the
cidfilter.pl script itself.
The following ring actions were created:
| ring
| Causes the terminal to beep
|
| display
| Uses xmessage to display the
call information on the screen
|
| log
| Writes the call record to an ever-growing phone log
|
| mail
| Sends me email letting me know about the call
|
| cell
| Send a text message to my cell phone saying who called and when
|
Those actions are associated with classes thusly (in the
classlist file):
| friend
| display, ring, log, mail, cell
|
| known
| display, ring, log, mail
|
| default
| display, log
|
I also went ahead and added area-code decoding so I can tell where a long
distance call is coming from. To get the address book integration I required
I created a separate script which exports the abook address book and creates a valid
phonebook file. The abook2phonebook.pl
file can be found in the downloadable
archive.
BUGS AND ENHANCEMENTS
The system has been in more or less steady use for the last 3 years and is
working well. There are a few bugs or enhancements that I will never get
around to fixing or doing:
- If I pick up the phone before the 2nd ring the cid record is somehow
stored in side the modem and doesn't get fired until the
next call is received at which time two calls appear to be arriving
immediately. These old, stale calls could be filtered out by comparing
the cid time to the system clock time and dicarding anything that's too
old (taking into account general clock skew).
- The
ring action could play sound files (if I had a sound
card and speakers).
- Sometimes after a system reboot the serial port is in a state that
causes the
cidlistener.pl to loop. I'm sure it's something
that could be fixed if I know more about Linux serial ports and their attr
modes and things.
- It would be nice if the
cidlistener.pl script ran a a UNIX
daemon. I've found Perl code that does this by forking and emancipating
the process from its parents, but I didn't have any luck doing it myself.
For now I just run it in a screen session
which I actually prefer.
- It would be nice if my abook phonebook was real real-time without
having to export it periodically to phonebook format.
- Having a webalizer style
post processing tool for the log files would be nifty, especially if it
interfaced with one of the many phone reverse phone directories.
- It would be cool if the filter checked my usual sleeping hours or IRC
/away status to decide if the
ring action could go through or
not.
|