commit e2dba6ee86fee26359a307a6214643c362a0f3ce Author: Rod Wright Date: Tue Feb 24 21:24:38 2026 -0500 Initial commit for version 1.0.0 diff --git a/brlaser-master/CMakeLists.txt b/brlaser-master/CMakeLists.txt new file mode 100644 index 0000000..15f430c --- /dev/null +++ b/brlaser-master/CMakeLists.txt @@ -0,0 +1,126 @@ +cmake_minimum_required(VERSION 3.1) +project(brlaser CXX) +set(BRLASER_VERSION "4") + +if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "No build type selected, default to RelWithDebInfo") + set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Build type (default RelWithDebInfo)" FORCE) +endif() + +include(CMakePushCheckState) +include(CheckCXXCompilerFlag) +include(CheckIncludeFileCXX) + + +## Enable assertions for all builds +## (cmake by default sets NDEBUG for release builds) + +foreach(var + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_MINSIZEREL) + string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )" " " "${var}" "${${var}}") +endforeach() + + +## Configure the compiler + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +macro(extra_cxx_compiler_flag FLAG) + string(REGEX REPLACE "[^A-Za-z_0-9]" "_" SFLAG ${FLAG}) + check_cxx_compiler_flag(${FLAG} COMPILER_SUPPORT_${SFLAG}) + if(COMPILER_SUPPORT_${SFLAG}) + set(EXTRA_CXX_FLAGS "${EXTRA_CXX_FLAGS} ${FLAG}") + endif() +endmacro(extra_cxx_compiler_flag) + +# Compiler warnings +extra_cxx_compiler_flag("-Wall") +extra_cxx_compiler_flag("-Wno-missing-braces") +# Some security flags +extra_cxx_compiler_flag("-fstack-protector-strong") +extra_cxx_compiler_flag("-Wformat") +extra_cxx_compiler_flag("-Werror=format-security") +extra_cxx_compiler_flag("-D_FORTIFY_SOURCE=2") +# Enable the supported flags, but give priority to CXXFLAGS env var +set(CMAKE_CXX_FLAGS "${EXTRA_CXX_FLAGS} ${CMAKE_CXX_FLAGS}") + + +## Configure CUPS + +find_program(CUPS_CONFIG NAMES cups-config) +if(NOT CUPS_CONFIG) + message(FATAL_ERROR "cups-config command not found. Are the CUPS development packages installed?") +endif() +execute_process( + COMMAND "${CUPS_CONFIG}" --datadir + OUTPUT_VARIABLE CUPS_DATA_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process( + COMMAND "${CUPS_CONFIG}" --serverbin + OUTPUT_VARIABLE CUPS_SERVER_BIN + OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process( + COMMAND "${CUPS_CONFIG}" --cflags + OUTPUT_VARIABLE CUPS_CFLAGS + OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process( + COMMAND "${CUPS_CONFIG}" --ldflags + OUTPUT_VARIABLE CUPS_LDFLAGS + OUTPUT_STRIP_TRAILING_WHITESPACE) +execute_process( + COMMAND "${CUPS_CONFIG}" --image --libs + OUTPUT_VARIABLE CUPS_LIBS + OUTPUT_STRIP_TRAILING_WHITESPACE) + +cmake_push_check_state() +set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${CUPS_CFLAGS}") +check_include_file_cxx(cups/raster.h HAVE_CUPS_RASTER_H) +cmake_pop_check_state() +if(NOT HAVE_CUPS_RASTER_H) + message(SEND_ERROR " header not found. Are the CUPS development packages installed?") +endif() + + +## Build instructions + +configure_file( + "${PROJECT_SOURCE_DIR}/brlaser.drv.in" + "${PROJECT_BINARY_DIR}/brlaser.drv") + +configure_file( + "${PROJECT_SOURCE_DIR}/config.h.in" + "${PROJECT_BINARY_DIR}/config.h") + +include_directories("${PROJECT_BINARY_DIR}") + +add_executable(rastertobrlaser src/main.cc src/job.cc src/line.cc src/debug.cc) +target_compile_options(rastertobrlaser PRIVATE ${CUPS_CFLAGS}) +target_link_libraries(rastertobrlaser ${CUPS_LIBS}) +target_link_libraries(rastertobrlaser ${CUPS_LDFLAGS}) + +add_executable(brdecode src/brdecode.cc) +add_executable(test_lest test/test_lest.cc) +add_executable(test_line test/test_line.cc src/line.cc) +add_executable(test_block test/test_block.cc) + +enable_testing() +add_test(test_lest test_lest) +add_test(test_line test_line) +add_test(test_block test_block) + +# Autotools-style "make check" command +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) +add_dependencies(check test_lest test_line test_block) + + +# Installation + +install( + TARGETS rastertobrlaser + DESTINATION "${CUPS_SERVER_BIN}/filter") +install( + FILES "${PROJECT_BINARY_DIR}/brlaser.drv" + DESTINATION "${CUPS_DATA_DIR}/drv") diff --git a/brlaser-master/COPYING b/brlaser-master/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/brlaser-master/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/brlaser-master/ChangeLog b/brlaser-master/ChangeLog new file mode 100644 index 0000000..4fbd9a2 --- /dev/null +++ b/brlaser-master/ChangeLog @@ -0,0 +1,9 @@ +brlaser v3 (2014-07-07) + Added DCP-7065DN description. + +brlaser v2 (2014-06-29) + Suppport compilation with GCC 4.6. + Add a basic test suite. + +brlaser v1 (2013-12-30) + Initial release. diff --git a/brlaser-master/README.md b/brlaser-master/README.md new file mode 100644 index 0000000..7b79fea --- /dev/null +++ b/brlaser-master/README.md @@ -0,0 +1,85 @@ +brlaser: Brother laser printer driver +===================================== + +brlaser is a CUPS driver for Brother laser printers. + +Although most Brother printers support a standard printer language +such as PCL or PostScript, not all do. If you have a monochrome +Brother laser printer (or multi-function device) and the other open +source drivers don't work, this one might help. + +This driver is known to work with these printers: + +* Brother DCP-1510 +* Brother DCP-7030 +* Brother DCP-7040 +* Brother DCP-7055 +* Brother DCP-7055W +* Brother DCP-7065DN +* Brother HL-L2300D +* Brother MFC-7360N + + +Other printers +-------------- + +If your printer isn't included in the list above, just try selecting +any entry marked 'brlaser' and see if it works. + +If it does, please create a new issue here in Github and include the +output of this command: + + sudo lpinfo --include-schemes usb -l -v + +Then I'll be able to add a proper entry for your printer. + + +Installation +------------ + +Some operating systems already ship this driver. This is the case for +at least Debian, Ubuntu, Raspbian, openSUSE and Arch Linux. Look for a +package named `printer-driver-brlaser`. + +You'll also need Ghostscript, in case that's not installed +automatically. + +Once brlaser is installed, you can add your printer using the usual +CUPS interface. + + +Building from source +-------------------- + +To compile brlaser you'll need CMake and the CUPS development packages +(libcups2-dev, libcupsimage2-dev or similar). + +Get the code by cloning the git repo . Compile and install with these commands: + + cmake . + make + sudo make install + +It might be needed to restart CUPS after this. + +[latest release]: https://github.com/pdewacht/brlaser/releases/latest + + +Copyright +--------- + +Copyright © 2013 Peter De Wachter + +brlaser is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +brlaser is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with brlaser. If not, see . diff --git a/brlaser-master/brlaser.drv.in b/brlaser-master/brlaser.drv.in new file mode 100644 index 0000000..84542cc --- /dev/null +++ b/brlaser-master/brlaser.drv.in @@ -0,0 +1,143 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#define USING "using @CMAKE_PROJECT_NAME@ v@BRLASER_VERSION@" + +// Include standard font and media definitions +#include +#include + +// List the fonts that are supported, in this case all standard fonts... +Font * + +// Manufacturer and driver version. +Manufacturer "Brother" +Version "@BRLASER_VERSION@" + +// Each filter provided by the driver... +Filter application/vnd.cups-raster 33 rastertobrlaser + +// Supported resolutions. +// The 1200dpi mode is weird: we need to send 1200x1200dpi raster +// data, but Brother only advertises 1200x600dpi. I wonder what +// is going on there. +// The 300dpi mode is reportedly not supported on all printers, so +// it's listed in individual printer blocks where we believe it works. +// Resolution k 1 0 0 0 "300dpi/300 DPI" +*Resolution k 1 0 0 0 "600dpi/600 DPI" +Resolution k 1 0 0 0 "1200dpi/1200HQ" + +// Supported page sizes. +HWMargins 8 8 8 16 +*MediaSize A4 +MediaSize A5 +MediaSize A6 +MediaSize B5 +MediaSize B6 +MediaSize EnvC5 +MediaSize EnvMonarch +MediaSize EnvDL +MediaSize Executive +MediaSize Legal +MediaSize Letter + +// Input trays. Numbers must match the filter source code. +*InputSlot 0 "Auto/Auto-select" +InputSlot 1 "Tray1/Tray 1" +InputSlot 2 "Tray2/Tray 2" +InputSlot 3 "Tray3/Tray 3" +InputSlot 4 "MPTray/MP Tray" +InputSlot 5 "Manual/Manual" + +// Media types. +*MediaType 0 "PLAIN/Plain paper" +MediaType 1 "THIN/Thin paper" +MediaType 2 "THICK/Thick paper" +MediaType 3 "THICKER/Thicker paper" +MediaType 4 "BOND/Bond paper" +MediaType 5 "TRANS/Transparencies" +MediaType 6 "ENV/Envelopes" +MediaType 7 "ENV-THICK/Thick envelopes" +MediaType 8 "ENV-THIN/Thin envelopes" + +Option "brlaserEconomode/Toner save mode" Boolean AnySetup 10 + *Choice False/Off "<>setpagedevice" + Choice True/On "<>setpagedevice" + + +{ + ModelName "DCP-1510" + Attribute "NickName" "" "Brother DCP-1510 series, $USING" + Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,XL2HB;MDL:DCP-1510 series;CLS:PRINTER;CID:Brother Laser Type1;" + Resolution k 1 0 0 0 "300dpi/300 DPI" + PCFileName "br1510.ppd" +} + +{ + ModelName "DCP-7030" + Attribute "NickName" "" "Brother DCP-7030, $USING" + Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:DCP-7030;CLS:PRINTER;" + Resolution k 1 0 0 0 "300dpi/300 DPI" + PCFileName "br7030.ppd" +} + +{ + ModelName "DCP-7040" + Attribute "NickName" "" "Brother DCP-7040, $USING" + Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:DCP-7040;CLS:PRINTER;" + Resolution k 1 0 0 0 "300dpi/300 DPI" + PCFileName "br7040.ppd" +} + +{ + ModelName "DCP-7055" + Attribute "NickName" "" "Brother DCP-7055, $USING" + Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:DCP-7055;CLS:PRINTER;CID:Brother Laser Type1;" + Resolution k 1 0 0 0 "300dpi/300 DPI" + PCFileName "br7055.ppd" +} + +{ + ModelName "DCP-7055W" + Attribute "NickName" "" "Brother DCP-7055W, $USING" + Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:DCP-7055W;CLS:PRINTER;CID:Brother Laser Type1;" + Resolution k 1 0 0 0 "300dpi/300 DPI" + PCFileName "br7055w.ppd" +} + +{ + ModelName "DCP-7065DN" + Attribute "NickName" "" "Brother DCP-7065DN, $USING" + Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:DCP-7065DN;CLS:PRINTER;CID:Brother Laser Type1;" + Duplex rotated + PCFileName "br7065dn.ppd" +} + +{ + ModelName "HL-L2300D" + Attribute "NickName" "" "Brother HL-L2300D, $USING" + Attribute "1284DeviceID" "" " MFG:Brother;CMD:PJL,HBP;MDL:HL-L2300D series;CLS:PRINTER;CID:Brother Laser Type1;" + Duplex rotated + PCFileName "brl2300d.ppd" +} + +{ + ModelName "MFC-7360N" + Attribute "NickName" "" "Brother MFC-7360N, $USING" + Attribute "1284DeviceID" "" "MFG:Brother;CMD:PJL,HBP;MDL:MFC-7360N;CLS:PRINTER;CID:Brother Laser Type1;" + PCFileName "br7360n.ppd" +} diff --git a/brlaser-master/config.h.in b/brlaser-master/config.h.in new file mode 100644 index 0000000..601ac5e --- /dev/null +++ b/brlaser-master/config.h.in @@ -0,0 +1,2 @@ +#define PACKAGE "@CMAKE_PROJECT_NAME@" +#define VERSION "@BRLASER_VERSION@" diff --git a/brlaser-master/src/block.h b/brlaser-master/src/block.h new file mode 100644 index 0000000..13daea1 --- /dev/null +++ b/brlaser-master/src/block.h @@ -0,0 +1,68 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#ifndef BLOCK_H +#define BLOCK_H + +#include +#include +#include + +class block { + public: + block(): line_bytes_(0) { + lines_.reserve(max_lines_per_block_); + } + + bool empty() const { + return line_bytes_ == 0; + } + + void add_line(std::vector &&line) { + assert(!line.empty()); + assert(line_fits(line.size())); + line_bytes_ += line.size(); + lines_.emplace_back(line); + } + + bool line_fits(unsigned size) { + return lines_.size() != max_lines_per_block_ + && line_bytes_ + size < max_block_size_; + } + + void flush(FILE *f) { + if (!empty()) { + fprintf(f, "%dw%c%c", + line_bytes_ + 2, 0, + static_cast(lines_.size())); + for (auto &line : lines_) { + fwrite(line.data(), 1, line.size(), f); + } + line_bytes_ = 0; + lines_.clear(); + } + } + + private: + static const unsigned max_block_size_ = 16350; + static const unsigned max_lines_per_block_ = 128; + + std::vector> lines_; + int line_bytes_; +}; + +#endif // BLOCK_H diff --git a/brlaser-master/src/brdecode.cc b/brlaser-master/src/brdecode.cc new file mode 100644 index 0000000..bcd3ec7 --- /dev/null +++ b/brlaser-master/src/brdecode.cc @@ -0,0 +1,225 @@ +// A quick-and-dirty tool to convert print files back to pbm images. +// +// Copyright 2013 Peter De Wachter +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +const size_t MAX_LINE_SIZE = 2000; + +FILE *in_file; +std::vector> page; +std::vector line; +size_t line_offset; + + +class unexpected_eof: public std::exception { + public: + virtual const char *what() const noexcept { + return "Unexpected EOF"; + } +}; + +class line_overflow: public std::exception { + public: + virtual const char *what() const noexcept { + return "Unreasonable long line, aborting"; + } +}; + + +uint8_t get() { + int ch = getc(in_file); + if (ch < 0) + throw unexpected_eof(); + return ch; +} + +unsigned read_overflow() { + uint8_t ch; + unsigned sum = 0; + do { + ch = get(); + sum += ch; + } while (ch == 255); + return sum; +} + +void read_repeat(uint8_t cmd) { + uint16_t offset = (cmd >> 5) & 3; + if (offset == 3) + offset += read_overflow(); + uint16_t count = cmd & 31; + if (count == 31) + count += read_overflow(); + count += 2; + uint8_t data = get(); + + size_t end = line_offset + offset + count; + if (end > line.size()) { + if (end > MAX_LINE_SIZE) + throw line_overflow(); + line.resize(end); + } + line_offset += offset; + std::fill_n(line.begin() + line_offset, count, data); + line_offset += count; +} + +void read_substitute(uint8_t cmd) { + uint16_t offset = (cmd >> 3) & 15; + if (offset == 15) + offset += read_overflow(); + uint16_t count = cmd & 7; + if (count == 7) + count += read_overflow(); + count += 1; + + size_t end = line_offset + offset + count; + if (end > line.size()) { + if (end > MAX_LINE_SIZE) + throw line_overflow(); + line.resize(end); + } + line_offset += offset; + std::generate_n(line.begin() + line_offset, count, get); + line_offset += count; +} + +void read_edit() { + int8_t cmd = get(); + if (cmd < 0) { + read_repeat(cmd); + } else { + read_substitute(cmd); + } +} + +void read_line() { + uint8_t num_edits = get(); + if (num_edits == 255) { + line.clear(); + } else { + line_offset = 0; + for (int i = 0; i < num_edits; ++i) { + read_edit(); + } + } + page.push_back(line); +} + +void read_block() { + unsigned count = get(); + count = count * 256 + get(); + for (unsigned i = 0; i < count; ++i) { + read_line(); + } +} + +bool read_page() { + bool in_esc = false; + int ch; + + page.clear(); + line.clear(); + while ((ch = getc(in_file)) >= 0) { + if (ch == '\f') { + break; + } else if (ch == 033) { + in_esc = true; + } else if (in_esc && ch == 'w') { + read_block(); + } else if (in_esc && (ch >= 'A' && ch <= 'Z')) { + in_esc = false; + } + } + return !page.empty(); +} + +void write_pnm(FILE *f) { + size_t height = page.size(); + size_t width = 0; + for (auto &l : page) { + width = std::max(width, l.size()); + } + + fprintf(f, "P4 %zd %zd\n", width * 8, height); + std::vector empty(width); + for (auto &l : page) { + fwrite(l.data(), 1, l.size(), f); + fwrite(empty.data(), 1, width - l.size(), f); + } +} + +} // namespace + +int main(int argc, char *argv[]) { + const char *in_filename; + std::string out_prefix; + + if (argc > 2) { + in_filename = argv[1]; + out_prefix = argv[2]; + } else if (argc > 1) { + in_filename = argv[1]; + out_prefix = argv[1]; + } else { + in_filename = nullptr; + out_prefix = "page"; + } + + if (in_filename) { + in_file = fopen(in_filename, "rb"); + if (!in_file) { + fprintf(stderr, "Can't open file \"%s\"\n", in_filename); + return 1; + } + } else { + in_file = stdin; + if (isatty(0)) { + fprintf(stderr, "No filename given and no input on stdin\n"); + return 1; + } + } + + try { + int page_num = 1; + while (read_page()) { + std::string out_filename = out_prefix + + "-" + std::to_string(page_num) + ".pbm"; + FILE *out_file = fopen(out_filename.c_str(), "wb"); + if (!out_file) { + fprintf(stderr, "Can't write file \"%s\"\n", out_filename.c_str()); + return 1; + } + write_pnm(out_file); + fclose(out_file); + fprintf(stderr, "%s\n", out_filename.c_str()); + ++page_num; + } + } catch (std::exception &e) { + fprintf(stderr, "%s\n", e.what()); + return 1; + } + return 0; +} diff --git a/brlaser-master/src/debug.cc b/brlaser-master/src/debug.cc new file mode 100644 index 0000000..041b414 --- /dev/null +++ b/brlaser-master/src/debug.cc @@ -0,0 +1,107 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include "config.h" +#include "debug.h" +#include +#include + +namespace { + +template +void dump(const char *name, const T &value) { + std::cerr << "DEBUG: " PACKAGE ": page header: " << name << " = " << value << '\n'; +} + +template +void dump(const char *name, const T (&value)[N]) { + std::cerr << "DEBUG: " PACKAGE ": page header: " << name << " ="; + for (int i = 0; i < N; ++i) { + std::cerr << ' ' << value[i]; + } + std::cerr << '\n'; +} + +void dump(const char *name, const char *value) { + std::cerr << "DEBUG: " PACKAGE ": page header: " << name << " = \"" << value << "\"\n"; +} + +template +void dump(const char *name, const char (&value)[N][M]) { + std::cerr << "DEBUG: " PACKAGE ": page header: " << name << " ="; + for (int i = 0; i < N; ++i) { + std::cerr << " \"" << value[i] << '"'; + } + std::cerr << '\n'; +} + +} // namespace + + +void dump_page_header(const cups_page_header2_t &h) { +#define d(f) dump(#f, h.f) + d(MediaClass); + d(MediaColor); + d(MediaType); + d(OutputType); + d(AdvanceDistance); + d(AdvanceMedia); + d(Collate); + d(CutMedia); + d(Duplex); + d(HWResolution); + d(ImagingBoundingBox); + d(InsertSheet); + d(Jog); + d(LeadingEdge); + d(Margins); + d(ManualFeed); + d(MediaPosition); + d(MediaWeight); + d(MirrorPrint); + d(NegativePrint); + d(NumCopies); + d(Orientation); + d(OutputFaceUp); + d(PageSize); + d(Separations); + d(TraySwitch); + d(Tumble); + d(cupsWidth); + d(cupsHeight); + d(cupsMediaType); + d(cupsBitsPerColor); + d(cupsBitsPerPixel); + d(cupsBytesPerLine); + d(cupsColorOrder); + d(cupsColorSpace); + d(cupsCompression); + d(cupsRowCount); + d(cupsRowFeed); + d(cupsRowStep); + d(cupsNumColors); + d(cupsBorderlessScalingFactor); + d(cupsPageSize); + d(cupsImagingBBox); + d(cupsInteger); + d(cupsReal); + d(cupsString); + d(cupsMarkerType); + d(cupsRenderingIntent); + d(cupsPageSizeName); +#undef d +} diff --git a/brlaser-master/src/debug.h b/brlaser-master/src/debug.h new file mode 100644 index 0000000..d1eff52 --- /dev/null +++ b/brlaser-master/src/debug.h @@ -0,0 +1,25 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#ifndef DEBUG_H +#define DEBUG_H + +#include + +void dump_page_header(const cups_page_header2_t &h); + +#endif diff --git a/brlaser-master/src/job.cc b/brlaser-master/src/job.cc new file mode 100644 index 0000000..440fc6d --- /dev/null +++ b/brlaser-master/src/job.cc @@ -0,0 +1,118 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include "job.h" +#include +#include +#include +#include "line.h" +#include "block.h" + + +job::job(FILE *out, const std::string &job_name) + : out_(out), + job_name_(job_name), + page_params_() { + // Delete dubious characters from job name + std::replace_if(job_name_.begin(), job_name_.end(), [](char c) { + return c < 32 || c >= 127 || c == '"' || c == '\\'; + }, ' '); + + begin_job(); +} + +job::~job() { + end_job(); +} + +void job::begin_job() { + for (int i = 0; i < 128; ++i) { + putc(0, out_); + } + fprintf(out_, "\033%%-12345X@PJL\n"); + fprintf(out_, "@PJL JOB NAME=\"%s\"\n", job_name_.c_str()); +} + +void job::end_job() { + fprintf(out_, "\033%%-12345X@PJL\n"); + fprintf(out_, "@PJL EOJ NAME=\"%s\"\n", job_name_.c_str()); + fprintf(out_, "\033%%-12345X\n"); +} + +void job::write_page_header() { + fprintf(out_, "\033%%-12345X@PJL\n"); + if (page_params_.resolution != 1200) { + fprintf(out_, "@PJL SET RAS1200MODE = FALSE\n"); + fprintf(out_, "@PJL SET RESOLUTION = %d\n", page_params_.resolution); + } else { + fprintf(out_, "@PJL SET RAS1200MODE = TRUE\n"); + fprintf(out_, "@PJL SET RESOLUTION = 600\n"); + } + fprintf(out_, "@PJL SET ECONOMODE = %s\n", + page_params_.economode ? "ON" : "OFF"); + fprintf(out_, "@PJL SET SOURCETRAY = %s\n", + page_params_.sourcetray.c_str()); + fprintf(out_, "@PJL SET MEDIATYPE = %s\n", + page_params_.mediatype.c_str()); + fprintf(out_, "@PJL SET PAPER = %s\n", + page_params_.papersize.c_str()); + fprintf(out_, "@PJL SET PAGEPROTECT = AUTO\n"); + fprintf(out_, "@PJL SET ORIENTATION = PORTRAIT\n"); + fprintf(out_, "@PJL ENTER LANGUAGE = PCL\n"); + + fputs("\033E", out_); + fprintf(out_, "\033&l%dX", std::max(1, page_params_.num_copies)); + + if (page_params_.duplex) { + fputs("\033&l2S", out_); + } +} + +void job::encode_page(const page_params &page_params, + int lines, + int linesize, + nextline_fn nextline) { + if (!(page_params_ == page_params)) { + page_params_ = page_params; + write_page_header(); + } + + std::vector line(linesize); + std::vector reference(linesize); + block block; + + if (!nextline(line)) { + return; + } + block.add_line(encode_line(line)); + std::swap(line, reference); + + fputs("\033*b1030m", out_); + + for (int i = 1; i < lines && nextline(line); ++i) { + std::vector encoded = encode_line(line, reference); + if (!block.line_fits(encoded.size())) { + block.flush(out_); + } + block.add_line(std::move(encoded)); + std::swap(line, reference); + } + + block.flush(out_); + fputs("1030M\f", out_); + fflush(out_); +} diff --git a/brlaser-master/src/job.h b/brlaser-master/src/job.h new file mode 100644 index 0000000..2ae7ea5 --- /dev/null +++ b/brlaser-master/src/job.h @@ -0,0 +1,68 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#ifndef JOB_H +#define JOB_H + +#include +#include +#include +#include + +struct page_params { + int num_copies; + int resolution; + bool duplex; + bool economode; + std::string sourcetray; + std::string mediatype; + std::string papersize; + + bool operator==(const page_params &o) const { + return num_copies == o.num_copies + && resolution == o.resolution + && duplex == o.duplex + && economode == o.economode + && sourcetray == o.sourcetray + && mediatype == o.mediatype + && papersize == o.papersize; + } +}; + +class job { + public: + typedef bool (*nextline_fn)(std::vector &buf); + + explicit job(FILE *out, const std::string &job_name); + ~job(); + + void encode_page(const page_params ¶ms, + int lines, + int linesize, + nextline_fn nextline); + + private: + void begin_job(); + void end_job(); + void write_page_header(); + + FILE *out_; + std::string job_name_; + page_params page_params_; +}; + +#endif // JOB_H diff --git a/brlaser-master/src/line.cc b/brlaser-master/src/line.cc new file mode 100644 index 0000000..6489118 --- /dev/null +++ b/brlaser-master/src/line.cc @@ -0,0 +1,191 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include "line.h" +#include +#include +using std::vector; + +namespace { + +void write_overflow(int value, vector *out) { + if (value >= 0) { + if (value < 255) { + out->push_back(value); + } else { + out->insert(out->end(), value / 255, 255); + out->push_back(value % 255); + } + } +} + +template +void write_substitute(int offset, + Iterator first, + Iterator last, + vector *out) { + assert(offset >= 0); + assert(offset < 10000); + assert(first != last); + + const int offset_max = 15; + const int count_max = 7; + int count = std::distance(first, last) - 1; + + int offset_low = std::min(offset, offset_max); + int count_low = std::min(count, count_max); + out->push_back((offset_low << 3) | count_low); + write_overflow(offset - offset_max, out); + write_overflow(count - count_max, out); + out->insert(out->end(), first, last); +} + +void write_repeat(int offset, int count, int value, vector *out) { + assert(offset >= 0); + assert(offset < 10000); + assert(count >= 2); + assert(count < 10000); + + const int offset_max = 3; + const int count_max = 31; + count -= 2; + + int offset_low = std::min(offset, offset_max); + int count_low = std::min(count, count_max); + out->push_back(128 | (offset_low << 5) | count_low); + write_overflow(offset - offset_max, out); + write_overflow(count - count_max, out); + out->push_back(value); +} + + +bool all_zeros(const vector &buf) { + return std::none_of(buf.begin(), buf.end(), [](uint8_t b) { return b; }); +} + +template +int skip_to_next_mismatch(Iterator1 *first1, + Iterator1 last1, + Iterator2 *first2) { + auto mismatch_it = std::mismatch(*first1, last1, *first2); + int skipped = std::distance(*first1, mismatch_it.first); + *first1 = mismatch_it.first; + *first2 = mismatch_it.second; + return skipped; +} + +template +int repeat_length(Iterator first, Iterator last) { + if (first != last) { + auto k = *first; + auto mismatch = std::find_if(std::next(first), last, + [=](decltype(k) x) { return x != k; }); + return std::distance(first, mismatch); + } + return 0; +} + +template +int substitute_length(Iterator1 first1, Iterator1 last1, Iterator2 first2) { + if (first1 != last1) { + Iterator1 it1 = first1; + Iterator2 it2 = first2; + Iterator1 next1 = std::next(first1); + Iterator2 next2 = std::next(first2); + Iterator1 prev1 = first1; + while (next1 != last1) { + if ((*it1 == *it2 && *next1 == *next2)) { + return std::distance(first1, it1); + } + if (*it1 == *next1 && *it1 == *prev1) { + return std::distance(first1, prev1); + } + prev1 = it1; + it1 = next1; it2 = next2; + ++next1; ++next2; + } + } + return std::distance(first1, last1); +} + +size_t reserve_size(const vector &line) { + // Big enough to store the line uncompressed together with an Substitute + // command with many overflow bytes. + return line.size() + 16; +} + +} // namespace + +vector encode_line(const vector &line, + const vector &reference) { + assert(line.size() == reference.size()); + if (all_zeros(line)) { + return vector(1, 0xFF); + } + + vector output; + output.reserve(reserve_size(line)); + output.push_back(0); // first byte is the edit count + + const uint8_t max_edits = 254; + int num_edits = 0; + + auto line_it = line.begin(); + auto ref_it = reference.begin(); + while (1) { + int offset = skip_to_next_mismatch(&line_it, line.end(), &ref_it); + if (line_it == line.end()) { + // No more differences, we're done. + break; + } + + if (++num_edits == max_edits) { + // We've run out of edits. Just output the rest of the line in a big + // substitute command. + write_substitute(offset, line_it, line.end(), &output); + break; + } + + int s = substitute_length(line_it, line.end(), ref_it); + if (s > 0) { + write_substitute(offset, line_it, std::next(line_it, s), &output); + line_it += s; + ref_it += s; + } else { + int r = repeat_length(line_it, line.end()); + assert(r >= 2); + write_repeat(offset, r, *line_it, &output); + line_it += r; + ref_it += r; + } + } + + assert(num_edits <= max_edits); + output[0] = num_edits; + return output; +} + +vector encode_line(const vector &line) { + if (all_zeros(line)) { + return vector(1, 0xFF); + } + vector buf; + buf.reserve(reserve_size(line)); + buf.push_back(1); + write_substitute(0, line.begin(), line.end(), &buf); + return buf; +} diff --git a/brlaser-master/src/line.h b/brlaser-master/src/line.h new file mode 100644 index 0000000..d9d8716 --- /dev/null +++ b/brlaser-master/src/line.h @@ -0,0 +1,31 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#ifndef LINE_H +#define LINE_H + +#include +#include + +std::vector encode_line( + const std::vector &line, + const std::vector &reference); + +std::vector encode_line( + const std::vector &line); + +#endif // LINE_H diff --git a/brlaser-master/src/main.cc b/brlaser-master/src/main.cc new file mode 100644 index 0000000..6eafcdd --- /dev/null +++ b/brlaser-master/src/main.cc @@ -0,0 +1,205 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2013 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "job.h" +#include "debug.h" + + +namespace { + +cups_raster_t *ras; +volatile sig_atomic_t interrupted = 0; + + +void sigterm_handler(int sig) { + interrupted = 1; +} + + +bool next_line(std::vector &buf) { + if (interrupted) { + return false; + } + return cupsRasterReadPixels(ras, buf.data(), buf.size()) == buf.size(); +} + + +bool plain_ascii_string(const char *str) { + bool result = true; + for (; result && *str; str++) { + result = *str >= 32 && *str <= 126; + } + return result; +} + +std::string ascii_job_name(const char *job_id, const char *job_user, const char *job_name) { + std::array parts = {{ + job_id, + job_user, + job_name + }}; + std::string result; + for (const char *part : parts) { + if (*part && plain_ascii_string(part)) { + if (!result.empty()) { + result += '/'; + } + result += part; + } + } + if (result.empty()) { + result = "brlaser"; + } + const int max_size = 79; + if (result.size() > max_size) { + result.resize(max_size); + } + return result; +} + +page_params build_page_params(const cups_page_header2_t &header) { + static const std::array sources = {{ + "AUTO", "T1", "T2", "T3", "MP", "MANUAL" + }}; + static const std::map sizes = { + { "A4", "A4" }, + { "A5", "A5" }, + { "A6", "A6" }, + { "B5", "B5" }, + { "B6", "B6" }, + { "EnvC5", "C5" }, + { "EnvMonarch", "MONARCH" }, + { "EnvPRC5", "DL" }, + { "EnvDL", "DL" }, + { "Executive", "EXECUTIVE" }, + { "Legal", "LEGAL" }, + { "Letter", "LETTER" } + }; + + page_params p = { }; + p.num_copies = header.NumCopies; + p.resolution = header.HWResolution[0]; + p.economode = header.cupsInteger[10]; + p.mediatype = header.MediaType; + p.duplex = header.Duplex; + + if (header.MediaPosition < sources.size()) + p.sourcetray = sources[header.MediaPosition]; + else + p.sourcetray = sources[0]; + + auto size_it = sizes.find(header.cupsPageSizeName); + if (size_it != sizes.end()) + p.papersize = size_it->second; + else + p.papersize = "A4"; + + return p; +} + +} // namespace + + +int main(int argc, char *argv[]) { + fprintf(stderr, "INFO: %s version %s\n", PACKAGE, VERSION); + + if (argc != 6 && argc != 7) { + fprintf(stderr, "ERROR: rastertobrlaser job-id user title copies options [file]\n"); + fprintf(stderr, "INFO: This program is a CUPS filter. It is not intended to be run manually.\n"); + return 1; + } + const char *job_id = argv[1]; + const char *job_user = argv[2]; + const char *job_name = argv[3]; + // const int job_copies = atoi(argv[4]); + // const char *job_options = argv[5]; + const char *job_filename = argv[6]; + // const char *job_charset = getenv("CHARSET"); + + signal(SIGTERM, sigterm_handler); + signal(SIGPIPE, SIG_IGN); + + int fd = STDIN_FILENO; + if (job_filename) { + fd = open(job_filename, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "ERROR: " PACKAGE ": Unable to open raster file\n"); + return 1; + } + } + +#ifdef __OpenBSD__ + if (pledge("stdio", nullptr) != 0) { + fprintf(stderr, "ERROR: " PACKAGE ": pledge failed\n"); + return 1; + } +#endif + + ras = cupsRasterOpen(fd, CUPS_RASTER_READ); + if (!ras) { + fprintf(stderr, "DEBUG: " PACKAGE ": Cannot read raster data. Most likely an earlier filter in the pipeline failed.\n"); + return 1; + } + + int pages = 0; + { + job job(stdout, ascii_job_name(job_id, job_user, job_name)); + cups_page_header2_t header; + while (!interrupted && cupsRasterReadHeader2(ras, &header)) { + if (header.cupsBitsPerPixel != 1 + || header.cupsBitsPerColor != 1 + || header.cupsNumColors != 1 + || header.cupsBytesPerLine > 10000) { + fprintf(stderr, "ERROR: " PACKAGE ": Page %d: Bogus raster data.\n", pages + 1); + dump_page_header(header); + return 1; + } + if (pages == 0) { + fprintf(stderr, "DEBUG: " PACKAGE ": Page header of first page\n"); + dump_page_header(header); + } + job.encode_page(build_page_params(header), + header.cupsHeight, + header.cupsBytesPerLine, + next_line); + fprintf(stderr, "PAGE: %d %d\n", ++pages, header.NumCopies); + } + } + + if (pages == 0) { + fprintf(stderr, "ERROR: " PACKAGE ": No pages were found.\n"); + return 1; + } + + fflush(stdout); + if (ferror(stdout)) { + fprintf(stderr, "DEBUG: " PACKAGE ": Could not write print data. Most likely the CUPS backend failed.\n"); + return 1; + } + return 0; +} diff --git a/brlaser-master/test/lest.hpp b/brlaser-master/test/lest.hpp new file mode 100644 index 0000000..efc9442 --- /dev/null +++ b/brlaser-master/test/lest.hpp @@ -0,0 +1,199 @@ +// Copyright 2013 by Martin Moene +// +// lest is based on ideas by Kevlin Henney, see video at +// http://skillsmatter.com/podcast/agile-testing/kevlin-henney-rethinking-unit-testing-in-c-plus-plus +// +// Distributed under the Boost Software License, Version 1.0: +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#ifndef LEST_LEST_H_INCLUDED +#define LEST_LEST_H_INCLUDED + +#include +#include +#include +#include +#include + +#ifndef lest_NO_SHORT_ASSERTION_NAMES +# define EXPECT lest_EXPECT +# define EXPECT_THROWS lest_EXPECT_THROWS +# define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS +#endif + +#define lest_EXPECT( expr ) \ + try \ + { \ + if ( ! (expr) ) \ + throw lest::failure{ lest_LOCATION, #expr }; \ + } \ + catch( lest::failure const & ) \ + { \ + throw ; \ + } \ + catch( std::exception const & e ) \ + { \ + throw lest::unexpected{ lest_LOCATION, #expr, lest::with_message( e.what() ) }; \ + } \ + catch(...) \ + { \ + throw lest::unexpected{ lest_LOCATION, #expr, "of unknown type" }; \ + } + +#define lest_EXPECT_THROWS( expr ) \ + for (;;) \ + { \ + try { lest::serum( expr ); } catch (...) { break; } \ + throw lest::expected{ lest_LOCATION, #expr }; \ + } + +#define lest_EXPECT_THROWS_AS( expr, excpt ) \ + for (;;) \ + { \ + try { lest::serum( expr ); } catch ( excpt & ) { break; } catch (...) {} \ + throw lest::expected{ lest_LOCATION, #expr, lest::of_type( #excpt ) }; \ + } + +#define lest_LOCATION lest::location{__FILE__, __LINE__} + +namespace lest { + +struct test +{ + const std::string name; + const std::function behaviour; +}; + +struct location +{ + const std::string file; + const int line; + + location( std::string file, int line ) + : file{ file }, line{ line } {} +}; + +struct comment +{ + const std::string text; + + comment( std::string text ) : text{ text } {} + explicit operator bool() { return ! text.empty(); } +}; + +struct message : std::runtime_error +{ + const std::string kind; + const location where; + const comment note; + + ~message() throw() {} // GCC 4.6 + + message( std::string kind, location where, std::string expr, std::string note = "" ) + : std::runtime_error{ expr }, kind{ kind }, where{ where }, note{ note } {} +}; + +struct failure : message +{ + failure( location where, std::string expr ) + : message{ "failed", where, expr } {} +}; + +struct expected : message +{ + expected( location where, std::string expr, std::string excpt = "" ) + : message{ "failed: didn't get exception", where, expr, excpt } {} +}; + +struct unexpected : message +{ + unexpected( location where, std::string expr, std::string note ) + : message{ "failed: got unexpected exception", where, expr, note } {} +}; + +inline bool serum( bool verum ) { return verum; } + +inline std::string with_message( std::string text ) +{ + return "with message \"" + text + "\""; +} + +inline std::string of_type( std::string text ) +{ + return "of type " + text; +} + +inline std::string pluralise( int n, std::string text ) +{ + return n == 1 ? text : text + "s"; +} + +inline std::ostream & operator<<( std::ostream & os, comment note ) +{ + return os << (note ? " " + note.text : "" ); +} + +inline std::ostream & operator<<( std::ostream & os, location where ) +{ +#ifdef __GNUG__ + return os << where.file << ":" << where.line; +#else + return os << where.file << "(" << where.line << ")"; +#endif +} + +inline void report( std::ostream & os, message const & e, std::string test ) +{ + os << e.where << ": " << e.kind << e.note << ": " << test << ": " << e.what() << std::endl; +} + +template +int run( test const (&specification)[N], std::ostream & os = std::cout ) +{ + int failures = 0; + + for ( auto & testing : specification ) + { + try + { + testing.behaviour(); + } + catch( message const & e ) + { + ++failures; + report( os, e, testing.name ); + } + } + + if ( failures > 0 ) + { + os << failures << " out of " << N << " " << pluralise(N, "test") << " failed." << std::endl; + } + + return failures; +} + +} // namespace lest + +#endif // LEST_LEST_H_INCLUDED diff --git a/brlaser-master/test/tempfile.h b/brlaser-master/test/tempfile.h new file mode 100644 index 0000000..f83e306 --- /dev/null +++ b/brlaser-master/test/tempfile.h @@ -0,0 +1,54 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2014 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#ifndef TEMPFILE_H +#define TEMPFILE_H + +#include +#include +#include + +class tempfile { + public: + explicit tempfile() + : ptr_(0), + size_(0), + file_(open_memstream(&ptr_, &size_)) { + } + + ~tempfile() { + fclose(file_); + free(ptr_); + } + + FILE *file() { + return file_; + } + + std::vector data() { + if (fflush(file_)) + return std::vector(); + return std::vector(ptr_, ptr_ + size_); + } + + private: + char *ptr_; + size_t size_; + FILE *file_; +}; + +#endif // TEMPFILE_H diff --git a/brlaser-master/test/test_block.cc b/brlaser-master/test/test_block.cc new file mode 100644 index 0000000..e5fd103 --- /dev/null +++ b/brlaser-master/test/test_block.cc @@ -0,0 +1,91 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2014 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include "lest.hpp" +#include +#include +#include "tempfile.h" +#include "../src/block.h" + +typedef std::vector vec; + +const lest::test specification[] = { + "A block is created empty", + [] { + block b; + EXPECT(b.empty()); + }, + + "Adding a line makes a block no longer empty", + [] { + block b; + b.add_line(vec{1}); + EXPECT(!b.empty()); + }, + + "A block can contain 128 lines", + [] { + block b; + for (int i = 0; i < 128; ++i) { + EXPECT(b.line_fits(1)); + b.add_line(vec(1)); + } + EXPECT(!b.line_fits(1)); + }, + + "A block has a size limit of about 16 kilobyte", + [] { + block b; + for (int i = 0; i < 16; ++i) { + EXPECT(b.line_fits(1000)); + b.add_line(vec(1000)); + } + EXPECT(!b.line_fits(400)); + }, + + "Flushing an empty block does nothing", + [] { + block b; + tempfile f; + b.flush(f.file()); + EXPECT(f.data().empty()); + }, + + "Flush() writes the lines to a file with a proper header", + [] { + block b; + for (uint8_t n = 1; n < 6; ++n) { + b.add_line(vec{n, n}); + } + tempfile f; + b.flush(f.file()); + EXPECT(( f.data() == vec{'1','2','w',0,5,1,1,2,2,3,3,4,4,5,5} )); + }, + + "After flush() a block is empty again", + [] { + block b; + b.add_line(vec{1}); + tempfile f; + b.flush(f.file()); + EXPECT(b.empty()); + } +}; + +int main() { + return lest::run(specification); +} diff --git a/brlaser-master/test/test_lest.cc b/brlaser-master/test/test_lest.cc new file mode 100644 index 0000000..1eb7d6a --- /dev/null +++ b/brlaser-master/test/test_lest.cc @@ -0,0 +1,291 @@ +// Copyright 2013 by Martin Moene +// +// Distributed under the Boost Software License, Version 1.0: +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +#include "lest.hpp" +#include + +using namespace lest; + +const lest::test specification[] = +{ + "Function to suppress warning \"expression has no effect\" acts as identity function", [] + { + EXPECT( false == serum( false ) ); + EXPECT( true == serum( true ) ); + }, + + "Function with_message() returns correct string", [] + { + std::string msg = "Let writing tests become irresistibly easy and attractive."; + EXPECT( "with message \"" + msg + "\"" == with_message( msg ) ); + }, + + "Function of_type() returns correct string", [] + { + std::string msg = "this_type"; + EXPECT( "of type " + msg == of_type( msg ) ); + }, + + "Function pluralise() adds 's' except for 1 item", [] + { + std::string word = "hammer"; + EXPECT( word == pluralise( 1, word ) ); + for ( auto i : {0,2,3,4,5,6,7,8,9,10,11,12} ) + EXPECT( word + "s" == pluralise( i, word ) ); + }, + + "Location constructs properly", [] + { + char const * file = __FILE__; int line = __LINE__; + location where{ file, line }; + EXPECT( file == where.file ); + EXPECT( line == where.line ); + }, + + "Comment constructs properly", [] + { + std::string text = __FILE__; + comment note = text; + EXPECT( text == note.text ); + }, + + "Comment converted to bool indicates absence or presence of comment", [] + { + EXPECT( false == bool( comment( "") ) ); + EXPECT( true == bool( comment("x") ) ); + }, + + "Failure exception type constructs and prints properly", [] + { + std::string name = "test-name"; + failure msg( location{"filename.cpp", 765}, "expression" ); + + std::ostringstream os; + report( os, msg, name ); + +#ifndef __GNUG__ + EXPECT( os.str() == "filename.cpp(765): failed: test-name: expression\n" ); +#else + EXPECT( os.str() == "filename.cpp:765: failed: test-name: expression\n" ); +#endif + }, + + "Expected exception type constructs and prints properly", [] + { + std::string name = "test-name"; + expected msg( location{"filename.cpp", 765}, "expression" ); + + std::ostringstream os; + report( os, msg, name ); + +#ifndef __GNUG__ + EXPECT( os.str() == "filename.cpp(765): failed: didn't get exception: test-name: expression\n" ); +#else + EXPECT( os.str() == "filename.cpp:765: failed: didn't get exception: test-name: expression\n" ); +#endif + }, + + "Unexpected exception type constructs and prints properly", [] + { + std::string name = "test-name"; + unexpected msg( location{"filename.cpp", 765}, "expression", "exception-type" ); + + std::ostringstream os; + report( os, msg, name ); + +#ifndef __GNUG__ + EXPECT( os.str() == "filename.cpp(765): failed: got unexpected exception exception-type: test-name: expression\n" ); +#else + EXPECT( os.str() == "filename.cpp:765: failed: got unexpected exception exception-type: test-name: expression\n" ); +#endif + }, + + "Expect generates no message exception for a succeeding test", [] + { + test pass = { "P", [] { EXPECT( true ); } }; + + try { pass.behaviour(); } + catch(...) { throw failure(location{__FILE__,__LINE__}, "unexpected error generated"); } + }, + + "Expect generates a message exception for a failing test", [] + { + test fail = { "F", [] { EXPECT( false ); } }; + + for (;;) + { + try { fail.behaviour(); } catch ( message & ) { break; } + throw failure(location{__FILE__,__LINE__}, "no error generated"); + } + }, + + "Expect succeeds for success (true) and failure (false)", [] + { + test pass[] = {{ "P", [] { EXPECT( true ); } }}; + test fail[] = {{ "F", [] { EXPECT( false ); } }}; + + std::ostringstream os; + + EXPECT( 0 == run( pass, os ) ); + EXPECT( 1 == run( fail, os ) ); + }, + + "Expect succeeds for integer comparation", [] + { + test pass [] = {{ "P" , [] { EXPECT( 7 == 7 ); EXPECT( 7 != 8 ); + EXPECT( 7 >= 6 ); EXPECT( 7 <= 8 ); + EXPECT( 7 > 6 ); EXPECT( 7 < 8 ); } }}; + test fail_1[] = {{ "F1", [] { EXPECT( 7 == 8 ); } }}; + test fail_2[] = {{ "F2", [] { EXPECT( 7 != 7 ); } }}; + test fail_3[] = {{ "F3", [] { EXPECT( 7 <= 6 ); } }}; + test fail_4[] = {{ "F4", [] { EXPECT( 7 >= 8 ); } }}; + test fail_5[] = {{ "F5", [] { EXPECT( 7 < 6 ); } }}; + test fail_6[] = {{ "F6", [] { EXPECT( 7 > 8 ); } }}; + + std::ostringstream os; + + EXPECT( 0 == run( pass , os ) ); + EXPECT( 1 == run( fail_1, os ) ); + EXPECT( 1 == run( fail_2, os ) ); + EXPECT( 1 == run( fail_3, os ) ); + EXPECT( 1 == run( fail_4, os ) ); + EXPECT( 1 == run( fail_5, os ) ); + EXPECT( 1 == run( fail_6, os ) ); + }, + + "Expect succeeds for string comparation", [] + { + std::string a("a"); std::string b("b"); + test pass [] = {{ "P" , [=]() { EXPECT( a == a ); EXPECT( a != b ); + EXPECT( b >= a ); EXPECT( a <= b ); + EXPECT( b > a ); EXPECT( a < b ); } }}; + test fail_1[] = {{ "F1", [=]() { EXPECT( a == b ); } }}; + test fail_2[] = {{ "F2", [=]() { EXPECT( a != a ); } }}; + test fail_3[] = {{ "F3", [=]() { EXPECT( b <= a ); } }}; + test fail_4[] = {{ "F4", [=]() { EXPECT( a >= b ); } }}; + test fail_5[] = {{ "F5", [=]() { EXPECT( b < a ); } }}; + test fail_6[] = {{ "F6", [=]() { EXPECT( a > b ); } }}; + + std::ostringstream os; + + EXPECT( 0 == run( pass , os ) ); + EXPECT( 1 == run( fail_1, os ) ); + EXPECT( 1 == run( fail_2, os ) ); + EXPECT( 1 == run( fail_3, os ) ); + EXPECT( 1 == run( fail_4, os ) ); + EXPECT( 1 == run( fail_5, os ) ); + EXPECT( 1 == run( fail_6, os ) ); + }, + + "Function run() returns the right failure count", [] + { + test pass [] = {{ "P" , [] { EXPECT( 1==1 ); } }}; + test fail_1[] = {{ "F1", [] { EXPECT( 0==1 ); } }}; + test fail_3[] = {{ "F1", [] { EXPECT( 0==1 ); } }, + { "F2", [] { EXPECT( 0==1 ); } }, + { "F3", [] { EXPECT( 0==1 ); } },}; + + std::ostringstream os; + + EXPECT( 0 == run( pass , os ) ); + EXPECT( 1 == run( fail_1, os ) ); + EXPECT( 3 == run( fail_3, os ) ); + }, + + "Expect succeeds with an unexpected standard exception", [] + { + std::string text = "hello-world"; + test pass[] = {{ "P", [=]() { EXPECT( (throw std::runtime_error(text), true) ); } }}; + + std::ostringstream os; + + EXPECT( 1 == run( pass, os ) ); + EXPECT( std::string::npos != os.str().find(text) ); + }, + + "Expect succeeds with an unexpected non-standard exception", [] + { + test pass[] = {{ "P", [] { EXPECT( (throw 77, true) ); } }}; + + std::ostringstream os; + + EXPECT( 1 == run( pass, os ) ); + }, + + "Expect_throws succeeds with an expected standard exception", [] + { + std::string text = "hello-world"; + test pass[] = {{ "P", [=]() { EXPECT_THROWS( (throw std::runtime_error(text), true) ); } }}; + test fail[] = {{ "F", [ ]() { EXPECT_THROWS( true ); } }}; + + std::ostringstream os; + + EXPECT( 0 == run( pass, os ) ); + EXPECT( 1 == run( fail, os ) ); + }, + + "Expect_throws succeeds with an expected non-standard exception", [] + { + test pass[] = {{ "P", [] { EXPECT_THROWS( (throw 77, true) ); } }}; + test fail[] = {{ "F", [] { EXPECT_THROWS( true ); } }}; + + std::ostringstream os; + + EXPECT( 0 == run( pass, os ) ); + EXPECT( 1 == run( fail, os ) ); + }, + + "Expect_throws_as succeeds with a specific expected standard exception", [] + { + test pass[] = {{ "P", [] { EXPECT_THROWS_AS( (throw std::bad_alloc(), true), std::bad_alloc ); } }}; + test fail[] = {{ "F", [] { EXPECT_THROWS_AS( (throw std::bad_alloc(), true), std::runtime_error ); } }}; + + std::ostringstream os; + + EXPECT( 0 == run( pass, os ) ); + EXPECT( 1 == run( fail, os ) ); + }, + + "Expect_throws_as succeeds with a specific expected non-standard exception", [] + { + test pass[] = {{ "P", [] { EXPECT_THROWS_AS( (throw 77, true), int ); } }}; + test fail[] = {{ "F", [] { EXPECT_THROWS_AS( (throw 77, true), std::runtime_error ); } }}; + + std::ostringstream os; + + EXPECT( 0 == run( pass, os ) ); + EXPECT( 1 == run( fail, os ) ); + }, +}; + +int main() +{ + return lest::run( specification ); +} + +// cl -nologo -Wall -EHsc test_lest.cpp && test_lest +// g++ -Wall -Wextra -Weffc++ -std=c++11 -o test_lest.exe test_lest.cpp && test_lest + diff --git a/brlaser-master/test/test_line.cc b/brlaser-master/test/test_line.cc new file mode 100644 index 0000000..9ab12c6 --- /dev/null +++ b/brlaser-master/test/test_line.cc @@ -0,0 +1,150 @@ +// This file is part of the brlaser printer driver. +// +// Copyright 2014 Peter De Wachter +// +// brlaser is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// brlaser is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with brlaser. If not, see . + +#include "lest.hpp" +#include +#include +#include +#include "../src/line.h" + +typedef std::vector vec; + + +uint8_t sub(uint8_t offset, uint8_t count) { + assert(offset < 16); + assert(count < 8); + return (offset << 3) | count; +} + +uint8_t rep(uint8_t offset, uint8_t count) { + assert(offset < 4); + assert(count < 32); + return 128 | (offset << 5) | count; +} + + +const lest::test specification[] = { + "Don't crash on zero-length lines", + [] { + EXPECT(( encode_line(vec{}) == vec{0xFF} )); + EXPECT(( encode_line(vec{}, vec{}) == vec{0xFF} )); + }, + + "Encoding an initial blank line", + [] { + EXPECT(( encode_line(vec{0,0,0}) == vec{0xFF} )); + }, + + "Encoding an initial non-blank line", + [] { + EXPECT(( encode_line(vec{1,2,3}) == (vec{1,sub(0,2),1,2,3}) )); + }, + + "Encoding a (non-initial) blank line", + [] { + EXPECT(( encode_line(vec{0,0,0}, vec{1,2,3}) == vec{0xFF} )); + }, + + "Encoding a repeated line", + [] { + EXPECT(( encode_line(vec{1,2,3}, vec{1,2,3}) == vec{0} )); + }, + + "Using a subsitute command", + [] { + EXPECT(( encode_line(vec{0,0,1,2,3,0,0}, vec(7)) == vec{1,sub(2,2),1,2,3} )); + }, + + "Using a repeat command", + [] { + EXPECT(( encode_line(vec{0,0,1,1,0,0}, vec(6)) == vec{1,rep(2,0),1} )); + }, + + "Repeat command followed by substitute command", + [] { + EXPECT(( encode_line(vec{1,1,1,2,3}, vec(5)) == vec{2,rep(0,1),1,sub(0,1),2,3} )); + }, + + "Substitute comand followed by repeat command", + [] { + EXPECT(( encode_line(vec{3,2,1,1,1}, vec(5)) == vec{2,sub(0,1),3,2,rep(0,1),1} )); + }, + + "Substitute with an unmodified byte in the middle", + [] { + EXPECT(( encode_line(vec{1,2,3,0,1,2,3}, vec(7)) == vec{1,sub(0,6),1,2,3,0,1,2,3} )); + }, + + "Substitue with two unmodified bytes in the middle", + [] { + EXPECT(( encode_line(vec{1,2,3,0,0,1,2,3}, vec(8)) == vec{2,sub(0,2),1,2,3,sub(2,2),1,2,3} )); + }, + + "Repeat with an unmodified byte in the middle", + [] { + EXPECT(( encode_line(vec{1,1,1,0,1,1,1}, vec(7)) == vec{2,rep(0,1),1,rep(1,1),1} )); + }, + + "254 edits needed for a single line", + [] { + vec line, result; + for (int i = 0; i < 254; ++i) + line.insert(line.end(), {0,0,1}); + result.push_back(254); + for (int i = 0; i < 254; ++i) + result.insert(result.end(), {sub(2,0),1}); + EXPECT(( encode_line(line, vec(line.size())) == result )); + }, + + "Give up if more than 254 edits needed...", + [] { + vec line, result; + for (int i = 0; i < 255; ++i) + line.insert(line.end(), {0,0,1}); + result.push_back(254); + for (int i = 0; i < 253; ++i) + result.insert(result.end(), {sub(2,0),1}); + result.insert(result.end(), {sub(2,3),1,0,0,1}); + EXPECT(( encode_line(line, vec(line.size())) == result )); + }, + + "Repeat command with overflow bytes", + [] { + vec line(3, 0); + line.insert(line.end(), 512, 1); + vec ref(line.size(), 0); + vec expected{1,rep(3,31),0,255,224,1}; + EXPECT(encode_line(line, ref) == expected); + }, + + "Substitute command with overflow bytes", + [] { + vec expected{1,sub(15,7),255,0,255,237}; + vec line(270, 0); + for (int i = 0; i < 250; ++i) { + expected.insert(expected.end(), {1,2}); + line.insert(line.end(), {1,2}); + } + vec ref(line.size(), 0); + EXPECT(encode_line(line, ref) == expected); + }, +}; + + +int main() { + return lest::run(specification); +} diff --git a/etc/apt/preferences.d/mozilla-firefox.pref b/etc/apt/preferences.d/mozilla-firefox.pref new file mode 100644 index 0000000..8743ea3 --- /dev/null +++ b/etc/apt/preferences.d/mozilla-firefox.pref @@ -0,0 +1,7 @@ +Package: * > +Pin: release o=LP-PPA-mozillateam +Pin-Priority: 1001 + +Package: firefox +Pin: version 1:1snap1-0ubuntu2 +Pin-Priority: -1 diff --git a/etc/apt/preferences.d/nosnap.pref b/etc/apt/preferences.d/nosnap.pref new file mode 100644 index 0000000..c425d07 --- /dev/null +++ b/etc/apt/preferences.d/nosnap.pref @@ -0,0 +1,3 @@ +Package: snapd +Pin: release a=* +Pin-Priority: -10 diff --git a/etc/needrestart/conf.d/no-prompt.conf b/etc/needrestart/conf.d/no-prompt.conf new file mode 100644 index 0000000..b04affd --- /dev/null +++ b/etc/needrestart/conf.d/no-prompt.conf @@ -0,0 +1 @@ +$nrconf{restart} = 'a'; diff --git a/etc/openkiosk.conf-chromium b/etc/openkiosk.conf-chromium new file mode 100644 index 0000000..efd7e8f --- /dev/null +++ b/etc/openkiosk.conf-chromium @@ -0,0 +1,45 @@ +# openkiosk.conf +# +# Configuration file for OpenKiosk + +# Debug flag. Set to 1 to cause startkiosk.sh to output helpful +# information to ~/startkiosk.log. +# Set to 0 for production use, or the log could fill up your filesystem! +DEBUG="0" + +# URL to load for the kiosk browser. +TGT_URL="https://localhost:10000" + +# Interval in seconds to poll the URL for changes. +# This should be enabled where the kiosk is used as a display for a file +# fetched from a URL. Do not use for an interactive kiosk. +# Set to 0 to disable polling or for an interactive kiosk. +POLL_INTERVAL="0" + +# Display blanking is controlled by DPMS. For a display-only kiosk, +# set INHIBIT_BLANK to "1" to prevent screen blanking, ignoring the +# DSP parameters. If INHIBIT_BLANK is set to "0", the DSP parameters +# control the number of seconds for standby, suspend, and off modes. +# If you find that your display is going to sleep and not waking up, try +# setting the OFF and/or SUSP parameters to 0 which will disable them. +INHIBIT_BLANK="0" +DSP_STBY_SEC="600" +DSP_SUSP_SEC="1200" +DSP_OFF_SEC="1800" + +# Display rotation. Can be used to control the orientation of the display. +# Values are one of "normal", "left", "right", or "inverted". +ROTATION="normal" + +# For standard kiosk functionality +APP_CMD="chromium-browser --test-type --ignore-certificate-errors --kiosk --no-first-run --check-for-update-interval=1 --simulate-upgrade --incognito $TGT_URL" +ALIVE_STRING="chromium-browse" +KILL_CMD="killall chromium-browser" +CLEANUP_CMD="/usr/local/bin/kiosk_cleanup.sh" + +#----------------------------------------------------------------------- +# For test use +#APP_CMD="xterm" +#ALIVE_STRING="xterm" +#KILL_CMD="killall xterm" +#CLEANUP_CMD="sleep 1" diff --git a/etc/openkiosk.conf-firefox b/etc/openkiosk.conf-firefox new file mode 100644 index 0000000..5326a97 --- /dev/null +++ b/etc/openkiosk.conf-firefox @@ -0,0 +1,41 @@ +# openkiosk.conf +# +# Configuration file for OpenKiosk + +# Debug flag. Set to 1 to cause startkiosk.sh to output helpful +# information to ~/startkiosk.log. +# Set to 0 for production use, or the log could fill up your filesystem! +DEBUG="0" + +# URL to load for the kiosk browser. +TGT_URL="https://localhost:10000" + +# Interval in seconds to poll the URL for changes. +# This should be enabled where the kiosk is used as a display for a file +# fetched from a URL. Do not use for an interactive kiosk. +# Set to 0 to disable polling or for an interactive kiosk. +POLL_INTERVAL="0" + +# Display blanking is controlled by DPMS. For a display-only kiosk, +# set INHIBIT_BLANK to "1" to prevent screen blanking, ignoring the +# DSP parameters. If INHIBIT_BLANK is set to "0", the DSP parameters +# control the number of seconds for standby, suspend, and off modes. +# If you find that your display is going to sleep and not waking up, try +# setting the OFF and/or SUSP parameters to 0 which will disable them. +INHIBIT_BLANK="0" +DSP_STBY_SEC="600" +DSP_SUSP_SEC="1200" +DSP_OFF_SEC="1800" + +# For standard kiosk functionality +APP_CMD="firefox -private --kiosk $TGT_URL" +ALIVE_STRING="firefox" +KILL_CMD="killall firefox" +CLEANUP_CMD="/usr/local/bin/kiosk_cleanup.sh" + +#----------------------------------------------------------------------- +# For test use +#APP_CMD="xterm" +#ALIVE_STRING="xterm" +#KILL_CMD="killall xterm" +#CLEANUP_CMD="sleep 1" diff --git a/home/customer/.config/openbox/rc.xml b/home/customer/.config/openbox/rc.xml new file mode 100644 index 0000000..fc8d3b0 --- /dev/null +++ b/home/customer/.config/openbox/rc.xml @@ -0,0 +1,744 @@ + + + + + + 10 + 20 + + + + yes + + no + + yes + + no + + 200 + + no + + + + + Smart + +
yes
+ + Primary + + 1 + +
+ + + Clearlooks + NLIMC + + yes + yes + + sans + 8 + + bold + + normal + + + + sans + 8 + + bold + + normal + + + + sans + 9 + + normal + + normal + + + + sans + 9 + + normal + + normal + + + + sans + 9 + + bold + + normal + + + + sans + 9 + + bold + + normal + + + + + + + 1 + 1 + + + + 875 + + + + + yes + Nonpixel + + Center + + + + + 10 + + 10 + + + + + + + 0 + 0 + 0 + 0 + + + + TopLeft + + 0 + 0 + no + Above + + Vertical + + no + 300 + + 300 + + Middle + + + + + + + + pkill firefox;pkill chromium-browser + + + + + + true + + + + + + true + + + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + true + + + + + + true + + + + + true + + + + + + true + + + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + + true + + + + + + shutdown -P now + + + + + + shutdown -r now + + + C-g + + + + 1 + + 500 + + 400 + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + previous + + + next + + + previous + + + next + + + previous + + + next + + + + + + + + + + + + + + no + + + + + + + + + + + yes + + + + + + + + + + + + + + + + + + + + + + + + + client-menu + + + + + + top + + + + + + left + + + + + + right + + + + + + bottom + + + + + + client-menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + client-menu + + + + + client-menu + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + vertical + + + horizontal + + + + + + + + + + + + + + + + + previous + + + next + + + + previous + + + next + + + previous + + + next + + + + + + + + + + + + + + + + + + + previous + + + next + + + previous + + + next + + + + + + + + + + + +
diff --git a/home/customer/.profile b/home/customer/.profile new file mode 100644 index 0000000..f6dfaf6 --- /dev/null +++ b/home/customer/.profile @@ -0,0 +1,23 @@ +# ~/.profile: executed by the command interpreter for login shells. +# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login +# exists. +# see /usr/share/doc/bash/examples/startup-files for examples. +# the files are located in the bash-doc package. + +# the default umask is set in /etc/profile; for setting the umask +# for ssh logins, install and configure the libpam-umask package. +#umask 022 + +# if running bash +if [ -n "$BASH_VERSION" ]; then + # include .bashrc if it exists + if [ -f "$HOME/.bashrc" ]; then + . "$HOME/.bashrc" + fi +fi + +# set PATH so it includes user's private bin if it exists +if [ -d "$HOME/bin" ] ; then + PATH="$HOME/bin:$PATH" +fi +/usr/bin/startx /etc/X11/Xsession /usr/local/bin/startkiosk.sh -- :0 diff --git a/home/customer/openkiosk_mozilla_profile.tar.gz b/home/customer/openkiosk_mozilla_profile.tar.gz new file mode 100644 index 0000000..42108c3 Binary files /dev/null and b/home/customer/openkiosk_mozilla_profile.tar.gz differ diff --git a/kiosk-setup.sh b/kiosk-setup.sh new file mode 100644 index 0000000..9faf2f6 --- /dev/null +++ b/kiosk-setup.sh @@ -0,0 +1,249 @@ +#!/bin/bash + +# kiosk-setup.sh +# OpenKiosk Browser Terminal Setup +# Copyright (C) 2024 Rod Wright + +# SPDX-License-Identifier: GPL-2.0 + +OK_VERSION="1.0.0" + +# Test for superuser +current_user=`whoami` +current_login=`who am i | awk '{print $1}'` +if [ "$current_user" != "root" ] +then + echo "You must have root privileges to run this setup." + echo "Try 'sudo ./kiosk-setup.sh'" + exit 1 +fi + +echo "" +echo " Welcome to OpenKiosk $OK_VERSION" +echo "" +echo "" +echo "This script will configure a Debian based system to be a Kiosk Browser terminal." +echo "" +echo "" +echo "To continue with the setup of OpenKiosk, press enter. Otherwise," +echo -n "press ctrl-c to quit." +read continueok +echo "" +echo "" + +# Determine OS Release version +echo -n "OS information: " +echo "" +cat /etc/os-release +echo "" +sleep 5 + +# Copy in the needed files +echo "Copying files..." +chmod +x usr/local/bin/* +cp -Rv etc/* /etc/ +cp -v usr/local/bin/* /usr/local/bin +cp -v lib/systemd/system/getty@tty1.service /lib/systemd/system +rm /lib/systemd/system/ctrl-alt-del.target +ln -s /dev/null /lib/systemd/system/ctrl-alt-del.target +echo "...done." + +# Make sure OS is up to date +echo "Updating Operating System..." +sleep 5 +apt update && apt dist-upgrade -y +echo "...done." +echo "" + +# Remove snap if installed +if snap list >/dev/null 2>&1; then + echo "Removing snap..." + snap remove lxd + snap remove core20 + snap remove snapd + systemctl stop snapd + systemctl disable snapd + systemctl mask snapd + apt purge snapd -y + apt-mark hold snapd + rm -rf /home/*/snap/ + rm -rf /root/snap/ + rm -rf /snap + rm -rf /var/snap + rm -rf /var/lib/snapd + echo "...done." + # Add the firefox deb repository since we won't be getting snap + add-apt-repository -y ppa:mozillateam/ppa +fi + +# Install packages +echo "" +echo "" +echo "Installing required kiosk packages..." +sleep 5 +echo "" + +# If we are on a Raspberry Pi 5, we'll need to install this for the +# xorg server to start +if cat /proc/cpuinfo|grep -q "Raspberry Pi 5" >/dev/null 2>&1 +then + apt install -y gldriver-test +fi + +# If we are on a Raspberry Pi running Raspbian we use chromium-browser. +# If we are on anything else, we use firefox. +if cat /etc/os-release|grep -q "Raspbian" >/dev/null 2>&1 +then + browser_pkg="chromium-browser" + ln -sf /etc/openkiosk.conf-chromium /etc/openkiosk.conf +else + browser_pkg="firefox" + ln -sf /etc/openkiosk.conf-firefox /etc/openkiosk.conf +fi + +# Install required packages +apt update +apt install -y --no-install-recommends xorg openbox $browser_pkg +apt install -y cups libcups2-dev cmake +systemctl enable getty@tty1.service +cd brlaser-master && cmake . && make && make install && cd .. +myhn=`hostname` +infotimer=10 +echo "" +echo "" +echo "" +echo "The cups print server has been installed." +echo "After the kiosk is set up and working, you can use another network" +echo "computer to point a web browser to $myhn:631 to add a printer" +echo "of your choosing." +while [ $infotimer -gt 0 ] +do + sleep 1 + ((infotimer-=1)) +done +echo "" + +# Download and install webmin +echo "Installing webmin..." +skipwebmin="false" +curl -o setup-repos.sh https://raw.githubusercontent.com/webmin/webmin/master/setup-repos.sh +if [ $? -ne 0 ] +then + echo "Warning: failed to download Webmin repo setup script." + echo -n "Ignore and [c]ontinue or [A]bort? [c/A]: " + read wmfailchoice + if [ "$wmfailchoice" = "C" -o "$wmfailchoice" = "c" ] + then + skipwebmin="true" + echo "Continuing without installing Webmin. You should investigate the failure" + echo "and install Webmin manually after the kiosk is set up if you would like" + echo "to be able to manage the kiosk from another computer with a GUI instead" + echo "of through ssh only." + echo -n "Press enter to continue." + read continueok + echo "" + else + echo "Aborting kiosk setup." + exit 1 + fi +fi +if [ "$skipwebmin" = "false" ] +then + sh setup-repos.sh -f + apt install -y --install-recommends webmin +fi +echo "...done." + +# Install user config +echo "" +echo "Creating default user..." +cloneuser `who am i | awk '{print $1}'` customer +mkdir -p /home/customer/.config/openbox +cp home/customer/.profile /home/customer +cp home/customer/.config/openbox/rc.xml /home/customer/.config/openbox +cp home/customer/openkiosk_mozilla_profile.tar.gz /home/customer +chown customer:customer /home/customer/openkiosk_mozilla_profile.tar.gz +chown -R customer:customer /home/customer/.config /home/customer/.profile +echo "...done." +echo "" + +# Prompt for URL and kiosk type +echo "" +echo "This web browser based kiosk will need to know the site you would" +echo "like to load. This can be a normal website or a file to be displayed" +echo "in the browser, but must be available as a web URL." +echo "" +echo "Note that in kiosk mode, your normal navigation buttons and mouse" +echo "right-click menus are not available, so you will have no way to go" +echo "back or forward in a page unless the page itself provides that" +echo "capability." +url_ok=false +server_url="https://localhost:10000" +while ! $url_ok +do + echo "" + echo "Please enter complete URL." + echo -n "[https://localhost:10000] :" + read server_url + if [[ $server_url == "" ]] + then + server_url="https://localhost:10000" + fi + if ! `wget --no-check-certificate -q -o /dev/null -O /dev/null $server_url` + then + echo "" + echo "There was an error retrieving the URL you entered. The URL must" + echo "be a complete URL of the format \"http://somesite.com/somepage\"." + echo "If this URL is on the local network, try using the IP address or" + echo "the local domain. For example, instead of \"http://myserver/mypage\"," + echo "try \"http://192.168.1.1/mypage\" or \"http://myserver.local/mypage\"." + else + url_ok=true + fi +done +sed -i 's,'TGT_URL=.*','TGT_URL="\"$server_url\""',' /etc/openkiosk.conf-firefox +sed -i 's,'TGT_URL=.*','TGT_URL="\"$server_url\""',' /etc/openkiosk.conf-chromium +echo "" +type_choice="none" +while [ "$type_choice" = "none" ] +do + echo "Will this kiosk be an interactive kiosk or a display-only kiosk?" + echo -n "[I]nteractive or [D]isplay-only? [I] :" + read kiosk_type + echo "" + if [ "$kiosk_type" = "D" -o "$kiosk_type" = "d" ] + then + echo "Configuring for display-only kiosk." + echo "How often would you like to check for changes to the page being" + echo "displayed? Specify the number of seconds. Enter 0 to disable" + echo "periodic checking." + echo -n "Seconds between checks? [60] :" + read poll_interval + echo "" + if [ "$poll_interval" = "" ]; then poll_interval=60; fi + sed -i 's,'POLL_INTERVAL=.*','POLL_INTERVAL="\"$poll_interval\""',' /etc/openkiosk.conf-firefox + sed -i 's,'POLL_INTERVAL=.*','POLL_INTERVAL="\"$poll_interval\""',' /etc/openkiosk.conf-chromium + echo "Disabling screen blanking." + sed -i 's,'INHIBIT_BLANK=.*','INHIBIT_BLANK="\"1\""',' /etc/openkiosk.conf-firefox + sed -i 's,'INHIBIT_BLANK=.*','INHIBIT_BLANK="\"1\""',' /etc/openkiosk.conf-chromium + type_choice="D" + elif [ "$kiosk_type" = "I" -o "$kiosk_type" = "i" ] + then + echo "Configuring for interactive kiosk." + type_choice="I" + else + echo "Please enter I for interactive or D for display-only." + fi +done +echo "" +echo "Kiosk configuration is now complete. " +echo "" +echo "The system must be rebooted for the configuration to take effect." +echo -n "Enter R to reboot now, or hit enter to return to shell. " +read rebootok +if [ "$rebootok" = "R" -o "$rebootok" = "r" ] +then + reboot +else + exit 0 +fi diff --git a/lib/systemd/system/getty@tty1.service b/lib/systemd/system/getty@tty1.service new file mode 100644 index 0000000..5e77963 --- /dev/null +++ b/lib/systemd/system/getty@tty1.service @@ -0,0 +1,53 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Getty on %I +Documentation=man:agetty(8) man:systemd-getty-generator(8) +Documentation=http://0pointer.de/blog/projects/serial-console.html +After=systemd-user-sessions.service plymouth-quit-wait.service +After=rc-local.service + +# If additional gettys are spawned during boot then we should make +# sure that this is synchronized before getty.target, even though +# getty.target didn't actually pull it in. +Before=getty.target +IgnoreOnIsolate=yes + +# IgnoreOnIsolate causes issues with sulogin, if someone isolates +# rescue.target or starts rescue.service from multi-user.target or +# graphical.target. +Conflicts=rescue.service +Before=rescue.service + +# On systems without virtual consoles, don't start any getty. Note +# that serial gettys are covered by serial-getty@.service, not this +# unit. +ConditionPathExists=/dev/tty0 + +[Service] +# the VT is cleared by TTYVTDisallocate +ExecStart=-/sbin/agetty -a customer --noclear %I $TERM +Type=idle +Restart=always +RestartSec=0 +UtmpIdentifier=%I +TTYPath=/dev/%I +TTYReset=yes +TTYVHangup=yes +TTYVTDisallocate=yes +KillMode=process +IgnoreSIGPIPE=no +SendSIGHUP=yes + +# Unset locale for the console getty since the console has problems +# displaying some internationalized messages. +Environment=LANG= LANGUAGE= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION= + +[Install] +WantedBy=getty.target +DefaultInstance=tty1 diff --git a/usr/local/bin/cloneuser b/usr/local/bin/cloneuser new file mode 100644 index 0000000..78dba58 --- /dev/null +++ b/usr/local/bin/cloneuser @@ -0,0 +1,19 @@ +#!/bin/bash +SRC=$1 +DEST=$2 + +SRC_GROUPS=`id -Gn ${SRC}` +SRC_SHELL=$(awk -F : -v name=${SRC} '(name == $1) { print $7 }' /etc/passwd) +RAND_PW=`date +%s | sha256sum | base64 | head -c 32 ; echo` + +echo "Creating user $DEST" +useradd --shell ${SRC_SHELL} --password ${RAND_PW} --create-home ${DEST} +for grp in ${SRC_GROUPS};do + if [ "$grp" != "$SRC" ]; then + echo "Adding user $DEST to group $grp." + usermod -a -G $grp ${DEST} + fi +done + + + diff --git a/usr/local/bin/kiosk_cleanup.sh b/usr/local/bin/kiosk_cleanup.sh new file mode 100644 index 0000000..90bbba4 --- /dev/null +++ b/usr/local/bin/kiosk_cleanup.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# kiosk_cleanup.sh + +rm -rf /home/customer/.{config,cache}/chromium/ +rm -rf /home/customer/.cache/mozilla +rm -rf /home/customer/.mozilla +tar -C /home/customer -xf /home/customer/openkiosk_mozilla_profile.tar.gz +chown -R customer:customer /home/customer/.mozilla diff --git a/usr/local/bin/startkiosk.sh b/usr/local/bin/startkiosk.sh new file mode 100644 index 0000000..2f41cc7 --- /dev/null +++ b/usr/local/bin/startkiosk.sh @@ -0,0 +1,116 @@ +#!/bin/bash +# startkiosk.sh + +source /etc/openkiosk.conf + +function check_conf() { + debuglog "Checking configuration file for changes." + new_conf_md5=`md5sum /etc/openkiosk.conf|cut -d " " -f1` + debuglog "New config file checksum: $new_conf_md5" + curr_conf_md5=`cat /home/customer/curr_conf_md5.txt` + debuglog "Current config file checksum: $curr_conf_md5" + diff <(echo $new_conf_md5) <(echo $curr_conf_md5) >/dev/null 2>&1 + if [ "$?" -eq "1" ] + then + debuglog "Config file has changed!" + echo $new_conf_md5 > /home/customer/curr_conf_md5.txt + debuglog "Killing browser" + $KILL_CMD + return 1 + else + return 0 + fi +} + +function check_url() { + debuglog "Checking URL for changes" + new_url_md5=`wget -q -o /dev/null -O - $TGT_URL|md5sum|cut -d " " -f1` + debuglog "New URL checksum: $new_url_md5" + curr_url_md5=`cat /home/customer/curr_url_md5.txt` + debuglog "Current URL checksum: $curr_url_md5" + diff <(echo $new_url_md5) <(echo $curr_url_md5) >/dev/null 2>&1 + if [ "$?" -eq "1" ] + then + debuglog "URL has changed!" + echo $new_url_md5>/home/customer/curr_url_md5.txt + debuglog "Killing browser" + $KILL_CMD + return 1 + else + return 0 + fi +} + +function debuglog() { + if [ "$DEBUG" -eq "1" ] + then + if [ ! -e "/home/customer/startkiosk.log" ] + then + echo "startkiosk log started : "`date +%Y-%m-%d %H:%M:%S` > /home/customer/startkiosk.log + fi + echo `date +%H:%M:%S` "$1">>/home/customer/startkiosk.log + fi +} + +function set_blank_params() { + if [ "$INHIBIT_BLANK" -eq "1" ] + then + xset s off + xset -dpms + else + xset s off + xset +dpms + xset dpms $DSP_STBY_SEC $DSP_SUSP_SEC $DSP_OFF_SEC + fi +} + +function set_rot_params() { + output_name=`xrandr --listactivemonitors|grep 0:|rev|cut -d " " -f1|rev` + xrandr --output $output_name --rotate $ROTATION +} + +openbox-session & +sleep 1 +set_blank_params +$KILL_CMD +$CLEANUP_CMD + +# start application +$APP_CMD & + +sleep 3 + +new_url_md5=`wget -q -o /dev/null -O - $TGT_URL|md5sum|cut -d " " -f1` +echo $new_url_md5>/home/customer/curr_url_md5.txt +new_conf_md5=`md5sum /etc/openkiosk.conf|cut -d " " -f1` +echo $new_conf_md5 > /home/customer/curr_conf_md5.txt + +while true +do + +debuglog "Monitoring for URL and config file changes..." +# Pull in changes in the configuration file +debuglog "Reading config file" +source /etc/openkiosk.conf + +if ! pgrep $ALIVE_STRING +then + # relaunch application if it terminates + debuglog "Restarting browser" + $APP_CMD & +fi + +if [ "$POLL_INTERVAL" -eq "0" ] +then + sleep 1 + debuglog "Polling not enabled" + if ! check_conf; then set_blank_params;set_rot_params;fi +else + sleep $POLL_INTERVAL + debuglog "Polling enabled" + if ! check_conf; then set_blank_params;set_rot_params;fi + check_url +fi +done + +exit 0