1#!/usr/bin/env python
2
3# This script speaks the incoming caller ID for the SIP client Twinkle
4# The following programs are needed: espeak, ffmpeg and sox, mpc is optional
5# aptitude install ffmpeg espeak sox mpc
6# Further information about Twinkle scripts can be found at
7# http://mfnboer.home.xs4all.nl/twinkle/manual.html#profile_scripts
8
9import os, subprocess, sys, re
10import config
11
12def get_caller_id(from_hdr):
13    caller_id = from_hdr[from_hdr.find(":")+1:from_hdr.find("@")]
14    # remove all non digits from caller id
15    caller_id = re.sub("\D", "", caller_id)
16    # remove two digit country identification if present
17    if not caller_id.startswith("0"):
18        return caller_id[2:]
19    return caller_id
20
21def caller_from_addressbook(caller_id):
22    try:
23        callers = subprocess.check_output([config.khard_exe, "phone", "--parsable", caller_id]).strip()
24    except subprocess.CalledProcessError:
25        return caller_id
26    if len(callers.split("\n")) == 1:
27        return callers.split("\t")[1]
28    else:
29        # the contact contains multiple phone numbers and we have to obtain the right phone label
30        regexp = re.compile(caller_id, re.IGNORECASE)
31        for entry in callers.split("\n"):
32            if regexp.search(re.sub("\D", "", entry.split("\t")[0])) != None:
33                return "%s (%s)" % (entry.split("\t")[1], entry.split("\t")[2])
34        return callers.split("\n")[0].split("\t")[1]
35
36def create_ringtone(caller_id):
37    if os.path.exists(config.new_ringtone) == True:
38        os.remove(config.new_ringtone)
39    if config.language == "de":
40        subprocess.call(["espeak", "-v", "de", "-s", "300", "-w", config.tmp_mono_file, caller_id])
41    else:
42        subprocess.call(["espeak", "-v", "en-us", "-s", "300", "-w", config.tmp_mono_file, caller_id])
43    subprocess.call(["ffmpeg", "-i", config.tmp_mono_file, "-ar", "48000", "-ac", "2", "-y", config.tmp_file_stereo],
44            stdout=open('/dev/null', 'w'), stderr=open('/dev/null', 'w'))
45    subprocess.call(["sox", config.constant_ringtone_segment, config.tmp_file_stereo, config.new_ringtone])
46
47
48# main part of the script
49if os.path.exists(config.constant_ringtone_segment) == False:
50    print("The constant part of the ringtone file is missing. Create the sounds folder in your twinkle config and put a wav file in it")
51    sys.exit(1)
52
53# pause the music playback
54# I use a MPD server for playing music so I pause it with the client MPC
55# You can disable that in the config.py file
56if config.stop_music:
57    mpc_output = subprocess.check_output(["mpc", "-h", config.mpd_host, "-p", str(config.mpd_port), "status"])
58    if "playing" in mpc_output:
59        subprocess.call(["mpc", "-h", config.mpd_host, "-p", str(config.mpd_port), "pause"])
60        music_tmp_file = open(config.mpd_lockfile, "w")
61        music_tmp_file.close()
62
63if "SIP_FROM" in os.environ:
64    from_hdr = os.environ["SIP_FROM"]
65    # parse the caller ID of the string
66    caller_id = get_caller_id(from_hdr)
67    # look into the addressbook
68    if caller_id != "":
69        caller_id = caller_from_addressbook(caller_id)
70    else:
71        caller_id = "anonymous"
72    # create the ringtone
73    if config.language == "de":
74        create_ringtone("Anruf von " + caller_id)
75    else:
76        create_ringtone("Call from " + caller_id)
77    # save the caller id for later use
78    with open(config.caller_id_filename, "w") as caller_id_file:
79        caller_id_file.write(caller_id)
80    # if the file creation was successful and the file exists, tell twinkle to use it as the ringtone
81    # else do nothing and play the standard ringtone
82    if os.path.exists(config.new_ringtone) == True:
83        print("ringtone=" + config.new_ringtone)
84sys.exit()
85