Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtmail / dtmail / DmxPrintJob.C
1 /* $TOG: DmxPrintJob.C /main/30 1998/07/23 18:11:50 mgreess $ */
2
3 /*
4  *+SNOTICE
5  *
6  *      $:$
7  *
8  *      RESTRICTED CONFIDENTIAL INFORMATION:
9  *      
10  *      The information in this document is subject to special
11  *      restrictions in a confidential disclosure agreement between
12  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
13  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
14  *      Sun's specific written approval.  This document and all copies
15  *      and derivative works thereof must be returned or destroyed at
16  *      Sun's request.
17  *
18  *      Copyright 1994 Sun Microsystems, Inc.  All rights reserved.
19  *
20  *+ENOTICE
21  */
22 /*
23  *                   Common Desktop Environment
24  *
25  *   (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
26  *   (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
27  *   (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
28  *   (c) Copyright 1993, 1994, 1995 Novell, Inc.
29  *   (c) Copyright 1995 Digital Equipment Corp.
30  *   (c) Copyright 1995 Fujitsu Limited
31  *   (c) Copyright 1995 Hitachi, Ltd.
32  *                                                                   
33  *
34  *                     RESTRICTED RIGHTS LEGEND                              
35  *
36  *Use, duplication, or disclosure by the U.S. Government is subject to
37  *restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
38  *Technical Data and Computer Software clause in DFARS 252.227-7013.  Rights
39  *for non-DOD U.S. Government Departments and Agencies are as set forth in
40  *FAR 52.227-19(c)(1,2).
41
42  *Hewlett-Packard Company, 3000 Hanover Street, Palo Alto, CA 94304 U.S.A.
43  *International Business Machines Corp., Route 100, Somers, NY 10589 U.S.A. 
44  *Sun Microsystems, Inc., 2550 Garcia Avenue, Mountain View, CA 94043 U.S.A.
45  *Novell, Inc., 190 River Road, Summit, NJ 07901 U.S.A.
46  *Digital Equipment Corp., 111 Powdermill Road, Maynard, MA 01754, U.S.A.
47  *Fujitsu Limited, 1015, Kamikodanaka Nakahara-Ku, Kawasaki 211, Japan
48  *Hitachi, Ltd., 6, Kanda Surugadai 4-Chome, Chiyoda-ku, Tokyo 101, Japan
49  */
50
51
52 #include <errno.h>
53 #include <pwd.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 #include <sys/param.h>
59 #include <X11/Intrinsic.h>
60 #include <X11/Shell.h>
61 #include <Xm/Xm.h>
62 #include <Xm/PushB.h>
63 #include <Xm/Print.h>
64 #include "Dmx.h"
65 #include "DmxPrintJob.h"
66 #include "DmxPrintOptions.h"
67 #include "DmxPrintOutput.h"
68 #include "DmxPrintSetup.h"
69 #include "DtMailGenDialog.hh"
70 #include "DtMailDialogCallbackData.hh"
71 #include "MailMsg.h"
72 #include "OptCmd.h"
73 #include "RoamApp.h"
74
75
76 //
77 // Public class methods
78 //
79
80 DmxPrintJob::DmxPrintJob(
81                         char            *filename,
82                         DtMailBoolean   silent,
83                         MainWindow      *window
84                          ) : UIComponent( "PrintJob" )
85 {
86     _next_msg = (DmxMsg *) NULL;
87     _filename = strdup(filename);
88     _mailbox = (DmxMailbox *) NULL;
89     _parent = window;
90     _print_output = (DmxPrintOutput *) NULL;
91     _print_setup = (DmxPrintSetup *) NULL;
92     _print_data = (DtPrintSetupData *) XtMalloc(sizeof(DtPrintSetupData));
93     memset((void*) _print_data, 0, sizeof(DtPrintSetupData));
94     _pshell = (Widget) NULL;
95     _silent = silent;
96
97     _spool_msg_info = (DmxMsgInfo *) NULL;
98     _spool_nmsgs_done = 0;
99     _spool_nmsgs_total = 0;
100     _spool_npages_done = 0;
101     _spool_npages_total = 0;
102     _w = XtCreateWidget(_name, coreWidgetClass, _parent->baseWidget(), NULL, 0);
103     installDestroyHandler();
104
105     _nextpage_shell = NULL;
106     _nextpage_button = NULL;
107 }
108
109 DmxPrintJob::~DmxPrintJob (void)
110 {
111     //
112     // Unregister the fact that we have a print job running so
113     // dtmail can terminate.
114     //
115     if (_parent != NULL)
116       _parent->unregisterPendingTask();
117
118     if (_filename)
119     {
120         free(_filename);
121         _filename = NULL;
122     }
123     if (_mailbox)
124     {
125         delete _mailbox;
126         _mailbox = NULL;
127     }
128     if (_spool_msg_info)
129     {
130         XtFree((char*) _spool_msg_info);
131         _spool_msg_info = NULL;
132     }
133     if (_print_output)
134     {
135         delete _print_output;
136         _print_output = NULL;
137     }
138     if (_print_setup)
139     {
140         delete _print_setup;
141         _print_setup = NULL;
142     }
143     if (_pshell)
144     {
145         XtDestroyWidget(_pshell);
146         _pshell = NULL;
147     }
148     if (_print_data)
149     {
150         DtPrintFreeSetupData(_print_data);
151         XtFree((char *) _print_data);
152         _print_data = NULL;
153     }
154     if (_nextpage_shell)
155     {
156         XtDestroyWidget(_nextpage_shell);
157         _nextpage_shell = NULL;
158     }
159     if (_w)
160     {
161         //
162         //  Do not destroy this widget.
163         //  BasicComponent takes care of this for us.
164         //
165     }
166 }
167
168 /*
169  * Name: DmxPrintJob::cancel
170  * Description:
171  *      Public method used to cancel the print job.
172  */
173 void
174 DmxPrintJob::cancel(void)
175 {
176
177     _parent->clearStatus();
178
179     if (NULL != _pshell)
180     {
181         Display *display = XtDisplay(_pshell);
182
183         theRoamApp.unregisterActivePrintDisplay(display);
184         if (display == theRoamApp.getErrorPrintDisplay())
185         {
186             //
187             // Need to display an error dialog;
188             //
189             DtMailGenDialog *genDialog = new DtMailGenDialog(
190                                                         "Dialog",
191                                                         _parent->baseWidget());
192             char *errMsg =
193               GETMSG(
194                 DT_catd, 21, 23,
195                 "The X Print Server is temporarily out of resources.");
196
197             genDialog->setToErrorDialog(GETMSG(DT_catd, 1, 6, "Mailer"),
198                                         errMsg);
199             genDialog->post_and_return(GETMSG(DT_catd, 3, 9, "OK"), NULL);
200             delete genDialog;
201
202             theRoamApp.setErrorPrintDisplay(NULL);
203         }
204     }
205     delete this;
206 }
207
208 /*
209  * Name: DmxPrintJob::execute
210  * Description:
211  *      Public method used to execute the print job.
212  */
213 void
214 DmxPrintJob::execute (void)
215 {
216     theRoamApp.busyAllWindows();
217     _print_setup = new DmxPrintSetup(
218                                 _parent->baseWidget(),
219                                 &DmxPrintJob::printCB, (XtPointer) this,
220                                 &DmxPrintJob::cancelCB, (XtPointer) this,
221                                 &DmxPrintJob::closeDisplayCB, (XtPointer) this,
222                                 &DmxPrintJob::pdmSetupCB, (XtPointer) this);
223
224     //
225     // load in the messages
226     //
227     _mailbox = new DmxMailbox(_filename);
228     _mailbox->loadMessages();
229     _next_msg = _mailbox->firstMessage();
230
231     if (_mailbox->numMessages() == 1)
232     {
233         int     i,j,last_space;
234         char    *orig_subject = _next_msg->getMessageHeader(DMXSUBJ);
235         int     orig_len = strlen(orig_subject);
236         char    *subject = (char*) malloc(orig_len+1);
237         char    *filename = (char*) malloc(MAXPATHLEN+1);
238
239         
240         for (i=0,j=0,last_space=0; i<orig_len; i++)
241         {
242             if (isspace(orig_subject[i]))
243             {
244                 if (last_space < i-1)
245                   subject[j++] = ' ';
246                 last_space = i;
247             }
248             else if (orig_subject[i] == '/')
249               subject[j++] = '\\';
250             else
251               subject[j++] = orig_subject[i];
252         }
253         subject[j] = '\0';
254         sprintf(filename, "%s/%s.ps", getenv("HOME"), subject);
255
256         _print_setup->setPrintToFileName(filename);
257         free(orig_subject);
258         free(subject);
259         free(filename);
260     }
261     theRoamApp.unbusyAllWindows();
262
263     if (_silent) {
264         if (DTM_TRUE != _print_setup->getDefaultPrintData(_print_data))
265           //
266           // DtPrintSetupDialog is popped up automatically.
267           //
268           return;
269
270         createPrintShell();
271         doPrint();
272     } else {
273         _print_setup->display();
274     }
275 }
276
277
278
279 //
280 // Private class methods
281 //
282
283 /*
284  * Name: DmxPrintJob::createPrintShell
285  * Description:
286  *      Creates the XmPrint Shell widget.
287  */
288 void
289 DmxPrintJob::createPrintShell (void)
290 {
291     DtMailEnv           dmxenv;
292     DtMail::Session     *d_session = theRoamApp.session()->session();
293
294     if (_pshell != NULL) return;
295
296     //
297     // Create the print shell and
298     // the print output widgets
299     //
300 #ifdef PRINT_TO_VIDEO 
301     XmString    xms;
302
303     /*
304      * Create a dialog shell widget on the video display.
305      */
306     _pshell = XmCreateDialogShell(_parent->baseWidget(), "PrintVideo", NULL, 0);
307
308     _nextpage_shell = XtVaCreateWidget(
309                         "PrintNextPage",
310                          topLevelShellWidgetClass,
311                          _parent->baseWidget(),
312                          XmNx, 0,
313                          XmNy, 0,
314                          NULL);
315
316     xms = XmStringCreateLocalized("Push for Next Page");
317     _nextpage_button = XtVaCreateManagedWidget(
318                                 "NextPageButton",
319                                 xmPushButtonWidgetClass,
320                                 _nextpage_shell,
321                                 XmNlabelString, xms,
322                                 XmNwidth, 300,
323                                 XmNheight, 300,
324                                 NULL);
325     XmStringFree(xms);
326
327     XtAddCallback(
328                 _nextpage_button,
329                 XmNactivateCallback, 
330                 &DmxPrintJob::printOnePageCB,
331                 (XtPointer) this);
332
333     XtRealizeWidget(_nextpage_shell);
334     XtManageChild(_nextpage_shell);
335 #else
336     /*
337      * Create an XmPrintShell widget on the video display.
338      */
339     _pshell = XmPrintSetup(
340                 _parent->baseWidget(),
341                 XpGetScreenOfContext(
342                                 _print_data->print_display,
343                                 _print_data->print_context),
344                 "Print",
345                 NULL, 0);
346
347     XtAddCallback(
348                 _pshell,
349                 XmNpageSetupCallback,
350                 &DmxPrintJob::printOnePageCB,
351                 (XtPointer) this);
352     XtAddCallback(
353                 _pshell,
354                 XmNpdmNotificationCallback,
355                 &DmxPrintJob::pdmNotificationCB,
356                 (XtPointer) this);
357 #endif
358 }
359
360
361 /*
362  * Name: DmxPrintJob::createOutputWidgets
363  * Description:
364  *      Creates the DmxPrintOutput object to be used for printing.
365  */
366 void
367 DmxPrintJob::createOutputWidgets (void)
368 {
369     DtMailEnv           dmxenv;
370     DtMail::Session     *d_session = theRoamApp.session()->session();
371     DtMailBoolean       parse_error = DTM_FALSE;
372     const char          *top;
373     const char          *right;
374     const char          *bottom;
375     const char          *left;
376
377     _print_output = new DmxPrintOutput( _pshell );
378     _print_output->setWrapToFit(_print_setup->useWordWrap());
379     top         = DmxPrintOptions::getMarginSpec(DTPRINT_OPTION_MARGIN_TOP);
380     right       = DmxPrintOptions::getMarginSpec(DTPRINT_OPTION_MARGIN_RIGHT);
381     bottom      = DmxPrintOptions::getMarginSpec(DTPRINT_OPTION_MARGIN_BOTTOM);
382     left        = DmxPrintOptions::getMarginSpec(DTPRINT_OPTION_MARGIN_LEFT);
383     _print_output->setPageMargins(top, right, bottom, left, &parse_error);
384     if (parse_error)
385     {
386         DtMailGenDialog *genDialog = new DtMailGenDialog(
387                                                         "Dialog",
388                                                         _parent->baseWidget());
389         char            *errMsg = (char *) XtMalloc(1024);
390         char            *i18nMsg;
391
392         i18nMsg = GETMSG(
393                         DT_catd, 21, 2,
394                         "One of the following margin specifiers \n has incorrect syntax: \n %s \n %s \n %s \n %s \nContinue using default margins?"
395                         );
396
397         sprintf(errMsg, i18nMsg, top, right, bottom, left);
398         genDialog->setToErrorDialog(
399                             GETMSG(DT_catd, 21, 3, "Mailer"),
400                             errMsg);
401         XtFree(errMsg);
402
403         genDialog->post_and_return(
404                             GETMSG(DT_catd, 21, 4, "OK"),
405                             NULL);
406         delete genDialog;
407     }
408
409     XtRealizeWidget( _pshell );
410
411     if (NULL != top)
412       free((void*) top);
413     if (NULL != right)
414       free((void*) right);
415     if (NULL != bottom)
416       free((void*) bottom);
417     if (NULL != left)
418       free((void*) left);
419 }
420
421 void
422 ok_cb(DtMailGenDialog *genDialog)
423 {
424     delete genDialog;
425 }
426
427 /*
428  * Name: DmxPrintJob::doPrint
429  * Description:
430  *      Creates a DmxMailbox and loads the contents of the message file.
431  *      Initializes the mailbox to iterate through the messages.
432  *      Calls XmPrintToFile or XpStartJob to initiate printing.
433  */
434 void
435 DmxPrintJob::doPrint (void)
436 {
437     DtMailEnv           dmxenv;
438     DtMail::Session     *d_session = theRoamApp.session()->session();
439     XPSaveData          dest = XPSpool;
440
441     //
442     // Notify the user that we're printing
443     //
444     if (_parent != NULL) {
445         char *buf = new char[1024];
446         char *msg = GETMSG(DT_catd, 21, 1, "Printing %s ...");
447         sprintf(buf, msg, _filename);
448         _parent->setStatus(buf);
449
450         //
451         // Register the fact that we have a print job running so
452         // dtmail will not terminate in the middle.
453         //
454         _parent->registerPendingTask();
455         delete [] buf;
456     }
457
458     //
459     // load in the messages
460     //
461     // Moved to DmxPrintJob::execute
462     //
463     //_mailbox = new DmxMailbox(_filename);
464     //_mailbox->loadMessages();
465     //_next_msg = _mailbox->firstMessage();
466
467     if (_next_msg)
468       _spool_msg_info = (DmxMsgInfo *) XtCalloc(
469                                         _mailbox->numMessages(),
470                                         sizeof(DmxMsgInfo));
471
472 #ifndef PRINT_TO_VIDEO
473     if (_print_data == NULL) return;
474
475     if (_print_data->destination == DtPRINT_TO_FILE)
476       dest = XPGetData;
477
478     theRoamApp.registerActivePrintDisplay(XtDisplay(_pshell));
479     XpStartJob(XtDisplay(_pshell), dest);
480     XFlush(XtDisplay(_pshell));
481
482     if (_print_data->destination == DtPRINT_TO_FILE)
483     {
484         if (FALSE == XmPrintToFile(
485                         XtDisplay(_pshell),
486                         _print_data->dest_info,
487                         (XPFinishProc) &DmxPrintJob::finishedPrintToFile,
488                         (XPointer) this))
489         {
490             char                *fmt = "%s\n%s:  %s";
491             DtMailGenDialog     *genDialog;
492             char                *appmessage = NULL;
493             char                *message = NULL;
494             char                *sysmessage = strerror(errno);
495             Widget              w = (Widget) this->_parent->baseWidget();
496  
497             XpCancelJob(XtDisplay(_pshell), False);
498             XFlush(XtDisplay(_pshell));
499
500             genDialog = new DtMailGenDialog("Dialog", w);
501             appmessage = (char *) GETMSG(
502                                 DT_catd, 21, 14,
503                                 "'Print to File'  was unsuccessful.");
504  
505             if (NULL == sysmessage)
506             {
507                 message = XtMalloc(strlen(appmessage) + 1);
508                 sprintf(message, "%s", appmessage);
509             }
510             else
511             {
512                 message = XtMalloc(
513                                 strlen(appmessage) +
514                                 strlen(sysmessage) +
515                                 strlen(_print_data->dest_info) +
516                                 strlen(fmt) + 1);
517                 sprintf(
518                         message, fmt,
519                         appmessage, _print_data->dest_info, sysmessage);
520             }
521  
522             genDialog->setToErrorDialog(
523                             GETMSG(DT_catd, 21, 3, "Mailer"),
524                             message);
525 #if 0
526             genDialog->post_and_return(
527                             GETMSG(DT_catd, 21, 4, "OK"),
528                             NULL);
529             delete genDialog;
530 #else
531             genDialog->post((void*) genDialog, (DialogCallback) ok_cb);
532 #endif
533             XtFree(message);
534  
535             this->cancel();
536         }
537     }
538 #endif
539 }
540
541
542
543 Boolean
544 DmxPrintJob::loadOutputWidgets(void)
545 {
546     if (! _next_msg)
547       return FALSE;
548
549     _print_output->clearContents();
550     _spool_nmsgs_done = 0;
551     _spool_nmsgs_total = 0;
552     _spool_npages_done = 0;
553     _spool_npages_total = 0;
554
555     do
556     {
557 #if 0
558         _next_msg->display(
559                         DmxPrintOptions::getPrintedHeaders(),
560                         (DmxMsg::DmxPrintOutputProc) fprintf,
561                         (XtPointer) stdout);
562 #endif
563         _next_msg->display(
564                         DmxPrintOptions::getPrintedHeaders(),
565                         &DmxPrintOutput::appendContents,
566                         (XtPointer) _print_output);
567
568         switch (DmxPrintOptions::getMessageSeparator())
569         {
570           case DMX_SEPARATOR_BLANK_LINE:
571             _print_output->appendNewLine();
572             _print_output->appendNewLine();
573             break;
574           case DMX_SEPARATOR_CHARACTER_LINE:
575             {
576                 #define DMXPJ_MAX_SEPARATOR_LENGTH 100
577                 char    *buffer;
578                 const char *separator_string;
579                 int     len, nchars;
580
581                 separator_string = DmxPrintOptions::getSeparatorString();
582                 len = strlen(separator_string);
583                 nchars = _print_output->getCharactersPerLine() - 5;
584 #ifdef PRINT_TO_VIDEO
585                 fprintf(stderr, "getCharactersPerLine:  <%d>\n", nchars);
586 #endif
587                 nchars = (nchars < DMXPJ_MAX_SEPARATOR_LENGTH) ?
588                          nchars : DMXPJ_MAX_SEPARATOR_LENGTH;
589                 buffer = XtMalloc(nchars+len+1);
590                 *buffer = '\0';
591                 for (int i=0; i<nchars-1; i+=len)
592                 {
593                     int nbytes = (len < nchars-i) ? len : nchars-i;
594                     strncat(buffer, separator_string, nbytes);
595                 }
596                 buffer[nchars-1] = '\0';
597
598                 _print_output->appendNewLine();
599                 _print_output->appendContents((void*) _print_output, buffer);
600                 _print_output->appendNewLine();
601                 _print_output->appendNewLine();
602
603                 XtFree(buffer);
604                 if (NULL != separator_string)
605                   free((void*) separator_string);
606                 
607                 break;
608             }
609           case DMX_SEPARATOR_PAGE_BREAK:
610           case DMX_SEPARATOR_NEW_JOB:
611             _print_output->appendPageBreak();
612             break;
613           case DMX_SEPARATOR_NEW_LINE:
614           default:
615             _print_output->appendNewLine();
616             break;
617         }
618
619         assert(_spool_nmsgs_total < _mailbox->numMessages());
620         _spool_msg_info[_spool_nmsgs_total].msg = _next_msg;
621         _spool_msg_info[_spool_nmsgs_total].end_position =
622             _print_output->getLastPosition();
623
624         _spool_nmsgs_total++;
625
626     } while ( (  (_next_msg = _mailbox->nextMessage()) != (DmxMsg *) NULL  ) &&
627               (  (! _print_setup->printSeparately()) ||
628                  (_print_data->destination == DtPRINT_TO_FILE )  )
629             );
630
631
632     _print_output->setTopPosition(0);
633     _spool_npages_total = _print_output->getNumLines() +
634                         _print_output->getLinesPerPage() - 1;
635     _spool_npages_total /= _print_output->getLinesPerPage();
636
637     return TRUE;
638 }
639
640 void
641 DmxPrintJob::printOnePageCB(
642                         Widget,
643                         XtPointer client_data,
644                         XtPointer call_data)
645 {
646     DmxPrintJob         *thisJob = (DmxPrintJob *) client_data;
647
648     XmPrintShellCallbackStruct  *pscbs = (XmPrintShellCallbackStruct*)call_data;
649     DmxMsg                      *currmsg;
650     int                         top = 0;
651
652     if (thisJob->_print_output == NULL)
653     {
654         
655         Dimension       width, height;
656
657         width = 0; height=0;
658         XtVaGetValues(
659                 thisJob->_pshell,
660                 XmNwidth, &width,
661                 XmNheight, &height,
662                 NULL);
663 #if PRINT_TO_VIDEO
664         printf("PrintShell in PrintOnePageCB: <W %d - H %d>\n", width, height);
665 #endif
666
667         if (width < 100 || height < 100)
668         {
669             width = 2550; height=3250;
670             XtVaSetValues(
671                     thisJob->_pshell,
672                     XmNwidth, width,
673                     XmNheight, height,
674                     NULL);
675             width = 0; height=0;
676             XtVaGetValues(
677                     thisJob->_pshell,
678                     XmNwidth, &width,
679                     XmNheight, &height,
680                     NULL);
681
682 #if PRINT_TO_VIDEO
683             printf("PrintShell in PrintOnePageCB: <W %d - H %d>\n",
684                    width,height);
685 #endif
686         }
687
688         thisJob->createOutputWidgets();
689         if (! thisJob->loadOutputWidgets())
690         {
691             thisJob->cancel();
692             return;
693         }
694     }
695
696 #ifndef PRINT_TO_VIDEO 
697     if (pscbs->last_page)
698 #else
699     if (thisJob->_spool_npages_done == thisJob->_spool_npages_total)
700 #endif
701     {
702         int     dest = XPSpool;
703
704         //
705         // This spool job is done.
706         // Try spooling the next one.
707         //
708         if (! thisJob->loadOutputWidgets())
709         {
710             if (thisJob->_print_data->destination != DtPRINT_TO_FILE)
711               thisJob->cancel();
712             return;
713         }
714
715         //
716         // Register a work proc to print one page at a time
717         //
718 #ifndef PRINT_TO_VIDEO 
719         if (thisJob->_print_data->destination == DtPRINT_TO_FILE)
720           dest = XPGetData;
721
722         XpStartJob(XtDisplay(thisJob->_pshell), dest);
723         XFlush(XtDisplay(thisJob->_pshell));
724
725         if (thisJob->_print_data->destination == DtPRINT_TO_FILE)
726           XmPrintToFile(
727                 XtDisplay(thisJob->_pshell),
728                 thisJob->_print_data->dest_info,
729                 (XPFinishProc) &DmxPrintJob::finishedPrintToFile,
730                 (XPointer) thisJob);
731 #endif
732
733         return;
734     }
735
736     if (thisJob->_spool_npages_done == 0)
737     {
738         thisJob->_print_output->setTopPosition(0);
739     }
740     else if (! thisJob->_print_output->pageDown())
741     {
742 #ifndef PRINT_TO_VIDEO 
743         pscbs->last_page = TRUE;
744 #endif
745         return;
746     }
747     else
748     {
749         int top = thisJob->_print_output->getTopPosition();
750         int currmsg_i = thisJob->_spool_nmsgs_done;
751
752         //
753         // Find the index into the ._spool_msg_info array of the
754         // message which will begin the next page.  This message
755         // will be used to set the header and footer strings.
756         //
757         while (top > thisJob->_spool_msg_info[currmsg_i].end_position &&
758                currmsg_i < thisJob->_spool_nmsgs_total)
759           currmsg_i++;
760
761         assert(top <= thisJob->_spool_msg_info[currmsg_i].end_position);
762         thisJob->_spool_nmsgs_done = currmsg_i;
763     }
764
765     currmsg = thisJob->_spool_msg_info[thisJob->_spool_nmsgs_done].msg;
766     assert(currmsg != (DmxMsg *) NULL);
767     if (currmsg == (DmxMsg *) NULL)
768     {
769 #ifndef PRINT_TO_VIDEO 
770         pscbs->last_page = TRUE;
771 #endif
772         return;
773     }
774
775     //
776     // Update header and footer strings.
777     //
778     thisJob->_spool_npages_done++;
779     thisJob->updatePageHeaders(
780                 currmsg,
781                 DmxPrintOptions::getHdrFtrSpec(DTPRINT_OPTION_HEADER_LEFT),
782                 DmxPrintOptions::getHdrFtrSpec(DTPRINT_OPTION_HEADER_RIGHT),
783                 DmxPrintOptions::getHdrFtrSpec(DTPRINT_OPTION_FOOTER_LEFT),
784                 DmxPrintOptions::getHdrFtrSpec(DTPRINT_OPTION_FOOTER_RIGHT)
785                 );
786
787 #ifndef PRINT_TO_VIDEO 
788     if (thisJob->_spool_npages_done >= thisJob->_spool_npages_total)
789       pscbs->last_page = TRUE;
790 #endif
791 }
792
793
794 void
795 DmxPrintJob::updatePageHeaders(
796                                 DmxMsg                  *msg,
797                                 DmxStringTypeEnum       hl_type,
798                                 DmxStringTypeEnum       hr_type,
799                                 DmxStringTypeEnum       fl_type,
800                                 DmxStringTypeEnum       fr_type
801                                 )
802 {
803     char *hl_string,
804          *hr_string,
805          *fl_string,
806          *fr_string;
807
808     if (msg == (DmxMsg *) NULL)
809       return;
810
811     hl_string = getPageHeaderString(msg, hl_type);
812     hr_string = getPageHeaderString(msg, hr_type);
813     fl_string = getPageHeaderString(msg, fl_type);
814     fr_string = getPageHeaderString(msg, fr_type);
815     
816     _print_output->setHdrFtrStrings(
817                                 hl_string,
818                                 hr_string,
819                                 fl_string,
820                                 fr_string);
821     
822     if (DMX_NONE_STRING == hl_type && DMX_NONE_STRING == hr_type)
823       _print_output->hideHeaders();
824     else
825       _print_output->showHeaders();
826
827     if (DMX_NONE_STRING == fl_type && DMX_NONE_STRING == fr_type)
828       _print_output->hideFooters();
829     else
830       _print_output->showFooters();
831
832     free(hl_string);
833     free(hr_string);
834     free(fl_string);
835     free(fr_string);
836 }
837
838 char *
839 DmxPrintJob::getPageHeaderString(
840                                 DmxMsg                  *msg,
841                                 DmxStringTypeEnum       type
842                                    )
843 {
844     char *format,
845          *buf = (char *) NULL;
846
847
848     if (msg == (DmxMsg *) NULL)
849       return NULL;
850
851     switch (type)
852     {
853         case DMX_NONE_STRING:
854             buf = strdup(" ");
855             break;
856         case DMX_CC_HEADER_STRING:
857             {
858                 char    *hdrstr = msg->getMessageHeader(DMXCC);
859
860                 format = GETMSG(DT_catd, 21, 5, "Cc:  %s");
861                 buf = (char *) malloc(strlen(format) + strlen(hdrstr) + 1); 
862                 if (buf != (char *) NULL)
863                   sprintf(buf, format, hdrstr);
864                 
865                 free(hdrstr);
866             }
867             break;
868         case DMX_DATE_HEADER_STRING:
869             {
870                 char    *hdrstr = msg->getMessageHeader(DMXDATE);
871
872                 format = GETMSG(DT_catd, 21, 6, "Date:  %s");
873                 buf = (char *) malloc(strlen(format) + strlen(hdrstr) + 1); 
874                 if (buf != (char *) NULL)
875                   sprintf(buf, format, hdrstr);
876                 
877                 free(hdrstr);
878             }
879             break;
880         case DMX_FROM_HEADER_STRING:
881             {
882                 char    *hdrstr = msg->getMessageHeader(DMXFROM);
883
884                 format = GETMSG(DT_catd, 21, 7, "From:  %s");
885                 buf = (char *) malloc(strlen(format) + strlen(hdrstr) + 1); 
886                 if (buf != (char *) NULL)
887                   sprintf(buf, format, hdrstr);
888                 
889                 free(hdrstr);
890             }
891             break;
892         case DMX_SUBJECT_HEADER_STRING:
893             {
894                 char    *hdrstr = msg->getMessageHeader(DMXSUBJ);
895
896                 format = GETMSG(DT_catd, 21, 8, "Subject:  %s");
897                 buf = (char *) malloc(strlen(format) + strlen(hdrstr) + 1); 
898                 if (buf != (char *) NULL)
899                   sprintf(buf, format, hdrstr);
900                 
901                 free(hdrstr);
902             }
903             break;
904         case DMX_TO_HEADER_STRING:
905             {
906                 char    *hdrstr = msg->getMessageHeader(DMXTO);
907
908                 format = GETMSG(DT_catd, 21, 9, "To:  %s");
909                 buf = (char *) malloc(strlen(format) + strlen(hdrstr) + 1); 
910                 if (buf != (char *) NULL)
911                   sprintf(buf, format, hdrstr);
912                 
913                 free(hdrstr);
914             }
915             break;
916         case DMX_PAGE_NUMBER_STRING:
917             // 
918             // Allocate space for the format and the translated page number.
919             //
920             {
921                 format = GETMSG(DT_catd, 21, 10, "Page %d of %d");
922                 buf = (char *) malloc(strlen(format) + 16); 
923                 if (buf != (char *) NULL)
924                   sprintf(buf, format, _spool_npages_done, _spool_npages_total);
925             }
926             break;
927         case DMX_USER_NAME_STRING:
928             // 
929             // Allocate space for the format and the username.
930             //
931             {
932                 struct passwd   *pw;
933                 
934                 format = GETMSG(DT_catd, 21, 11, "Mail For:  %s");
935                 pw = getpwuid(getuid());
936                 buf = (char *) malloc(strlen(format) + strlen(pw->pw_name) + 1);
937                 if (buf != (char *) NULL)
938                   sprintf(buf, format, pw->pw_name);
939             }
940             break;
941         default:
942             buf = strdup("DEFAULT not impld");
943             break;
944     }
945     return buf;
946 }
947
948 /*
949  * Name: DmxPrintJob::finishedPrintToFile
950  * Description:
951  */
952 void
953 DmxPrintJob::finishedPrintToFile(
954                         Display         *display,
955                         XPContext,
956                         XPGetDocStatus  status,
957                         XPointer        client_data)
958
959 {
960     DmxPrintJob *thisJob = (DmxPrintJob*) client_data;
961     Widget      w = (Widget) thisJob->_parent->baseWidget();
962     char        *message = NULL;
963
964     if (status != XPGetDocFinished)
965     {
966         DtMailGenDialog *genDialog = new DtMailGenDialog("Dialog", w);
967
968         message = (char *) GETMSG(
969                                 DT_catd, 21, 14,
970                                 "'Print to File'  was unsuccessful.");
971         genDialog->setToErrorDialog(
972                             GETMSG(DT_catd, 21, 3, "Mailer"),
973                             message);
974         genDialog->post_and_return(
975                             GETMSG(DT_catd, 21, 4, "OK"),
976                             NULL);
977         delete genDialog;
978     }
979     else if (display != theRoamApp.getErrorPrintDisplay())
980     {
981         DtMailGenDialog *genDialog = new DtMailGenDialog("Dialog", w);
982
983         message = (char *) GETMSG(
984                                 DT_catd, 21, 15,
985                                 "'Print to File' completed successfully");
986
987         genDialog->setToWarningDialog(
988                             GETMSG(DT_catd, 21, 3, "Mailer"),
989                             message);
990         genDialog->post_and_return(
991                             GETMSG(DT_catd, 21, 4, "OK"),
992                             NULL);
993         delete genDialog;
994     }
995     thisJob->cancel();
996 }
997
998 /*
999  * Name: DmxPrintJob::cancelCB
1000  * Description:
1001  *      An XtCallbackProc which can be added to the callback list of
1002  *      a widget to cancel the print job passed back as client_data.
1003  */
1004 void
1005 DmxPrintJob::cancelCB (Widget, XtPointer client_data, XtPointer)
1006 {
1007     DmxPrintJob *thisJob = (DmxPrintJob *) client_data;
1008
1009     thisJob->cancel();
1010 }
1011
1012 /*
1013  * Name: DmxPrintJob::closeDisplayCB
1014  * Description:
1015  *      An XtCallbackProc which can be added to the callback list of
1016  *      a widget to react to the print setup closing the display.
1017  */
1018 void
1019 DmxPrintJob::closeDisplayCB (Widget, XtPointer client_data, XtPointer call_data)
1020 {
1021     DmxPrintJob *thisJob = (DmxPrintJob *) client_data;
1022     DtPrintSetupCallbackStruct *pbs = (DtPrintSetupCallbackStruct *) call_data;
1023
1024     if (thisJob->_pshell != NULL)
1025     {
1026         XtDestroyWidget(thisJob->_pshell);
1027         thisJob->_pshell = NULL;
1028     }
1029     DtPrintFreeSetupData(thisJob->_print_data);
1030 }
1031
1032 /*
1033  * Name: DmxPrintJob::pdmNotificationCB
1034  * Description:
1035  *       XmNpdmNotificationCallback for the XmPrintShell
1036  */
1037 void
1038 DmxPrintJob::pdmNotificationCB(
1039                         Widget,
1040                         XtPointer client_data,
1041                         XtPointer call_data)
1042 {
1043     DmxPrintJob                 *thisJob = (DmxPrintJob *) client_data;
1044     XmPrintShellCallbackStruct  *pscbs = (XmPrintShellCallbackStruct*)call_data;
1045     char                        *message = NULL;
1046
1047     switch (pscbs->reason)
1048     {
1049     
1050         case XmCR_PDM_NONE:
1051         case XmCR_PDM_START_ERROR:
1052         case XmCR_PDM_START_VXAUTH:
1053         case XmCR_PDM_START_PXAUTH:
1054             message = (char *) GETMSG(
1055                         DT_catd, 21, 24,
1056                         "Print Dialog Manager error - setup failed.");
1057             break;
1058         default:
1059             message = NULL;
1060             break;
1061     }
1062
1063     if (message != NULL)
1064     {
1065         DtMailGenDialog *genDialog = new DtMailGenDialog(
1066                                                 "Dialog",
1067                                                 thisJob->_parent->baseWidget());
1068         genDialog->setToErrorDialog(
1069                             GETMSG(DT_catd, 21, 3, "Mailer"),
1070                             message);
1071         genDialog->post_and_return(
1072                             GETMSG(DT_catd, 21, 25, "Continue"),
1073                             NULL);
1074         delete genDialog;
1075     }
1076 }
1077
1078 /*
1079  * Name: DmxPrintJob::pdmSetupCB
1080  * Description:
1081  *      An XtCallbackProc which can be added to the callback list of
1082  *      a widget to execute the print job passed back as client_data.
1083  */
1084 void
1085 DmxPrintJob::pdmSetupCB(
1086                 Widget print_setup,
1087                 XtPointer client_data,
1088                 XtPointer call_data)
1089 {
1090     DmxPrintJob *thisJob = (DmxPrintJob *) client_data;
1091     DtPrintSetupCallbackStruct *pbs = (DtPrintSetupCallbackStruct *) call_data;
1092
1093     DtPrintCopySetupData(thisJob->_print_data, pbs->print_data);
1094     thisJob->createPrintShell();
1095
1096     if (thisJob->_pshell)
1097     {
1098         Widget  shell = print_setup;
1099
1100         while (! (shell == NULL || XtIsShell(shell)) )
1101           shell = XtParent(shell);
1102
1103         if (shell)
1104           XmPrintPopupPDM(thisJob->_pshell, shell);
1105         else
1106           fprintf(stderr, "Internal Error %s:  Missing XmPrintShell\n");
1107     }
1108 }
1109
1110 /*
1111  * Name: DmxPrintJob::printCB
1112  * Description:
1113  *      An XtCallbackProc which can be added to the callback list of
1114  *      a widget to execute the print job passed back as client_data.
1115  */
1116 void
1117 DmxPrintJob::printCB (Widget, XtPointer client_data, XtPointer call_data)
1118 {
1119     DmxPrintJob *thisJob = (DmxPrintJob *) client_data;
1120     DtPrintSetupCallbackStruct *pbs = (DtPrintSetupCallbackStruct *) call_data;
1121
1122     /* TBD: Save options??? */
1123
1124     DtPrintCopySetupData(thisJob->_print_data, pbs->print_data);
1125     thisJob->createPrintShell();
1126     thisJob->doPrint();
1127 }