Incoming adv: Unterschied zwischen den Versionen

Aus Neobikers Wiki
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
Zeile 38: Zeile 38:
# @return the constructed config file object
# @return the constructed config file object
def read_Configfiles(file=""):
def read_Configfiles(file=""):
        import ConfigParser
import ConfigParser
        config=ConfigParser.ConfigParser()
config=ConfigParser.ConfigParser()
        if (file==""):
if (file==""):
                config.readfp(open(configfile_fax))
config.readfp(open(configfile_fax))
                config.readfp(open(configfile_voice))
config.readfp(open(configfile_voice))
                 try:
                 try:  
                    config.readfp(open(configfile_phonebook))
    config.readfp(open(configfile_phonebook))
                 except:
                 except:
                     pass
                     pass
        else:
else:
                config.readfp(open(file))
config.readfp(open(file))
        for s in config.sections():
for s in config.sections():
                for o in config.options(s):
for o in config.options(s):
                        value=config.get(s,o)
value=config.get(s,o)
                        if (len(value)>1 and value[0]=='"'):
if (len(value)>1 and value[0]=='"'):
                                config.set(s,o,value[1:-1])
config.set(s,o,value[1:-1])
        if (not config.has_section('GLOBAL')):
if (not config.has_section('GLOBAL')):
                raise IOError("invalid config file, section GLOBAL missing")
raise IOError("invalid config file, section GLOBAL missing")
        return config
return config


# read_phonebook ()
# read_phonebook ()
Zeile 62: Zeile 62:
#
#
# read_phonebook (number):
# read_phonebook (number):
#    number:   tel number
#    number: tel number
#
#
# return: name
# return: name
Zeile 108: Zeile 108:
# ----------------------------------------
# ----------------------------------------
# check_date ()
# check_date ()
#    check if user program date fits actual date
#    check if user program date fits actual date  
#
#
# check_date (pdate, adate):
# check_date (pdate, adate):
Zeile 128: Zeile 128:
     for i in range(len(idate)):
     for i in range(len(idate)):
         if idate[i] and idate[i] != '*':
         if idate[i] and idate[i] != '*':
             pdate[i] = int(idate[i])
             pdate[i] = int(idate[i])  
     return pdate == adate;
     return pdate == adate;


Zeile 136: Zeile 136:
#
#
# check_date_section (config, dsect, adate):
# check_date_section (config, dsect, adate):
#    config:   config file
#    config: config file
#    dsect:     date section list of dates
#    dsect: date section list of dates
#    adate:     actual date
#    adate: actual date
#
#
# return: True/False if 'adate' is listed/not listed
# return: True/False if 'adate' is listed/not listed
Zeile 145: Zeile 145:
     """check_date_section () check if date is listed in date section"""
     """check_date_section () check if date is listed in date section"""


     # check all entries in date section
     # check all entries in date section  
     # every entry (item) can be a list of dates
     # every entry (item) can be a list of dates
     for i in range(len(config.items(dsect))):
     for i in range(len(config.items(dsect))):
Zeile 158: Zeile 158:
#
#
# prog_time (ptime, atime):
# prog_time (ptime, atime):
#    ptime:     program time intervall
#    ptime: program time intervall
#    atime:     actual time
#    atime: actual time
#
#
# return: True/False if 'ptime' fit's actual time
# return: True/False if 'ptime' fit's actual time
Zeile 165: Zeile 165:
def prog_time (ptime, atime):
def prog_time (ptime, atime):
     """prog_time() check if actual time fits user program time interval"""
     """prog_time() check if actual time fits user program time interval"""
 
     # a '*' fits always...
     # a '*' fits always...
     if ptime == '*': return True
     if ptime == '*': return True
Zeile 213: Zeile 213:
#
#
# check_caller_section (config, csect, call_from):
# check_caller_section (config, csect, call_from):
#    config:   config file
#    config: config file
#    csect:     caller-section
#    csect: caller-section
#    call_from: caller number
#    call_from: caller number
#
#
Zeile 222: Zeile 222:
     """check_caller_section () check if call_from is listed in callers section"""
     """check_caller_section () check if call_from is listed in callers section"""


     # check all entries in caller section
     # check all entries in caller section  
     # every entry (item) can be a list of numbers
     # every entry (item) can be a list of numbers
     # standardise numbers (delete blanks etc.)
     # standardise numbers (delete blanks etc.)
Zeile 236: Zeile 236:
#
#
# check_caller (config, callers, call_from):
# check_caller (config, callers, call_from):
#    config:   config file
#    config: config file
#    callers:   list of numbers or sections
#    callers: list of numbers or sections  
#    call_from: caller number
#    call_from: caller number
#
#
Zeile 268: Zeile 268:
#
#
# prog_active (config, dates, times, wdays):
# prog_active (config, dates, times, wdays):
#    config:   config file
#    config: config file
#    dates:     program dates
#    dates: program dates
#    times:     program time intervals
#    times: program time intervals
#    wdays:     program week days
#    wdays: program week days
#
#
# return: True/False if programm is active/not active
# return: True/False if programm is active/not active
Zeile 292: Zeile 292:
     else:
     else:
         return False
         return False
 
     # check the times in user program
     # check the times in user program
     for i in range(len(times.split(','))):
     for i in range(len(times.split(','))):
Zeile 325: Zeile 325:
#
#
# read_prog (config, section, call_from)
# read_prog (config, section, call_from)
#    config:   config file
#    config: config file
#    section:   section in config file to read
#    section: section in config file to read
#    call_from: caller number
#    call_from: caller number
#
#
Zeile 339: Zeile 339:
     prog = "prog" + str(i)
     prog = "prog" + str(i)
     while config.has_option(section, prog):
     while config.has_option(section, prog):
         # progX = [dates, times, weekdays, message, delay, length, callers]
         # progX = [dates, times, weekdays, message, delay, length, callers]  
         p = config.get(section, prog).split()
         p = config.get(section, prog).split()
         if prog_active(config, p[0], p[1], p[2]):
         if prog_active(config, p[0], p[1], p[2]):
Zeile 361: Zeile 361:
#
#
# callIncoming(call,service,call_from,call_to)
# callIncoming(call,service,call_from,call_to)
#    call     reference to the call. Needed by all capisuite functions
#    call reference to the call. Needed by all capisuite functions
#    service   one of SERVICE_FAXG3, SERVICE_VOICE, SERVICE_OTHER
#    service one of SERVICE_FAXG3, SERVICE_VOICE, SERVICE_OTHER
#    call_from string containing the number of the calling party
#    call_from string containing the number of the calling party
#    call_to   string containing the number of the called party
#    call_to string containing the number of the called party


def callIncoming(call,service,call_from,call_to):
def callIncoming(call,service,call_from,call_to):
        # read sections in config file
# read sections in config file
        try:
try:
                 locale.setlocale(locale.LC_ALL, 'de_DE')
                 locale.setlocale(locale.LC_ALL, 'de_DE')
                config=read_Configfiles()
config=read_Configfiles()
                userlist=config.sections()
userlist=config.sections()
                userlist.remove('GLOBAL')
userlist.remove('GLOBAL')
                # search for call_to in the user sections
        # search for call_to in the user sections
                curr_user=""
curr_user=""
                for u in userlist:
for u in userlist:
                        if config.has_option(u,'voice_numbers'):
if config.has_option(u,'voice_numbers'):
                                numbers=config.get(u,'voice_numbers')
numbers=config.get(u,'voice_numbers')
                                if (call_to in numbers.split(',') or numbers=="*"):
if (call_to in numbers.split(',') or numbers=="*"):
                                        if (service==capisuite.SERVICE_VOICE):
if (service==capisuite.SERVICE_VOICE):
                                                curr_user=u
curr_user=u
                                                curr_service=capisuite.SERVICE_VOICE
curr_service=capisuite.SERVICE_VOICE
                                                break
break
                                        if (service==capisuite.SERVICE_FAXG3):
if (service==capisuite.SERVICE_FAXG3):
                                                curr_user=u
curr_user=u
                                                curr_service=capisuite.SERVICE_FAXG3
curr_service=capisuite.SERVICE_FAXG3
                                                break
break


                        if config.has_option(u,'fax_numbers'):
if config.has_option(u,'fax_numbers'):
                                numbers=config.get(u,'fax_numbers')
numbers=config.get(u,'fax_numbers')
                                if (call_to in numbers.split(',') or numbers=="*"):
if (call_to in numbers.split(',') or numbers=="*"):
                                        if (service in (capisuite.SERVICE_FAXG3,capisuite.SERVICE_VOICE)):
if (service in (capisuite.SERVICE_FAXG3,capisuite.SERVICE_VOICE)):
                                                curr_user=u
curr_user=u
                                                curr_service=capisuite.SERVICE_FAXG3
curr_service=capisuite.SERVICE_FAXG3
                                                break
break


        except IOError,e:
except IOError,e:
                capisuite.error("Error occured during config file reading: "+e+" Disconnecting...")
capisuite.error("Error occured during config file reading: "+e+" Disconnecting...")
                capisuite.reject(call,0x34A9)
capisuite.reject(call,0x34A9)
                return
return


         # answer the call with the right service
         # answer the call with the right service
        if (curr_user==""):
if (curr_user==""):
                capisuite.log("call from "+call_from+" to "+call_to+" ignoring",1,call)
capisuite.log("call from "+call_from+" to "+call_to+" ignoring",1,call)
                capisuite.reject(call,1)
capisuite.reject(call,1)
                return
return


         # XXX: neobiker's _adv
         # XXX: neobiker's _adv
        try:
try:
                phonebook=cs_helpers.readConfig(configfile_phonebook)
phonebook=cs_helpers.readConfig(configfile_phonebook)
        except IOError,e:
except IOError,e:
                capisuite.error("Warning: Error occured during phonebook file reading: "+e)
capisuite.error("Warning: Error occured during phonebook file reading: "+e)


        try:
try:
                if (curr_service==capisuite.SERVICE_VOICE):
if (curr_service==capisuite.SERVICE_VOICE):
                         # XXX: neobiker's _adv
                         # XXX: neobiker's _adv
                         user_prog = read_prog(config, curr_user, call_from)
                         user_prog = read_prog(config, curr_user, call_from)
Zeile 420: Zeile 420:
                             delay = user_prog['delay']
                             delay = user_prog['delay']
                         else:
                         else:
                            delay=cs_helpers.getOption(config,curr_user,"voice_delay")
    delay=cs_helpers.getOption(config,curr_user,"voice_delay")
                         caller_name = read_phonebook(call_from)
                         caller_name = read_phonebook(call_from)
                         called_name = read_phonebook(call_to)
                         called_name = read_phonebook(call_to)
                        if (delay==None):
