# Linux Fax Stack Setup (HylaFax & SIP) Linux Fax Stack using Hylafax and t38modem. ***THIS GUIDE IS WIP*** This guide was created using information from the opalvoip wiki (http://wiki.opalvoip.org/index.php?n=Main.HomePage) ## Software stack ### ptlib (legacy) library for doing a little bit of everything. ### Opal Voice codec used by e.g. mumble. ### t38modem Emulates a serial modem from SIP connection ### HylaFax Enterprise grade software, managing physical and emulated modems. Has some problems: https://github.com/lexbailey/compilerfax/blob/main/hylafax_is_broken ## Operating Systems Unfortunately this software stack uses a lot of legacy software. Because of this, this guide was only tested on specific software versions ### Debian 12 Bookworm For Debian 12, we'll only install dependencies which are hard requirements. For this guide we'll use ptlib 2.18.6 and opal 3.18.6. #### Installing Requirements First we'll need some packages ```bash apt-get install build-essential git wget pkg-config libssl-dev libsrtp2-dev libspandsp-dev -y ``` #### Download sourcecode Versions: - libpt (2.18.6) https://sourceforge.net/projects/opalvoip/files/v3.18 Cygni/Stable 6/ - opal (3.18.6) https://sourceforge.net/projects/opalvoip/files/v3.18 Cygni/Stable 6/ - t38mdem (4.6.2) https://github.com/hehol/t38modem/releases/tag/4.6.2 #### ptlib ```bash ./configure make make install ``` #### opal ```bash ./configure make -j5 make runtest make install ``` #### t38modem If you are getting an error about `-1` not being able to be casted to a `long unsigned int` due to `-Wnarrowing` inside `dle.cxx`, you can add `-Wno-narrowing` after the `CPPFLAGS` in the Makefile to disable this error ```bash git clone https://github.com/hehol/t38modem cd t38modem make ``` If running the t38modem executable, you should run these commands ```bash cp /usr/local/lib/libpt.so.2.18.6 /lib cp /usr/local/lib/libopal.so.3.18.6 /lib ``` To install t38modem run ```bash cp ./t38modem /usr/local/bin ``` ### Ubuntu 20.04 LTS Was tested on Ubuntu 20.04 LTS VM (VirtualBox, LXC?) You can relies heavily on http://wiki.opalvoip.org/index.php?n=Main.HomePage Versions: - libpt (2.18.6) https://sourceforge.net/projects/opalvoip/files/v3.18 Cygni/Stable 6/ - opal (3.18.6) https://sourceforge.net/projects/opalvoip/files/v3.18 Cygni/Stable 6/ - t38mdem (4.6.2) https://github.com/hehol/t38modem/releases/tag/4.6.2 Follow http://wiki.opalvoip.org/index.php?n=Main.BuildingPTLibUnix and http://wiki.opalvoip.org/index.php?n=Main.HomePage **but** - Don't use `libavformat-dev` -> Compile error in Opal - Configure script needs `pkg-config` to be installed to find ptlib install - On SourceForge downloads `.tar.bz2` files for *nix #### Build PTLib - Version 2.18.6 - Dependency of Opal, bundled with Opal source code (SourceForge) - http://wiki.opalvoip.org/index.php?n=Main.BuildingPTLibUnix - **TODO: Remove dependencies, most of them are optional** ```bash sudo apt install \ g++ git make autoconf libpcap-dev libexpat1-dev libssl-dev libsasl2-dev libldap2-dev \ unixodbc-dev liblua5.3-dev libv8-dev libncurses-dev libsdl2-dev \ libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev pkg-config ``` - PTLib will be installed in the `/usr/local` tree -> set `PKG_CONFIG_PATH` to be findable (compile time) - Set `LD_LIBRARY_PATH` to find PTLib at compile and run time - Set `PTLIBPLUGINDIR` (compile and run time) - (To compile as static library: `./configure --disable-shared`) ```bash export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig # compile time export LD_LIBRARY_PATH=/usr/local/lib # compile and run time export PTLIBPLUGINDIR=/usr/local/lib/ptlib-x.y.z # compile and run time cd ptlib-x.y.z/ ./configure make sudo make install ``` #### Build Opal - Version 3.18.6 - http://wiki.opalvoip.org/index.php?n=Main.BuildingOpalUnix - Dont use `libavcodec-dev` -> Compile error - **TODO: Remove dependencies, most of them are optional** ```bash sudo apt install \ libsrtp2-dev libgsm1-dev libspeex-dev libopus-dev libx264-dev \ libvpx-dev libtheora-dev libspandsp-dev dahdi ``` - (To compile as static library: `./configure --disable-shared`) ```bash export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig # compile time export LD_LIBRARY_PATH=/usr/local/lib # compile and run time export PTLIBPLUGINDIR=/usr/local/lib/ptlib-x.y.z:/usr/local/lib/opal-a.b.c # compile and run time cd opal-a.b.c/ ./configure make sudo make install ``` #### t38modem - https://github.com/hehol/t38modem, Version 4.6.2 - https://github.com/T38Modem/t38modem could also be used, but seems to be not as maintained - If you are getting error about `-1` not being able to be casted to a `long unsigned int` due to `-Wnarrowing` inside `dle.cxx`, you can add `-Wno-narrowing` after the `CPPFLAGS` in the Makefile to disable this error ```bash cd t38modem-x.y.z/ make sudo cp ./t38modem /usr/local/bin ``` - t38modem can only find Opal if `LD_LIBRARY_PATH` and `PTLIBPLUGINDIR` are environment variables to the program
## Configuring t38modem ### Init script - To automatically start t38modem, you need to create Systemd services, as well as start and stop scripts - script is adapted from https://web.archive.org/web/20111231021042/https://www.foriamroot.org/hylafax-6-0-debian-or-ubuntu-t38modem-1-0-asterisk-1-6/ First we'll create the configuration directory under `/etc` using `sudo mkdir -p /etc/t38modem/bin/`. Then create a file named `/etc/t38modem/bin/run` using the following content. It will be the script to manage the current status of t38modem. ```bash #!/bin/bash # /etc/t38modem/bin/run export LD_LIBRARY_PATH=/usr/local/lib export PTLIBPLUGINDIR=/usr/local/lib/ptlib-2.18.6:/usr/local/lib/opal-3.18.6 # Adjust lib versions! if [ -z "${1}" ]; then >&2 echo "Config file path not set! Aborting..." exit 1 fi . "${1}" command="t38modem --ptty +/dev/ttyT38-${T38MODEM_PTTY_ID} --sip-proxy ${T38MODEM_SIP_USERNAME}:${T38MODEM_SIP_PASSWORD}@${T38MODEM_SIP_SERVER} --sip-register ${T38MODEM_SIP_USERNAME}@${T38MODEM_SIP_SERVER},${T38MODEM_SIP_PASSWORD} --sip-listen udp\$:5060 --stun ${T38MODEM_STUN_SERVER} --route t38:.*=sip:@${T38MODEM_SIP_SERVER} --route sip:.*=t38:" if [ "$T38MODEM_DISABLE_T38" = true ]; then command="${command} --disable-t38-mode --audio" fi exec $command ``` And then we'll have to make it executable like this. ```bash sudo chmod +x /etc/t38modem/bin/run ``` #### Quick script overview - Using this script, it is possible to start t38modem with a config file as an argument - `-t` enables debugging - More `t`'s is deeper debugging (e.g. `-tttt`) - If t38modem says it was able to create the virtual modem but `/dev/ttyT38-1` is not available, you do not have sufficient permissions - Configuration is specified in `/etc/t38modem/config/XX` ### Create the configuration file Create a file using the following contents at `/etc/t38modem/config/XX`. ```bash # /etc/t38modem/config T38MODEM_PTTY_ID="XX" # /dev/ttyT38-XX T38MODEM_SIP_USERNAME="USERNAME" T38MODEM_SIP_PASSWORD="PASSWORD" T38MODEM_SIP_SERVER="voip.example.com" T38MODEM_STUN_SERVER="stun.example.com:1234" T38MODEM_DISABLE_T38=false # enable if your SIP server prefers G.711 ``` You should give only root access to the config. ```bash sudo chown root:root -R /etc/t38modem/config/ sudo chmod 700 -R /etc/t38modem/config/ ``` ### Testing your setup - You can now communicate with your modem `/dev/ttyT38-XX`, just as if it was a real Hayes compatible modem (https://www.computerhope.com/atcom.htm) - Test using minicom, configure it to point to our modem. Each command is initiated by a Return - Dial a number: - Get the attention of the modem: `at` -> `OK` - Dial: `atd[NUMBER]`, replace '[NUMBER]' using the number, you want to call - If all works correctly you should be able to answer the phone and hear a single beep - Answer a call: - Get the attention of the modem: `at` -> `OK` - *Call the number of your modem* - -> `RING` - Answer the call: `ata` -> `CONNECT` - You should now hear your modem "talking" to you - Pitfalls: - If you are already connected to your SIP server it may not give proper response codes. My provider returns `500 Internal Server Error` - Test the command before running the init script! - Do not try to used `ATO` to switch to a data connection, t38modem will return `ERROR`. Thats hardcoded in `pmodeme.cxx` in `void ModemEngineBody::HandleCmdRest(PString &resp)`. Dont let that hodld you back. ### systemd service If you want to run a fax server, you can create a systemd service template to let your emulated fax modem start automatically on system boot. To do this you have to copy paste the following into `/etc/systemd/system/t38modem@.service`. ```toml # /etc/systemd/system/t38modem@.service [Unit] Description=t38modem After=network-online.target Wants=network-online.target AssertPathExists=/etc/t38modem/config/%i [Service] Type=simple Restart=always ExecStart=/etc/t38modem/bin/run /etc/t38modem/config/%i [Install] WantedBy=multi-user.target ``` Enable and start the service for your config file (`/etc/t38modem/config/XX`) using the following commands: ```bash sudo systemctl daemon-reload sudo systemctl enable t38modem@XX.service sudo systemctl start t38modem@XX.service ```
## Install HylaFax These instructions were tested using Hylafax version 6 - `sudo apt install hylafax-server` - Set Postfix Configuration to **Local only** in dpkg-reconfigure menu ## Configure HylaFax - Run `sudo faxsetup` - Add new modem - Enter correct modem port (`ttyT38-XX`) - Enter dialing configuration (see Dial Rules for Eventphone EPVPN) - Accept default configuration for everything else - It should automatically detect it to be a `T38FAX` modem - Look at `man sendfax` to send faxes - `fgetty` (the service to receive faxes) should be enabled automatically - Bugs: - If you get some protocol errors, just let HylaFax do its thing. Fax over SIP is not stable at all in my experience - If your call is cleared because it `Could not find common media capabilities` t38modem may not have been able to load PTLib or Opal. Check your library paths! ### Cron - Alias your fax admin account as `FaxMaster` (`/etc/aliases`) ```bash # /etc/aliases # [...] # HylaFax FaxMaster: $USER # replace with fax admin account ``` - Add standard tasks to crontab file: `crontab -e` ```bash 0 * * * * /usr/sbin/faxqclean 25 23 * * * sh /usr/sbin/faxcron | mail FaxMaster ``` ### Dial Rules for Eventphone EPVPN If you want to use Eventhone EPVPN, you can apply the following dial settings onto your modems. You can find the config at `/etc/hylafax/config.ttyT38-1`. In this case `ttyT38-1` is the modem block device. ``` # /etc/hylafax/config.ttyXX CountryCode: 1 AreaCode: 999 ``` ## FaxDispatch - https://legacy.hylafax.org/content/Advanced_Permissions_with_6.0 # TODO - **TODO: Test on Debian / RockPi / RaspberryPi** - **TODO: Test on Eventphone Infra** - **TODO: Package t38modem with service files and config**