コマンドラインでFAX送信 on macOS

# 中身はともかくとにかく送信したい

``sh sendfax.sh 0312345678 sample.pdf``
と叩けば送信されます。macOS sierraで動いているシェルスクリプトです。プリンタ複合機はEPSON PX-M7050F

```sh:sendfax.sh
#!/bin/sh
#
# Usage: sendfax [-r Resolution] PHONENUMBER file
#
# Arguments:
#   PHONENUMBER     0123456789

TAG=$(basename $0)
logger -is -t $TAG "launched. "$*
absolute_dir=$(cd $(dirname $0) && pwd)
export LANG=c
export LC_ALL=c

PDFINFO=/usr/local/bin/pdfinfo
PRINTQUEUE=FAX
PPD=/etc/cups/ppd/${PRINTQUEUE}.ppd

##### GET Resolution INFO FROM PPD
function getresolution {
IFS_bak=$IFS
IFS=$'\n'
KEY=Resolution
TEMP=$(sed -n -e "/\*OpenUI \*${KEY}/,/\*CloseUI: \*${KEY}/p" $PPD|sed -n -e "s/^.${KEY}[[:cntrl:]]*\(.*\):.*/\1/p")
for val in $TEMP
do
    echo $val|sed -e "s/\(.*\)\/\(.*\)/	\2		\1/"
done
IFS=$IFS_bak
}

function usage {
    cat <<-EOF
    $(basename ${0}) is a tool for send fax by EPSON All-In-One Printer
    Usage:
        $(basename ${0}) [-r Resolution] PHONENUMBER file
    Arguments:
        PHONENUMBER     0123456789
    Resolution:
EOF
getresolution
exit 1
}

##### DPI
#com.epson.ijfax.EPFAXResolution=
#Resolution=
resolution=203x196dpi
while getopts r: OPT
do
	case $OPT in
		"r")
            resolution=$OPTARG
		;;
	esac
done
shift $(($OPTIND - 1))

##### VERIFY NUMBER OF ARGV
if [ $# -ne 2 ]
then
    usage
fi
number=$(echo $1|tr -cd '[:digit:]')
file=$2

##### GET PageSize INFO FROM PPD
KEY=PageSize
TEMP="$(sed -n -e "/\*OpenUI \*${KEY}/,/\*CloseUI: \*${KEY}/p" $PPD|sed -n -e "s/^.${KEY}[[:cntrl:]]*\(.*\):.*/\1/p"|xargs -0)"
PageSize=$TEMP

pages=$($PDFINFO "$file"|grep -e '^Pages:'|grep -o '[0-9]\+')
TEMP=($($PDFINFO -f 1 -l $pages "$file"|sed -Ene '/^Page.*size/s/.*size:[^0-9]*([0-9.]+) x ([0-9.]+).*/\1 \2/p'|sort -gk1,1 -gk2,2|tail -1))
size=($(for v in "${TEMP[@]}"; do echo "$v"; done|sort -n))
short=${size[0]%.*}
long=${size[1]%.*}

### PaperDimension
### A4      "595 842 "
### Letter  "612 792 " 
### Legal   "612 1008 "
### B4      "729 1032 "
### Ledger  "792 1224 "
### A3      "842 1191 "
if   [ $short -le 595 -a $long -le 842 -a "$(echo $PageSize|grep -o 'A4')" = A4 ]
then
    media=A4
elif [ $short -le 612 -a $long -le 792 -a "$(echo $PageSize|grep -o 'Letter')" = Letter ]
then
    media=Letter
elif [ $short -le 612 -a $long -le 1008 -a "$(echo $PageSize|grep -o 'Legal')" = Legal ]
then
    media=Legal
elif [ $short -le 729 -a $long -le 1032 -a "$(echo $PageSize|grep -o 'B4')" = B4 ]
then
    media=B4
elif [ $short -le 792 -a $long -le 1224 -a "$(echo $PageSize|grep -o 'Ledger')" = Ledger ]
then
    media=Ledger
elif [ $short -le 842 -a $long -le 1191 -a "$(echo $PageSize|grep -o 'A3')" = A3 ]
then
    media=A3
else
    media=A4 ### DEFAULT
fi

##### MAKE OPTIONS
options="-ofit-to-page"
options=${options}" -o com.epson.ijfax.DialingPrefix= -o com.epson.ijfax.RecipientList..a.0..d.Company= -o com.epson.ijfax.RecipientList..a.0..d.Name= -o com.epson.ijfax.RecipientList..a.0..d.FaxNumber="
options=${options}${number}
options=${options}" -o com.epson.ijfax.EPFAXResolution="${resolution}
options=${options}" -o Resolution="${resolution}
options=${options}" -o EPIJ_PageSize="${media} 
options=${options}" -o PageSize="${media} 
options=${options}" -o media="${media}

logger -is -t $TAG "lp -d $PRINTQUEUE $options \"$file\""
lp -d $PRINTQUEUE $options "$file"

logger -is -t $TAG "done."
```

# 動機
1. FAXで情報のやり取りするの止めようよ、止めたいよ。メールでいいじゃん、Dropboxでいいじゃん。とはいえ業界（そんな業界早晩絶滅するはず）では少数派。渋々、FAXを使っている。
2. プリンタ複合機にはFAXの送受信機能があるし、無駄なプリントを省きたいやら、無駄な手作業を省きたいやらで、コマンドラインからFAX送信したいのに、macOS用にはなぜかツールが提供されてない。
3. Linux用にコマンドラインツールが提供されているのに、macOSにはないのはなぜだ？同じCUPSじゃないのか？

