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