1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: print.c 942 2008-03-04 18:21:33Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2020 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
21 #include "../c-client/mail.h" /* for MAILSTREAM and friends */
22 #include "../c-client/osdep.h"
23 #include "../c-client/rfc822.h" /* for soutr_t and such */
24 #include "../c-client/misc.h" /* for cpystr proto */
25 #include "../c-client/utf8.h" /* for CHARSET and such*/
26 #include "../c-client/imap4r1.h"
28 #include "../../pith/charconv/utf8.h"
29 #include "../../pith/charconv/filesys.h"
31 #include "../../pith/osdep/color.h"
32 #include "../../pith/osdep/temp_nam.h"
33 #include "../../pith/osdep/err_desc.h"
34 #include "../../pith/osdep/collate.h"
36 #include "../../pith/debug.h"
37 #include "../../pith/conf.h"
38 #include "../../pith/store.h"
39 #include "../../pith/filttype.h"
41 #include "../../pico/estruct.h" /* for ctrl() */
42 #include "../../pico/keydefs.h" /* for KEY_* */
44 #include "../status.h"
45 #include "../signal.h"
47 #include "../../pico/estruct.h"
48 #include "../../pico/pico.h"
49 #include "../mailview.h"
52 #include "../../pico/osdep/mswin.h"
55 #include "../../pico/osdep/raw.h"
57 #include "termin.gen.h"
62 /*======================================================================
65 Functions having to do with printing on paper and forking of spoolers
67 In general one calls open_printer() to start printing. One of
68 the little print functions to send a line or string, and then
69 call print_end() when complete. This takes care of forking off a spooler
70 and piping the stuff down it. No handles or anything here because there's
71 only one printer open at a time.
78 static char *trailer
; /* so both open and close_printer can see it */
81 #endif /* !_WINDOWS */
84 /*----------------------------------------------------------------------
87 Args: desc -- Description of item to print. Should have one trailing blank.
89 Return value: < 0 is a failure.
92 This does most of the work of popen so we can save the standard output of the
93 command we execute and send it back to the user.
96 open_printer(char *desc
)
99 char command
[201], prompt
[200];
100 int cmd
, rc
, just_one
;
101 char *p
, *init
, *nick
;
102 char aname
[100], wname
[100];
104 int done
= 0, i
, lastprinter
, cur_printer
= 0;
107 static ESCKEY_S ekey
[] = {
108 /* TRANSLATORS: these are command labels for printing screen */
109 {'y', 'y', "Y", N_("Yes")},
110 {'n', 'n', "N", N_("No")},
111 /* TRANSLATORS: go to Previous Printer in list */
112 {ctrl('P'), 10, "^P", N_("Prev Printer")},
113 {ctrl('N'), 11, "^N", N_("Next Printer")},
115 /* TRANSLATORS: use Custom Print command */
116 {'c', 'c', "C", N_("CustomPrint")},
117 {KEY_UP
, 10, "", ""},
118 {KEY_DOWN
, 11, "", ""},
119 {-1, 0, NULL
, NULL
}};
129 command
[sizeof(command
)-1] = '\0';
131 if(ps_global
->VAR_PRINTER
== NULL
){
132 q_status_message(SM_ORDER
| SM_DING
, 3, 5,
133 "No printer has been chosen. Use SETUP on main menu to make choice.");
137 /* Is there just one print command available? */
138 just_one
= (ps_global
->printer_category
!=3&&ps_global
->printer_category
!=2)
139 || (ps_global
->printer_category
== 2
140 && !(ps_global
->VAR_STANDARD_PRINTER
141 && ps_global
->VAR_STANDARD_PRINTER
[0]
142 && ps_global
->VAR_STANDARD_PRINTER
[1]))
143 || (ps_global
->printer_category
== 3
144 && !(ps_global
->VAR_PERSONAL_PRINT_COMMAND
145 && ps_global
->VAR_PERSONAL_PRINT_COMMAND
[0]
146 && ps_global
->VAR_PERSONAL_PRINT_COMMAND
[1]));
148 if(F_ON(F_CUSTOM_PRINT
, ps_global
))
149 ekey
[CUSTOM_KEY
].ch
= 'c'; /* turn this key on */
151 ekey
[CUSTOM_KEY
].ch
= -2; /* turn this key off */
154 ekey
[PREV_KEY
].ch
= -2; /* turn these keys off */
155 ekey
[NEXT_KEY
].ch
= -2;
156 ekey
[UP_KEY
].ch
= -2;
157 ekey
[DOWN_KEY
].ch
= -2;
160 ekey
[PREV_KEY
].ch
= ctrl('P'); /* turn these keys on */
161 ekey
[NEXT_KEY
].ch
= ctrl('N');
162 ekey
[UP_KEY
].ch
= KEY_UP
;
163 ekey
[DOWN_KEY
].ch
= KEY_DOWN
;
165 * count how many printers in list and find the default in the list
167 if(ps_global
->printer_category
== 2)
168 list
= ps_global
->VAR_STANDARD_PRINTER
;
170 list
= ps_global
->VAR_PERSONAL_PRINT_COMMAND
;
172 for(i
= 0; list
[i
]; i
++)
173 if(strcmp(ps_global
->VAR_PRINTER
, list
[i
]) == 0)
180 ps_global
->mangled_footer
= 1;
184 fs_give((void **)&init
);
187 fs_give((void **)&trailer
);
190 printer
= ps_global
->VAR_PRINTER
;
192 printer
= list
[cur_printer
];
194 parse_printer(printer
, &nick
, &p
, &init
, &trailer
, NULL
, NULL
);
195 strncpy(command
, p
, sizeof(command
)-1);
196 command
[sizeof(command
)-1] = '\0';
197 fs_give((void **)&p
);
198 /* TRANSLATORS: Print something1 using something2.
199 For example, Print configuration using printer three. */
200 snprintf(prompt
, sizeof(prompt
), _("Print %s using \"%s\" ? "),
202 *nick
? nick
: command
);
203 prompt
[sizeof(prompt
)-1] = '\0';
205 fs_give((void **)&nick
);
207 cmd
= radio_buttons(prompt
, -FOOTER_ROWS(ps_global
),
208 ekey
, 'y', 'x', help
, RB_NORM
);
212 q_status_message1(SM_ORDER
, 0, 9,
213 "Printing with command \"%s\"", command
);
218 cur_printer
= (cur_printer
>0)
224 cur_printer
= (cur_printer
<lastprinter
)
245 fs_give((void **)&init
);
248 fs_give((void **)&trailer
);
250 snprintf(prompt
, sizeof(prompt
), "Enter custom command : ");
251 prompt
[sizeof(prompt
)-1] = '\0';
256 int flags
= OE_APPEND_CURRENT
;
258 rc
= optionally_enter(command
, -FOOTER_ROWS(ps_global
), 0,
259 sizeof(command
), prompt
, NULL
, help
, &flags
);
266 help
= (help
== NO_HELP
) ? h_custom_print
: NO_HELP
;
268 removing_trailing_white_space(command
);
269 removing_leading_white_space(command
);
270 q_status_message1(SM_ORDER
, 0, 9,
271 "Printing with command \"%s\"", command
);
276 if(cmd
== 'x' || cmd
== 'n'){
277 q_status_message(SM_ORDER
, 0, 2, "Print cancelled");
279 fs_give((void **)&init
);
282 fs_give((void **)&trailer
);
287 display_message('x');
289 ps_global
->print
= (PRINT_S
*)fs_get(sizeof(PRINT_S
));
290 memset(ps_global
->print
, 0, sizeof(PRINT_S
));
292 strncpy(aname
, ANSI_PRINTER
, sizeof(aname
)-1);
293 aname
[sizeof(aname
)-1] = '\0';
294 strncat(aname
, "-no-formfeed", sizeof(aname
)-strlen(aname
)-1);
295 strncpy(wname
, WYSE_PRINTER
, sizeof(wname
)-1);
296 wname
[sizeof(wname
)-1] = '\0';
297 strncat(wname
, "-no-formfeed", sizeof(wname
)-strlen(wname
)-1);
298 if(strucmp(command
, ANSI_PRINTER
) == 0
299 || strucmp(command
, aname
) == 0
300 || strucmp(command
, WYSE_PRINTER
) == 0
301 || strucmp(command
, wname
) == 0){
302 /*----------- Attached printer ---------*/
303 q_status_message(SM_ORDER
, 0, 9,
304 "Printing to attached desktop printer...");
305 display_message('x');
306 xonxoff_proc(1); /* make sure XON/XOFF used */
307 crlf_proc(1); /* AND LF->CR xlation */
308 if(strucmp(command
, ANSI_PRINTER
) == 0
309 || strucmp(command
, aname
) == 0){
310 fputs("\033[5i", stdout
);
315 printf("%c", 18); /* aux on for wyse60,
316 Chuck Everett <ceverett@odessa.edu> */
319 ps_global
->print
->fp
= stdout
;
320 if(strucmp(command
, ANSI_PRINTER
) == 0
321 || strucmp(command
, WYSE_PRINTER
) == 0){
322 /* put formfeed at the end of the trailer string */
324 int len
= strlen(trailer
);
326 fs_resize((void **)&trailer
, len
+2);
328 trailer
[len
+1] = '\0';
331 trailer
= cpystr("\f");
335 /*----------- Print by forking off a UNIX command ------------*/
336 dprint((4, "Printing using command \"%s\"\n",
337 command
? command
: "?"));
338 ps_global
->print
->result
= temp_nam(NULL
, "pine_prt");
339 if(ps_global
->print
->result
&&
340 (ps_global
->print
->pipe
= open_system_pipe(command
,
341 &ps_global
->print
->result
, NULL
,
342 PIPE_WRITE
| PIPE_STDERR
, 0,
343 pipe_callback
, NULL
))){
344 ps_global
->print
->fp
= ps_global
->print
->pipe
->out
.f
;
347 if(ps_global
->print
->result
){
348 our_unlink(ps_global
->print
->result
);
349 fs_give((void **)&ps_global
->print
->result
);
352 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
353 "Error opening printer: %s",
354 error_description(errno
));
355 dprint((2, "Error popening printer \"%s\"\n",
356 error_description(errno
)));
358 fs_give((void **)&init
);
361 fs_give((void **)&trailer
);
367 ps_global
->print
->err
= 0;
370 fputs(init
, ps_global
->print
->fp
);
372 fs_give((void **)&init
);
377 cb
.cbufend
= cb
.cbuf
;
380 LPTSTR desclpt
= NULL
;
383 desclpt
= utf8_to_lptstr(desc
);
385 if (status
= mswin_print_ready (0, desclpt
)) {
386 q_status_message1(SM_ORDER
| SM_DING
, 3, 4,
387 "Error starting print job: %s",
388 mswin_print_error(status
));
390 fs_give((void **) &desclpt
);
396 fs_give((void **) &desclpt
);
398 q_status_message(SM_ORDER
, 0, 9, "Printing to windows printer...");
399 display_message('x');
401 /* init print control structure */
402 ps_global
->print
= (PRINT_S
*)fs_get(sizeof(PRINT_S
));
403 memset(ps_global
->print
, 0, sizeof(PRINT_S
));
405 ps_global
->print
->err
= 0;
406 #endif /* _WINDOWS */
413 /*----------------------------------------------------------------------
416 If we're piping to a spooler close down the pipe and wait for the process
417 to finish. If we're sending to an attached printer send the escape sequence.
418 Also let the user know the result of the print
426 fputs(trailer
, ps_global
->print
->fp
);
428 fs_give((void **)&trailer
);
431 if(ps_global
->print
->fp
== stdout
) {
433 fputs("\033[4i", stdout
);
435 printf("%c", 20); /* aux off for wyse60 */
438 if(F_OFF(F_PRESERVE_START_STOP
, ps_global
))
439 xonxoff_proc(0); /* turn off XON/XOFF */
441 crlf_proc(0); /* turn off CF->LF xlantion */
443 (void) close_system_pipe(&ps_global
->print
->pipe
, NULL
, pipe_callback
);
444 display_output_file(ps_global
->print
->result
, "PRINT", NULL
, 1);
445 if(ps_global
->print
&& ps_global
->print
->result
)
446 fs_give((void **) &ps_global
->print
->result
);
450 #endif /* _WINDOWS */
453 fs_give((void **) &ps_global
->print
);
455 q_status_message(SM_ASYNC
, 0, 3, "Print command completed");
456 display_message('x');
460 /*----------------------------------------------------------------------
461 Print a single character, translate from UTF-8 to user's locale charset.
463 Args: c -- char to print
464 Returns: 1 on success, 0 on ps_global->print->err
471 unsigned char obuf
[MAX(MB_LEN_MAX
,32)];
473 if(!ps_global
->print
->err
474 && (outchars
= utf8_to_locale(c
, &cb
, obuf
, sizeof(obuf
)))){
475 for(i
= 0; i
< outchars
&& !ps_global
->print
->err
; i
++)
476 if(putc(obuf
[i
], ps_global
->print
->fp
) == EOF
)
477 ps_global
->print
->err
= 1;
480 if(!ps_global
->print
->err
481 && (ps_global
->print
->err
= mswin_print_char_utf8(c
)))
482 q_status_message1(SM_ORDER
, 0, 9, "Print cancelled: %s",
483 mswin_print_error((unsigned short)ps_global
->print
->err
));
484 #endif /* _WINDOWS */
486 return(!ps_global
->print
->err
);
490 /*----------------------------------------------------------------------
491 Send a line of text to the printer
493 Args: line -- Text to print
497 print_text(char *line
)
500 int slen
= strlen(line
);
502 while(!ps_global
->print
->err
&& slen
--)
503 if(print_char(*line
++) == 0)
504 ps_global
->print
->err
= 1;
506 if(!ps_global
->print
->err
507 && (ps_global
->print
->err
= mswin_print_text_utf8(line
)))
508 q_status_message1(SM_ORDER
, 0, 9, "Print cancelled: %s",
509 mswin_print_error((unsigned short)ps_global
->print
->err
));
510 #endif /* _WINDOWS */
514 /*----------------------------------------------------------------------
515 printf style formatting with one arg for printer
517 Args: line -- The printf control string
518 a1 -- The 1st argument for printf
521 print_text1(char *line
, char *a1
)
525 if(!ps_global
->print
->err
&& snprintf(buf
, sizeof(buf
), line
, a1
) < 0)
526 ps_global
->print
->err
= 1;