summaryrefslogtreecommitdiffstats
path: root/clients/ivamVoiceBox.py
diff options
context:
space:
mode:
Diffstat (limited to 'clients/ivamVoiceBox.py')
-rw-r--r--clients/ivamVoiceBox.py291
1 files changed, 291 insertions, 0 deletions
diff --git a/clients/ivamVoiceBox.py b/clients/ivamVoiceBox.py
new file mode 100644
index 0000000..252ce98
--- /dev/null
+++ b/clients/ivamVoiceBox.py
@@ -0,0 +1,291 @@
+
+import getopt, sys, os, time, re
+import ivamApi, ivamCore, ivamDefs
+
+from ivamUtil import getContents, setContents
+
+class VoiceBox(ivamApi.Processor):
+
+ # Constants
+ STATE_INVALID, STATE_WELCOME, STATE_WELCOME_BEEP, STATE_RECORD, STATE_PRE_FINISH, STATE_FINISH, STATE_AUTH, STATE_MESSAGE, STATE_AUTH_OK, STATE_NO_MORE_MESSAGES, STATE_MESSAGE_BEEP, STATE_REMOVED, STATE_EMPTY = range(13)
+ AUTH_TIMEOUT = 20
+
+ # State
+ currentState = STATE_INVALID
+ fileSuffix = ".ulaw.gz"
+
+ def getClip(self, s):
+ return "%s/%s%s" % (self.directory, s, self.fileSuffix)
+
+ def onConnect(self, c, callerNumber, ringNumber):
+
+ if ivamCore.DEBUG:
+ ivamCore.log("onConnect()")
+
+ self.callerNumber = callerNumber
+ self.ringNumber = ringNumber
+
+ self.currentState = self.STATE_WELCOME
+ c.playClip(self.getClip("welcome"))
+
+ def loginComplete(self, c):
+ self.messages = self.getMessageNames()
+ self.currentMessage = 0
+
+ ivamCore.log("Successful login from %s for MSN %s." % (self.callerNumber, self.ringNumber))
+
+ if len(self.messages) == 0:
+ self.currentState = self.STATE_EMPTY
+ c.playClip(self.getClip("empty"))
+ else:
+ self.currentState = self.STATE_MESSAGE_BEEP
+ c.playClip(self.getClip("beep"))
+
+ def onClipFinish(self, c, fname):
+
+ if ivamCore.DEBUG:
+ ivamCore.log("onClipFinish('%s')" % fname)
+
+ if self.currentState == self.STATE_WELCOME:
+ self.currentState = self.STATE_WELCOME_BEEP;
+ c.playClip(self.getClip("beep"))
+
+ elif self.currentState == self.STATE_WELCOME_BEEP:
+ self.currentState = self.STATE_RECORD
+ c.recordClip(self.nextMessageName(), True)
+ c.setTimeout(self.recordTime)
+
+ elif self.currentState == self.STATE_PRE_FINISH:
+ self.currentState = self.STATE_FINISH
+ c.hangup()
+
+ elif self.currentState == self.STATE_AUTH:
+
+ # Silence ...
+ pass
+
+ elif self.currentState == self.STATE_AUTH_OK:
+
+ self.loginComplete(c)
+
+ elif self.currentState == self.STATE_MESSAGE_BEEP:
+
+ while True:
+
+ if self.currentMessage >= len(self.messages):
+ self.currentState = self.STATE_NO_MORE_MESSAGES
+ c.playClip(self.getClip("nomoremessages"))
+ else:
+ self.currentState = self.STATE_MESSAGE
+
+ try:
+ c.playClip(self.messages[self.currentMessage])
+ except IOError, e:
+ del(self.messages[self.currentMessage])
+
+ if len(self.messages) > 0:
+ continue
+
+ self.currentState = self.STATE_EMPTY
+ c.playClip(self.getClip("empty"))
+
+ break
+
+ elif self.currentState == self.STATE_MESSAGE:
+
+ self.currentMessage +=1
+ self.currentState = self.STATE_MESSAGE_BEEP
+ c.playClip(self.getClip("beep"))
+
+ elif self.currentState == self.STATE_REMOVED:
+
+ if len(self.messages) == 0:
+ self.currentState = self.STATE_EMPTY
+ c.playClip(self.getClip("empty"))
+ else:
+ self.currentState = self.STATE_MESSAGE_BEEP
+ c.playClip(self.getClip("beep"))
+
+ elif self.currentState == self.STATE_NO_MORE_MESSAGES:
+
+ # Silence ...
+ pass
+
+ elif self.currentState == self.STATE_EMPTY:
+
+ # Silence ...
+ pass
+
+ def onDtmfEvent(self, c, event):
+
+ if ivamCore.DEBUG:
+ ivamCore.log("onDtmfEvent(%c)" % event)
+
+ if ((self.currentState == self.STATE_WELCOME) or (self.currentState == self.STATE_WELCOME_BEEP)) and (event == '0'):
+
+ if self.pin == "":
+ self.loginComplete(c)
+
+ elif self.pin == "-":
+ self.currentState = self.STATE_FINISH
+ c.hangup()
+
+ else:
+ self.currentState = self.STATE_AUTH
+ self.inputPin = ""
+ c.stopPlayback()
+ c.playClip(self.getClip("auth"))
+ c.setTimeout(self.AUTH_TIMEOUT)
+
+ elif self.currentState == self.STATE_AUTH:
+ c.stopPlayback()
+ self.inputPin += event
+
+ if len(self.inputPin) >= len(self.pin):
+ c.setTimeout(0)
+
+ if self.inputPin == self.pin:
+ self.currentState = self.STATE_AUTH_OK
+ c.playClip(self.getClip("authok"))
+ else:
+ self.currentState = self.STATE_FINISH
+ c.hangup()
+
+ elif self.currentState in [self.STATE_MESSAGE, self.STATE_MESSAGE_BEEP, self.STATE_NO_MORE_MESSAGES] :
+
+ if event == '0':
+
+ if self.currentMessage >= len(self.messages):
+ self.currentMessage = len(self.messages)-1
+
+ os.remove(self.messages[self.currentMessage])
+ ivamCore.log("Sucessfully removed message '%s' on behalf of %s for MSN %s." % (self.messages[self.currentMessage], self.callerNumber, self.ringNumber))
+ del(self.messages[self.currentMessage])
+
+
+ self.currentState = self.STATE_REMOVED
+ c.playClip(self.getClip("removed"))
+
+ else:
+ changed = False
+
+ if event in ['4', '2']:
+ self.currentMessage -= 1
+ changed = True
+
+ if event in ['6', '8']:
+ self.currentMessage += 1
+ changed = True
+
+ if event == '5':
+ changed = True
+
+ if event == '1':
+ self.currentMessage = 0
+ changed = True
+
+ if event == '7':
+ self.currentMessage = len(self.messages)-1
+ changed = True
+
+ if self.currentMessage < 0:
+ self.currentMessage = 0
+
+ if self.currentMessage >= len(self.messages):
+ self.currentMessage = len(self.messages)-1
+
+ if changed:
+ self.currentState = self.STATE_MESSAGE_BEEP
+ c.playClip(self.getClip("beep"))
+
+ else:
+ c.flushOutput()
+ c.stopPlayback2()
+
+ def onTimeout(self, c):
+
+ if ivamCore.DEBUG:
+ ivamCore.log("onTimeout()")
+
+ if self.currentState == self.STATE_RECORD:
+ self.currentState = self.STATE_PRE_FINISH
+ c.stopRecording()
+ c.playClip(self.getClip("beep"))
+
+ elif self.currentState == self.STATE_AUTH:
+ self.currentState = self.STATE_FINISH
+ c.hangup()
+
+ def onRecordFinish(self, c, fname):
+
+ if ivamCore.DEBUG:
+ ivamCore.log("onRecordFinish(%s)" % fname)
+
+ ivamCore.log("Sucessfully recorded new message '%s' from %s for MSN %s." % (fname, self.callerNumber, self.ringNumber))
+
+ os.environ["SPOOLDIR"] = self.directory
+ ivamCore.log("Starting new message notification program.")
+ r=os.spawnvp(os.P_WAIT, self.messageProgram, (self.messageProgram, fname))
+ ivamCore.log("Program finished (return value is %i)." % r)
+
+ def getMessageNames(self):
+
+ f = os.listdir(self.messageDirectory)
+ f = map(lambda e: "%s/%s" % (self.messageDirectory, e), f)
+ f.sort()
+ f.reverse()
+ return f
+
+ def nextMessageName(self):
+
+ return "%s/%010u:%s:%s%s" % (self.messageDirectory, time.time(), self.ringNumber, self.callerNumber, self.fileSuffix)
+
+ def setPin(self, pin):
+
+ if ivamCore.DEBUG:
+ ivamCore.log("setPin('%s')" % pin)
+
+ if re.match('^([0-9#*]*|-)$', pin).end() is None:
+ ivamCore.log("Invalid PIN. PIN has to consist of 0-9#*. Use '-' for always denying access.")
+ raise Exception, "Invalid PIN"
+
+ self.pin = pin
+
+ def setDirectory(self, dname):
+ if dname.find("/") == -1:
+ dname = "%s/%s" % (ivamDefs.spoolDirectory, dname)
+
+ self.directory = dname
+ self.messageDirectory = dname + "/messages"
+
+
+ try:
+ self.setPin(getContents("%s/PIN" % dname))
+ except Exception:
+ self.pin = "-"
+
+ try:
+ self.recordTime = int(getContents("%s/RECORD_TIME" % dname))
+ except Exception:
+ self.recordTime = 60
+
+ self.messageProgram = "%s/newmessage" % dname
+
+
+
+def setupVoiceBox(dname, pin = "-", recordTime = 60, email = "root"):
+ if dname.find("/") == -1:
+ dname = "%s/%s" % (ivamDefs.spoolDirectory, dname)
+
+ os.mkdir(dname, 0770)
+ os.mkdir("%s/messages" % dname, 0770)
+
+ setContents("%s/PIN" % dname, pin)
+ setContents("%s/RECORD_TIME" % dname, `recordTime`)
+ setContents("%s/EMAIL" % dname, email)
+
+ ulaw = map(lambda e: e+".ulaw.gz", ('welcome', 'beep', 'empty', 'nomoremessages', 'auth', 'authok', 'removed'))
+
+ for f in ulaw + ['newmessage', 'README']:
+ os.symlink("%s/%s" % (ivamDefs.shareDirectory, f), "%s/%s" % (dname, f))
+