2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
17 #include "../c-client/mail.h" /* for MAILSTREAM and friends */
18 #include "../c-client/osdep.h"
19 #include "../c-client/rfc822.h" /* for soutr_t and such */
20 #include "../c-client/misc.h" /* for cpystr proto */
21 #include "../c-client/utf8.h" /* for CHARSET and such*/
22 #include "../c-client/imap4r1.h"
24 #include "../../pith/charconv/utf8.h"
25 #include "../../pith/charconv/filesys.h"
27 #include "../../pith/osdep/color.h"
28 #include "../../pith/osdep/temp_nam.h"
29 #include "../../pith/osdep/err_desc.h"
30 #include "../../pith/osdep/collate.h"
32 #include "../../pith/debug.h"
33 #include "../../pith/conf.h"
34 #include "../../pith/store.h"
35 #include "../../pith/filttype.h"
37 #include "../../pico/estruct.h" /* for ctrl() */
38 #include "../../pico/keydefs.h" /* for KEY_* */
40 #include "../status.h"
41 #include "../signal.h"
43 #include "../../pico/estruct.h"
44 #include "../../pico/pico.h"
45 #include "../mailview.h"
48 #include "../../pico/osdep/mswin.h"
51 #include "../../pico/osdep/raw.h"
53 #include "termin.gen.h"
58 /*======================================================================
61 Functions having to do with printing on paper and forking of spoolers
63 In general one calls open_printer() to start printing. One of
64 the little print functions to send a line or string, and then
65 call print_end() when complete. This takes care of forking off a spooler
66 and piping the stuff down it. No handles or anything here because there's
67 only one printer open at a time.
74 static char *trailer
; /* so both open and close_printer can see it */
77 #endif /* !_WINDOWS */
80 /*----------------------------------------------------------------------
83 Args: desc -- Description of item to print. Should have one trailing blank.
85 Return value: < 0 is a failure.
88 This does most of the work of popen so we can save the standard output of the
89 command we execute and send it back to the user.
92 open_printer(char *desc
)
95 char command
[201], prompt
[200];
96 int cmd
, rc
, just_one
;
97 char *p
, *init
, *nick
;
98 char aname
[100], wname
[100];
100 int done
= 0, i
, lastprinter
= 0, cur_printer
= 0;
103 static ESCKEY_S ekey
[] = {
104 /* TRANSLATORS: these are command labels for printing screen */
105 {'y', 'y', "Y", N_("Yes")},
106 {'n', 'n', "N", N_("No")},
107 /* TRANSLATORS: go to Previous Printer in list */
108 {ctrl('P'), 10, "^P", N_("Prev Printer")},
109 {ctrl('N'), 11, "^N", N_("Next Printer")},
111 /* TRANSLATORS: use Custom Print command */
112 {'c', 'c', "C", N_("CustomPrint")},
113 {KEY_UP
, 10, "", ""},
114 {KEY_DOWN
, 11, "", ""},
115 {-1, 0, NULL
, NULL
}};
125 command
[sizeof(command
)-1] = '\0';
127 if(ps_global
->VAR_PRINTER
== NULL
){
128 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
129 "No printer has been chosen. Use SETUP on main menu to make choice.");
133 /* Is there just one print command available? */
134 just_one
= (ps_global
->printer_category
!=3&&ps_global
->printer_category
!=2)
135 || (ps_global
->printer_category
== 2
136 && !(ps_global
->VAR_STANDARD_PRINTER
137 && ps_global
->VAR_STANDARD_PRINTER
[0]
138 && ps_global
->VAR_STANDARD_PRINTER
[1]))
139 || (ps_global
->printer_category
== 3
140 && !(ps_global
->VAR_PERSONAL_PRINT_COMMAND
141 && ps_global
->VAR_PERSONAL_PRINT_COMMAND
[0]
142 && ps_global
->VAR_PERSONAL_PRINT_COMMAND
[1]));
144 if(F_ON(F_CUSTOM_PRINT
, ps_global
))
145 ekey
[CUSTOM_KEY
].ch
= 'c'; /* turn this key on */
147 ekey
[CUSTOM_KEY
].ch
= -2; /* turn this key off */
150 ekey
[PREV_KEY
].ch
= -2; /* turn these keys off */
151 ekey
[NEXT_KEY
].ch
= -2;
152 ekey
[UP_KEY
].ch
= -2;
153 ekey
[DOWN_KEY
].ch
= -2;
156 ekey
[PREV_KEY
].ch
= ctrl('P'); /* turn these keys on */
157 ekey
[NEXT_KEY
].ch
= ctrl('N');
158 ekey
[UP_KEY
].ch
= KEY_UP
;
159 ekey
[DOWN_KEY
].ch
= KEY_DOWN
;
161 * count how many printers in list and find the default in the list
163 if(ps_global
->printer_category
== 2)
164 list
= ps_global
->VAR_STANDARD_PRINTER
;
166 list
= ps_global
->VAR_PERSONAL_PRINT_COMMAND
;
168 for(i
= 0; list
[i
]; i
++)
169 if(strcmp(ps_global
->VAR_PRINTER
, list
[i
]) == 0)
176 ps_global
->mangled_footer
= 1;
180 fs_give((void **)&init
);
183 fs_give((void **)&trailer
);
186 printer
= ps_global
->VAR_PRINTER
;
188 printer
= list
[cur_printer
];
190 parse_printer(printer
, &nick
, &p
, &init
, &trailer
, NULL
, NULL
);
191 strncpy(command
, p
, sizeof(command
)-1);
192 command
[sizeof(command
)-1] = '\0';
193 fs_give((void **)&p
);
194 /* TRANSLATORS: Print something1 using something2.
195 For example, Print configuration using printer three. */
196 snprintf(prompt
, sizeof(prompt
), _("Print %s using \"%s\" ? "),
198 *nick
? nick
: command
);
199 prompt
[sizeof(prompt
)-1] = '\0';
201 fs_give((void **)&nick
);
203 cmd
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
),
204 ekey
, 'y', 'x', help
, RB_NORM
);
208 q_status_message1(SM_ORDER
, 0, 9,
209 "Printing with command \"%s\"", command
);
214 cur_printer
= (cur_printer
>0)
220 cur_printer
= (cur_printer
<lastprinter
)
241 fs_give((void **)&init
);
244 fs_give((void **)&trailer
);
246 snprintf(prompt
, sizeof(prompt
), "Enter custom command : ");
247 prompt
[sizeof(prompt
)-1] = '\0';
252 int flags
= OE_APPEND_CURRENT
;
254 rc
= optionally_enter(command
, -FOOTER_ROWS(ps_global
), 0,
255 sizeof(command
), prompt
, NULL
, help
, &flags
);
262 help
= (help
== NO_HELP
) ? h_custom_print
: NO_HELP
;
264 removing_trailing_white_space(command
);
265 removing_leading_white_space(command
);
266 q_status_message1(SM_ORDER
, 0, 9,
267 "Printing with command \"%s\"", command
);
272 if(cmd
== 'x' || cmd
== 'n'){
273 q_status_message(SM_ORDER
, 0, 2, "Print cancelled");
275 fs_give((void **)&init
);
278 fs_give((void **)&trailer
);
283 display_message('x');
285 ps_global
->print
= (PRINT_S
*)fs_get(sizeof(PRINT_S
));
286 memset(ps_global
->print
, 0, sizeof(PRINT_S
));
288 strncpy(aname
, ANSI_PRINTER
, sizeof(aname
)-1);
289 aname
[sizeof(aname
)-1] = '\0';
290 strncat(aname
, "-no-formfeed", sizeof(aname
)-strlen(aname
)-1);
291 strncpy(wname
, WYSE_PRINTER
, sizeof(wname
)-1);
292 wname
[sizeof(wname
)-1] = '\0';
293 strncat(wname
, "-no-formfeed", sizeof(wname
)-strlen(wname
)-1);
294 if(strucmp(command
, ANSI_PRINTER
) == 0
295 || strucmp(command
, aname
) == 0
296 || strucmp(command
, WYSE_PRINTER
) == 0
297 || strucmp(command
, wname
) == 0){
298 /*----------- Attached printer ---------*/
299 q_status_message(SM_ORDER
, 0, 9,
300 "Printing to attached desktop printer...");
301 display_message('x');
302 xonxoff_proc(1); /* make sure XON/XOFF used */
303 crlf_proc(1); /* AND LF->CR xlation */
304 if(strucmp(command
, ANSI_PRINTER
) == 0
305 || strucmp(command
, aname
) == 0){
306 fputs("\033[5i", stdout
);
311 printf("%c", 18); /* aux on for wyse60,
312 Chuck Everett <ceverett@odessa.edu> */
315 ps_global
->print
->fp
= stdout
;
316 if(strucmp(command
, ANSI_PRINTER
) == 0
317 || strucmp(command
, WYSE_PRINTER
) == 0){
318 /* put formfeed at the end of the trailer string */
320 int len
= strlen(trailer
);
322 fs_resize((void **)&trailer
, len
+2);
324 trailer
[len
+1] = '\0';
327 trailer
= cpystr("\f");
331 /*----------- Print by forking off a UNIX command ------------*/
332 dprint((4, "Printing using command \"%s\"\n",
333 command
? command
: "?"));
334 ps_global
->print
->result
= temp_nam(NULL
, "pine_prt");
335 if(ps_global
->print
->result
&&
336 (ps_global
->print
->pipe
= open_system_pipe(command
,
337 &ps_global
->print
->result
, NULL
,
338 PIPE_WRITE
| PIPE_STDERR
, 0,
339 pipe_callback
, NULL
))){
340 ps_global
->print
->fp
= ps_global
->print
->pipe
->out
.f
;
343 if(ps_global
->print
->result
){
344 our_unlink(ps_global
->print
->result
);
345 fs_give((void **)&ps_global
->print
->result
);
348 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
349 "Error opening printer: %s",
350 error_description(errno
));
351 dprint((2, "Error popening printer \"%s\"\n",
352 error_description(errno
)));
354 fs_give((void **)&init
);
357 fs_give((void **)&trailer
);
363 ps_global
->print
->err
= 0;
366 fputs(init
, ps_global
->print
->fp
);
368 fs_give((void **)&init
);
373 cb
.cbufend
= cb
.cbuf
;
376 LPTSTR desclpt
= NULL
;
379 desclpt
= utf8_to_lptstr(desc
);
381 if (status
= mswin_print_ready (0, desclpt
)) {
382 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
383 "Error starting print job: %s",
384 mswin_print_error(status
));
386 fs_give((void **) &desclpt
);
392 fs_give((void **) &desclpt
);
394 q_status_message(SM_ORDER
, 0, 9, "Printing to windows printer...");
395 display_message('x');
397 /* init print control structure */
398 ps_global
->print
= (PRINT_S
*)fs_get(sizeof(PRINT_S
));
399 memset(ps_global
->print
, 0, sizeof(PRINT_S
));
401 ps_global
->print
->err
= 0;
402 #endif /* _WINDOWS */
409 /*----------------------------------------------------------------------
412 If we're piping to a spooler close down the pipe and wait for the process
413 to finish. If we're sending to an attached printer send the escape sequence.
414 Also let the user know the result of the print
422 fputs(trailer
, ps_global
->print
->fp
);
424 fs_give((void **)&trailer
);
427 if(ps_global
->print
->fp
== stdout
) {
429 fputs("\033[4i", stdout
);
431 printf("%c", 20); /* aux off for wyse60 */
434 if(F_OFF(F_PRESERVE_START_STOP
, ps_global
))
435 xonxoff_proc(0); /* turn off XON/XOFF */
437 crlf_proc(0); /* turn off CF->LF xlantion */
439 (void) close_system_pipe(&ps_global
->print
->pipe
, NULL
, pipe_callback
);
440 display_output_file(ps_global
->print
->result
, "PRINT", NULL
, 1);
441 if(ps_global
->print
&& ps_global
->print
->result
)
442 fs_give((void **) &ps_global
->print
->result
);
446 #endif /* _WINDOWS */
449 fs_give((void **) &ps_global
->print
);
451 q_status_message(SM_ASYNC
, 0, 3, "Print command completed");
452 display_message('x');
456 /*----------------------------------------------------------------------
457 Print a single character, translate from UTF-8 to user's locale charset.
459 Args: c -- char to print
460 Returns: 1 on success, 0 on ps_global->print->err
467 unsigned char obuf
[MAX(MB_LEN_MAX
,32)];
469 if(!ps_global
->print
->err
470 && (outchars
= utf8_to_locale(c
, &cb
, obuf
, sizeof(obuf
)))){
471 for(i
= 0; i
< outchars
&& !ps_global
->print
->err
; i
++)
472 if(putc(obuf
[i
], ps_global
->print
->fp
) == EOF
)
473 ps_global
->print
->err
= 1;
476 if(!ps_global
->print
->err
477 && (ps_global
->print
->err
= mswin_print_char_utf8(c
)))
478 q_status_message1(SM_ORDER
, 0, 9, "Print cancelled: %s",
479 mswin_print_error((unsigned short)ps_global
->print
->err
));
480 #endif /* _WINDOWS */
482 return(!ps_global
->print
->err
);
486 /*----------------------------------------------------------------------
487 Send a line of text to the printer
489 Args: line -- Text to print
493 print_text(char *line
)
496 int slen
= strlen(line
);
498 while(!ps_global
->print
->err
&& slen
--)
499 if(print_char(*line
++) == 0)
500 ps_global
->print
->err
= 1;
502 if(!ps_global
->print
->err
503 && (ps_global
->print
->err
= mswin_print_text_utf8(line
)))
504 q_status_message1(SM_ORDER
, 0, 9, "Print cancelled: %s",
505 mswin_print_error((unsigned short)ps_global
->print
->err
));
506 #endif /* _WINDOWS */
510 /*----------------------------------------------------------------------
511 printf style formatting with one arg for printer
513 Args: line -- The printf control string
514 a1 -- The 1st argument for printf
517 print_text1(char *line
, char *a1
)
521 if(!ps_global
->print
->err
&& snprintf(buf
, sizeof(buf
), line
, a1
) < 0)
522 ps_global
->print
->err
= 1;