if (delay==None):
                                capisuite.error("voice_delay not found for user "+curr_user+"! -> rejecting call")
capisuite.error("voice_delay not found for user "+curr_user+"! -> rejecting call")
                                capisuite.reject(call,0x34A9)
capisuite.reject(call,0x34A9)
                                return
return
                        capisuite.log("call from "+caller_name+" to "+called_name+" for "+curr_user+" connecting with voice",1,call)
capisuite.log("call from "+caller_name+" to "+called_name+" for "+curr_user+" connecting with voice",1,call)
                        capisuite.connect_voice(call,int(delay))
capisuite.connect_voice(call,int(delay))
                        voiceIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config)
voiceIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config)
                elif (curr_service==capisuite.SERVICE_FAXG3):
elif (curr_service==capisuite.SERVICE_FAXG3):
                         caller_name = read_phonebook(call_from)
                         caller_name = read_phonebook(call_from)
                         called_name = read_phonebook(call_to)
                         called_name = read_phonebook(call_to)
                        faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,0)
faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,0)
        except capisuite.CallGoneError: # catch exceptions from connect_*
except capisuite.CallGoneError: # catch exceptions from connect_*
                (cause,causeB3)=capisuite.disconnect(call)
(cause,causeB3)=capisuite.disconnect(call)
                capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)
capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)


# -------------------------------------------------------------------
# -------------------------------------------------------------------
Zeile 449: Zeile 449:


def faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,already_connected):
def faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,already_connected):
        try:
try:
                udir=cs_helpers.getOption(config,"","fax_user_dir")
udir=cs_helpers.getOption(config,"","fax_user_dir")
                if (udir==None):
if (udir==None):
                        capisuite.error("global option fax_user_dir not found! -> rejecting call")
capisuite.error("global option fax_user_dir not found! -> rejecting call")
                        capisuite.reject(call,0x34A9)
capisuite.reject(call,0x34A9)
                        return
return
                udir=os.path.join(udir,curr_user)+"/"
udir=os.path.join(udir,curr_user)+"/"
                if (not os.access(udir,os.F_OK)):
if (not os.access(udir,os.F_OK)):
                        userdata=pwd.getpwnam(curr_user)
userdata=pwd.getpwnam(curr_user)
                        os.mkdir(udir,0700)
os.mkdir(udir,0700)
                        os.chown(udir,userdata[2],userdata[3])
os.chown(udir,userdata[2],userdata[3])
                if (not os.access(udir+"received/",os.F_OK)):
if (not os.access(udir+"received/",os.F_OK)):
                        userdata=pwd.getpwnam(curr_user)
userdata=pwd.getpwnam(curr_user)
                        os.mkdir(udir+"received/",0700)
os.mkdir(udir+"received/",0700)
                        os.chown(udir+"received/",userdata[2],userdata[3])
os.chown(udir+"received/",userdata[2],userdata[3])
        except KeyError:
except KeyError:
                capisuite.error("user "+curr_user+" is not a valid system user. Disconnecting",call)
capisuite.error("user "+curr_user+" is not a valid system user. Disconnecting",call)
                capisuite.reject(call,0x34A9)
capisuite.reject(call,0x34A9)
                return
return
        filename="" # assure the variable is defined...
filename="" # assure the variable is defined...
        try:
try:
                stationID=cs_helpers.getOption(config,curr_user,"fax_stationID")
stationID=cs_helpers.getOption(config,curr_user,"fax_stationID")
                if (stationID==None):
if (stationID==None):
                        capisuite.error("Warning: fax_stationID not found for user "+curr_user+" -> using empty string")
capisuite.error("Warning: fax_stationID not found for user "+curr_user+" -> using empty string")
                        stationID=""
stationID=""
                headline=cs_helpers.getOption(config,curr_user,"fax_headline","") # empty string is no problem here
headline=cs_helpers.getOption(config,curr_user,"fax_headline","") # empty string is no problem here
                capisuite.log("call from "+caller_name+" to "+called_name+" for "+curr_user+" connecting with fax",1,call)
capisuite.log("call from "+caller_name+" to "+called_name+" for "+curr_user+" connecting with fax",1,call)
                if (already_connected):
if (already_connected):
                        faxInfo=capisuite.switch_to_faxG3(call,stationID,headline)
faxInfo=capisuite.switch_to_faxG3(call,stationID,headline)
                else:
else:
                        faxInfo=capisuite.connect_faxG3(call,stationID,headline,0)
faxInfo=capisuite.connect_faxG3(call,stationID,headline,0)
                if (faxInfo!=None and faxInfo[3]==1):
if (faxInfo!=None and faxInfo[3]==1):
                        faxFormat="cff" # color fax
faxFormat="cff" # color fax
                else:
else:
                        faxFormat="sff" # normal b&w fax
faxFormat="sff" # normal b&w fax
                filename=cs_helpers.uniqueName(udir+"received/","fax",faxFormat)
filename=cs_helpers.uniqueName(udir+"received/","fax",faxFormat)
                capisuite.fax_receive(call,filename)
capisuite.fax_receive(call,filename)
                (cause,causeB3)=capisuite.disconnect(call)
(cause,causeB3)=capisuite.disconnect(call)
                capisuite.log("connection finished with cause 0x%x,0x%x" % (cause,causeB3),1,call)
capisuite.log("connection finished with cause 0x%x,0x%x" % (cause,causeB3),1,call)


        except capisuite.CallGoneError: # catch this here to get the cause info in the mail
except capisuite.CallGoneError: # catch this here to get the cause info in the mail
                (cause,causeB3)=capisuite.disconnect(call)
(cause,causeB3)=capisuite.disconnect(call)
                capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)
capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)


        if (os.access(filename,os.R_OK)):
if (os.access(filename,os.R_OK)):
                cs_helpers.writeDescription(filename,
cs_helpers.writeDescription(filename,
                  "call_from=\""+call_from+"\"\ncall_to=\""+call_to+"\"\ntime=\""
  "call_from=\""+call_from+"\"\ncall_to=\""+call_to+"\"\ntime=\""
                  +time.ctime()+"\"\ncause=\"0x%x/0x%x\"\n" % (cause,causeB3))
  +time.ctime()+"\"\ncause=\"0x%x/0x%x\"\n" % (cause,causeB3))
                userdata=pwd.getpwnam(curr_user)
userdata=pwd.getpwnam(curr_user)
                os.chmod(filename,0600)
os.chmod(filename,0600)
                os.chown(filename,userdata[2],userdata[3])
os.chown(filename,userdata[2],userdata[3])
                os.chmod(filename[:-3]+"txt",0600)
os.chmod(filename[:-3]+"txt",0600)
                os.chown(filename[:-3]+"txt",userdata[2],userdata[3])
os.chown(filename[:-3]+"txt",userdata[2],userdata[3])


                fromaddress=cs_helpers.getOption(config,curr_user,"fax_email_from","")
fromaddress=cs_helpers.getOption(config,curr_user,"fax_email_from","")
                if (fromaddress==""):
if (fromaddress==""):
                        fromaddress=curr_user
fromaddress=curr_user
                mailaddress=cs_helpers.getOption(config,curr_user,"fax_email","")
mailaddress=cs_helpers.getOption(config,curr_user,"fax_email","")
                if (mailaddress==""):
if (mailaddress==""):
                        mailaddress=curr_user
mailaddress=curr_user
                 action=cs_helpers.getOption(config,curr_user,"fax_action","").lower()
                 action=cs_helpers.getOption(config,curr_user,"fax_action","").lower()
                if (action not in ("mailandsave","saveonly")):
if (action not in ("mailandsave","saveonly")):
                        capisuite.error("Warning: No valid fax_action definition found for user "+curr_user+" -> assuming SaveOnly")
capisuite.error("Warning: No valid fax_action definition found for user "+curr_user+" -> assuming SaveOnly")
                        action="saveonly"
action="saveonly"
                if (action=="mailandsave"):
if (action=="mailandsave"):
                         # XXX: changed Mail text
                         # XXX: changed Mail text
                         caller_details = ""
                         caller_details = ""
                         if (caller_name == call_from):
                         if (caller_name == call_from):
                             caller_name, caller_details = check_number_online (call_from)
                             caller_name, caller_details = check_number_online (call_from)
                        cs_helpers.sendMIMEMail(fromaddress, mailaddress,
cs_helpers.sendMIMEMail(fromaddress, mailaddress,
                           "Fax von "+caller_name+" an "+called_name, faxFormat,
                           "Fax von "+caller_name+" an "+called_name, faxFormat,
                            "Fax Sender: "+caller_name+" ("+call_from+")\n"
    "Fax Sender: "+caller_name+" ("+call_from+")\n"
                            +"            "+caller_details+"\n"
    +"            "+caller_details+"\n"
                             +"Datum:      "+time.strftime("%c")+"\n\n"
                             +"Datum:      "+time.strftime("%c")+"\n\n"
                            +"Siehe Anhang.\nDas Fax wurde gespeichert unter: "+filename+"\n",
    +"Siehe Anhang.\nDas Fax wurde gespeichert unter: "+filename+"\n",
                           filename)
                           filename)


Zeile 536: Zeile 536:


def voiceIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config):
def voiceIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config):
        try:
try:
                udir=cs_helpers.getOption(config,"","voice_user_dir")
udir=cs_helpers.getOption(config,"","voice_user_dir")
                if (udir==None):
if (udir==None):
                        capisuite.error("global option voice_user_dir not found! -> rejecting call")
capisuite.error("global option voice_user_dir not found! -> rejecting call")
                        capisuite.reject(call,0x34A9)
capisuite.reject(call,0x34A9)
                        return
return
                udir=os.path.join(udir,curr_user)+"/"
udir=os.path.join(udir,curr_user)+"/"
                if (not os.access(udir,os.F_OK)):
if (not os.access(udir,os.F_OK)):
                        userdata=pwd.getpwnam(curr_user)
userdata=pwd.getpwnam(curr_user)
                        os.mkdir(udir,0700)
os.mkdir(udir,0700)
                        os.chown(udir,userdata[2],userdata[3])
os.chown(udir,userdata[2],userdata[3])
                if (not os.access(udir+"received/",os.F_OK)):
if (not os.access(udir+"received/",os.F_OK)):
                        userdata=pwd.getpwnam(curr_user)
userdata=pwd.getpwnam(curr_user)
                        os.mkdir(udir+"received/",0700)
os.mkdir(udir+"received/",0700)
                        os.chown(udir+"received/",userdata[2],userdata[3])
