1 /*
2 Copyright (C) 2011-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: dkwt-pr.ctr
12 */
13 
14 /**	@file dkwt-pr.c The dkwt-pr module.
15 */
16 
17 
18 #include <libdk3c/dk3all.h>
19 #include <dkwt/dkt.h>
20 #include <dkwt/dkwt.h>
21 #include <libdk3c/dk3unused.h>
22 
23 
24 
25 
26 
27 
28 
29 
30 /**	Job structure for dkwt printers.
31 */
32 typedef struct {
33   dk3_app_t		*app;		/**< Application structure. */
34   dkChar const * const	*msg;		/**< Localized message texts. */
35   dkChar const * const	*kwnl;		/**< Keywords, not localized. */
36   dk3_option_set_t	*opt;		/**< Command line options. */
37   int			 exval;		/**< Exit status code. */
38   int			 f_long;	/**< Flag: Long output. */
39 } DKWT_PRINTERS_J;
40 
41 
42 
43 /**	Data for the option set.
44 */
45 static dk3_option_t const dkwt_printers_options[] = {
46   { dkT('l'), dkT("long"), 0 }
47 };
48 
49 /**	Number of options in the dkt_sort_options array.
50 */
51 static size_t const dkwt_printers_szoptions =
52 sizeof(dkwt_printers_options)/sizeof(dk3_option_t);
53 
54 
55 
56 /**	Initialize job structure.
57 	@param	j	Job structure to initialize.
58 */
59 static
60 void
dkwt_printers_job_init(DKWT_PRINTERS_J * j)61 dkwt_printers_job_init(DKWT_PRINTERS_J *j)
62 {
63   j->app = NULL; j->msg = NULL; j->kwnl = NULL; j->opt = NULL;
64   j->exval = DKT_RESULT_ERR_UNSPECIFIC;
65   j->f_long = 0;
66 }
67 
68 
69 
70 /**	Clean up job structure.
71 	@param	j	Job structure to clean up.
72 */
73 static
74 void
dkwt_printers_job_cleanup(DKWT_PRINTERS_J * j)75 dkwt_printers_job_cleanup(DKWT_PRINTERS_J *j)
76 {
77   if(j) {
78     if(j->opt) {
79       dk3opt_close(j->opt);
80     } j->opt = NULL;
81   }
82 }
83 
84 
85 
86 /**	Process command line arguments.
87 	@param	j	Job structure.
88 	@return	1 on success (can continue), 0 on error.
89 */
90 static
91 int
dkwt_printers_process_argv(DKWT_PRINTERS_J * j)92 dkwt_printers_process_argv(DKWT_PRINTERS_J *j)
93 {
94   int back = 0;
95   int			 xargc;
96   dkChar const * const	*xargv;
97   xargc = dk3app_get_argc(j->app);
98   xargv = dk3app_get_argv(j->app);
99 
100   xargv++; xargv++; xargc--; xargc--;
101   j->opt = dk3opt_open_app(
102     dkwt_printers_options,
103     dkwt_printers_szoptions,
104     dkT('\0'),
105     NULL,
106     xargc,
107     xargv,
108     j->app
109   );
110   if(j->opt) {
111     if(0 == dk3opt_get_error_code(j->opt)) {
112       back = 1;
113       if(dk3opt_is_set(j->opt, dkT('l'))) {
114         j->f_long = 1;
115       }
116     } else { j->exval = DKT_RESULT_ERR_OPTION; }
117   } else { j->exval = DKT_RESULT_ERR_OPTION; }
118   return  back;
119 }
120 
121 
122 
123 /**	Show details about a printer.
124 	@param	j	Job structure.
125 	@param	txt	Detail value.
126 	@param	mi	Index of detail name in message array.
127 */
128 static
129 void
dkwt_pr_details(DKWT_PRINTERS_J * j,dkChar const * txt,size_t mi)130 dkwt_pr_details(DKWT_PRINTERS_J *j, dkChar const *txt, size_t mi)
131 {
132   if(txt) {
133     if(dk3str_len(txt)) {
134       dk3sf_fputs((j->msg)[mi], stdout);
135       dk3sf_fputs(txt, stdout);
136       dk3sf_fputc(dkT('\n'), stdout);
137     }
138   }
139 }
140 
141 
142 
143 /**	Run the "list printers" command.
144 	@param	j	Job structure.
145 */
146 static
147 void
dkwt_printers_run(DKWT_PRINTERS_J * j)148 dkwt_printers_run(DKWT_PRINTERS_J *j)
149 {
150   dkwt_printer_list_t	*pl;
151   dkwt_printer_t	*pr;
152   int			 not_first = 0;
153   dkChar const		*ptr;
154 
155   pl = dkwt_tool_open_printer_list(j->app, j->f_long);
156   if(pl) {
157     dkwt_tool_printer_list_reset(pl);
158     dk3sf_initialize_stdout();
159     while((pr = dkwt_tool_printer_list_next(pl)) != NULL) {
160       if((j->f_long) && (not_first)) {
161         dk3sf_fputc(dkT('\n'), stdout);
162       } not_first = 1;
163       if(pr->printerName) {
164         dk3sf_fputs(pr->printerName, stdout);
165 	dk3sf_fputc(dkT('\n'), stdout);
166 	if(j->f_long) {
167 	  ptr = pr->printerName;
168 	  while(*(ptr++)) { dk3sf_fputc(dkT('-'), stdout); }
169 	  dk3sf_fputc(dkT('\n'), stdout);
170 	  dkwt_pr_details(j, pr->comment, 44);
171 	  dkwt_pr_details(j, pr->description, 45);
172 	  dkwt_pr_details(j, pr->location, 46);
173 	  dkwt_pr_details(j, pr->serverName, 47);
174 	  dkwt_pr_details(j, pr->shareName, 48);
175 	  dkwt_pr_details(j, pr->portName, 49);
176 	  dkwt_pr_details(j, pr->driverName, 50);
177 	  dkwt_pr_details(j, pr->deviceName, 51);
178 	  dkwt_pr_details(j, pr->separatorFile, 52);
179 	  dkwt_pr_details(j, pr->printProcessor, 53);
180 	  dkwt_pr_details(j, pr->dataType, 54);
181 	  dkwt_pr_details(j, pr->parameters, 55);
182 	}
183       }
184     }
185     dkwt_tool_close_printer_list(pl);
186   } else {
187     j->exval = DKT_RESULT_ERR_MEMORY;
188   }
189 }
190 
191 
192 
193 int
dkwt_printers(dk3_app_t * app,dkChar const * const * msg,dkChar const * const * kwnl)194 dkwt_printers(
195   dk3_app_t		*app,
196   dkChar const * const	*msg,
197   dkChar const * const	*kwnl
198 )
199 {
200   int			back = DKT_RESULT_ERR_UNSPECIFIC;
201   DKWT_PRINTERS_J	j;
202 
203   dkwt_printers_job_init(&j);
204   j.app = app; j.msg = msg; j.kwnl = kwnl;
205   if(dkwt_printers_process_argv(&j)) {
206     back = j.exval = DKT_RESULT_OK;
207     dkwt_printers_run(&j);
208   }
209   dkwt_printers_job_cleanup(&j);
210   return back;
211 }
212 
213 
214 
215 
216 /**	Job structure for dkwt print.
217 */
218 typedef struct {
219   dkChar const		*deviceName;	/**< Device name from command line. */
220   dkChar const		*printerName;	/**< Printer name to use. */
221   dk3_app_t		*app;		/**< Application structure. */
222   dkChar const * const	*msg;		/**< Localized message texts. */
223   dkChar const * const	*kwnl;		/**< Keywords, not localized. */
224   dk3_option_set_t	*opt;		/**< Command line options. */
225   int			 exval;		/**< Exit status code. */
226 } DKWT_PRINT_J;
227 
228 
229 
230 /**	Data for the option set.
231 */
232 static dk3_option_t const dkwt_print_options[] = {
233   { dkT('d'), dkT("device"), 1 }
234 };
235 
236 /**	Number of options in the dkt_print_options array.
237 */
238 static size_t const dkwt_print_szoptions =
239 sizeof(dkwt_print_options)/sizeof(dk3_option_t);
240 
241 
242 
243 /**	Initialize job structure.
244 	@param	j	Job structure to initialize.
245 */
246 static
247 void
dkwt_print_job_init(DKWT_PRINT_J * j)248 dkwt_print_job_init(DKWT_PRINT_J *j)
249 {
250   j->deviceName = NULL; j->printerName = NULL;
251   j->app = NULL; j->msg = NULL; j->kwnl = NULL;
252   j->opt = NULL;
253   j->exval = DKT_RESULT_ERR_UNSPECIFIC;
254 }
255 
256 
257 
258 /**	Clean up job structure.
259 	@param	j	Job structure to clean up.
260 */
261 static
262 void
dkwt_print_job_cleanup(DKWT_PRINT_J * j)263 dkwt_print_job_cleanup(DKWT_PRINT_J *j)
264 {
265   if(j->opt) {
266     dk3opt_close(j->opt);
267   } j->opt = NULL;
268 }
269 
270 
271 
272 /**	Process command line arguments.
273 	@param	j	Job structure.
274 	@return	1 on success (can continue), 0 on error.
275 */
276 static
277 int
dkwt_print_process_argv(DKWT_PRINT_J * j)278 dkwt_print_process_argv(DKWT_PRINT_J *j)
279 {
280   int back = 0;
281   int			 xargc;
282   dkChar const * const	*xargv;
283 
284   xargc = dk3app_get_argc(j->app);
285   xargv = dk3app_get_argv(j->app);
286   xargv++; xargv++; xargc--; xargc--;
287   j->opt = dk3opt_open_app(
288     dkwt_print_options,
289     dkwt_print_szoptions,
290     dkT('\0'),
291     NULL,
292     xargc,
293     xargv,
294     j->app
295   );
296   if(j->opt) {
297     if(0 == dk3opt_get_error_code(j->opt)) {
298       back = 1;
299       if(dk3opt_is_set(j->opt, dkT('d'))) {
300         j->deviceName = dk3opt_get_short_arg(j->opt, dkT('d'));
301 	if(!(j->deviceName)) {
302 	  j->exval = DKT_RESULT_ERR_OPTION;
303 	  back = 0;
304 	}
305       }
306     } else {
307       j->exval = DKT_RESULT_ERR_OPTION;
308     }
309   } else {
310     j->exval = DKT_RESULT_ERR_OPTION;
311   }
312   return back;
313 }
314 
315 
316 
317 /**	Schedule a file to a printer.
318 	@param	j	Job structure.
319 	@param	hFile	Destination file handle.
320 	@param	fn	Source file name.
321 */
322 static
323 void
dkwt_print_schedule_file(DKWT_PRINT_J * j,HANDLE hFile,dkChar const * fn)324 dkwt_print_schedule_file(DKWT_PRINT_J *j, HANDLE hFile, dkChar const *fn)
325 {
326   FILE 		*fipo;
327   char		buffer[4096];
328   size_t	bytes;
329   DWORD		written;
330 
331   fipo = dk3sf_fopen_app(fn, dk3app_not_localized(36), j->app);
332   if(fipo) {
333     do {
334       bytes = dk3sf_fread_app(buffer, 1, sizeof(buffer), fipo, j->app);
335       if(bytes > 0) {
336         written = 0;
337 	if(!WriteFile(
338 	      hFile, (void const *)buffer, (DWORD)bytes, &written, NULL
339 	    )
340 	  )
341 	{
342 	  dk3app_log_i1(j->app, DK3_LL_ERROR, 120);
343 	  j->exval = DKT_RESULT_ERR_OUTPUT;
344 	}
345       }
346     } while(bytes > 0);
347     fclose(fipo);
348   } else {
349     j->exval = DKT_RESULT_ERR_FILENAME;
350   }
351 }
352 
353 
354 
355 /**	Print to a printer.
356 	@param	j	Job structure.
357 	@param	pn	Printer name.
358 */
359 static
360 void
dkwt_print_to_printer(DKWT_PRINT_J * j,dkChar * pn)361 dkwt_print_to_printer(DKWT_PRINT_J *j, dkChar *pn)
362 {
363   HANDLE	hPr;
364   HANDLE	hFile;
365   char		ajbu[sizeof(ADDJOB_INFO_1) + (sizeof(dkChar)*DK3_MAX_PATH)];
366   DWORD		dwLev = (DWORD)1;
367   DWORD		dwSz;
368   DWORD		dwNeeded;
369 #if DK3_CHAR_SIZE > 1
370   ADDJOB_INFO_1W	*aji1;
371 #else
372   ADDJOB_INFO_1A	*aji1;
373 #endif
374   int		ok;
375   DWORD		dwAcc;
376   DWORD		dwSh;
377   DWORD		dwDisp;
378   DWORD		dwAttr;
379   int		oldmode;
380   char		db[4096];
381   int		bytes;
382   DWORD		written;
383   int		nfn;		/* Number of file names. */
384   int		i;		/* Current file name index. */
385   dkChar const	*curarg;	/* Current argument. */
386   dkChar const	*curfn;		/* Current file name. */
387   dk3_dir_t	*fne;		/* File name expander. */
388 
389   ok = 0;
390 #if DK3_CHAR_SIZE > 1
391   if(OpenPrinterW(pn, &hPr, NULL))
392 #else
393   if(OpenPrinterA(pn, &hPr, NULL))
394 #endif
395   {
396     dwSz = sizeof(ajbu);
397     dwNeeded = (DWORD)0UL;
398 #if DK3_CHAR_SIZE > 1
399     if(AddJobW(hPr, dwLev, (LPBYTE)ajbu, dwSz, &dwNeeded))
400 #else
401     if(AddJobA(hPr, dwLev, (LPBYTE)ajbu, dwSz, &dwNeeded))
402 #endif
403     {
404 #if DK3_CHAR_SIZE > 1
405       aji1 = (ADDJOB_INFO_1W *)ajbu;
406 #else
407       aji1 = (ADDJOB_INFO_1A *)ajbu;
408 #endif
409       if(aji1->Path) {
410         hFile  = INVALID_HANDLE_VALUE;
411         dwAcc  = GENERIC_WRITE;
412 	dwSh   = FILE_SHARE_READ;
413 	dwDisp = CREATE_ALWAYS;
414 	dwAttr = FILE_ATTRIBUTE_NORMAL;
415 #if DK3_CHAR_SIZE > 1
416 	hFile = CreateFileW(aji1->Path,dwAcc,dwSh,NULL,dwDisp,dwAttr,NULL);
417 #else
418 	hFile = CreateFileA(aji1->Path,dwAcc,dwSh,NULL,dwDisp,dwAttr,NULL);
419 #endif
420 	if(hFile != INVALID_HANDLE_VALUE) {
421 	  if(dk3opt_get_num_args(j->opt) > 0) {
422 	    nfn = dk3opt_get_num_args(j->opt);
423 	    for(i = 0; i < nfn; i++) {
424 	      curarg = dk3opt_get_arg(j->opt, i);
425 	      if(curarg) {
426 	        if(dk3sf_must_expand(curarg)) {
427 		  fne = dk3dir_fne_open_app(curarg, j->app);
428 		  if(fne) {
429 		    if(dk3dir_get_number_of_files(fne) > 0) {
430 		      while(dk3dir_get_next_file(fne)) {
431 		        curfn = dk3dir_get_fullname(fne);
432 			if(curfn) {
433 			  dkwt_print_schedule_file(j, hFile, curfn);
434 			} else {
435 			  /* BUG */
436 			}
437 		      }
438 		    } else {
439 		      /* ERROR: No such file */
440 		      dk3app_log_i3(j->app, DK3_LL_ERROR, 215, 216, curarg);
441 		      j->exval = DKT_RESULT_ERR_FILENAME;
442 		    }
443 		    dk3dir_close(fne);
444 		  } else {
445 		    /* ERROR: No file name expander. */
446 		    j->exval = DKT_RESULT_ERR_FILENAME;
447 		  }
448 		} else {
449 		  dkwt_print_schedule_file(j, hFile, curarg);
450 		}
451 	      } else {
452 	        j->exval = DKT_RESULT_ERR_UNSPECIFIC;
453 	      }
454 	    }
455 	  } else {
456 	    oldmode = _setmode(0, _O_BINARY);
457 	    do {
458 	      bytes = _read(0, db, sizeof(db));
459 	      if(bytes > 0) {
460 	        written = 0;
461 	        if(!WriteFile(
462 		     hFile, (void const *)db, (DWORD)bytes, &written, NULL
463 		   )
464 		)
465 		{
466 		  /* ERROR: Failed to write bytes! */
467 		  dk3app_log_i1(j->app, DK3_LL_ERROR, 120);
468 		  j->exval = DKT_RESULT_ERR_OUTPUT;
469 		}
470 	      }
471 	    } while(bytes > 0);
472 	    _setmode(0, oldmode);
473 	  }
474 	  ok = 1;
475 	  CloseHandle(hFile);
476 	} else {
477 	  /* ERROR: Failed to create print file! */
478 	  dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 56, 57, aji1->Path);
479 	  j->exval = DKT_RESULT_ERR_UNSPECIFIC;
480 	}
481         if(ok) {
482 	  if(ScheduleJob(hPr, aji1->JobId)) {
483 	  } else {
484 	    /* ERROR: Failed to schedule job */
485 	    dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 58);
486 	  }
487 	}
488       } else {
489         j->exval = DKT_RESULT_ERR_UNSPECIFIC;
490       }
491     } else {
492       /* ERROR: AddJob failed! */
493       dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 59);
494       j->exval = DKT_RESULT_ERR_UNSPECIFIC;
495     }
496     ClosePrinter(hPr);
497   } else {
498     /* ERROR: Failed to open printer! */
499     dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 60, 61, pn);
500     j->exval = DKT_RESULT_ERR_OPTION;
501   }
502 }
503 
504 
505 
506 /**	Run the "dkwt print" command.
507 	@param	j	Job structure.
508 */
509 static
510 void
dkwt_print_run(DKWT_PRINT_J * j)511 dkwt_print_run(DKWT_PRINT_J *j)
512 {
513   dkwt_printer_list_t		*pl;
514   dkwt_printer_t		*pr;
515   dkChar			 bu[DK3_MAX_PATH];
516   DWORD				 dwSz;
517   int				 found = 0;
518 
519   pl = dkwt_tool_open_printer_list(j->app, 1);
520   if(pl) {
521     if(j->deviceName) {
522       dkwt_tool_printer_list_reset(pl);
523       do {
524         pr = dkwt_tool_printer_list_next(pl);
525 	if(pr) {
526 	  if((pr->portName) && (pr->printerName)) {
527 	    if(dk3str_cmp(pr->portName, j->deviceName) == 0) {
528 	      found = -1;
529 	      if(dk3str_len(pr->printerName) < DK3_SIZEOF(bu,dkChar)) {
530 	        dk3str_cpy_not_overlapped(bu, pr->printerName);
531 		found = 1;
532 	      } else {
533 	        /* ERROR: Printer name too long! */
534 		dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 62);
535 	      }
536 	    }
537 	  }
538 	}
539       } while((pr) && (found == 0));
540       if(found == 1) {
541         dkwt_print_to_printer(j, bu);
542       } else {
543         if(found == 0) {
544 	  /* ERROR: No printer found for device! */
545 	  dk3app_log_3(j->app, DK3_LL_ERROR, j->msg, 63, 64, j->deviceName);
546 	  j->exval = DKT_RESULT_ERR_OPTION;
547 	}
548       }
549     } else {
550       dwSz = DK3_SIZEOF(bu,dkChar);
551 #if DK3_CHAR_SIZE > 1
552       if(GetDefaultPrinterW(bu, &dwSz))
553 #else
554       if(GetDefaultPrinterA(bu, &dwSz))
555 #endif
556       {
557         if(dwSz < DK3_SIZEOF(bu,dkChar)) {
558 	  bu[dwSz] = dkT('\0');
559 	} else {
560 	  bu[DK3_SIZEOF(bu,dkChar)-1] = dkT('\0');
561 	}
562 	dkwt_print_to_printer(j, bu);
563       } else {
564         /* ERROR: Failed to find default printer. */
565 	dk3app_log_1(j->app, DK3_LL_ERROR, j->msg, 65);
566 	j->exval = DKT_RESULT_ERR_UNSPECIFIC;
567       }
568     }
569     dkwt_tool_close_printer_list(pl);
570   } else {
571     j->exval = DKT_RESULT_ERR_MEMORY;
572   }
573 }
574 
575 
576 int
dkwt_print(dk3_app_t * app,dkChar const * const * msg,dkChar const * const * kwnl)577 dkwt_print(
578   dk3_app_t		*app,
579   dkChar const * const	*msg,
580   dkChar const * const	*kwnl
581 )
582 {
583   int			back = DKT_RESULT_ERR_UNSPECIFIC;
584   DKWT_PRINT_J		j;
585 
586   dkwt_print_job_init(&j);
587   j.app = app; j.msg = msg; j.kwnl = kwnl;
588   if(dkwt_print_process_argv(&j)) {
589     back = j.exval = DKT_RESULT_OK;
590     dkwt_print_run(&j);
591   }
592   dkwt_print_job_cleanup(&j);
593   back = j.exval;
594 
595   return back;
596 }
597 
598