All pastes #941307 Raw Edit

voicemail

public text v1 · immutable
·published 2008-03-13 16:49 UTC
rendered paste body
""" 
WikiPBX web GUI front-end for FreeSWITCH <www.freeswitch.org>
Copyright (C) 2007, Branch Cut <www.branchcut.com>
License Version: MPL 1.1
"""

import os
os.environ['DJANGO_SETTINGS_MODULE']='wikipbx.settings'

from freeswitch import *
from wikipbx.wikipbxweb.models import *
from wikipbx import mailutil
reload(mailutil)
import wikipbx.ivr.baseivr
reload(wikipbx.ivr.baseivr)
from wikipbx.ivr.baseivr import BaseIvr
from pytz import timezone
import datetime
import time
import md5

class VoicemailIvr(BaseIvr):

    def __init__(self, session):
        super(VoicemailIvr, self).__init__(session)
        self.mailbox_name = self.session.getVariable("mailbox")
        self.userprofile = None
        if self.mailbox_name and self.mailbox_name != "None":
            mbn = self.mailbox_name
            userprofs = UserProfile.objects.filter(account=self.account, user__email=mbn)
            if userprofs:
                self.userprofile = userprofs[0]
        self.uuid = self.session.getVariable("uuid")

        # the number dialed, we can use this to match it with an
        # existing endpoint, and then from there figure out what
        # userprofile to use for storing voicemail
        self.dest_num = self.session.getVariable("destination_number")
        if not self.dest_num or self.dest_num == "None":        
            self.dest_num = None