os.chown(udir+"received/",userdata[2],userdata[3])
        except KeyError:
except KeyError:
                capisuite.error("user "+curr_user+" is not a valid system user. Disconnecting",call)
capisuite.error("user "+curr_user+" is not a valid system user. Disconnecting",call)
                capisuite.reject(call,0x34A9)
capisuite.reject(call,0x34A9)
                return
return
        filename=cs_helpers.uniqueName(udir+"received/","voice","la")
filename=cs_helpers.uniqueName(udir+"received/","voice","la")
        action=cs_helpers.getOption(config,curr_user,"voice_action","").lower()
action=cs_helpers.getOption(config,curr_user,"voice_action","").lower()
        if (action not in ("mailandsave","saveonly","none")):
if (action not in ("mailandsave","saveonly","none")):
                capisuite.error("Warning: No valid voice_action definition found for user "+curr_user+" -> assuming SaveOnly")
capisuite.error("Warning: No valid voice_action definition found for user "+curr_user+" -> assuming SaveOnly")
                action="saveonly"
action="saveonly"
        try:
try:
                capisuite.enable_DTMF(call)
capisuite.enable_DTMF(call)
                 # XXX: neobiker's _adv
                 # XXX: neobiker's _adv
                 user_prog = read_prog(config, curr_user, call_from)
                 user_prog = read_prog(config, curr_user, call_from)
Zeile 567: Zeile 567:
                     userannouncement = udir + user_prog['message']
                     userannouncement = udir + user_prog['message']
                 else:
                 else:
                    userannouncement=udir+cs_helpers.getOption(config,curr_user,"announcement","announcement.la")
    userannouncement=udir+cs_helpers.getOption(config,curr_user,"announcement","announcement.la")
                pin=cs_helpers.getOption(config,curr_user,"pin","")
pin=cs_helpers.getOption(config,curr_user,"pin","")
                if (os.access(userannouncement,os.R_OK)):
if (os.access(userannouncement,os.R_OK)):
                        capisuite.audio_send(call,userannouncement,1)
capisuite.audio_send(call,userannouncement,1)
                else:
else:
                        if (call_to!="-"):
if (call_to!="-"):
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"anrufbeantworter-von.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"anrufbeantworter-von.la"),1)
                                cs_helpers.sayNumber(call,call_to,curr_user,config)
cs_helpers.sayNumber(call,call_to,curr_user,config)
                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-nachricht.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-nachricht.la"),1)


                if (action!="none"):
if (action!="none"):
                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"),1)
                         # XXX: neobiker's _adv
                         # XXX: neobiker's _adv
                         if user_prog:
                         if user_prog:
                             length = user_prog['length']
                             length = user_prog['length']
                         else:
                         else:
                            length=cs_helpers.getOption(config,curr_user,"record_length","60")
    length=cs_helpers.getOption(config,curr_user,"record_length","60")
                        silence_timeout=cs_helpers.getOption(config,curr_user,"record_silence_timeout","5")
silence_timeout=cs_helpers.getOption(config,curr_user,"record_silence_timeout","5")
                        capisuite.audio_receive(call,filename,int(length), int(silence_timeout),1)
capisuite.audio_receive(call,filename,int(length), int(silence_timeout),1)


                dtmf_list=capisuite.read_DTMF(call,0)
dtmf_list=capisuite.read_DTMF(call,0)
                if (dtmf_list=="X"):
if (dtmf_list=="X"):
                        if (os.access(filename,os.R_OK)):
if (os.access(filename,os.R_OK)):
                                os.unlink(filename)
os.unlink(filename)
                        faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,1)
faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,1)
                elif (dtmf_list!="" and pin!=""):
elif (dtmf_list!="" and pin!=""):
                        dtmf_list+=capisuite.read_DTMF(call,3) # wait 5 seconds for input
dtmf_list+=capisuite.read_DTMF(call,3) # wait 5 seconds for input
                        count=1
count=1
                        while (count<3 and pin!=dtmf_list):  # try again if input was wrong
while (count<3 and pin!=dtmf_list):  # try again if input was wrong
                                capisuite.log("wrong PIN entered...",1,call)
capisuite.log("wrong PIN entered...",1,call)
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
                                dtmf_list=capisuite.read_DTMF(call,3)
dtmf_list=capisuite.read_DTMF(call,3)
                                count+=1
count+=1
                        if (pin==dtmf_list):
if (pin==dtmf_list):
                                if (os.access(filename,os.R_OK)):
if (os.access(filename,os.R_OK)):
                                        os.unlink(filename)
os.unlink(filename)
                                capisuite.log("Starting remote inquiry...",1,call)
capisuite.log("Starting remote inquiry...",1,call)
                                remoteInquiry(call,udir,curr_user,config)
remoteInquiry(call,udir,curr_user,config)


                (cause,causeB3)=capisuite.disconnect(call)
(cause,causeB3)=capisuite.disconnect(call)
                capisuite.log("connection finished with cause 0x%x,0x%x" % (cause,causeB3),1,call)
capisuite.log("connection finished with cause 0x%x,0x%x" % (cause,causeB3),1,call)


        except capisuite.CallGoneError: # catch this here to get the cause info in the mail
except capisuite.CallGoneError: # catch this here to get the cause info in the mail
                (cause,causeB3)=capisuite.disconnect(call)
(cause,causeB3)=capisuite.disconnect(call)
                capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)
capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)


        if (os.access(filename,os.R_OK)):
if (os.access(filename,os.R_OK)):
                cs_helpers.writeDescription(filename,
cs_helpers.writeDescription(filename,
                  "call_from=\""+call_from+"\"\ncall_to=\""+call_to+"\"\ntime=\""
  "call_from=\""+call_from+"\"\ncall_to=\""+call_to+"\"\ntime=\""
                  +time.ctime()+"\"\ncause=\"0x%x/0x%x\"\n" % (cause,causeB3))
  +time.ctime()+"\"\ncause=\"0x%x/0x%x\"\n" % (cause,causeB3))
                userdata=pwd.getpwnam(curr_user)
userdata=pwd.getpwnam(curr_user)
                os.chmod(filename,0600)
os.chmod(filename,0600)
                os.chown(filename,userdata[2],userdata[3])
os.chown(filename,userdata[2],userdata[3])
                os.chmod(filename[:-2]+"txt",0600)
os.chmod(filename[:-2]+"txt",0600)
                os.chown(filename[:-2]+"txt",userdata[2],userdata[3])
os.chown(filename[:-2]+"txt",userdata[2],userdata[3])


                fromaddress=cs_helpers.getOption(config,curr_user,"voice_email_from","")
fromaddress=cs_helpers.getOption(config,curr_user,"voice_email_from","")
                if (fromaddress==""):
if (fromaddress==""):
                        fromaddress=curr_user
fromaddress=curr_user
                mailaddress=cs_helpers.getOption(config,curr_user,"voice_email","")
mailaddress=cs_helpers.getOption(config,curr_user,"voice_email","")
                if (mailaddress==""):
if (mailaddress==""):
                        mailaddress=curr_user
mailaddress=curr_user
                if (action=="mailandsave"):
if (action=="mailandsave"):
                         # XXX: changed Mail text
                         # XXX: changed Mail text
                         caller_details = ""
                         caller_details = ""
                         if (caller_name == call_from):
                         if (caller_name == call_from):
                             caller_name, caller_details = check_number_online (call_from)
                             caller_name, caller_details = check_number_online (call_from)
                        cs_helpers.sendMIMEMail(fromaddress, mailaddress,
cs_helpers.sendMIMEMail(fromaddress, mailaddress,
                           "Nachricht von "+caller_name+" fuer "+called_name, "la",
                           "Nachricht von "+caller_name+" fuer "+called_name, "la",
                            "Anrufer: "+caller_name+" ("+call_from+")\n"
    "Anrufer: "+caller_name+" ("+call_from+")\n"
                            +"        "+caller_details+"\n"
    +"        "+caller_details+"\n"
                             +"Laenge:  "+str(os.stat(filename)[6]/8/1024)+" Sek.\n"
                             +"Laenge:  "+str(os.stat(filename)[6]/8/1024)+" Sek.\n"
                             +"Datum:  "+time.strftime("%c")+"\n"
                             +"Datum:  "+time.strftime("%c")+"\n"
                             +"Nummer:  "+called_name+" ("+call_to+")\n\n"
                             +"Nummer:  "+called_name+" ("+call_to+")\n\n"
                            +"Siehe Anhang.\nDas File wurde gespeichert unter: "+filename+"\n",
    +"Siehe Anhang.\nDas File wurde gespeichert unter: "+filename+"\n",
                           filename)
                           filename)


Zeile 660: Zeile 660:
#
#
def remoteInquiry(call,userdir,curr_user,config):
def remoteInquiry(call,userdir,curr_user,config):
        import time,fcntl,errno,os
import time,fcntl,errno,os
        # acquire lock
# acquire lock
        lockfile=open(userdir+"received/inquiry_lock","w")
lockfile=open(userdir+"received/inquiry_lock","w")
        try:
try:
                fcntl.lockf(lockfile,fcntl.LOCK_EX | fcntl.LOCK_NB) # only one inquiry at a time!
fcntl.lockf(lockfile,fcntl.LOCK_EX | fcntl.LOCK_NB) # only one inquiry at a time!


        except IOError,err: # can't get the lock
except IOError,err: # can't get the lock
                if (err.errno in (errno.EACCES,errno.EAGAIN)):
if (err.errno in (errno.EACCES,errno.EAGAIN)):
                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fernabfrage-aktiv.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fernabfrage-aktiv.la"))
                        lockfile.close()
lockfile.close()
                        return
return


        try:
try:
                # read directory contents
# read directory contents
                messages=os.listdir(userdir+"received/")
messages=os.listdir(userdir+"received/")
                messages=filter (lambda s: re.match("voice-.*\.la",s),messages)  # only use voice-* files
messages=filter (lambda s: re.match("voice-.*\.la",s),messages)  # only use voice-* files
                messages=map(lambda s: int(re.match("voice-([0-9]+)\.la",s).group(1)),messages) # filter out numbers
messages=map(lambda s: int(re.match("voice-([0-9]+)\.la",s).group(1)),messages) # filter out numbers
                messages.sort()
messages.sort()


                # read the number of the message heard last at the last inquiry
# read the number of the message heard last at the last inquiry
                lastinquiry=-1
lastinquiry=-1
                if (os.access(userdir+"received/last_inquiry",os.W_OK)):
