printer.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. 'use strict';
  2. // @ts-check
  3. // ==================================================================================
  4. // printers.js
  5. // ----------------------------------------------------------------------------------
  6. // Description: System Information - library
  7. // for Node.js
  8. // Copyright: (c) 2014 - 2022
  9. // Author: Sebastian Hildebrandt
  10. // ----------------------------------------------------------------------------------
  11. // License: MIT
  12. // ==================================================================================
  13. // 15. printers
  14. // ----------------------------------------------------------------------------------
  15. const exec = require('child_process').exec;
  16. // const execSync = require('child_process').execSync;
  17. const util = require('./util');
  18. // const fs = require('fs');
  19. let _platform = process.platform;
  20. const _linux = (_platform === 'linux' || _platform === 'android');
  21. const _darwin = (_platform === 'darwin');
  22. const _windows = (_platform === 'win32');
  23. const _freebsd = (_platform === 'freebsd');
  24. const _openbsd = (_platform === 'openbsd');
  25. const _netbsd = (_platform === 'netbsd');
  26. const _sunos = (_platform === 'sunos');
  27. const winPrinterStatus = {
  28. 1: 'Other',
  29. 2: 'Unknown',
  30. 3: 'Idle',
  31. 4: 'Printing',
  32. 5: 'Warmup',
  33. 6: 'Stopped Printing',
  34. 7: 'Offline',
  35. };
  36. function parseLinuxCupsHeader(lines) {
  37. const result = {};
  38. if (lines && lines.length) {
  39. if (lines[0].indexOf(' CUPS v') > 0) {
  40. const parts = lines[0].split(' CUPS v');
  41. result.cupsVersion = parts[1];
  42. }
  43. }
  44. return result;
  45. }
  46. function parseLinuxCupsPrinter(lines) {
  47. const result = {};
  48. const printerId = util.getValue(lines, 'PrinterId', ' ');
  49. result.id = printerId ? parseInt(printerId, 10) : null;
  50. result.name = util.getValue(lines, 'Info', ' ');
  51. result.model = lines.length > 0 && lines[0] ? lines[0].split(' ')[0] : '';
  52. result.uri = util.getValue(lines, 'DeviceURI', ' ');
  53. result.uuid = util.getValue(lines, 'UUID', ' ');
  54. result.status = util.getValue(lines, 'State', ' ');
  55. result.local = util.getValue(lines, 'Location', ' ').toLowerCase().startsWith('local');
  56. result.default = null;
  57. result.shared = util.getValue(lines, 'Shared', ' ').toLowerCase().startsWith('yes');
  58. return result;
  59. }
  60. function parseLinuxLpstatPrinter(lines, id) {
  61. const result = {};
  62. result.id = id;
  63. result.name = util.getValue(lines, 'Description', ':', true);
  64. result.model = lines.length > 0 && lines[0] ? lines[0].split(' ')[0] : '';
  65. result.uri = null;
  66. result.uuid = null;
  67. result.status = lines.length > 0 && lines[0] ? (lines[0].indexOf(' idle') > 0 ? 'idle' : (lines[0].indexOf(' printing') > 0 ? 'printing' : 'unknown')) : null;
  68. result.local = util.getValue(lines, 'Location', ':', true).toLowerCase().startsWith('local');
  69. result.default = null;
  70. result.shared = util.getValue(lines, 'Shared', ' ').toLowerCase().startsWith('yes');
  71. return result;
  72. }
  73. function parseDarwinPrinters(printerObject, id) {
  74. const result = {};
  75. const uriParts = printerObject.uri.split('/');
  76. result.id = id;
  77. result.name = printerObject._name;
  78. result.model = uriParts.length ? uriParts[uriParts.length - 1] : '';
  79. result.uri = printerObject.uri;
  80. result.uuid = null;
  81. result.status = printerObject.status;
  82. result.local = printerObject.printserver === 'local';
  83. result.default = printerObject.default === 'yes';
  84. result.shared = printerObject.shared === 'yes';
  85. return result;
  86. }
  87. function parseWindowsPrinters(lines, id) {
  88. const result = {};
  89. const status = parseInt(util.getValue(lines, 'PrinterStatus', ':'), 10);
  90. result.id = id;
  91. result.name = util.getValue(lines, 'name', ':');
  92. result.model = util.getValue(lines, 'DriverName', ':');
  93. result.uri = null;
  94. result.uuid = null;
  95. result.status = winPrinterStatus[status] ? winPrinterStatus[status] : null;
  96. result.local = util.getValue(lines, 'Local', ':').toUpperCase() === 'TRUE';
  97. result.default = util.getValue(lines, 'Default', ':').toUpperCase() === 'TRUE';
  98. result.shared = util.getValue(lines, 'Shared', ':').toUpperCase() === 'TRUE';
  99. return result;
  100. }
  101. function printer(callback) {
  102. return new Promise((resolve) => {
  103. process.nextTick(() => {
  104. let result = [];
  105. if (_linux || _freebsd || _openbsd || _netbsd) {
  106. let cmd = 'cat /etc/cups/printers.conf 2>/dev/null';
  107. exec(cmd, function (error, stdout) {
  108. // printers.conf
  109. if (!error) {
  110. const parts = stdout.toString().split('<Printer ');
  111. const printerHeader = parseLinuxCupsHeader(parts[0]);
  112. for (let i = 1; i < parts.length; i++) {
  113. const printers = parseLinuxCupsPrinter(parts[i].split('\n'));
  114. if (printers.name) {
  115. printers.engine = 'CUPS';
  116. printers.engineVersion = printerHeader.cupsVersion;
  117. result.push(printers);
  118. }
  119. }
  120. }
  121. if (result.length === 0) {
  122. if (_linux) {
  123. cmd = 'export LC_ALL=C; lpstat -lp 2>/dev/null; unset LC_ALL';
  124. // lpstat
  125. exec(cmd, function (error, stdout) {
  126. const parts = ('\n' + stdout.toString()).split('\nprinter ');
  127. for (let i = 1; i < parts.length; i++) {
  128. const printers = parseLinuxLpstatPrinter(parts[i].split('\n'), i);
  129. result.push(printers);
  130. }
  131. });
  132. if (callback) {
  133. callback(result);
  134. }
  135. resolve(result);
  136. } else {
  137. if (callback) {
  138. callback(result);
  139. }
  140. resolve(result);
  141. }
  142. } else {
  143. if (callback) {
  144. callback(result);
  145. }
  146. resolve(result);
  147. }
  148. });
  149. }
  150. if (_darwin) {
  151. let cmd = 'system_profiler SPPrintersDataType -json';
  152. exec(cmd, function (error, stdout) {
  153. if (!error) {
  154. try {
  155. const outObj = JSON.parse(stdout.toString());
  156. if (outObj.SPPrintersDataType && outObj.SPPrintersDataType.length) {
  157. for (let i = 0; i < outObj.SPPrintersDataType.length; i++) {
  158. const printer = parseDarwinPrinters(outObj.SPPrintersDataType[i], i);
  159. result.push(printer);
  160. }
  161. }
  162. } catch (e) {
  163. util.noop();
  164. }
  165. }
  166. if (callback) {
  167. callback(result);
  168. }
  169. resolve(result);
  170. });
  171. }
  172. if (_windows) {
  173. util.powerShell('Get-WmiObject Win32_Printer | select PrinterStatus,Name,DriverName,Local,Default,Shared | fl').then((stdout, error) => {
  174. if (!error) {
  175. const parts = stdout.toString().split(/\n\s*\n/);
  176. for (let i = 0; i < parts.length; i++) {
  177. const printer = parseWindowsPrinters(parts[i].split('\n'), i);
  178. if (printer.name || printer.model) {
  179. result.push(parseWindowsPrinters(parts[i].split('\n'), i));
  180. }
  181. }
  182. }
  183. if (callback) {
  184. callback(result);
  185. }
  186. resolve(result);
  187. });
  188. }
  189. if (_sunos) {
  190. resolve(null);
  191. }
  192. });
  193. });
  194. }
  195. exports.printer = printer;