# 解説
##### 上記のスクリプトで重要なのは以下の部分です。

```
##### MAKE OPTIONS
1. options="-ofit-to-page"
2. options=${options}" -o com.epson.ijfax.DialingPrefix= -o com.epson.ijfax.RecipientList..a.0..d.Company= -o com.epson.ijfax.RecipientList..a.0..d.Name= -o com.epson.ijfax.RecipientList..a.0..d.FaxNumber="
3. options=${options}${number}
4. options=${options}" -o com.epson.ijfax.EPFAXResolution="${resolution}
5. options=${options}" -o Resolution="${resolution}
6. options=${options}" -o EPIJ_PageSize="${media} 
7. options=${options}" -o PageSize="${media} 
8. options=${options}" -o media="${media}

9. logger -is -t $TAG "lp -d $PRINTQUEUE $options \"$file\""
10. lp -d $PRINTQUEUE $options "$file"
```
`lp`コマンドでオプションに`lpoptions -l`では出てこないオプションを指定してやることで、PDFファイルを印刷する代わりにFAX送信します。しかし、最低でもこれらのオプションを指定しないとFAX送信できませんでした。オプションが多いのでスクリプトにまとめてしまった方が楽なのです。

1. 拡大縮小してサイズ調整オプション
2. 宛先電話番号指定オプション
3. FAX番号
4. 解像度オプション
5. 解像度オプション
6. ページサイズオプション
7. ページサイズオプション
8. ページサイズオプション

2.でcom.epson.ijfax.DialingPrefix=とキーに対応する値を指定してないのですが、キーそのものの指定がないと送信されませんでした。その他の...Companyとか...Nameとかも同じ。

4.5.と解像度を2回指定したり、6.7.8.と用紙サイズを3回指定したりして重複の無駄がありますが、これも一つでも省くとうまくいきませんでした。

9.は単にログを取ってるだけ。
10.で送信実行

##### その他の部分の概説

```
TAG=$(basename $0)
logger -is -t $TAG "launched. "$*
absolute_dir=$(cd $(dirname $0) && pwd)
export LANG=c
export LC_ALL=c
```
たいした意味はありません。

```
PDFINFO=/usr/local/bin/pdfinfo
PRINTQUEUE=FAX
PPD=/etc/cups/ppd/${PRINTQUEUE}.ppd
```
ここではスクリプトの初期設定部分です。

* PDFINFO：PDFのページサイズを取得するために`pdfinfo`というコマンドラインツールを指定してます。
* PRINTQUEUE：プリンタ名です。印刷ダイアログの「プリンタ：」で指定するものになります。
* PPD：PRINTQUEUEのパスに空白が含まれていたらクウォートしてください。いろいろ面倒になるから、プリンタ名をつけるときに空白を含まないようにした方が何かと楽です。

```
##### GET Resolution INFO FROM PPD
以下略
...
```
コメントのとおりです。

```
##### DPI
#com.epson.ijfax.EPFAXResolution=
#Resolution=
resolution=203x196dpi
以下略
...
```
解像度を変更する部分です。`resolution=203x196dpi`でデフォルト指定してます。

```
##### VERIFY NUMBER OF ARGV
以下略
...
```
コマンドライン引数の数のチェックしFAX番号とPDFファイル名を取得してます。

```
##### GET PageSize INFO FROM PPD
以下略
...
```
PPDから用紙サイズの選択肢を取得したのち、送信するPDFの縦横(長短)サイズを取得してます。`pdfinfo`というコマンドラインツールが必要です。`homebrew`などで別途インストールしてください。

```
### PaperDimension
以下略
...
```
縮小されない範囲で最も近い用紙サイズを探してます。

以上の部分は概ね用紙サイズの判定ですので、用紙サイズを固定してしまえば、ほぼ削除してしまってもFAX送信そのものはできます。

# 環境
#### 実行環境
macOS Sierra
EPSON PX-M7050F
プリンタはインクジェット複合機ですので、同じEPSONの複合機なら．．．（うまくいきそう）

#### その他の環境
EPSONの他の複合機やBrother、Canonといった他社の複合機はオプションが違うはずです。そこでオプションの探し方。

```sudo cupsctl --debug-logging```とすると```/var/log/cups/error_log```にログが残ります。この状態で、プレビュー.appなどからFAX送信をします。ログ中に

D [08/Jan/2017:12:00:00 +0900] [Job 666] argv[5]="AP_ColorMatchingMode=AP_VendorColorMatching AP_D_InputSlot= APCustomColorMatchingProfile=sRGB ApplicationBundleName=Preview noBookletBinding..b. BookletType..n.=0 nocollate ColorModel=RGB com.apple.print.DocumentTicket.PMSpoolFormat=application/pdf com.apple.print.JobInfo.PMApplicationName=プレビュー com.......

このようなargv[5]の内容が吐き出されています。argv[5]が```lp```コマンド時に指定したオプションの中身になります。

あとは試行錯誤しながらオプションを探します。少しばかり根気がいります（5000文字くらいあります）。

# 事案

私の仕事では、問い合わせに応じて図面や書類をFAX送信するという作業があります。なので、それらをひとまとめにしてPDFにしておき、FileMaker PROで分類、まとめてあります。
あとは、データを選択して、電話番号を入力しボタンを押下するだけの作業にしてあります。
今日入ってきたアルバイトでもできる作業になりました。

# 参考

https://www.cups.org/doc/options.html
https://www.cups.org/doc/api-filter.html