if (os.access(userdir+"received/last_inquiry",os.W_OK)):
                        lastfile=open(userdir+"received/last_inquiry","r")
lastfile=open(userdir+"received/last_inquiry","r")
                        lastinquiry=int(lastfile.readline())
lastinquiry=int(lastfile.readline())
                        lastfile.close()
lastfile.close()


                # sort out old messages
# sort out old messages
                oldmessages=[]
oldmessages=[]
                i=0
i=0
                while (i<len(messages)):
while (i<len(messages)):
                        if (messages[i]<=lastinquiry):
if (messages[i]<=lastinquiry):
                                oldmessages.append(messages[i])
oldmessages.append(messages[i])
                                del messages[i]
del messages[i]
                        else:
else:
                                i+=1
i+=1


                cs_helpers.sayNumber(call,str(len(messages)),curr_user,config)
cs_helpers.sayNumber(call,str(len(messages)),curr_user,config)
                if (len(messages)==1):
if (len(messages)==1):
                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachricht.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachricht.la"),1)
                else:
else:
                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachrichten.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachrichten.la"),1)


                # menu for record new announcement
# menu for record new announcement
                cmd=""
cmd=""
                while (cmd not in ("1","9")):
while (cmd not in ("1","9")):
                        if (len(messages)+len(oldmessages)):
if (len(messages)+len(oldmessages)):
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"zum-abhoeren-1.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"zum-abhoeren-1.la"),1)
                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fuer-neue-ansage-9.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fuer-neue-ansage-9.la"),1)
                        cmd=capisuite.read_DTMF(call,0,1)
cmd=capisuite.read_DTMF(call,0,1)
                if (cmd=="9"):
if (cmd=="9"):
                        newAnnouncement(call,userdir,curr_user,config)
newAnnouncement(call,userdir,curr_user,config)
                        return
return


                # start inquiry
# start inquiry
                for curr_msgs in (messages,oldmessages):
for curr_msgs in (messages,oldmessages):
                        cs_helpers.sayNumber(call,str(len(curr_msgs)),curr_user,config)
cs_helpers.sayNumber(call,str(len(curr_msgs)),curr_user,config)
                        if (curr_msgs==messages):
if (curr_msgs==messages):
                                if (len(curr_msgs)==1):
if (len(curr_msgs)==1):
                                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachricht.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachricht.la"),1)
                                else:
else:
                                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachrichten.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachrichten.la"),1)
                        else:
else:
                                if (len(curr_msgs)==1):
if (len(curr_msgs)==1):
                                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht.la"),1)
                                else:
else:
                                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachrichten.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachrichten.la"),1)


                        i=0
i=0
                        while (i<len(curr_msgs)):
while (i<len(curr_msgs)):
                                filename=userdir+"received/voice-"+str(curr_msgs[i])+".la"
filename=userdir+"received/voice-"+str(curr_msgs[i])+".la"
                                descr=cs_helpers.readConfig(filename[:-2]+"txt")
descr=cs_helpers.readConfig(filename[:-2]+"txt")
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht.la"),1)
                                cs_helpers.sayNumber(call,str(i+1),curr_user,config)
cs_helpers.sayNumber(call,str(i+1),curr_user,config)
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"von.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"von.la"),1)
                                cs_helpers.sayNumber(call,descr.get('GLOBAL','call_from'),curr_user,config)
cs_helpers.sayNumber(call,descr.get('GLOBAL','call_from'),curr_user,config)
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fuer.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fuer.la"),1)
                                cs_helpers.sayNumber(call,descr.get('GLOBAL','call_to'),curr_user,config)
cs_helpers.sayNumber(call,descr.get('GLOBAL','call_to'),curr_user,config)
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"am.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"am.la"),1)
                                # XXX: neobiker (use locale 'C' here, or use
                                # locale DE while writing the .txt file line 614)
                                 locale.setlocale(locale.LC_ALL, 'C')
                                 locale.setlocale(locale.LC_ALL, 'C')
                                calltime=time.strptime(descr.get('GLOBAL','time'))
calltime=time.strptime(descr.get('GLOBAL','time'))
                                cs_helpers.sayNumber(call,str(calltime[2]),curr_user,config)
cs_helpers.sayNumber(call,str(calltime[2]),curr_user,config)
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"..la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"..la"),1)
                                cs_helpers.sayNumber(call,str(calltime[1]),curr_user,config)
cs_helpers.sayNumber(call,str(calltime[1]),curr_user,config)
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"..la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"..la"),1)
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"um.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"um.la"),1)
                                cs_helpers.sayNumber(call,str(calltime[3]),curr_user,config)
cs_helpers.sayNumber(call,str(calltime[3]),curr_user,config)
                                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"uhr.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"uhr.la"),1)
                                cs_helpers.sayNumber(call,str(calltime[4]),curr_user,config)
cs_helpers.sayNumber(call,str(calltime[4]),curr_user,config)
                                capisuite.audio_send(call,filename,1)
capisuite.audio_send(call,filename,1)
                                cmd=""
cmd=""
                                while (cmd not in ("1","4","5","6")):
while (cmd not in ("1","4","5","6")):
                                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"erklaerung.la"),1)
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"erklaerung.la"),1)
                                        cmd=capisuite.read_DTMF(call,0,1)
cmd=capisuite.read_DTMF(call,0,1)
                                if (cmd=="1"):
if (cmd=="1"):
                                        os.remove(filename)
os.remove(filename)
                                        os.remove(filename[:-2]+"txt")
os.remove(filename[:-2]+"txt")
                                        del curr_msgs[i]
del curr_msgs[i]
                                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht-geloescht.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht-geloescht.la"))
                                elif (cmd=="4"):
elif (cmd=="4"):
                                        if (curr_msgs[i]>lastinquiry):
if (curr_msgs[i]>lastinquiry):
                                                lastinquiry=curr_msgs[i]
lastinquiry=curr_msgs[i]
                                                lastfile=open(userdir+"received/last_inquiry","w")
lastfile=open(userdir+"received/last_inquiry","w")
                                                lastfile.write(str(curr_msgs[i])+"\n")
lastfile.write(str(curr_msgs[i])+"\n")
                                                lastfile.close()
lastfile.close()
                                        i+=1
i+=1
                                elif (cmd=="5"):
elif (cmd=="5"):
                                        i-=1
i-=1
                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"keine-weiteren-nachrichten.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"keine-weiteren-nachrichten.la"))


        finally:
finally:
                # unlock
# unlock
                fcntl.lockf(lockfile,fcntl.LOCK_UN)
fcntl.lockf(lockfile,fcntl.LOCK_UN)
                lockfile.close()
lockfile.close()
                os.unlink(userdir+"received/inquiry_lock")
os.unlink(userdir+"received/inquiry_lock")


# ---------------------------------------------------------------------------
# ---------------------------------------------------------------------------
Zeile 786: Zeile 784:


def newAnnouncement(call,userdir,curr_user,config):
def newAnnouncement(call,userdir,curr_user,config):
        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-neue-ansage-komplett.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-neue-ansage-komplett.la"))
        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
        cmd=""
cmd=""
        while (cmd!="1"):
while (cmd!="1"):
                capisuite.audio_receive(call,userdir+"announcement-tmp.la",60,3)
capisuite.audio_receive(call,userdir+"announcement-tmp.la",60,3)
                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-ansage-lautet.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-ansage-lautet.la"))
                capisuite.audio_send(call,userdir+"announcement-tmp.la")
capisuite.audio_send(call,userdir+"announcement-tmp.la")
                capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"wenn-einverstanden-1.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"wenn-einverstanden-1.la"))
                cmd=capisuite.read_DTMF(call,0,1)
cmd=capisuite.read_DTMF(call,0,1)
                if (cmd!="1"):
if (cmd!="1"):
                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-neue-ansage-kurz.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-neue-ansage-kurz.la"))
                        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
        userannouncement=userdir+cs_helpers.getOption(config,curr_user,"announcement","announcement.la")
userannouncement=userdir+cs_helpers.getOption(config,curr_user,"announcement","announcement.la")
        os.rename(userdir+"announcement-tmp.la",userannouncement)
os.rename(userdir+"announcement-tmp.la",userannouncement)
        userdata=pwd.getpwnam(curr_user)
userdata=pwd.getpwnam(curr_user)
        os.chown(userannouncement,userdata[2],userdata[3])
os.chown(userannouncement,userdata[2],userdata[3])


        capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"ansage-gespeichert.la"))
capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"ansage-gespeichert.la"))