#----- VOICEMAIL PLAYER ----------------------------------------------------
class VoicemailPlayerIvr(VoicemailIvr):

    #--- INIT ---------------
    def __init__(self, session):
        super(VoicemailPlayerIvr, self).__init__(session)
        self.login_attempts = 0
    
    #--- MAIN ---------------
    def main(self):
        logged_in = self.login()
        if not logged_in:
            console_log("INFO", "Not Logged In...\n")
            return
        self.browse_voicemails()

    #--- BROWSE VOICEMAILS ---------------
    def browse_voicemails(self):
        console_log("INFO", "Browsing Voicemails...\n")
        self.playbeep()
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-hello.wav")
        if self.userprof:
            voicemails = Voicemail.objects.filter(account=self.account,userprofile=self.userprof)
            voicemails = voicemails.order_by("id")
        else:
            # account wide login
            voicemails = Voicemail.objects.filter(account=self.account,userprofile__isnull=True)

        #self.speak("There are %s voicemail messages" % len(voicemails))
        console_log("INFO", "Num Voicemails: %s\n" % len(voicemails))
        self.playbeep()
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-you_have.wav")
        numberfile="/usr/local/freeswitch/sounds/en/us/callie/digits/8000/" +  str(len(voicemails)) + "." + "wav"
        self.session.streamFile(numberfile)
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-messages.wav")

        if not voicemails:
            self.playbeep()
            self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-goodbye.wav")
            self.playbeep()
            return

        for voicemail in voicemails:
            self.play_voicemail(voicemail)

        #self.speak("There are no more voicemail messages.  Goodbye")
        console_log("INFO", "No more voicemails...\n")
        self.playbeep()
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-goodby.wav")
        self.playbeep()
        
    #--- PLAY VOICEMAIL ---------------
    def play_voicemail(self, voicemail):
        #self.speak("Going to play voicemail %s" % voicemail.id)
        console_log("INFO", "Playing VoiceMail: %d\n"  % voicemail )
        self.playbeep()
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-new.wav")
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-message.wav")
        self.session.streamFile(voicemail.get_path())
        self.post_play_options(voicemail)

    #--- POST PLAY OPTIONS ---------------
    def post_play_options(self, voicemail):
        #thing2say = "Press 1 to replay voicemail. "
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-listen_to_recording_again.wav")
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-press.wav")
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/digits/8000/1.wav")
        #thing2say += "Press 2 to delete voicemail. "
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-delete_recording.wav")
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-press.wav")
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/digits/8000/2.wav")
        #tempfile = self.make_tts_file(thing2say)
        #in_rslt = self.session.playAndGetDigits(1,1,3,6000,
        #                                        "*#",tempfile,
        #                                        "", "","")[1]
        selection = self.session.getDigits("",5,10,"","",2000)[1]
        console_log("INFO","user input: %s\n" % str(in_rslt))
        if not selection:
            #self.speak("Sorry, no input detected")
            console_log("INFO", "No Input destected...\n")
        else:
            if int(selection) == 1:
                self.play_voicemail(voicemail)
            elif int(selection) == 2:
                vmid = voicemail.id
                voicemail.delete()
                #self.speak("Voicemail %s has been deleted" % str(vmid))
                self.playbeep()
                self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-deleted.wav")
                self.playbeep()
            else:
                #self.speak("%s is an invalid option.  Goodbye" % in_rslt)
                self.playbeep()
                self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-goodby.wav")
                self.playbeep()

    #--- LOGIN ---------------
    def login(self):

        if self.login_attempts > 5:
            #self.speak("Sorry, maximum number of login attempts exceeded")
            self.playbeep()
            self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-abort.wav")
            return False

        self.login_attempts += 1


        #----- Get a mailbox id --------------------------------------------------------
        # TODO: only prompt if ${sip_authorized} is not "true")
        #thing2say = "Welcome to voicemail player.  Please enter mailbox i d followed by the pound sign"
        console_log("INFO", "In VoiceMailPlayerIvr...\n")
        numtries=3
        trynum=0
        while trynum < numtries: 
            self.playbeep()
            #time.sleep(2)
            self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-listen_new.wav")
            self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-enter_id.wav")
            self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/digits/8000/pound.wav")
            user_id = self.session.getDigits("",10,10,"*#","#",4000)[1]                 # 4 second delay
            #*dtmf_buf,buflen,maxdigits,terminators,char *terminator,int timeout
            #tempfile = self.make_tts_file(thing2say)
            #in_rslt = self.session.playAndGetDigits(1,10,3,4000,"*#",tempfile,"","","")[1]
            #min_digits,max_digits,max_tries,timeout,*terminators,*audio_files,*bad_input_audio_files,*dtmf_buf,*digits_regex

            if user_id:             # if something entered
                console_log("INFO","Checking For Mailbox ID: %s\n" % str(user_id))
                #--- check if mailbox id exists in current account ---
                self.userprof = None
                userprofs = UserProfile.objects.filter(account=self.account, mailbox=user_id)
                if not userprofs:
                    #speakable = " ".join(in_rslt)
                    #self.speak("Sorry, no mailbox with id: %s" % speakable, stream=False)
                    console_log("INFO", "No Mailbox For: %s\n" % str(user_id))
                    self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-fail_auth.wav")
                    #return False       dont end because first attempt failed
                else:
                    console_log("INFO", "Mailbox Exists For: %s\n" % str(user_id))
                    self.userprof = userprofs[0]
                    break               # go get password

            trynum=trynum+1


        #----- if after numtries we still dont have a valid id, exit -----
        if not user_id:
            #self.speak("You did not enter anything.  Goodbye")
            #time.sleep(1)
            self.playbeep()
            self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-goodbye.wav")
            time.sleep(1)
            console_log("INFO", "You Did NOT Enter Anything...\n")
            return False


        #----- Get a Password -------------------------------
        #prompt them to enter password
        #thing2say = "Please enter mailbox password followed by the pound sign"
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-enter_pass.wav")
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/digits/8000/pound.wav")
        in_passwd = self.session.getDigits("",10,10,"*#","#",4000)[1]
        #tempfile = self.make_tts_file(thing2say)            
        #in_rslt = self.session.playAndGetDigits(1,10,3,4000,"*#",tempfile,"", "","")[1]
        console_log("INFO","Checking Password: %s\n" % str(in_passwd))
        if not in_passwd:
            #self.speak("You did not enter anything.  Goodbye", stream=False)
            self.playbeep()
            self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-choose_greeting_fail.wav")
            return False            # no password entered, goodby

        if not self.userprof.get_vm_password() == in_passwd:
            #speakable = " ".join(in_rslt)
            #self.speak("Sorry %s is not the correct password" % speakable, stream=False)
            self.playbeep()
            self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/conference/8000/conf-bad-pin.wav")
            return self.login()

        return True









