diff options
Diffstat (limited to 'clients/ivamVoiceBox.py')
-rw-r--r-- | clients/ivamVoiceBox.py | 291 |
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)) + |