#
#
Zeile 811: Zeile 809:
# Revision 1.8  2007/09/10 20:37:00  root
# Revision 1.8  2007/09/10 20:37:00  root
# optimized read_phonebook()
# optimized read_phonebook()
# ...
#
# ...
# Revision 1.7  2007/09/09 19:24:47  root
# Names now case sensitive
#
# Revision 1.6  2007/09/09 19:08:26  root
# phonebook.conf optional
#
# Revision 1.5  2007/09/09 19:05:26  root
# integrated phonebook sections in capisuite config
#
# Revision 1.4  2007/09/09 16:01:50  root
# added errorhandling and logging in check_number_online ()
#
# Revision 1.3  2007/09/09 15:29:16  root
# added German date format and record length to Email
#
# Revision 1.2  2007/09/09 13:49:40  root
# added phonebook function and reverse lookup online
#
# Revision 1.1  2007/09/09 13:22:42  root
# Revision 1.1  2007/09/09 13:22:42  root
# Initial revision
# Initial revision
##
#
# Revision 1.4  2007/01/23 14:42:11  root
# changed mail text to german and beatified layout
#
# Revision 1.3  2007/01/03 23:27:36  root
# none
#
# Revision 1.2  2007/01/03 23:23:27  root
# First checkin
#
# Revision 1.1  2007/01/03 23:18:13  root
# Initial revision
#
# Revision 1.9.2.1  2003/08/24 12:47:19  gernot
# Revision 1.9.2.1  2003/08/24 12:47:19  gernot
# - faxIncoming tried to reconnect when it was called after a switch from
# - faxIncoming tried to reconnect when it was called after a switch from
Zeile 824: Zeile 851:
# - replaced german umlaut in filename "nachricht-gelscht.la", can cause
# - replaced german umlaut in filename "nachricht-gelscht.la", can cause
#  problems on Redhat, thx to Herbert Hübner for reporting
#  problems on Redhat, thx to Herbert Hübner for reporting
# ...
#
# ...
# Revision 1.8  2003/06/16 10:21:05  gernot
# - define filename in any case (thx to Axel Schneck for reporting and
#  analyzing...)
#
# Revision 1.7  2003/05/25 13:38:30  gernot
# - support reception of color fax documents
#
# Revision 1.6  2003/04/10 21:29:51  gernot
# - support empty destination number for incoming calls correctly (austrian
#  telecom does this (sic))
# - core now returns "-" instead of "??" for "no number available" (much nicer
#  in my eyes)
# - new wave file used in remote inquiry for "unknown number"
#
# Revision 1.5  2003/03/20 09:12:42  gernot
# - error checking for reading of configuration improved, many options got
#  optional, others produce senseful error messages now if not found,
#  fixes bug# 531, thx to Dieter Pelzel for reporting
#
# Revision 1.4  2003/03/13 11:08:06  gernot
# - fix remote inquiry locking (should fix bug #534, but doesn't - anyway,
#  this fix is definitely necessary)
# - stricter permissions of saved files and created dirs, fixes #544
# - add "file://" prefix to the path shown in the mails to the user
#
# Revision 1.3  2003/02/21 13:13:34  gernot
# - removed some debug output (oops...)
#
# Revision 1.2  2003/02/21 11:02:17  gernot
# - removed os.setuid() from incoming script
#  -> fixes Bug #527
#
# Revision 1.1.1.1  2003/02/19 08:19:54  gernot
# initial checkin of 0.4
#
# Revision 1.11  2003/02/17 11:13:43  ghillie
# - remoteinquiry supports new and old messages now
#
# Revision 1.10  2003/02/03 14:50:08  ghillie
# - fixed small typo
#
# Revision 1.9  2003/01/31 16:32:41  ghillie
# - support "*" for "all numbers"
# - automatic switch voice->fax when SI says fax
#
# Revision 1.8  2003/01/31 11:24:41  ghillie
# - wrong user handling for more than one users fixed
# - creates user_dir/user and user_dir/user/received now separately as
#  idle.py can also create user_dir/user now
#
# Revision 1.7  2003/01/27 21:57:54  ghillie
# - fax_numbers and voice_numbers may not exist (no fatal error any more)
# - accept missing email option
# - fixed typo
#
# Revision 1.6  2003/01/27 19:24:29  ghillie
# - updated to use new configuration files for fax & answering machine
#
# Revision 1.5  2003/01/19 12:03:27  ghillie
# - use capisuite log functions instead of stdout/stderr
#
# Revision 1.4  2003/01/17 15:09:49  ghillie
# - cs_helpers.sendMail was renamed to sendMIMEMail
#
# Revision 1.3  2003/01/16 12:58:34  ghillie
# - changed DTMF timeout for pin to 3 seconds
# - delete recorded wave if fax or remote inquiry is recognized
# - updates in remoteInquiry: added menu for recording own announcement
# - fixed some typos
# - remoteInquiry: delete description file together with call if requested
# - new function: newAnnouncement
#
# Revision 1.2  2003/01/15 15:55:12  ghillie
# - added exception handler in callIncoming
# - faxIncoming: small typo corrected
# - voiceIncoming & remoteInquiry: updated to new config file system
#
# Revision 1.1  2003/01/13 16:12:58  ghillie
# - renamed from incoming.pyin to incoming.py as all previously processed
#  variables are moved to config and cs_helpers.pyin
#
# Revision 1.4  2002/12/18 14:34:56  ghillie
# - added some informational prints
# - accept voice calls to fax nr
#
# Revision 1.3  2002/12/16 15:04:51  ghillie
# - added missing path prefix to delete routing in remote inquiry
#
# Revision 1.2  2002/12/16 13:09:25  ghillie
# - added some comments about the conf_* vars
# - added conf_wavedir
# - added support for B3 cause now returned by disconnect()
# - corrected some dir entries to work in installed system
#
# Revision 1.1  2002/12/14 13:53:18  ghillie
# - idle.py and incoming.py are now auto-created from *.pyin
#
# Revision 1.4  2002/12/11 12:58:05  ghillie
# - read return value from disconnect()
# - added disconnect() to exception handler
#
# Revision 1.3  2002/12/09 15:18:35  ghillie
# - added disconnect() in exception handler
#
# Revision 1.2  2002/12/02 21:30:42  ghillie
# fixed some minor typos
#
# Revision 1.1  2002/12/02 21:15:55  ghillie
# - moved scripts to own directory
# - added remote-connect script to repository
#
# Revision 1.20  2002/12/02 20:59:44  ghillie
# another typo :-|
#
# Revision 1.19  2002/12/02 20:54:07  ghillie
# fixed small typo
#
# Revision 1.18  2002/12/02 16:51:32  ghillie
# nearly complete new script, supports answering machine, fax receiving and remote inquiry now
#
# Revision 1.17  2002/11/29 16:28:43  ghillie
# - updated syntax (connect_telephony -> connect_voice)
#
# Revision 1.16  2002/11/29 11:09:04  ghillie
# renamed CapiCom to CapiSuite (name conflict with MS crypto API :-( )
#
# Revision 1.15  2002/11/25 11:43:43  ghillie
# updated to new syntax
#
# Revision 1.14  2002/11/23 16:16:17  ghillie
# moved switch2fax after audio_receive()
#
# Revision 1.13  2002/11/22 15:48:58  ghillie
# renamed pcallcontrol module to capicom
#
# Revision 1.12  2002/11/22 15:02:39  ghillie
# - added automatic switch between speech and fax
# - some comments added
#
# Revision 1.11  2002/11/19 15:57:18  ghillie
# - Added missing throw() declarations
# - phew. Added error handling. All exceptions are caught now.
#
# Revision 1.10  2002/11/18 12:32:36  ghillie
# Revision 1.10  2002/11/18 12:32:36  ghillie
# - callIncoming lives now in __main__, not necessarily in pcallcontrol any more
# - callIncoming lives now in __main__, not necessarily in pcallcontrol any more

Version vom 25. April 2008, 20:47 Uhr

Download ISDN Files

File: incoming_adv.py

#              incoming_adv.py - advanced incoming script for capisuite
#              --------------------------------------------------------
#    copyright            : (c) 2007 by Neobiker
#    Version              : $Revision: 1.8 $
#    Date                 : $Date: 2007/09/10 20:37:00 $
#
#    original script      : incoming.py
#    copyright            : (C) 2002 by Gernot Hillier
#    email                : gernot@hillier.de
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#

# general imports
import locale,datetime,time,os,re,string,pwd,commands

# CapiSuite imports
import capisuite,cs_helpers

# phonebook file (neobiker's _adv)
configfile_phonebook="/etc/capisuite/phonebook.conf"
configfile_fax="/etc/capisuite/fax.conf"
configfile_voice="/etc/capisuite/answering_machine.conf"

# read_Configfiles ()
#     read configuration file and return a ConfigParser object
#
# The configfile is read from the path given above and the surrounding
# quotation marks from the values are removed
#
# @return the constructed config file object
def read_Configfiles(file=""):
	import ConfigParser
	config=ConfigParser.ConfigParser()
	if (file==""):
		config.readfp(open(configfile_fax))
		config.readfp(open(configfile_voice))
                try: 
		    config.readfp(open(configfile_phonebook))
                except:
                    pass
	else:
		config.readfp(open(file))
	for s in config.sections():
		for o in config.options(s):
			value=config.get(s,o)
			if (len(value)>1 and value[0]=='"'):
				config.set(s,o,value[1:-1])
	if (not config.has_section('GLOBAL')):
		raise IOError("invalid config file, section GLOBAL missing")
	return config

# read_phonebook ()
#     check if number is listed in phonebook
#
# read_phonebook (number):
#     number:	 tel number
#
# return: name

def read_phonebook (number):
    """read_phonebook () read name of number if listed in phonebook"""

    try:
        fd=open(configfile_phonebook)
    except:
        return number
    for line in fd:
        line=line.strip()
        if (not line) | line.startswith("#") | (not '=' in line):
            continue
        match=re.match(r'(.*?)\s*=\s*(.*)$', line)
        name=match.group(1)
        details=re.sub('[\s+()-]','',match.group(2))
        if re.sub('[\s+()-]','',number) in details.split(','):
            fd.close()
            return name
    fd.close()
    return number

# ----------------------------------------
# check_number_online ()
#     online reverse lookup
#
# check_number_online (number):
#     number:    tel number
#
# return: name, details

def check_number_online (number):
    """check_number_online () check if number if listed in online phonebook"""

    name = details = ""
    cmd = "tbident.sh " + number + " 2>/dev/null"
    try:
            number, name, details = commands.getoutput(cmd).split("|")
    except:
            capisuite.log("Error: "+cmd+" failed",1,call)
    return name, details

# ----------------------------------------
# check_date ()
#    check if user program date fits actual date 
#
# check_date (pdate, adate):
#     pdate: program date
#     adate: actual date
#
# return: True/False if 'pdate' fits 'adate'

def check_date (pdate, adate):
    """check_date() check if actual date fits user program date"""

    # a '*' fits always...
    if pdate == '*': return True

    # initialise day.month.year from actual date if field is undefined
    # update pdate fields day.month.year as defined in user program
    idate=pdate.split('.')
    pdate=adate[:]
    for i in range(len(idate)):
        if idate[i] and idate[i] != '*':
            pdate[i] = int(idate[i]) 
    return pdate == adate;

# ----------------------------------------
# check_date_section ()
#     check if date is listed in date section
#
# check_date_section (config, dsect, adate):
#     config:	 config file
#     dsect:	 date section list of dates
#     adate:	 actual date
#
# return: True/False if 'adate' is listed/not listed

def check_date_section (config, dsect, adate):
    """check_date_section () check if date is listed in date section"""

    # check all entries in date section 
    # every entry (item) can be a list of dates
    for i in range(len(config.items(dsect))):
        for pdate in config.items(dsect)[i][1].split(','):
            if check_date(pdate, adate):
                return True
    return False

# ----------------------------------------
# prog_time ()
#    check if actual time fits user program time interval
#
# prog_time (ptime, atime):
#     ptime:	 program time intervall
#     atime:	 actual time
#
# return: True/False if 'ptime' fit's actual time

def prog_time (ptime, atime):
    """prog_time() check if actual time fits user program time interval"""
 
    # a '*' fits always...
    if ptime == '*': return True

    # From: time intervall start
    # From: minutes are optional, set default to :00
    f0 = ptime.split('-')[0] + ':00'
    f  = [int(f0.split(':')[0]), int(f0.split(':')[1])]

    # To: time intervall end
    # To: minutes are optional, set default to :00
    t0 = ptime.split('-')[1] + ':00'
    t  = [int(t0.split(':')[0]), int(t0.split(':')[1])]

    # test actual time interval: From < PTime < To?
    # 1.st test: f < t (means: t < 23:59)
    # 2.nd test: f > t (means: t >= 00:00 -> on next day!)
    if f < t:
        return f <= atime <= t
    else:
        return not (t <= atime <= f)