#----- VOICEMAIL RECORDER ----------------------------------------------------
class VoicemailRecorderIvr(VoicemailIvr):

    def __init__(self, session):
        super(VoicemailRecorderIvr, self).__init__(session)

    def main(self):
        console_log("INFO", "Voicemail recorder starting ..\n")
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-record_message.wav")
        #self.speak("Welcome to voicemail recorder.")
        #self.speak("Please start speaking after the beep. "
        #                   "Press any key when finished. ")
        self.playbeep()

        # if there is no userprofile specified, we are going to
        # drop the voicemail into _each_ account admin's vm box
        self.admin = None
        if not self.userprofile:
            # choose the first account admin
            self.admin = self.account.admins.all()[0]
            voicemail = Voicemail(uuid=self.uuid, account=self.account, userprofile=self.admin)
            voicemail.save()
        else:
            voicemail = Voicemail(uuid=self.uuid, account=self.account, userprofile=self.userprofile)
            voicemail.save()

        vm_path = voicemail.get_path()

        max_len = 600 # 10 mins
        silence_threshold = 500
        silence_secs = 5
        self.session.recordFile(vm_path, max_len,  silence_threshold,  silence_secs)


        # TODO: allow them to listen, re-record
        # check asterisk vmail features
        console_log("INFO", "Voicemail has been recorded ..\n")
        #self.speak("Thank You.  Your voicemail has been recorded.  Goodbye")
        self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-goodbye.wav")

        # make sure its non empty, if so, just delete it and
        # skip the email notifications
        if voicemail.get_audio_length() == 0:
            console_log("INFO", "voicemail audio is empty, deleting\n")
            voicemail.delete()
            return

        # If account-wide, copy it to all _other_ admins mailboxes
        if not self.userprofile:
            admins = self.account.admins.all()
            for otheradmin in admins:
                if otheradmin == self.admin:
                    # skip the 1st admin we used earlier, already has vm
                    continue
                voicemail_copy = Voicemail(uuid=self.uuid,
                                           account=self.account,
                                           userprofile=otheradmin)
                voicemail_copy.save()
                # copy actual file
                voicemail.copy_audio(voicemail_copy.get_path())

        # TODO: add a direct link back to the webserver which displays all
        # details on the voicemail.  currently links back to homepage.

        # use this approach until hangup hook works ...  but will this code
        # get called if user hangs up abruptly?  so far in testing, seems
        # to work.
        console_log("INFO","sending email, session: %s\n" % str(self.session))
        caller_id_number = self.session.getVariable("caller_id_number")
        caller_id_name = self.session.getVariable("caller_id_name")
        login_link = ('<a href="http://%s:%s">login</a>' %
                      (self.account.server.fqdn,
                       self.account.server.http_port))
        msg_body = ("You have received a new voicemail (id=%s) "
                    "from %s (%s).  Please %s to listen to your message." %
                    (voicemail.id, caller_id_number, caller_id_name, login_link))

        # if a mailbox (web user) was explicitly specified, use email
        # associated with that web user.  otherwise, send a notice
        # to all account admins
        if self.userprofile:
            recipients = [self.userprofile.user.email]
        else:
            admins = self.account.admins.all()
            recipients = [x.user.email for x in admins]
        mailutil.acct_send(recipients=recipients,
                           subject="New voicemail: %s" % voicemail.id,
                           msg_body=msg_body,
                           account=self.account)
        console_log("INFO","sent email, session: %s\n" % str(self.session))
        #self.session.streamFile("/usr/local/freeswitch/sounds/en/us/callie/voicemail/8000/vm-goodbye.wav")

        # TODO: run other voicemail triggers (listen to events)


def handler(uuid):
    if not uuid:
        console_log("info", "\nNo uuid given\n")
        return
    session = PySession(uuid)
    try:
        vmaction = session.getVariable("vmaction")
        if vmaction == "play":
            #console_log("INFO", "Jumping to VoiceMailPlayerIvr...\n")
            vmplayer = VoicemailPlayerIvr(session)
            vmplayer.main()
        elif vmaction == "record":
            #console_log("INFO", "Jumping to VoiceMailRecorderIvr...\n")
            vmrecorder = VoicemailRecorderIvr(session)
            vmrecorder.main()
        else:
            console_log("error", "Invalid voicemail action: %s\n" % vmaction)
            #session.set_tts_parms("cepstral", "william")
            #session.speak("Sorry, the voicemail system had an error. "
            #              "Error code 101")
    except Exception, e:
        console_log("error", "Error running voicemail IVR: %s\n" % e)
        #session.set_tts_parms("cepstral", "william")
        #session.speak("Sorry, the voicemail system had an error. "
        #              "Error code 102")