Debian から AirPrint 対応プリンタに印刷する

# 概要

Linux から印刷するには、PostScript や ESC/P などのページ記述言語に対応したプリンタが必要という状況が長らく続いていました。が、Apple が iPhone から印刷するために開発した AirPrint という規格の普及により、大きく状況が変わりそうです。

AirPrint は、以下の3つの構成要素からなっています。

* [Bonjour](https://ja.wikipedia.org/wiki/Bonjour) プロトコルでプリンタを発見する。
* Apple Raster Format (image/urf) で印刷データを用意する。
* Internet Printing Protocol (IPP) で印刷データを送信する。

Apple Raster Format 以外の構成要素は標準化されているため、Linux でも対応しやすいわけです。AirPrint の類似規格として、[IPP Everywhere](https://www.pwg.org/ipp/everywhere.html) がありますが、AirPrint とは印刷データの形式が異なるだけです。

* [Bonjour](https://ja.wikipedia.org/wiki/Bonjour) プロトコルでプリンタを発見する。
* [PWG Raster Format](https://ftp.pwg.org/pub/pwg/candidates/cs-ippraster10-20120420-5102.4.pdf) (image/pwg-raster)  で印刷データを用意する。
* Internet Printing Protocol (IPP) で印刷データを送信する。

したがって、基本的には [Debian で IPP Everywhere を使えるよう設定](https://wiki.debian.org/IPPEverywhere)すれば、AirPrint 対応プリンタが利用できるようになります。

# 設定手順

最初に、cups-browsed と avahi-daemon の2つのパッケージをインストールします。

```shell-session
$ sudo apt install cups-browsed avahi-daemon
```

avahi-daemon が Bonjour プロトコルをつかさどるデーモンで、cups-browsed が Bonjour プロトコルによって発見されたプリンタを cups に通知・追加するデーモンです。

次に、`/etc/cups/cups-browsed.conf` に以下の設定を追加します。

```conf:/etc/cups/cups-browsed.conf
CreateIPPPrinterQueues All
```

これだけです！認識されていれば、以下のように `lpstat` コマンドで確認できるはずです。

```
$ lpstat -tv
Brother_DCP_J973N のデバイス: ipp://BRNXXXXXXXXXXXXX.local:631/ipp/print
```

筆者の環境では、[Brother DCP-J973N](https://www.brother.co.jp/product/printer/inkjet/dcpj973n/index.aspx) で印刷できています。

# トラブルシュート

残念ながら、多くの場合はトラブルシュートが必要になります。

## Bonjour のトラブルシュート

Bonjour でプリンタが見つかっているかどうかを確認するには、以下のようにします。

```shell-session
$ sudo apt install avahi-utils
$ avahi-browse -art
+ wlp2s0 IPv6 Brother DCP-J973N                             Internet Printer     local
+ wlp2s0 IPv4 Brother DCP-J973N                             Internet Printer     local
（以下略）
```

`avahi-browse` コマンドでプリンタが見つからないようであれば、ネットワークの動作を疑うことになります。筆者の環境では、[外部からの通信を全て拒否するように設定](https://qiita.com/tsuchm/items/1b28d1bb7714e3847ac1#%E5%A4%96%E9%83%A8%E3%81%8B%E3%82%89%E3%81%AE%E9%80%9A%E4%BF%A1%E3%82%92%E5%85%A8%E3%81%A6%E6%8B%92%E5%90%A6%E3%81%99%E3%82%8B)していたため、Bonjour が動作していませんでした。とりあえず、Bonjour が使っている5353番ポートに対する通信を許可するよう、`/etc/iptables/rules.v4` に以下のように記述しました。

```conf:/etc/iptables/rules.v4
# Generated by xtables-save v1.8.2 on Sat Jul 20 18:13:39 2019
*filter
:INPUT ACCEPT [256:44171]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [295:38238]
-A INPUT -p tcp -m tcp --dport 5353 -j ACCEPT
-A INPUT -p udp -m udp --dport 5353 -j ACCEPT
-A INPUT -i enp+ -m state --state INVALID,NEW -j DROP
-A INPUT -i wlp+ -m state --state INVALID,NEW -j DROP
-A FORWARD -i enp+ -m state --state INVALID,NEW -j DROP
-A FORWARD -i wlp+ -m state --state INVALID,NEW -j DROP
COMMIT
# Completed on Sat Jul 20 18:13:39 2019
```

## cups-browsed のトラブルシュート

`/etc/cups/cups-browsed.conf` に以下の設定を追加します。

```conf:/etc/cups/cups-browsed.conf
LogDir /var/log/cups
DebugLogging file
```

すると、`/var/log/cups/cups-browsed_log` に動作ログが残るようになりますので、その内容を検討します。筆者の場合、CreateIPPPrinterQueues ディレクティブの指定の誤りを、動作ログから発見しました。

## プリンタが IPP Everywhere に対応しているか確認する

以下のように `iptool` コマンドを実行して出力を確認します。

```sh
$ ipptool -tv ipp://プリンタのIPアドレス/ipp/print get-printer-attributes.test|grep -E "ipp-versions-supported|document-format-supported|get-printer-attributes"
"/usr/share/cups/ipptool/get-printer-attributes.test":
    Get printer attributes using get-printer-attributes                  [PASS]
        ipp-versions-supported (1setOf keyword) = 1.0,1.1,2.0
        document-format-supported (1setOf mimeMediaType) = application/octet-stream,image/urf,image/jpeg,image/pwg-raster
```

対応している IPP のバージョンが2.0以降であり、かつ、対応している文書フォーマットに image/pwg-raster が含まれていれば、IPP Everywhere に対応しています。

なお、cups-browsed を利用することなく、静的に IPP Everywhere 対応プリンタを追加したい場合は、以下のように `lpadmin` コマンドを使って追加することができます。

```sh
$ sudo lpadmin -p プリンタ名 -v ipp://プリンタのIPアドレス/ipp/print -E -m everywhere
```