baresip/baresip-1.1.0-fritzbox2baresip.patch

134 lines
5.1 KiB
Diff
Raw Normal View History

From b0669e837daefeaff482a04d6dc15df1c6ebc0f0 Mon Sep 17 00:00:00 2001
From: Robert Scheck <robert-scheck@users.noreply.github.com>
Date: Sat, 24 Apr 2021 09:22:26 +0200
Subject: [PATCH] Convert FRITZ!Box XML phone book into Baresip contacts
(#1382)
---
.github/workflows/tools.yml | 14 ++++++
tools/fritzbox2baresip | 94 +++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)
create mode 100644 .github/workflows/tools.yml
create mode 100755 tools/fritzbox2baresip
diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml
new file mode 100644
index 000000000..6cc62d606
--- /dev/null
+++ b/.github/workflows/tools.yml
@@ -0,0 +1,14 @@
+name: Tools
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: pylint
+ uses: cclauss/GitHub-Action-for-pylint@0.7.0
+ with:
+ args: "pylint tools/fritzbox2baresip"
diff --git a/tools/fritzbox2baresip b/tools/fritzbox2baresip
new file mode 100755
index 000000000..cba91630f
--- /dev/null
+++ b/tools/fritzbox2baresip
@@ -0,0 +1,94 @@
+#!/usr/bin/python3
+#
+# Copyright (c) 2021, Robert Scheck <robert@fedoraproject.org>
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+"""Convert FRITZ!Box XML phone book into Baresip contacts"""
+
+import sys
+import xml.etree.ElementTree
+
+def fail(msg):
+ """Print failure message to STDERR and end with non-zero exit code"""
+ print(msg, file=sys.stderr)
+ sys.exit(1)
+
+def usage():
+ """Handle mandatory and optional command line arguments"""
+ if len(sys.argv) not in range(2, 5):
+ fail(f"Usage: {sys.argv[0]} <FRITZ!Box XML> [<Baresip contacts>] "
+ "[<FRITZ!Box IP>]")
+
+ return sys.argv[1], \
+ sys.argv[2] if len(sys.argv) >= 3 else None, \
+ f"@{sys.argv[3]}" if len(sys.argv) == 4 else "@fritz.box"
+
+def convert(entries, src, host="@fritz.box"):
+ """Convert FRITZ!Box XML phone book into Baresip contacts"""
+ try:
+ types = {'home': '\N{house building}',
+ 'work': '\N{briefcase}',
+ 'mobile': '\N{mobile phone}'}
+ tree = xml.etree.ElementTree.parse(src)
+ for contact in tree.iter('contact'):
+ realname = contact.findtext("./person/realName")
+ for ntype in [*types]:
+ number = contact.findtext("./telephony/number"
+ f"[@type='{ntype}']")
+ if number is not None:
+ entries.append(f"{types[ntype]} {realname} <sip:{number}"
+ f"{'' if '@' in number else host}>")
+ except FileNotFoundError:
+ fail(f"Error: File '{src}' does not exist or can not be read!")
+ except xml.etree.ElementTree.ParseError:
+ fail(f"Error: File '{src}' is no FRITZ!Box XML phone book or damaged!")
+
+def write(entries, src=None, dst=None):
+ """Write Baresip contacts to file or STDOUT"""
+ try:
+ dst = None if dst == '-' else dst
+ sys.stdout.close = lambda: None
+ with (open(dst, 'w') if dst else sys.stdout) as contacts:
+ contacts.write("# SIP contacts\n")
+ contacts.write("# Source: "
+ f"{'(unknown)' if src is None else src }\n")
+ contacts.write('\n'.join(entries) + '\n')
+ except PermissionError:
+ fail(f"Error: File '{dst}' can not be created or written to!")
+
+def main():
+ """Handle command line arguments, convert phone book and write result"""
+ entries = []
+ src, dst, host = usage()
+ convert(entries, src, host)
+ write(entries, src, dst)
+
+if __name__ == "__main__":
+ main()