# ----------------------------------------
# prog_wday()
#     check if weekday is listed in user program
#
# prog_wday (pwday, wday):
#     pwday program weekday
#     wday  actual weekday
#
# return: True/False if 'wday' is listed/not listed

def prog_wday (pwday, wday):
    """prog_wday() check if weekday is listed in user program"""

    # a '*' fits always...
    if pwday == '*': return True

    wd={'MO': 0, 'DI': 1, 'MI': 2, 'DO': 3, 'FR': 4, 'SA': 5, 'SO': 6, \
                 'TU': 1, 'WE': 2, 'TH': 3,                   'SU': 6}

    return wday == wd[pwday.upper()]

# ----------------------------------------
# check_caller_section ()
#     check if call_from is listed in user caller-section
#
# check_caller_section (config, csect, call_from):
#     config:	 config file
#     csect:	 caller-section
#     call_from: caller number
#
# return: True/False if 'call_from' is listed/not listed

def check_caller_section (config, csect, call_from):
    """check_caller_section () check if call_from is listed in callers section"""

    # check all entries in caller section 
    # every entry (item) can be a list of numbers
    # standardise numbers (delete blanks etc.)
    for i in range(len(config.items(csect))):
        for j in config.items(csect)[i][1].split(','):
            if call_from == re.sub('[\s+()-]','',j):
                return True
    return False

# ----------------------------------------
# check_caller()
#    check if 'call_from' is listed in any callers list/section
#
# check_caller (config, callers, call_from):
#     config:	 config file
#     callers:	 list of numbers or sections 
#     call_from: caller number
#
# return: True/False if 'call_from' is listed/not listed

def check_caller (config, callers, call_from):
    """check_caller () check if caller_from matches group entries/section"""

    # a '*' fits always...
    if callers == '*': return True

    # check all entries in group entry (caller numbers)
    # every entry (item) can be a separate section
    # correct format of numbers (delete blanks etc.)
    for i in range(len(callers.split(','))):
        pcaller = re.sub('[\s+()-]', '', callers.split(',')[i])
        if pcaller in config.sections():
            if check_caller_section(config, pcaller, call_from):
                return True
        elif call_from == pcaller:
                return True
    return False

# ----------------------------------------
# prog_active()
#     check if given user program is active
#
# Check if Date/Time/Weekday fits actual date/time
# to see if user program is activ
#
# prog_active (config, dates, times, wdays):
#     config:	 config file
#     dates:	 program dates
#     times:	 program time intervals
#     wdays:	 program week days
#
# return: True/False if programm is active/not active

def prog_active (config, dates, times, wdays):
    """prog_active() check if given user program is active"""

    # get actual date / time
    d = datetime.datetime.now()

    # check the dates in user program
    for i in range(len(dates.split(','))):
        pdate = dates.split(',')[i]
        if pdate in config.sections():
            if check_date_section(config, pdate, [d.day, d.month, d.year]):
                break
        elif check_date(pdate, [d.day, d.month, d.year]):
            break
    # date didn't fit
    else:
        return False
 
    # check the times in user program
    for i in range(len(times.split(','))):
        ptime = times.split(',')[i]
        if prog_time(ptime, [d.hour, d.minute]):
            break
    # time intervals didn't fit
    else:
        return False

    # check the weekdays in user program
    for i in range(len(wdays.split(','))):
        pwday = wdays.split(',')[i]
        if prog_wday(pwday, d.weekday()):
            break
    # weekdays didn't fit
    else:
        return False

    # all tests OK til now
    return True

# ----------------------------------------
# read_prog()
#     read prog[dates, times, weekdays, message, delay, length, callers]
#
# It will search for a valid user program ('prog#') in the user section
# and reads coresponding definitions for
# - delay    the delay of vbox activation
# - message  the specific message to play
# - length   the max. record length
#
# read_prog (config, section, call_from)
#     config:	 config file
#     section:	 section in config file to read
#     call_from: caller number
#
# return: True/False if valid programm found or not
#         @user_prog['delay': xx, 'message': yy, 'length': zz]

def read_prog (config, section, call_from):
    """read_prog(section) read user specific program for vbox"""

    user_prog = {}
    i = 1
    prog = "prog" + str(i)
    while config.has_option(section, prog):
        # progX = [dates, times, weekdays, message, delay, length, callers] 
        p = config.get(section, prog).split()
        if prog_active(config, p[0], p[1], p[2]):
            if check_caller(config, re.sub('[\s+()-]', '', p[6]), call_from):
                user_prog['message'] = p[3]
                user_prog['delay']   = p[4]
                user_prog['length']  = p[5]
                return user_prog
        i += 1
        prog = "prog" + str(i)

    # empty user_prog = False
    return user_prog

# -------------------------------------------------------------------
# main function called by CapiSuite when an incoming call is received
# -------------------------------------------------------------------
#
# It will decide if this call should be accepted, with which service and for
# which user. The real call handling is done in faxIncoming and voiceIncoming.
#
# callIncoming(call,service,call_from,call_to)
#     call	reference to the call. Needed by all capisuite functions
#     service	one of SERVICE_FAXG3, SERVICE_VOICE, SERVICE_OTHER
#     call_from	string containing the number of the calling party
#     call_to	string containing the number of the called party

def callIncoming(call,service,call_from,call_to):
	# read sections in config file
	try:
                locale.setlocale(locale.LC_ALL, 'de_DE')
		config=read_Configfiles()
		userlist=config.sections()
		userlist.remove('GLOBAL')
	        # search for call_to in the user sections
		curr_user=""
		for u in userlist:
			if config.has_option(u,'voice_numbers'):
				numbers=config.get(u,'voice_numbers')
				if (call_to in numbers.split(',') or numbers=="*"):
					if (service==capisuite.SERVICE_VOICE):
						curr_user=u
						curr_service=capisuite.SERVICE_VOICE
						break
					if (service==capisuite.SERVICE_FAXG3):
						curr_user=u
						curr_service=capisuite.SERVICE_FAXG3
						break

			if config.has_option(u,'fax_numbers'):
				numbers=config.get(u,'fax_numbers')
				if (call_to in numbers.split(',') or numbers=="*"):
				 	if (service in (capisuite.SERVICE_FAXG3,capisuite.SERVICE_VOICE)):
						curr_user=u
						curr_service=capisuite.SERVICE_FAXG3
						break

	except IOError,e:
		capisuite.error("Error occured during config file reading: "+e+" Disconnecting...")
		capisuite.reject(call,0x34A9)
		return

        # answer the call with the right service
	if (curr_user==""):
		capisuite.log("call from "+call_from+" to "+call_to+" ignoring",1,call)
		capisuite.reject(call,1)
		return

        # XXX: neobiker's _adv
	try:
		phonebook=cs_helpers.readConfig(configfile_phonebook)
	except IOError,e:
		capisuite.error("Warning: Error occured during phonebook file reading: "+e)

	try:
		if (curr_service==capisuite.SERVICE_VOICE):
                        # XXX: neobiker's _adv
                        user_prog = read_prog(config, curr_user, call_from)
                        if user_prog:
                            delay = user_prog['delay']
                        else:
			    delay=cs_helpers.getOption(config,curr_user,"voice_delay")
                        caller_name = read_phonebook(call_from)
                        called_name = read_phonebook(call_to)
			if (delay==None):
				capisuite.error("voice_delay not found for user "+curr_user+"! -> rejecting call")
				capisuite.reject(call,0x34A9)
				return
			capisuite.log("call from "+caller_name+" to "+called_name+" for "+curr_user+" connecting with voice",1,call)
			capisuite.connect_voice(call,int(delay))
			voiceIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config)
		elif (curr_service==capisuite.SERVICE_FAXG3):
                        caller_name = read_phonebook(call_from)
                        called_name = read_phonebook(call_to)
			faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,0)
	except capisuite.CallGoneError: # catch exceptions from connect_*
		(cause,causeB3)=capisuite.disconnect(call)
		capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)

# -------------------------------------------------------------------
# @brief called by callIncoming when an incoming fax call is received
# -------------------------------------------------------------------
# @param call reference to the call. Needed by all capisuite functions
# @param call_from      string containing the number of the calling party
# @param call_to        string containing the number of the called party
# @param curr_user      name of the user who is responsible for this
# @param config         ConfigParser instance holding the config data
# @param already_connected 1 if we're already connected (that means we must switch to fax mode)

def faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,already_connected):
	try:
		udir=cs_helpers.getOption(config,"","fax_user_dir")
		if (udir==None):
			capisuite.error("global option fax_user_dir not found! -> rejecting call")
			capisuite.reject(call,0x34A9)
			return
		udir=os.path.join(udir,curr_user)+"/"
		if (not os.access(udir,os.F_OK)):
			userdata=pwd.getpwnam(curr_user)
			os.mkdir(udir,0700)
			os.chown(udir,userdata[2],userdata[3])
		if (not os.access(udir+"received/",os.F_OK)):
			userdata=pwd.getpwnam(curr_user)
			os.mkdir(udir+"received/",0700)
			os.chown(udir+"received/",userdata[2],userdata[3])
	except KeyError:
		capisuite.error("user "+curr_user+" is not a valid system user. Disconnecting",call)
		capisuite.reject(call,0x34A9)
		return
	filename="" # assure the variable is defined...
	try:
		stationID=cs_helpers.getOption(config,curr_user,"fax_stationID")
		if (stationID==None):
			capisuite.error("Warning: fax_stationID not found for user "+curr_user+" -> using empty string")
			stationID=""
		headline=cs_helpers.getOption(config,curr_user,"fax_headline","") # empty string is no problem here
		capisuite.log("call from "+caller_name+" to "+called_name+" for "+curr_user+" connecting with fax",1,call)
		if (already_connected):
			faxInfo=capisuite.switch_to_faxG3(call,stationID,headline)
		else:
			faxInfo=capisuite.connect_faxG3(call,stationID,headline,0)
		if (faxInfo!=None and faxInfo[3]==1):
			faxFormat="cff" # color fax
		else:
			faxFormat="sff" # normal b&w fax
		filename=cs_helpers.uniqueName(udir+"received/","fax",faxFormat)
		capisuite.fax_receive(call,filename)
		(cause,causeB3)=capisuite.disconnect(call)
		capisuite.log("connection finished with cause 0x%x,0x%x" % (cause,causeB3),1,call)

	except capisuite.CallGoneError: # catch this here to get the cause info in the mail
		(cause,causeB3)=capisuite.disconnect(call)
		capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)

	if (os.access(filename,os.R_OK)):
		cs_helpers.writeDescription(filename,
		  "call_from=\""+call_from+"\"\ncall_to=\""+call_to+"\"\ntime=\""
		  +time.ctime()+"\"\ncause=\"0x%x/0x%x\"\n" % (cause,causeB3))
		userdata=pwd.getpwnam(curr_user)
		os.chmod(filename,0600)
		os.chown(filename,userdata[2],userdata[3])
		os.chmod(filename[:-3]+"txt",0600)
		os.chown(filename[:-3]+"txt",userdata[2],userdata[3])

		fromaddress=cs_helpers.getOption(config,curr_user,"fax_email_from","")
		if (fromaddress==""):
			fromaddress=curr_user
		mailaddress=cs_helpers.getOption(config,curr_user,"fax_email","")
		if (mailaddress==""):
			mailaddress=curr_user
                action=cs_helpers.getOption(config,curr_user,"fax_action","").lower()
		if (action not in ("mailandsave","saveonly")):
			capisuite.error("Warning: No valid fax_action definition found for user "+curr_user+" -> assuming SaveOnly")
			action="saveonly"
		if (action=="mailandsave"):
                        # XXX: changed Mail text
                        caller_details = ""
                        if (caller_name == call_from):
                            caller_name, caller_details = check_number_online (call_from)
			cs_helpers.sendMIMEMail(fromaddress, mailaddress,
                          "Fax von "+caller_name+" an "+called_name, faxFormat,
			     "Fax Sender: "+caller_name+" ("+call_from+")\n"
			    +"            "+caller_details+"\n"
                            +"Datum:      "+time.strftime("%c")+"\n\n"
			    +"Siehe Anhang.\nDas Fax wurde gespeichert unter: "+filename+"\n",
                          filename)

