import getopt, sys import ivamApi, ivamCore, ivamDefs from ivamCore import log from ivamUtil import getContents, setContents DEBUG = False 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 # Use GZIP compression? useGzip = 1 def onConnect(self, c, callerNumber, calleeNumber): if DEBUG: log("onConnect()") self.callerNumber = callerNumber self.calleeNumber = calleeNumber self.currentState = self.STATE_WELCOME c.playClip("welcome") def loginComplete(self): self.messages = self.getMessageNames() self.currentMessage = 0 if len(self.messages) == 0: self.currentState = self.STATE_EMPTY c.playClip("empty") else: self.currentState = self.STATE_MESSAGE_BEEP c.playClip("beep") def onClipFinish(self, c, fname): if DEBUG: log("onClipFinish('%s')" % fname) if self.currentState == self.STATE_WELCOME: self.currentState = self.STATE_WELCOME_BEEP; c.playClip("beep") elif self.currentState == self.STATE_WELCOME_BEEP: self.currentState = self.STATE_RECORD c.recordClip(self.nextMessageName(), self.useGzip) 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() elif self.currentState == self.STATE_MESSAGE_BEEP: while True: if self.currentMessage >= len(self.messages): self.currentMessage = self.STATE_NO_MORE_MESSAGES c.playClip("nomoremessages") else: self.currentState = self.STATE_MESSAGE_BEEP try: c.playClip(self.messages[self.currentMessage]) break except IOError, e: del(self.messages[self.currentMessage]) if len(self.messages) == 0: self.currentState = self.STATE_EMPTY c.playClip("empty") continue elif self.currentState == self.STATE_MESSAGE: self.currentMessage +=1 self.currentState = self.STATE_MESSAGE_BEEP c.playClip("beep") elif self.currentState == self.STATE_REMOVE: if len(self.messages) == 0: self.currentState = self.STATE_EMPTY c.playClip("empty") else: self.currentState = self.STATE_MESSAGE_BEEP c.playClip("beep") elif self.currentState == self.STATE_NO_MORE_MESSAGES: # Silence ... pass elif self.currentState == self.STATE_EMPTY: self.currentState = self.STATE_FINISH c.hangup() def onDtmfEvent(self, c, event): if 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() elif self.pin == "-": self.currentState = self.STATE_FINISH c.hangup() else: self.currentState = self.STATE_AUTH self.inputPin = "" c.stopPlayback() c.playClip("auth") c.setTimeout(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("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] : changed = 0 if event == '0': if self.currentMessage >= len(self.messages): self.currentMessage = len(self.messages)-1 os.remove("%s.ulaw" % self.messages[self.currentMessage]) del(self.messages[self.currentMessage]) self.currentState = self.STATE_REMOVED c.playClip("removed") else: if event in ['4', '2']: self.currentMessage -= 1 changed = 1 if event in ['6', '8']: self.currentMessage += 1 changed = 1 if event == '5': changed = 1 if event == '1': self.currentMessage = 0 changed = 1 if event == '7': self.currentMessage = len(self.messages)-1 changed = 1 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("beep") else: c.stopPlayback() def onTimeout(self, c): if DEBUG: ivamCore.log("onTimeout()") if self.currentState == self.STATE_RECORD: self.currentState = self.STATE_PRE_FINISH c.stopRecording() c.playClip("beep") elif self.currentState in [self.STATE_AUTH, self.STATE_PIN2, self.STATE_PIN3, self.STATE_PIN4]: self.currentState = self.STATE_FINISH c.hangup() def onRecordFinish(self, c, fname): if DEBUG: ivamCore.log("onRecordFinish(%s)", fname) log("Starting new message notification program.") r = os.spawnvp(os.P_WAIT, self.messageProgram, [self.messageProgram, "%s.ulaw" % fname]) log("Program finished (return value is %i)." % r) def getMessageNames(self): f = filter(lambda e: e.startswith("message-"), os.listdir(self.directory)) f.sort() f.reverse() return f def nextMessageName(self): fn = "%s/message-%010i-%s-%s.ulaw" % (self.directory, time.time(), self.callerNumber, self.callerNumber) if self.useGzip: return fn+".gz" return fn def setPin(self, pin): if re.match('^([0-9#*]*|-)$', pin).end() is None: 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, path): self.directory = path try: self.setPin(getContents("%s/PIN" % path)) except Exception: self.pin = "-" try: self.recordTime = int(getContents("%s/RECORD_TIME" % path))) except Exception: self.recordTime = 60 messageProgram = "%s/NEWMESSAGE" % path def setupVoiceBox(dname, pin, recordTime): 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`) os.symlink