···1+{ lib, stdenv, fetchurl, pkgsi686Linux, dpkg, makeWrapper, coreutils, gnused, gawk, file, cups, util-linux, xxd, runtimeShell
2+, ghostscript, a2ps, bash }:
3+4+# Why:
5+# The executable "brprintconf_mfcj880dw" binary is looking for "/opt/brother/Printers/%s/inf/br%sfunc" and "/opt/brother/Printers/%s/inf/br%src".
6+# Whereby, %s is printf(3) string substitution for stdin's arg0 (the command's own filename) from the 10th char forwards, as a runtime dependency.
7+# e.g. Say the filename is "0123456789ABCDE", the runtime will be looking for /opt/brother/Printers/ABCDE/inf/brABCDEfunc.
8+# Presumably, the binary was designed to be deployed under the filename "printconf_mfcj880dw", whereby it will search for "/opt/brother/Printers/mfcj880dw/inf/brmfcj880dwfunc".
9+# For NixOS, we want to change the string to the store path of brmfcj880dwfunc and brmfcj880dwrc but we're faced with two complications:
10+# 1. Too little room to specify the nix store path. We can't even take advantage of %s by renaming the file to the store path hash since the variable is too short and can't contain the whole hash.
11+# 2. The binary needs the directory it's running from to be r/w.
12+# What:
13+# As such, we strip the path and substitution altogether, leaving only "brmfcj880dwfunc" and "brmfcj880dwrc", while filling the leftovers with nulls.
14+# Fully null terminating the cstrings is necessary to keep the array the same size and preventing overflows.
15+# We then use a shell script to link and execute the binary, func and rc files in a temporary directory.
16+# How:
17+# In the package, we dump the raw binary as a string of search-able hex values using hexdump. We execute the substitution with sed. We then convert the hex values back to binary form using xxd.
18+# We also write a shell script that invoked "mktemp -d" to produce a r/w temporary directory and link what we need in the temporary directory.
19+# Result:
20+# The user can run brprintconf_mfcj880dw in the shell.
21+22+stdenv.mkDerivation rec {
23+ pname = "mfcj880dwlpr";
24+ version = "1.0.0-0";
25+26+ src = fetchurl {
27+ url = "https://download.brother.com/welcome/dlf102038/mfcj880dwlpr-${version}.i386.deb";
28+ sha256 = "1680b301f660a407fe0b69f5de59c7473d2d66dc472a1589b0cd9f51736bfea7";
29+ };
30+31+ nativeBuildInputs = [ makeWrapper ];
32+ buildInputs = [ cups ghostscript dpkg a2ps ];
33+34+ dontUnpack = true;
35+36+ brprintconf_mfcj880dw_script = ''
37+ #!${runtimeShell}
38+ cd $(mktemp -d)
39+ ln -s @out@/usr/bin/brprintconf_mfcj880dw_patched brprintconf_mfcj880dw_patched
40+ ln -s @out@/opt/brother/Printers/mfcj880dw/inf/brmfcj880dwfunc brmfcj880dwfunc
41+ ln -s @out@/opt/brother/Printers/mfcj880dw/inf/brmfcj880dwrc brmfcj880dwrc
42+ ./brprintconf_mfcj880dw_patched "$@"
43+ '';
44+45+ installPhase = ''
46+ dpkg-deb -x $src $out
47+ substituteInPlace $out/opt/brother/Printers/mfcj880dw/lpd/filtermfcj880dw \
48+ --replace-fail /opt "$out/opt"
49+ substituteInPlace $out/opt/brother/Printers/mfcj880dw/lpd/psconvertij2 \
50+ --replace-fail "GHOST_SCRIPT=`which gs`" "GHOST_SCRIPT=${ghostscript}/bin/gs"
51+ substituteInPlace $out/opt/brother/Printers/mfcj880dw/inf/setupPrintcapij \
52+ --replace-fail "/opt/brother/Printers" "$out/opt/brother/Printers" \
53+ --replace-fail "printcap.local" "printcap"
54+55+ patchelf --set-interpreter ${pkgsi686Linux.stdenv.cc.libc.out}/lib/ld-linux.so.2 \
56+ --set-rpath $out/opt/brother/Printers/mfcj880dw/inf:$out/opt/brother/Printers/mfcj880dw/lpd \
57+ $out/opt/brother/Printers/mfcj880dw/lpd/brmfcj880dwfilter
58+ patchelf --set-interpreter ${pkgsi686Linux.stdenv.cc.libc.out}/lib/ld-linux.so.2 $out/usr/bin/brprintconf_mfcj880dw
59+60+ #stripping the hardcoded path.
61+ # /opt/brother/Printers/%s/inf/br%sfunc -> brmfcj880dwfunc
62+ # /opt/brother/Printers/%s/inf/br%src -> brmfcj880dwrc
63+ ${util-linux}/bin/hexdump -ve '1/1 "%.2X"' $out/usr/bin/brprintconf_mfcj880dw | \
64+ sed 's.2F6F70742F62726F746865722F5072696E746572732F25732F696E662F6272257366756E63.62726d66636a383830647766756e6300000000000000000000000000000000000000000000.' | \
65+ sed 's.2F6F70742F62726F746865722F5072696E746572732F25732F696E662F627225737263.62726d66636a3838306477726300000000000000000000000000000000000000000000.' | \
66+ ${xxd}/bin/xxd -r -p > $out/usr/bin/brprintconf_mfcj880dw_patched
67+ chmod +x $out/usr/bin/brprintconf_mfcj880dw_patched
68+ #executing from current dir. segfaults if it's not r\w.
69+ mkdir -p $out/bin
70+ echo -n "$brprintconf_mfcj880dw_script" > $out/bin/brprintconf_mfcj880dw
71+ chmod +x $out/bin/brprintconf_mfcj880dw
72+ substituteInPlace $out/bin/brprintconf_mfcj880dw --replace-fail @out@ $out
73+74+ # NOTE: opt/brother/Printers/mfcj880dw/lpd/brmfcj880dwfilter also has cardcoded paths, but we can not simply replace them
75+76+ mkdir -p $out/lib/cups/filter/
77+ ln -s $out/opt/brother/Printers/mfcj880dw/lpd/filtermfcj880dw $out/lib/cups/filter/brother_lpdwrapper_mfcj880dw
78+79+ wrapProgram $out/opt/brother/Printers/mfcj880dw/lpd/psconvertij2 \
80+ --prefix PATH ":" ${ lib.makeBinPath [ coreutils gnused gawk ] }
81+ wrapProgram $out/opt/brother/Printers/mfcj880dw/lpd/filtermfcj880dw \
82+ --prefix PATH ":" ${ lib.makeBinPath [ coreutils gnused file ghostscript a2ps ] }
83+ '';
84+85+ meta = with lib; {
86+ description = "Brother MFC-J880DW LPR driver";
87+ downloadPage = "https://support.brother.com/g/b/downloadlist.aspx?c=us&lang=en&prod=mfcj880dw_us_eu_as&os=128";
88+ homepage = "http://www.brother.com/";
89+ sourceProvenance = with sourceTypes; [ binaryNativeCode ];
90+ license = with licenses; unfree;
91+ maintainers = with maintainers; [ _6543 ];
92+ platforms = with platforms; linux;
93+ };
94+}