# ---------------------------------------------------------------------
# @brief called by callIncoming when an incoming voice call is received
# ---------------------------------------------------------------------
# @param call reference to the call. Needed by all capisuite functions
# @param call_from string containing the number of the calling party
# @param call_to string containing the number of the called party
# @param curr_user name of the user who is responsible for this
# @param config ConfigParser instance holding the config data

def voiceIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config):
	try:
		udir=cs_helpers.getOption(config,"","voice_user_dir")
		if (udir==None):
			capisuite.error("global option voice_user_dir not found! -> rejecting call")
			capisuite.reject(call,0x34A9)
			return
		udir=os.path.join(udir,curr_user)+"/"
		if (not os.access(udir,os.F_OK)):
			userdata=pwd.getpwnam(curr_user)
			os.mkdir(udir,0700)
			os.chown(udir,userdata[2],userdata[3])
		if (not os.access(udir+"received/",os.F_OK)):
			userdata=pwd.getpwnam(curr_user)
			os.mkdir(udir+"received/",0700)
			os.chown(udir+"received/",userdata[2],userdata[3])
	except KeyError:
		capisuite.error("user "+curr_user+" is not a valid system user. Disconnecting",call)
		capisuite.reject(call,0x34A9)
		return
	filename=cs_helpers.uniqueName(udir+"received/","voice","la")
	action=cs_helpers.getOption(config,curr_user,"voice_action","").lower()
	if (action not in ("mailandsave","saveonly","none")):
		capisuite.error("Warning: No valid voice_action definition found for user "+curr_user+" -> assuming SaveOnly")
		action="saveonly"
	try:
		capisuite.enable_DTMF(call)
                # XXX: neobiker's _adv
                user_prog = read_prog(config, curr_user, call_from)
                if user_prog:
                    userannouncement = udir + user_prog['message']
                else:
		    userannouncement=udir+cs_helpers.getOption(config,curr_user,"announcement","announcement.la")
		pin=cs_helpers.getOption(config,curr_user,"pin","")
		if (os.access(userannouncement,os.R_OK)):
			capisuite.audio_send(call,userannouncement,1)
		else:
			if (call_to!="-"):
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"anrufbeantworter-von.la"),1)
				cs_helpers.sayNumber(call,call_to,curr_user,config)
			capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-nachricht.la"),1)

		if (action!="none"):
			capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"),1)
                        # XXX: neobiker's _adv
                        if user_prog:
                            length = user_prog['length']
                        else:
			    length=cs_helpers.getOption(config,curr_user,"record_length","60")
			silence_timeout=cs_helpers.getOption(config,curr_user,"record_silence_timeout","5")
			capisuite.audio_receive(call,filename,int(length), int(silence_timeout),1)

		dtmf_list=capisuite.read_DTMF(call,0)
		if (dtmf_list=="X"):
			if (os.access(filename,os.R_OK)):
				os.unlink(filename)
			faxIncoming(call,call_from,caller_name,call_to,called_name,curr_user,config,1)
		elif (dtmf_list!="" and pin!=""):
			dtmf_list+=capisuite.read_DTMF(call,3) # wait 5 seconds for input
			count=1
			while (count<3 and pin!=dtmf_list):  # try again if input was wrong
				capisuite.log("wrong PIN entered...",1,call)
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
				dtmf_list=capisuite.read_DTMF(call,3)
				count+=1
			if (pin==dtmf_list):
				if (os.access(filename,os.R_OK)):
					os.unlink(filename)
				capisuite.log("Starting remote inquiry...",1,call)
				remoteInquiry(call,udir,curr_user,config)

		(cause,causeB3)=capisuite.disconnect(call)
		capisuite.log("connection finished with cause 0x%x,0x%x" % (cause,causeB3),1,call)

	except capisuite.CallGoneError: # catch this here to get the cause info in the mail
		(cause,causeB3)=capisuite.disconnect(call)
		capisuite.log("connection lost with cause 0x%x,0x%x" % (cause,causeB3),1,call)

	if (os.access(filename,os.R_OK)):
		cs_helpers.writeDescription(filename,
		  "call_from=\""+call_from+"\"\ncall_to=\""+call_to+"\"\ntime=\""
		  +time.ctime()+"\"\ncause=\"0x%x/0x%x\"\n" % (cause,causeB3))
		userdata=pwd.getpwnam(curr_user)
		os.chmod(filename,0600)
		os.chown(filename,userdata[2],userdata[3])
		os.chmod(filename[:-2]+"txt",0600)
		os.chown(filename[:-2]+"txt",userdata[2],userdata[3])

		fromaddress=cs_helpers.getOption(config,curr_user,"voice_email_from","")
		if (fromaddress==""):
			fromaddress=curr_user
		mailaddress=cs_helpers.getOption(config,curr_user,"voice_email","")
		if (mailaddress==""):
			mailaddress=curr_user
		if (action=="mailandsave"):
                        # XXX: changed Mail text
                        caller_details = ""
                        if (caller_name == call_from):
                            caller_name, caller_details = check_number_online (call_from)
			cs_helpers.sendMIMEMail(fromaddress, mailaddress,
                          "Nachricht von "+caller_name+" fuer "+called_name, "la",
			     "Anrufer: "+caller_name+" ("+call_from+")\n"
			    +"         "+caller_details+"\n"
                            +"Laenge:  "+str(os.stat(filename)[6]/8/1024)+" Sek.\n"
                            +"Datum:   "+time.strftime("%c")+"\n"
                            +"Nummer:  "+called_name+" ("+call_to+")\n\n"
			    +"Siehe Anhang.\nDas File wurde gespeichert unter: "+filename+"\n",
                          filename)


# -----------------------------------------------------------
# @brief remote inquiry function (uses german wave snippets!)
# -----------------------------------------------------------
# commands for remote inquiry
# delete message - 1
# next message - 4
# last message - 5
# repeat current message - 6
#
# @param call reference to the call. Needed by all capisuite functions
# @param userdir spool_dir of the current_user
# @param curr_user name of the user who is responsible for this
# @param config ConfigParser instance holding the config data
#
def remoteInquiry(call,userdir,curr_user,config):
	import time,fcntl,errno,os
	# acquire lock
	lockfile=open(userdir+"received/inquiry_lock","w")
	try:
		fcntl.lockf(lockfile,fcntl.LOCK_EX | fcntl.LOCK_NB) # only one inquiry at a time!

	except IOError,err: # can't get the lock
		if (err.errno in (errno.EACCES,errno.EAGAIN)):
			capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fernabfrage-aktiv.la"))
			lockfile.close()
			return

	try:
		# read directory contents
		messages=os.listdir(userdir+"received/")
		messages=filter (lambda s: re.match("voice-.*\.la",s),messages)  # only use voice-* files
		messages=map(lambda s: int(re.match("voice-([0-9]+)\.la",s).group(1)),messages) # filter out numbers
		messages.sort()

		# read the number of the message heard last at the last inquiry
		lastinquiry=-1
		if (os.access(userdir+"received/last_inquiry",os.W_OK)):
			lastfile=open(userdir+"received/last_inquiry","r")
			lastinquiry=int(lastfile.readline())
			lastfile.close()

		# sort out old messages
		oldmessages=[]
		i=0
		while (i<len(messages)):
			if (messages[i]<=lastinquiry):
				oldmessages.append(messages[i])
				del messages[i]
			else:
				i+=1

		cs_helpers.sayNumber(call,str(len(messages)),curr_user,config)
		if (len(messages)==1):
			capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachricht.la"),1)
		else:
			capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachrichten.la"),1)

		# menu for record new announcement
		cmd=""
		while (cmd not in ("1","9")):
			if (len(messages)+len(oldmessages)):
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"zum-abhoeren-1.la"),1)
			capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fuer-neue-ansage-9.la"),1)
			cmd=capisuite.read_DTMF(call,0,1)
		if (cmd=="9"):
			newAnnouncement(call,userdir,curr_user,config)
			return

		# start inquiry
		for curr_msgs in (messages,oldmessages):
			cs_helpers.sayNumber(call,str(len(curr_msgs)),curr_user,config)
			if (curr_msgs==messages):
				if (len(curr_msgs)==1):
					capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachricht.la"),1)
				else:
					capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-nachrichten.la"),1)
			else:
				if (len(curr_msgs)==1):
					capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht.la"),1)
				else:
					capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachrichten.la"),1)

			i=0
			while (i<len(curr_msgs)):
				filename=userdir+"received/voice-"+str(curr_msgs[i])+".la"
				descr=cs_helpers.readConfig(filename[:-2]+"txt")
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht.la"),1)
				cs_helpers.sayNumber(call,str(i+1),curr_user,config)
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"von.la"),1)
				cs_helpers.sayNumber(call,descr.get('GLOBAL','call_from'),curr_user,config)
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"fuer.la"),1)
				cs_helpers.sayNumber(call,descr.get('GLOBAL','call_to'),curr_user,config)
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"am.la"),1)
                                locale.setlocale(locale.LC_ALL, 'C')
				calltime=time.strptime(descr.get('GLOBAL','time'))
				cs_helpers.sayNumber(call,str(calltime[2]),curr_user,config)
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"..la"),1)
				cs_helpers.sayNumber(call,str(calltime[1]),curr_user,config)
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"..la"),1)
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"um.la"),1)
				cs_helpers.sayNumber(call,str(calltime[3]),curr_user,config)
				capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"uhr.la"),1)
				cs_helpers.sayNumber(call,str(calltime[4]),curr_user,config)
				capisuite.audio_send(call,filename,1)
				cmd=""
				while (cmd not in ("1","4","5","6")):
					capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"erklaerung.la"),1)
					cmd=capisuite.read_DTMF(call,0,1)
				if (cmd=="1"):
					os.remove(filename)
					os.remove(filename[:-2]+"txt")
					del curr_msgs[i]
					capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"nachricht-geloescht.la"))
				elif (cmd=="4"):
					if (curr_msgs[i]>lastinquiry):
						lastinquiry=curr_msgs[i]
						lastfile=open(userdir+"received/last_inquiry","w")
						lastfile.write(str(curr_msgs[i])+"\n")
						lastfile.close()
					i+=1
				elif (cmd=="5"):
					i-=1
		capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"keine-weiteren-nachrichten.la"))

	finally:
		# unlock
		fcntl.lockf(lockfile,fcntl.LOCK_UN)
		lockfile.close()
		os.unlink(userdir+"received/inquiry_lock")

