PageRenderTime 54ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/alpine/osdep/print.c

https://github.com/sergi/re-alpine
C | 528 lines | 370 code | 84 blank | 74 comment | 94 complexity | 4880eab3940b331faf531ee50d251ce4 MD5 | raw file
  1. #if !defined(lint) && !defined(DOS)
  2. static char rcsid[] = "$Id: print.c 942 2008-03-04 18:21:33Z hubert@u.washington.edu $";
  3. #endif
  4. /*
  5. * ========================================================================
  6. * Copyright 2006-2008 University of Washington
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * ========================================================================
  15. */
  16. #include <system.h>
  17. #include <general.h>
  18. #include "../c-client/mail.h" /* for MAILSTREAM and friends */
  19. #include "../c-client/osdep.h"
  20. #include "../c-client/rfc822.h" /* for soutr_t and such */
  21. #include "../c-client/misc.h" /* for cpystr proto */
  22. #include "../c-client/utf8.h" /* for CHARSET and such*/
  23. #include "../c-client/imap4r1.h"
  24. #include "../../pith/charconv/utf8.h"
  25. #include "../../pith/charconv/filesys.h"
  26. #include "../../pith/osdep/color.h"
  27. #include "../../pith/osdep/temp_nam.h"
  28. #include "../../pith/osdep/err_desc.h"
  29. #include "../../pith/osdep/collate.h"
  30. #include "../../pith/debug.h"
  31. #include "../../pith/conf.h"
  32. #include "../../pith/store.h"
  33. #include "../../pith/filttype.h"
  34. #include "../../pico/estruct.h" /* for ctrl() */
  35. #include "../../pico/keydefs.h" /* for KEY_* */
  36. #include "../status.h"
  37. #include "../signal.h"
  38. #include "../radio.h"
  39. #include "../../pico/estruct.h"
  40. #include "../../pico/pico.h"
  41. #include "../mailview.h"
  42. #ifdef _WINDOWS
  43. #include "../../pico/osdep/mswin.h"
  44. #endif
  45. #include "../../pico/osdep/raw.h"
  46. #include "termin.gen.h"
  47. #include "print.h"
  48. /*======================================================================
  49. print routines
  50. Functions having to do with printing on paper and forking of spoolers
  51. In general one calls open_printer() to start printing. One of
  52. the little print functions to send a line or string, and then
  53. call print_end() when complete. This takes care of forking off a spooler
  54. and piping the stuff down it. No handles or anything here because there's
  55. only one printer open at a time.
  56. ====*/
  57. #ifndef _WINDOWS
  58. static char *trailer; /* so both open and close_printer can see it */
  59. static int ansi_off;
  60. static CBUF_S cb;
  61. #endif /* !_WINDOWS */
  62. /*----------------------------------------------------------------------
  63. Open the printer
  64. Args: desc -- Description of item to print. Should have one trailing blank.
  65. Return value: < 0 is a failure.
  66. 0 a success.
  67. This does most of the work of popen so we can save the standard output of the
  68. command we execute and send it back to the user.
  69. ----*/
  70. int
  71. open_printer(char *desc)
  72. {
  73. #ifndef _WINDOWS
  74. char command[201], prompt[200];
  75. int cmd, rc, just_one;
  76. char *p, *init, *nick;
  77. char aname[100], wname[100];
  78. char *printer;
  79. int done = 0, i, lastprinter, cur_printer = 0;
  80. HelpType help;
  81. char **list;
  82. static ESCKEY_S ekey[] = {
  83. /* TRANSLATORS: these are command labels for printing screen */
  84. {'y', 'y', "Y", N_("Yes")},
  85. {'n', 'n', "N", N_("No")},
  86. /* TRANSLATORS: go to Previous Printer in list */
  87. {ctrl('P'), 10, "^P", N_("Prev Printer")},
  88. {ctrl('N'), 11, "^N", N_("Next Printer")},
  89. {-2, 0, NULL, NULL},
  90. /* TRANSLATORS: use Custom Print command */
  91. {'c', 'c', "C", N_("CustomPrint")},
  92. {KEY_UP, 10, "", ""},
  93. {KEY_DOWN, 11, "", ""},
  94. {-1, 0, NULL, NULL}};
  95. #define PREV_KEY 2
  96. #define NEXT_KEY 3
  97. #define CUSTOM_KEY 5
  98. #define UP_KEY 6
  99. #define DOWN_KEY 7
  100. trailer = NULL;
  101. init = NULL;
  102. nick = NULL;
  103. command[sizeof(command)-1] = '\0';
  104. if(ps_global->VAR_PRINTER == NULL){
  105. q_status_message(SM_ORDER | SM_DING, 3, 5,
  106. "No printer has been chosen. Use SETUP on main menu to make choice.");
  107. return(-1);
  108. }
  109. /* Is there just one print command available? */
  110. just_one = (ps_global->printer_category!=3&&ps_global->printer_category!=2)
  111. || (ps_global->printer_category == 2
  112. && !(ps_global->VAR_STANDARD_PRINTER
  113. && ps_global->VAR_STANDARD_PRINTER[0]
  114. && ps_global->VAR_STANDARD_PRINTER[1]))
  115. || (ps_global->printer_category == 3
  116. && !(ps_global->VAR_PERSONAL_PRINT_COMMAND
  117. && ps_global->VAR_PERSONAL_PRINT_COMMAND[0]
  118. && ps_global->VAR_PERSONAL_PRINT_COMMAND[1]));
  119. if(F_ON(F_CUSTOM_PRINT, ps_global))
  120. ekey[CUSTOM_KEY].ch = 'c'; /* turn this key on */
  121. else
  122. ekey[CUSTOM_KEY].ch = -2; /* turn this key off */
  123. if(just_one){
  124. ekey[PREV_KEY].ch = -2; /* turn these keys off */
  125. ekey[NEXT_KEY].ch = -2;
  126. ekey[UP_KEY].ch = -2;
  127. ekey[DOWN_KEY].ch = -2;
  128. }
  129. else{
  130. ekey[PREV_KEY].ch = ctrl('P'); /* turn these keys on */
  131. ekey[NEXT_KEY].ch = ctrl('N');
  132. ekey[UP_KEY].ch = KEY_UP;
  133. ekey[DOWN_KEY].ch = KEY_DOWN;
  134. /*
  135. * count how many printers in list and find the default in the list
  136. */
  137. if(ps_global->printer_category == 2)
  138. list = ps_global->VAR_STANDARD_PRINTER;
  139. else
  140. list = ps_global->VAR_PERSONAL_PRINT_COMMAND;
  141. for(i = 0; list[i]; i++)
  142. if(strcmp(ps_global->VAR_PRINTER, list[i]) == 0)
  143. cur_printer = i;
  144. lastprinter = i - 1;
  145. }
  146. help = NO_HELP;
  147. ps_global->mangled_footer = 1;
  148. while(!done){
  149. if(init)
  150. fs_give((void **)&init);
  151. if(trailer)
  152. fs_give((void **)&trailer);
  153. if(just_one)
  154. printer = ps_global->VAR_PRINTER;
  155. else
  156. printer = list[cur_printer];
  157. parse_printer(printer, &nick, &p, &init, &trailer, NULL, NULL);
  158. strncpy(command, p, sizeof(command)-1);
  159. command[sizeof(command)-1] = '\0';
  160. fs_give((void **)&p);
  161. /* TRANSLATORS: Print something1 using something2.
  162. For example, Print configuration using printer three. */
  163. snprintf(prompt, sizeof(prompt), _("Print %s using \"%s\" ? "),
  164. desc ? desc : "",
  165. *nick ? nick : command);
  166. prompt[sizeof(prompt)-1] = '\0';
  167. fs_give((void **)&nick);
  168. cmd = radio_buttons(prompt, -FOOTER_ROWS(ps_global),
  169. ekey, 'y', 'x', help, RB_NORM);
  170. switch(cmd){
  171. case 'y':
  172. q_status_message1(SM_ORDER, 0, 9,
  173. "Printing with command \"%s\"", command);
  174. done++;
  175. break;
  176. case 10:
  177. cur_printer = (cur_printer>0)
  178. ? (cur_printer-1)
  179. : lastprinter;
  180. break;
  181. case 11:
  182. cur_printer = (cur_printer<lastprinter)
  183. ? (cur_printer+1)
  184. : 0;
  185. break;
  186. case 'n':
  187. case 'x':
  188. done++;
  189. break;
  190. case 'c':
  191. done++;
  192. break;
  193. default:
  194. break;
  195. }
  196. }
  197. if(cmd == 'c'){
  198. if(init)
  199. fs_give((void **)&init);
  200. if(trailer)
  201. fs_give((void **)&trailer);
  202. snprintf(prompt, sizeof(prompt), "Enter custom command : ");
  203. prompt[sizeof(prompt)-1] = '\0';
  204. command[0] = '\0';
  205. rc = 1;
  206. help = NO_HELP;
  207. while(rc){
  208. int flags = OE_APPEND_CURRENT;
  209. rc = optionally_enter(command, -FOOTER_ROWS(ps_global), 0,
  210. sizeof(command), prompt, NULL, help, &flags);
  211. if(rc == 1){
  212. cmd = 'x';
  213. rc = 0;
  214. }
  215. else if(rc == 3)
  216. help = (help == NO_HELP) ? h_custom_print : NO_HELP;
  217. else if(rc == 0){
  218. removing_trailing_white_space(command);
  219. removing_leading_white_space(command);
  220. q_status_message1(SM_ORDER, 0, 9,
  221. "Printing with command \"%s\"", command);
  222. }
  223. }
  224. }
  225. if(cmd == 'x' || cmd == 'n'){
  226. q_status_message(SM_ORDER, 0, 2, "Print cancelled");
  227. if(init)
  228. fs_give((void **)&init);
  229. if(trailer)
  230. fs_give((void **)&trailer);
  231. return(-1);
  232. }
  233. display_message('x');
  234. ps_global->print = (PRINT_S *)fs_get(sizeof(PRINT_S));
  235. memset(ps_global->print, 0, sizeof(PRINT_S));
  236. strncpy(aname, ANSI_PRINTER, sizeof(aname)-1);
  237. aname[sizeof(aname)-1] = '\0';
  238. strncat(aname, "-no-formfeed", sizeof(aname)-strlen(aname)-1);
  239. strncpy(wname, WYSE_PRINTER, sizeof(wname)-1);
  240. wname[sizeof(wname)-1] = '\0';
  241. strncat(wname, "-no-formfeed", sizeof(wname)-strlen(wname)-1);
  242. if(strucmp(command, ANSI_PRINTER) == 0
  243. || strucmp(command, aname) == 0
  244. || strucmp(command, WYSE_PRINTER) == 0
  245. || strucmp(command, wname) == 0){
  246. /*----------- Attached printer ---------*/
  247. q_status_message(SM_ORDER, 0, 9,
  248. "Printing to attached desktop printer...");
  249. display_message('x');
  250. xonxoff_proc(1); /* make sure XON/XOFF used */
  251. crlf_proc(1); /* AND LF->CR xlation */
  252. if(strucmp(command, ANSI_PRINTER) == 0
  253. || strucmp(command, aname) == 0){
  254. fputs("\033[5i", stdout);
  255. ansi_off = 1;
  256. }
  257. else{
  258. ansi_off = 0;
  259. printf("%c", 18); /* aux on for wyse60,
  260. Chuck Everett <ceverett@odessa.edu> */
  261. }
  262. ps_global->print->fp = stdout;
  263. if(strucmp(command, ANSI_PRINTER) == 0
  264. || strucmp(command, WYSE_PRINTER) == 0){
  265. /* put formfeed at the end of the trailer string */
  266. if(trailer){
  267. int len = strlen(trailer);
  268. fs_resize((void **)&trailer, len+2);
  269. trailer[len] = '\f';
  270. trailer[len+1] = '\0';
  271. }
  272. else
  273. trailer = cpystr("\f");
  274. }
  275. }
  276. else{
  277. /*----------- Print by forking off a UNIX command ------------*/
  278. dprint((4, "Printing using command \"%s\"\n",
  279. command ? command : "?"));
  280. ps_global->print->result = temp_nam(NULL, "pine_prt");
  281. if(ps_global->print->result &&
  282. (ps_global->print->pipe = open_system_pipe(command,
  283. &ps_global->print->result, NULL,
  284. PIPE_WRITE | PIPE_STDERR, 0,
  285. pipe_callback, NULL))){
  286. ps_global->print->fp = ps_global->print->pipe->out.f;
  287. }
  288. else{
  289. if(ps_global->print->result){
  290. our_unlink(ps_global->print->result);
  291. fs_give((void **)&ps_global->print->result);
  292. }
  293. q_status_message1(SM_ORDER | SM_DING, 3, 4,
  294. "Error opening printer: %s",
  295. error_description(errno));
  296. dprint((2, "Error popening printer \"%s\"\n",
  297. error_description(errno)));
  298. if(init)
  299. fs_give((void **)&init);
  300. if(trailer)
  301. fs_give((void **)&trailer);
  302. return(-1);
  303. }
  304. }
  305. ps_global->print->err = 0;
  306. if(init){
  307. if(*init)
  308. fputs(init, ps_global->print->fp);
  309. fs_give((void **)&init);
  310. }
  311. cb.cbuf[0] = '\0';
  312. cb.cbufp = cb.cbuf;
  313. cb.cbufend = cb.cbuf;
  314. #else /* _WINDOWS */
  315. int status;
  316. LPTSTR desclpt = NULL;
  317. if(desc)
  318. desclpt = utf8_to_lptstr(desc);
  319. if (status = mswin_print_ready (0, desclpt)) {
  320. q_status_message1(SM_ORDER | SM_DING, 3, 4,
  321. "Error starting print job: %s",
  322. mswin_print_error(status));
  323. if(desclpt)
  324. fs_give((void **) &desclpt);
  325. return(-1);
  326. }
  327. if(desclpt)
  328. fs_give((void **) &desclpt);
  329. q_status_message(SM_ORDER, 0, 9, "Printing to windows printer...");
  330. display_message('x');
  331. /* init print control structure */
  332. ps_global->print = (PRINT_S *)fs_get(sizeof(PRINT_S));
  333. memset(ps_global->print, 0, sizeof(PRINT_S));
  334. ps_global->print->err = 0;
  335. #endif /* _WINDOWS */
  336. return(0);
  337. }
  338. /*----------------------------------------------------------------------
  339. Close printer
  340. If we're piping to a spooler close down the pipe and wait for the process
  341. to finish. If we're sending to an attached printer send the escape sequence.
  342. Also let the user know the result of the print
  343. ----*/
  344. void
  345. close_printer(void)
  346. {
  347. #ifndef _WINDOWS
  348. if(trailer){
  349. if(*trailer)
  350. fputs(trailer, ps_global->print->fp);
  351. fs_give((void **)&trailer);
  352. }
  353. if(ps_global->print->fp == stdout) {
  354. if(ansi_off)
  355. fputs("\033[4i", stdout);
  356. else
  357. printf("%c", 20); /* aux off for wyse60 */
  358. fflush(stdout);
  359. if(F_OFF(F_PRESERVE_START_STOP, ps_global))
  360. xonxoff_proc(0); /* turn off XON/XOFF */
  361. crlf_proc(0); /* turn off CF->LF xlantion */
  362. } else {
  363. (void) close_system_pipe(&ps_global->print->pipe, NULL, pipe_callback);
  364. display_output_file(ps_global->print->result, "PRINT", NULL, 1);
  365. if(ps_global->print && ps_global->print->result)
  366. fs_give((void **) &ps_global->print->result);
  367. }
  368. #else /* _WINDOWS */
  369. mswin_print_done();
  370. #endif /* _WINDOWS */
  371. if(ps_global->print)
  372. fs_give((void **) &ps_global->print);
  373. q_status_message(SM_ASYNC, 0, 3, "Print command completed");
  374. display_message('x');
  375. }
  376. /*----------------------------------------------------------------------
  377. Print a single character, translate from UTF-8 to user's locale charset.
  378. Args: c -- char to print
  379. Returns: 1 on success, 0 on ps_global->print->err
  380. ----*/
  381. int
  382. print_char(int c)
  383. {
  384. #ifndef _WINDOWS
  385. int i, outchars;
  386. unsigned char obuf[MAX(MB_LEN_MAX,32)];
  387. if(!ps_global->print->err
  388. && (outchars = utf8_to_locale(c, &cb, obuf, sizeof(obuf)))){
  389. for(i = 0; i < outchars && !ps_global->print->err; i++)
  390. if(putc(obuf[i], ps_global->print->fp) == EOF)
  391. ps_global->print->err = 1;
  392. }
  393. #else /* _WINDOWS */
  394. if(!ps_global->print->err
  395. && (ps_global->print->err = mswin_print_char_utf8(c)))
  396. q_status_message1(SM_ORDER, 0, 9, "Print cancelled: %s",
  397. mswin_print_error((unsigned short)ps_global->print->err));
  398. #endif /* _WINDOWS */
  399. return(!ps_global->print->err);
  400. }
  401. /*----------------------------------------------------------------------
  402. Send a line of text to the printer
  403. Args: line -- Text to print
  404. ----*/
  405. void
  406. print_text(char *line)
  407. {
  408. #ifndef _WINDOWS
  409. int slen = strlen(line);
  410. while(!ps_global->print->err && slen--)
  411. if(print_char(*line++) == 0)
  412. ps_global->print->err = 1;
  413. #else /* _WINDOWS */
  414. if(!ps_global->print->err
  415. && (ps_global->print->err = mswin_print_text_utf8(line)))
  416. q_status_message1(SM_ORDER, 0, 9, "Print cancelled: %s",
  417. mswin_print_error((unsigned short)ps_global->print->err));
  418. #endif /* _WINDOWS */
  419. }
  420. /*----------------------------------------------------------------------
  421. printf style formatting with one arg for printer
  422. Args: line -- The printf control string
  423. a1 -- The 1st argument for printf
  424. ----*/
  425. void
  426. print_text1(char *line, char *a1)
  427. {
  428. char buf[64000];
  429. if(!ps_global->print->err && snprintf(buf, sizeof(buf), line, a1) < 0)
  430. ps_global->print->err = 1;
  431. else
  432. print_text(buf);
  433. }