Phone Dial action

The Problem

Do you have not only email and web addresses in your MoinMoin Wiki, but also telephone numbers ?

Ever wanted to just click on them and the number being dialled automagically by your dialling device (which can be an Eurit series ISDN telephone, a modem or another Hayes-compatible device).

The Solution

Then click on some tag like  FON:01234567  (looks like this: FON:01234567 ) and see your phone dialling ;)

The Warning

This is my first piece of Python and MoinMoin code, so review is definitely needed.

For example, there is a known bug that it loads the FrontPage after you click on a FON link.

I think this can be easiliy fixed by some more experienced MoinMoin action programmer, so please help.

The Code

See: ActionMarket

New in 20020206: you can have characters like "-" and "/" in your phone numbers. They will be removed before the string gets sent to the phone.

   1 """
   2     MoinMoin - "PhoneDial" action
   3     =============================
   4 
   5     Copyright (c) 2002 by Thomas Waldmann <tw@waldmann-edv.de>
   6     All rights reserved, see COPYING for details.
   7 
   8     This is released under the Gnu General Public Licence. A copy of
   9     this can be found at http://www.opensource.org/licenses/gpl-license.html
  10 
  11     SerialLink class taken from PyGarmin (GPL), see http://pygarmin.sourceforge.net/
  12 
  13     So what is this thing doing and how it has to be configured ?
  14     =============================================================
  15 
  16     This action dials a phone number using an Eurit 40 ISDN telephone
  17     attached via a serial interface to the SERVERs COM ports.
  18 
  19     You maybe could also use a modem for dialing and then take the call
  20     with a phone attached to the same line. This action simply sends an
  21     ATD<phonenumber> to the device attached to the serial port.
  22 
  23     Add this to your moin_config.py:
  24     phonedial_serialdevice = "COM1"             (Win32 and untested)
  25     phonedial_serialdevice = "/dev/ttyS0"       (Linux)
  26     
  27     Add this to your ./data/intermap.txt (in your wiki):
  28     FON http://whatever/moin.cgi?action=PhoneDial&number=
  29     
  30     Add this to your pages (example):
  31     Ring my best friend: FON:0123456789
  32     
  33     After saving the page, the FON entry should get a link to the
  34     PhoneDial action. And if you click on it, it should dial the number
  35     using the device attached to the com port.
  36 
  37     BTW: these are my first footsteps in Python and MoinMoin Programming.
  38     
  39     So if you are more experienced concerning Python (and moinmoin), then
  40     please review this and please, if you improve it, send me a copy of your
  41     improvements. Thanks.
  42 
  43     Version History:
  44     
  45     20020110 first public version - "it works for me" 
  46     20020206 filtering out special characters like "-" or "/" for not
  47              confusing the Eurit phone
  48     
  49     Known Bugs:
  50     
  51     After clicking on a FON link, you will see the FrontPage.
  52     
  53     Known Limitations:
  54     
  55     It is the web server computer (where moin.cgi runs) that is dialling via
  56     the com port. If you work at a different PC far away from the server or
  57     if you have multiple phones you want to get dialling, you maybe need more
  58     than this script.
  59         
  60 """
  61 
  62 # is this all needed ?:
  63 import os, string, time, sys
  64 from MoinMoin import config, util, wikiutil, webapi
  65 from MoinMoin.Page import Page
  66 
  67 # Now some practical implementations
  68 
  69 class SerialLink:
  70    """
  71      A serial link will look something like this, though real
  72      implementations will probably override most of it.
  73    """
  74    def __init__(self, f, timeout = 5):
  75       self.f = f
  76       self.initserial()
  77       self.settimeout(timeout)
  78 
  79    def initserial(self):
  80       "Set up baud rate, handshaking, etc"
  81       pass
  82    
  83    def read(self, n):
  84       """
  85       Read n bytes and return them. Real implementations should
  86       raise a LinkException if there is a timeout > self.timeout
  87       """
  88       return self.f.read(n)
  89 
  90    def write(self, data):
  91       self.f.write(data)
  92 
  93    def settimeout(self, secs):
  94       self.timeout = secs
  95       
  96    def __del__(self):
  97       """Should close down any opened resources"""
  98       pass
  99 
 100 
 101 class UnixSerialLink(SerialLink):
 102 
 103    def __init__(self, device):
 104       f = open(device, "w+", 0)
 105       SerialLink.__init__(self, f)
 106 
 107    def initserial(self):
 108       from tty import *
 109       
 110       fd = self.f.fileno()
 111       setraw(fd)
 112       mode = tcgetattr(fd)
 113       mode[ISPEED] = mode[OSPEED] = B2400
 114       # mode[LFLAG] = mode[LFLAG] | ECHO
 115       tcsetattr(fd, TCSAFLUSH, mode)
 116 
 117    def read(self, n):
 118       import select
 119       
 120       i = 0
 121       data = []
 122       while i < n:
 123          iset,oset,eset = select.select([self.f.fileno()], [], [], self.timeout)
 124          if iset == []:
 125            raise LinkException, "time out"
 126          b = self.f.read(1)
 127          data.append(b)
 128          i = i + 1
 129       return string.join(data,'')
 130 
 131    def __del__(self):
 132       self.f.close()
 133 
 134 # Win32 Serial Link ==================================================
 135 
 136 if os.name == 'nt':
 137    from win32file import * 
 138    import win32con
 139 
 140 class Win32SerialLink(SerialLink):
 141    def __init__(self, device):
 142       self.device = device
 143       handle = CreateFile(device,
 144          win32con.GENERIC_READ | win32con.GENERIC_WRITE,
 145          0, # exclusive access
 146          None, # no security
 147          win32con.OPEN_EXISTING,
 148          0,
 149          None)
 150       SerialLink.__init__(self, handle)
 151 
 152    def initserial(self):
 153       # Remove anything that was there
 154       PurgeComm(self.f, PURGE_TXABORT | PURGE_RXABORT
 155          | PURGE_TXCLEAR | PURGE_RXCLEAR )
 156 
 157       # Setup the connection info.
 158       dcb = GetCommState( self.f )
 159       dcb.BaudRate = CBR_2400
 160       dcb.ByteSize = 8
 161       dcb.Parity = NOPARITY
 162       dcb.StopBits = ONESTOPBIT
 163       SetCommState(self.f, dcb)
 164 
 165    def read(self, n):
 166       buffer = AllocateReadBuffer(n)
 167       rc, data = ReadFile(self.f, buffer)
 168       if len(data) != n:
 169          raise LinkException, "time out";
 170       return data
 171 
 172    def write(self, n):
 173       rc,n = WriteFile(self.f, n)
 174       if rc:
 175          raise LinkException, "WriteFile error";
 176 
 177    def settimeout(self, secs):
 178       SerialLink.settimeout(self, secs)
 179       # Setup time-outs
 180       timeouts = 0xFFFFFFFF, 0, 1000*secs, 0, 1000*secs
 181       SetCommTimeouts(self.f, timeouts)
 182 
 183    def __del__(self):
 184       CloseHandle(self.f)
 185 
 186       
 187 class Eurit:
 188    """
 189    A representation of the Eurit telephone, which is connected
 190    via some physical connection, typically a SerialLink of some sort.
 191    """
 192    def __init__(self):
 193       if os.name == 'nt':
 194          serialDevice =  config.phonedial_serialdevice
 195          self.link = Win32SerialLink(serialDevice)
 196       else:
 197          serialDevice =  config.phonedial_serialdevice
 198          self.link = UnixSerialLink(serialDevice)
 199    
 200    # === this is the important part, here we do the dialling:
 201    def dial(self, number):
 202       self.link.write("ATD" + number + "\r");
 203    # ========================================================
 204 
 205 
 206 def execute(pagename, form):
 207 
 208     # get the phone number
 209     if form.has_key('number'):
 210         number = form['number'].value
 211     else:
 212         number = ""
 213 
 214     number = string.replace(number,'/','')
 215     number = string.replace(number,'-','')
 216     
 217     eurit = Eurit()
 218     eurit.dial(number)
 219     page = Page(pagename)
 220     page.send_page(form, msg="<b>Dialled " + number + ".</b>")
ActionMarket/PhoneDial.py

Support area

If you have questions, problems, bug reports, wishes, comments - put them here:

MoinMoin: ThomasWaldmannPhoneDial (last edited 2007-10-29 19:09:26 by localhost)