• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * USB printer backend for CUPS.
3  *
4  * Copyright © 2020-2024 by OpenPrinting.
5  * Copyright © 2007-2012 by Apple Inc.
6  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7  *
8  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
9  * information.
10  */
11 
12 /*
13  * Include necessary headers.
14  */
15 
16 #ifdef __APPLE__
17    /* A header order dependency requires this be first */
18 #  include <ApplicationServices/ApplicationServices.h>
19 #endif /* __APPLE__ */
20 
21 #include "backend-private.h"
22 
23 #ifdef _WIN32
24 #  include <io.h>
25 #else
26 #  include <unistd.h>
27 #  include <fcntl.h>
28 #  include <termios.h>
29 #endif /* _WIN32 */
30 
31 
32 /*
33  * Local functions...
34  */
35 
36 void	list_devices(void);
37 int	print_device(const char *uri, const char *hostname,
38 	             const char *resource, char *options,
39 		     int print_fd, int copies, int argc, char *argv[]);
40 
41 
42 /*
43  * Include the vendor-specific USB implementation...
44  */
45 
46 #ifdef HAVE_LIBUSB
47 #  include "usb-libusb.c"
48 #elif defined(__APPLE__)
49 #  include "usb-darwin.c"
50 #elif defined(__linux) || defined(__sun) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
51 #  include "usb-unix.c"
52 #else
53 /*
54  * Use dummy functions that do nothing on unsupported platforms...
55  * These can be used as templates for implementing USB printing on new
56  * platforms...
57  */
58 
59 /*
60  * 'list_devices()' - List all available USB devices to stdout.
61  */
62 
63 void
list_devices(void)64 list_devices(void)
65 {
66  /*
67   * Don't have any devices to list... Use output of the form:
68   *
69   *     direct usb:/make/model?serial=foo "Make Model" "USB Printer"
70   *
71   * Note that "Hewlett Packard" or any other variation MUST be mapped to
72   * "HP" for compatibility with the PPD and ICC specs.
73   */
74 }
75 
76 
77 /*
78  * 'print_device()' - Print a file to a USB device.
79  */
80 
81 int					/* O - Exit status */
print_device(const char * uri,const char * hostname,const char * resource,char * options,int print_fd,int copies,int argc,char * argv[])82 print_device(const char *uri,		/* I - Device URI */
83              const char *hostname,	/* I - Hostname/manufacturer */
84              const char *resource,	/* I - Resource/modelname */
85 	     char       *options,	/* I - Device options/serial number */
86 	     int        print_fd,	/* I - File descriptor to print */
87 	     int        copies,		/* I - Copies to print */
88 	     int	argc,		/* I - Number of command-line arguments (6 or 7) */
89 	     char	*argv[])	/* I - Command-line arguments */
90 {
91  /*
92   * Can't print, so just reference the arguments to eliminate compiler
93   * warnings and return and exit status of 1.  Normally you would use the
94   * arguments to send a file to the printer and return 0 if everything
95   * worked OK and non-zero if there was an error.
96   */
97 
98   (void)uri;
99   (void)hostname;
100   (void)resource;
101   (void)options;
102   (void)print_fd;
103   (void)copies;
104   (void)argc;
105   (void)argv;
106 
107   return (CUPS_BACKEND_FAILED);
108 }
109 #endif /* HAVE_LIBUSB */
110 
111 
112 /*
113  * 'main()' - Send a file to the specified USB port.
114  *
115  * Usage:
116  *
117  *    printer-uri job-id user title copies options [file]
118  */
119 
120 int					/* O - Exit status */
main(int argc,char * argv[])121 main(int  argc,				/* I - Number of command-line arguments (6 or 7) */
122      char *argv[])			/* I - Command-line arguments */
123 {
124   int		print_fd;		/* Print file */
125   int		copies;			/* Number of copies to print */
126   int		status;			/* Exit status */
127   int		port;			/* Port number (not used) */
128   const char	*uri;			/* Device URI */
129   char		method[255],		/* Method in URI */
130 		hostname[1024],		/* Hostname */
131 		username[255],		/* Username info (not used) */
132 		resource[1024],		/* Resource info (device and options) */
133 		*options;		/* Pointer to options */
134 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
135   struct sigaction action;		/* Actions for POSIX signals */
136 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
137 
138 
139  /*
140   * Make sure status messages are not buffered...
141   */
142 
143   setbuf(stderr, NULL);
144 
145  /*
146   * Ignore SIGPIPE signals...
147   */
148 
149 #ifdef HAVE_SIGSET
150   sigset(SIGPIPE, SIG_IGN);
151 #elif defined(HAVE_SIGACTION)
152   memset(&action, 0, sizeof(action));
153   action.sa_handler = SIG_IGN;
154   sigaction(SIGPIPE, &action, NULL);
155 #else
156   signal(SIGPIPE, SIG_IGN);
157 #endif /* HAVE_SIGSET */
158 
159  /*
160   * Check command-line...
161   */
162 
163   if (argc == 1)
164   {
165     list_devices();
166     return (CUPS_BACKEND_OK);
167   }
168   else if (argc != 6 && argc != 7)
169   {
170     _cupsLangPrintf(stderr,
171                     _("Usage: %s job-id user title copies options [file]"),
172                     argv[0]);
173     return (CUPS_BACKEND_FAILED);
174   }
175 
176  /*
177   * Extract the device name and options from the URI...
178   */
179 
180   uri = cupsBackendDeviceURI(argv);
181 
182   if (httpSeparateURI(HTTP_URI_CODING_ALL, uri,
183                       method, sizeof(method), username, sizeof(username),
184 		      hostname, sizeof(hostname), &port,
185 		      resource, sizeof(resource)) < HTTP_URI_OK)
186   {
187     _cupsLangPrintFilter(stderr, "ERROR",
188 			 _("No device URI found in argv[0] or in DEVICE_URI "
189                            "environment variable."));
190     return (1);
191   }
192 
193  /*
194   * See if there are any options...
195   */
196 
197   if ((options = strchr(resource, '?')) != NULL)
198   {
199    /*
200     * Yup, terminate the device name string and move to the first
201     * character of the options...
202     */
203 
204     *options++ = '\0';
205   }
206 
207  /*
208   * If we have 7 arguments, print the file named on the command-line.
209   * Otherwise, send stdin instead...
210   */
211 
212   if (argc == 6)
213   {
214     print_fd = 0;
215     copies   = 1;
216   }
217   else
218   {
219    /*
220     * Try to open the print file...
221     */
222 
223     if ((print_fd = open(argv[6], O_RDONLY)) < 0)
224     {
225       _cupsLangPrintError("ERROR", _("Unable to open print file"));
226       return (CUPS_BACKEND_FAILED);
227     }
228 
229     copies = atoi(argv[4]);
230   }
231 
232  /*
233   * Finally, send the print file...
234   */
235 
236   status = print_device(uri, hostname, resource, options, print_fd, copies,
237                         argc, argv);
238 
239  /*
240   * Close the input file and return...
241   */
242 
243   if (print_fd != 0)
244     close(print_fd);
245 
246   return (status);
247 }
248