Incoming adv: Unterschied zwischen den Versionen
Zur Navigation springen
Zur Suche springen
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
| (3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 6: | Zeile 6: | ||
# -------------------------------------------------------- | # -------------------------------------------------------- | ||
# copyright : (c) 2007 by Neobiker | # copyright : (c) 2007 by Neobiker | ||
# Version : $Revision: 1. | # Version : $Revision: 1.2 $ | ||
# Date : $Date: | # Date : $Date: 2009/04/22 18:14:20 $ | ||
# | # | ||
# original script : incoming.py | # original script : incoming.py | ||
| 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 | |||
config=ConfigParser.ConfigParser() | |||
if (file==""): | |||
config.readfp(open(configfile_fax)) | |||
config.readfp(open(configfile_voice)) | |||
try: | try: | ||
config.readfp(open(configfile_phonebook)) | |||
except: | except: | ||
pass | 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 () | # read_phonebook () | ||
| Zeile 62: | Zeile 62: | ||
# | # | ||
# read_phonebook (number): | # read_phonebook (number): | ||
# number: | # number: tel number | ||
# | # | ||
# return: name | # return: name | ||
| Zeile 85: | Zeile 85: | ||
fd.close() | fd.close() | ||
return number | return number | ||
# ---------------------------------------- | |||
# get_fax_pages () | |||
# get number of pages of the fax file | |||
# | |||
# get_fax_pages (fax): | |||
# fax: sff fax file | |||
# | |||
# return: pages | |||
def get_fax_pages (fax, call): | |||
"""get_fax_pages () get fax pages""" | |||
pages = "" | |||
cmd = "sfftobmp -t " + fax + " -o /dev/null 2>&1 | grep 'page(s)'" | |||
try: | |||
pages = commands.getoutput(cmd).split()[5] | |||
except: | |||
capisuite.log("Error: get_fax_pages() failed",1,call) | |||
capisuite.log("Error: "+cmd+" failed",1,call) | |||
return pages | |||
# ---------------------------------------- | # ---------------------------------------- | ||
| Zeile 95: | Zeile 116: | ||
# return: name, details | # return: name, details | ||
def check_number_online (number): | def check_number_online (number,call): | ||
"""check_number_online () check if number if listed in online phonebook""" | """check_number_online () check if number if listed in online phonebook""" | ||
| Zeile 103: | Zeile 124: | ||
number, name, details = commands.getoutput(cmd).split("|") | number, name, details = commands.getoutput(cmd).split("|") | ||
except: | except: | ||
capisuite.log("Error: check_number_online() failed",1,call) | |||
capisuite.log("Error: "+cmd+" failed",1,call) | capisuite.log("Error: "+cmd+" failed",1,call) | ||
return name, details | return name, details | ||
| Zeile 108: | Zeile 130: | ||
# ---------------------------------------- | # ---------------------------------------- | ||
# 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 150: | ||
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 158: | ||
# | # | ||
# check_date_section (config, dsect, adate): | # check_date_section (config, dsect, adate): | ||
# config: | # config: config file | ||
# dsect: | # dsect: date section list of dates | ||
# adate: | # adate: actual date | ||
# | # | ||
# return: True/False if 'adate' is listed/not listed | # return: True/False if 'adate' is listed/not listed | ||
| Zeile 145: | Zeile 167: | ||
"""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 180: | ||
# | # | ||
# prog_time (ptime, atime): | # prog_time (ptime, atime): | ||
# ptime: | # ptime: program time intervall | ||
# atime: | # atime: actual time | ||
# | # | ||
# return: True/False if 'ptime' fit's actual time | # return: True/False if 'ptime' fit's actual time | ||
| Zeile 165: | Zeile 187: | ||
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 235: | ||
# | # | ||
# check_caller_section (config, csect, call_from): | # check_caller_section (config, csect, call_from): | ||
# config: | # config: config file | ||
# csect: | # csect: caller-section | ||
# call_from: caller number | # call_from: caller number | ||
# | # | ||
| Zeile 222: | Zeile 244: | ||
"""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 258: | ||
# | # | ||
# check_caller (config, callers, call_from): | # check_caller (config, callers, call_from): | ||
# config: | # config: config file | ||
# callers: | # callers: list of numbers or sections | ||
# call_from: caller number | # call_from: caller number | ||
# | # | ||
| Zeile 268: | Zeile 290: | ||
# | # | ||
# prog_active (config, dates, times, wdays): | # prog_active (config, dates, times, wdays): | ||
# config: | # config: config file | ||
# dates: | # dates: program dates | ||
# times: | # times: program time intervals | ||
# wdays: | # 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 314: | ||
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 347: | ||
# | # | ||
# read_prog (config, section, call_from) | # read_prog (config, section, call_from) | ||
# config: | # config: config file | ||
# section: | # section: section in config file to read | ||
# call_from: caller number | # call_from: caller number | ||
# | # | ||
| Zeile 339: | Zeile 361: | ||
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 383: | ||
# | # | ||
# 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 | |||
try: | |||
locale.setlocale(locale.LC_ALL, 'de_DE') | 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 | # 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 | # 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 | # 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 442: | ||
delay = user_prog['delay'] | delay = user_prog['delay'] | ||
else: | else: | ||
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): | |||
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) | 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) | |||
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) | |||
# ------------------------------------------------------------------- | # ------------------------------------------------------------------- | ||
| Zeile 449: | Zeile 471: | ||
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: | |||
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() | 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 | # 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,call) | ||
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" | |||
+" "+caller_details+"\n" | |||
+"Datum: "+time.strftime("%c")+"\n\n" | +"Datum: "+time.strftime("%c")+"\n" | ||
+"Seiten: "+get_fax_pages(filename,call)+"\n\n" | |||
+"Siehe Anhang.\nDas Fax wurde gespeichert unter: "+filename+"\n", | |||
filename) | filename) | ||
| Zeile 536: | Zeile 559: | ||
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: | |||
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 | # 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 590: | ||
userannouncement = udir + user_prog['message'] | userannouncement = udir + user_prog['message'] | ||
else: | 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 | # 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") | |||
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 | # 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,call) | ||
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" | |||
+" "+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", | |||
filename) | filename) | ||
| Zeile 660: | Zeile 683: | ||
# | # | ||
def remoteInquiry(call,userdir,curr_user,config): | 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') | 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") | |||
# --------------------------------------------------------------------------- | # --------------------------------------------------------------------------- | ||
| Zeile 784: | Zeile 807: | ||
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,"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")) | |||
# | # | ||
| Zeile 807: | Zeile 830: | ||
# | # | ||
# $Log: incoming_adv.py,v $ | # $Log: incoming_adv.py,v $ | ||
# Revision 1.2 2009/04/22 18:14:20 root | |||
# added get_fax_pages() | |||
# | |||
# Revision 1.1 2008/11/05 15:42:59 root | |||
# Initial revision | |||
# | |||
# Revision 1.9 2008/04/26 09:45:29 root | |||
# stripped old RCS comments | |||
# | |||
# 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() | ||
| Zeile 842: | Zeile 874: | ||
# Revision 1.1 2007/01/03 23:18:13 root | # Revision 1.1 2007/01/03 23:18:13 root | ||
# Initial revision | # Initial revision | ||
# ... removed old comments | |||
# | # | ||
# Revision 1.9.2.1 2003/08/24 12:47:19 gernot | # Revision 1.9.2.1 2003/08/24 12:47:19 gernot | ||
| Zeile 847: | Zeile 880: | ||
# voice to fax mode, which lead to a call abort. Thx to Harald Jansen & | # voice to fax mode, which lead to a call abort. Thx to Harald Jansen & | ||
# Andreas Scholz for reporting! | # Andreas Scholz for reporting! | ||
# | # ... | ||
</pre> | </pre> | ||
Aktuelle Version vom 22. April 2009, 19:36 Uhr
File: incoming_adv.py
# incoming_adv.py - advanced incoming script for capisuite
# --------------------------------------------------------
# copyright : (c) 2007 by Neobiker
# Version : $Revision: 1.2 $
# Date : $Date: 2009/04/22 18:14:20 $
#
# 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
# ----------------------------------------
# get_fax_pages ()
# get number of pages of the fax file
#
# get_fax_pages (fax):
# fax: sff fax file
#
# return: pages
def get_fax_pages (fax, call):
"""get_fax_pages () get fax pages"""
pages = ""
cmd = "sfftobmp -t " + fax + " -o /dev/null 2>&1 | grep 'page(s)'"
try:
pages = commands.getoutput(cmd).split()[5]
except:
capisuite.log("Error: get_fax_pages() failed",1,call)
capisuite.log("Error: "+cmd+" failed",1,call)
return pages
# ----------------------------------------
# check_number_online ()
# online reverse lookup
#
# check_number_online (number):
# number: tel number
#
# return: name, details
def check_number_online (number,call):
"""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: check_number_online() failed",1,call)
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,call)
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"
+"Seiten: "+get_fax_pages(filename,call)+"\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,call)
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.2 2009/04/22 18:14:20 root
# added get_fax_pages()
#
# Revision 1.1 2008/11/05 15:42:59 root
# Initial revision
#
# Revision 1.9 2008/04/26 09:45:29 root
# stripped old RCS comments
#
# 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
# ... removed old comments
#
# 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!
# ...