# ---------------------------------------------------------------------------
# @brief remote inquiry: record new announcement (uses german wave snippets!)
# ---------------------------------------------------------------------------
# @param call reference to the call. Needed by all capisuite functions
# @param userdir spool_dir of the current_user
# @param curr_user name of the user who is responsible for this
# @param config ConfigParser instance holding the config data

def newAnnouncement(call,userdir,curr_user,config):
	capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-neue-ansage-komplett.la"))
	capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
	cmd=""
	while (cmd!="1"):
		capisuite.audio_receive(call,userdir+"announcement-tmp.la",60,3)
		capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"neue-ansage-lautet.la"))
		capisuite.audio_send(call,userdir+"announcement-tmp.la")
		capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"wenn-einverstanden-1.la"))
		cmd=capisuite.read_DTMF(call,0,1)
		if (cmd!="1"):
			capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"bitte-neue-ansage-kurz.la"))
			capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"beep.la"))
	userannouncement=userdir+cs_helpers.getOption(config,curr_user,"announcement","announcement.la")
	os.rename(userdir+"announcement-tmp.la",userannouncement)
	userdata=pwd.getpwnam(curr_user)
	os.chown(userannouncement,userdata[2],userdata[3])

	capisuite.audio_send(call,cs_helpers.getAudio(config,curr_user,"ansage-gespeichert.la"))

#
# History:
#
# $Log: incoming_adv.py,v $
# Revision 1.8  2007/09/10 20:37:00  root
# optimized read_phonebook()
#
# Revision 1.7  2007/09/09 19:24:47  root
# Names now case sensitive
#
# Revision 1.6  2007/09/09 19:08:26  root
# phonebook.conf optional
#
# Revision 1.5  2007/09/09 19:05:26  root
# integrated phonebook sections in capisuite config
#
# Revision 1.4  2007/09/09 16:01:50  root
# added errorhandling and logging in check_number_online ()
#
# Revision 1.3  2007/09/09 15:29:16  root
# added German date format and record length to Email
#
# Revision 1.2  2007/09/09 13:49:40  root
# added phonebook function and reverse lookup online
#
# Revision 1.1  2007/09/09 13:22:42  root
# Initial revision
#
# Revision 1.4  2007/01/23 14:42:11  root
# changed mail text to german and beatified layout
#
# Revision 1.3  2007/01/03 23:27:36  root
# none
#
# Revision 1.2  2007/01/03 23:23:27  root
# First checkin
#
# Revision 1.1  2007/01/03 23:18:13  root
# Initial revision
#
# Revision 1.9.2.1  2003/08/24 12:47:19  gernot
# - faxIncoming tried to reconnect when it was called after a switch from
#   voice to fax mode, which lead to a call abort. Thx to Harald Jansen &
#   Andreas Scholz for reporting!
#
# Revision 1.9  2003/06/27 07:51:09  gernot
# - replaced german umlaut in filename "nachricht-gelscht.la", can cause
#   problems on Redhat, thx to Herbert Hübner for reporting
#
# Revision 1.8  2003/06/16 10:21:05  gernot
# - define filename in any case (thx to Axel Schneck for reporting and
#   analyzing...)
#
# Revision 1.7  2003/05/25 13:38:30  gernot
# - support reception of color fax documents
#
# Revision 1.6  2003/04/10 21:29:51  gernot
# - support empty destination number for incoming calls correctly (austrian
#   telecom does this (sic))
# - core now returns "-" instead of "??" for "no number available" (much nicer
#   in my eyes)
# - new wave file used in remote inquiry for "unknown number"
#
# Revision 1.5  2003/03/20 09:12:42  gernot
# - error checking for reading of configuration improved, many options got
#   optional, others produce senseful error messages now if not found,
#   fixes bug# 531, thx to Dieter Pelzel for reporting
#
# Revision 1.4  2003/03/13 11:08:06  gernot
# - fix remote inquiry locking (should fix bug #534, but doesn't - anyway,
#   this fix is definitely necessary)
# - stricter permissions of saved files and created dirs, fixes #544
# - add "file://" prefix to the path shown in the mails to the user
#
# Revision 1.3  2003/02/21 13:13:34  gernot
# - removed some debug output (oops...)
#
# Revision 1.2  2003/02/21 11:02:17  gernot
# - removed os.setuid() from incoming script
#   -> fixes Bug #527
#
# Revision 1.1.1.1  2003/02/19 08:19:54  gernot
# initial checkin of 0.4
#
# Revision 1.11  2003/02/17 11:13:43  ghillie
# - remoteinquiry supports new and old messages now
#
# Revision 1.10  2003/02/03 14:50:08  ghillie
# - fixed small typo
#
# Revision 1.9  2003/01/31 16:32:41  ghillie
# - support "*" for "all numbers"
# - automatic switch voice->fax when SI says fax
#
# Revision 1.8  2003/01/31 11:24:41  ghillie
# - wrong user handling for more than one users fixed
# - creates user_dir/user and user_dir/user/received now separately as
#   idle.py can also create user_dir/user now
#
# Revision 1.7  2003/01/27 21:57:54  ghillie
# - fax_numbers and voice_numbers may not exist (no fatal error any more)
# - accept missing email option
# - fixed typo
#
# Revision 1.6  2003/01/27 19:24:29  ghillie
# - updated to use new configuration files for fax & answering machine
#
# Revision 1.5  2003/01/19 12:03:27  ghillie
# - use capisuite log functions instead of stdout/stderr
#
# Revision 1.4  2003/01/17 15:09:49  ghillie
# - cs_helpers.sendMail was renamed to sendMIMEMail
#
# Revision 1.3  2003/01/16 12:58:34  ghillie
# - changed DTMF timeout for pin to 3 seconds
# - delete recorded wave if fax or remote inquiry is recognized
# - updates in remoteInquiry: added menu for recording own announcement
# - fixed some typos
# - remoteInquiry: delete description file together with call if requested
# - new function: newAnnouncement
#
# Revision 1.2  2003/01/15 15:55:12  ghillie
# - added exception handler in callIncoming
# - faxIncoming: small typo corrected
# - voiceIncoming & remoteInquiry: updated to new config file system
#
# Revision 1.1  2003/01/13 16:12:58  ghillie
# - renamed from incoming.pyin to incoming.py as all previously processed
#   variables are moved to config and cs_helpers.pyin
#
# Revision 1.4  2002/12/18 14:34:56  ghillie
# - added some informational prints
# - accept voice calls to fax nr
#
# Revision 1.3  2002/12/16 15:04:51  ghillie
# - added missing path prefix to delete routing in remote inquiry
#
# Revision 1.2  2002/12/16 13:09:25  ghillie
# - added some comments about the conf_* vars
# - added conf_wavedir
# - added support for B3 cause now returned by disconnect()
# - corrected some dir entries to work in installed system
#
# Revision 1.1  2002/12/14 13:53:18  ghillie
# - idle.py and incoming.py are now auto-created from *.pyin
#
# Revision 1.4  2002/12/11 12:58:05  ghillie
# - read return value from disconnect()
# - added disconnect() to exception handler
#
# Revision 1.3  2002/12/09 15:18:35  ghillie
# - added disconnect() in exception handler
#
# Revision 1.2  2002/12/02 21:30:42  ghillie
# fixed some minor typos
#
# Revision 1.1  2002/12/02 21:15:55  ghillie
# - moved scripts to own directory
# - added remote-connect script to repository
#
# Revision 1.20  2002/12/02 20:59:44  ghillie
# another typo :-|
#
# Revision 1.19  2002/12/02 20:54:07  ghillie
# fixed small typo
#
# Revision 1.18  2002/12/02 16:51:32  ghillie
# nearly complete new script, supports answering machine, fax receiving and remote inquiry now
#
# Revision 1.17  2002/11/29 16:28:43  ghillie
# - updated syntax (connect_telephony -> connect_voice)
#
# Revision 1.16  2002/11/29 11:09:04  ghillie
# renamed CapiCom to CapiSuite (name conflict with MS crypto API :-( )
#
# Revision 1.15  2002/11/25 11:43:43  ghillie
# updated to new syntax
#
# Revision 1.14  2002/11/23 16:16:17  ghillie
# moved switch2fax after audio_receive()
#
# Revision 1.13  2002/11/22 15:48:58  ghillie
# renamed pcallcontrol module to capicom
#
# Revision 1.12  2002/11/22 15:02:39  ghillie
# - added automatic switch between speech and fax
# - some comments added
#
# Revision 1.11  2002/11/19 15:57:18  ghillie
# - Added missing throw() declarations
# - phew. Added error handling. All exceptions are caught now.
#
# Revision 1.10  2002/11/18 12:32:36  ghillie
# - callIncoming lives now in __main__, not necessarily in pcallcontrol any more
# - added some comments and header
#

Zurück zu CapiSuite

Zurück zum Portal