1 /*******************************************************************************
2 *									       *
3 * printUtils.c -- Nirvana library Printer Menu	& Printing Routines   	       *
4 *									       *
5 * Copyright (C) 1999 Mark Edel						       *
6 *									       *
7 * This is free software; you can redistribute it and/or modify it under the    *
8 * terms of the GNU General Public License as published by the Free Software    *
9 * Foundation; either version 2 of the License, or (at your option) any later   *
10 * version. In addition, you may distribute version of this program linked to   *
11 * Motif or Open Motif. See README for details.                                 *
12 *                                                                              *
13 * This software is distributed in the hope that it will be useful, but WITHOUT *
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or        *
15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License        *
16 * for more details.							       *
17 * 									       *
18 * You should have received a copy of the GNU General Public License along with *
19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple     *
20 * Place, Suite 330, Boston, MA  02111-1307 USA		                       *
21 *									       *
22 * Nirvana Text Editor	    						       *
23 *                                        				       *
24 * April 20, 1992							       *
25 *									       *
26 * Written by Arnulfo Zepeda-Navratil				               *
27 *            Centro de Investigacion y Estudio Avanzados ( CINVESTAV )         *
28 *            Dept. Fisica - Mexico                                             *
29 *            BITNET: ZEPEDA@CINVESMX                                           *
30 *									       *
31 * Modified by Donna Reid and Joy Kyriakopulos 4/8/93 - VMS port		       *
32 *									       *
33 *******************************************************************************/
34 
35 #ifdef HAVE_CONFIG_H
36 #include "../config.h"
37 #endif
38 
39 #include "printUtils.h"
40 #include "DialogF.h"
41 #include "misc.h"
42 #include "prefFile.h"
43 #include "nedit_malloc.h"
44 
45 #include <string.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <ctype.h>
50 #include <sys/types.h>
51 #ifdef VMS
52 #include "vmsparam.h"
53 #include <ssdef.h>
54 #include <lib$routines.h>
55 #include <descrip.h>
56 #include <starlet.h>
57 #include <lnmdef.h>
58 #include <clidef.h>
59 #else
60 #ifdef USE_DIRENT
61 #include <dirent.h>
62 #else
63 #include <sys/dir.h>
64 #endif /* USE_DIRENT */
65 #ifndef __MVS__
66 #include <sys/param.h>
67 #endif
68 #endif /*VMS*/
69 #include <sys/stat.h>
70 
71 #include <X11/StringDefs.h>
72 #include <X11/Intrinsic.h>
73 #include <X11/Shell.h>
74 #include <Xm/Xm.h>
75 #include <Xm/Form.h>
76 #include <Xm/LabelG.h>
77 #include <Xm/PushB.h>
78 #include <Xm/SeparatoG.h>
79 #include <Xm/Text.h>
80 
81 #ifdef HAVE_DEBUG_H
82 #include "../debug.h"
83 #endif
84 
85 /* Separator between directory references in PATH environmental variable */
86 #ifdef __EMX__  /* For OS/2 */
87 #define SEPARATOR ';'
88 #else
89 #define SEPARATOR ':'
90 #endif
91 
92 /* Number of extra pixels down to place a label even with a text widget */
93 #define LABEL_TEXT_DIFF 6
94 
95 /* Maximum text string lengths */
96 #define MAX_OPT_STR 20
97 #define MAX_QUEUE_STR 60
98 #define MAX_INT_STR 13
99 #define MAX_HOST_STR 100
100 #define MAX_PCMD_STR 100
101 #define MAX_NAME_STR 100
102 #define MAX_CMD_STR 256
103 #define VMS_MAX_JOB_NAME_STR 39
104 
105 #define N_PRINT_PREFS 7 /* must agree with number of preferences below */
106 struct printPrefDescrip {
107     PrefDescripRec printCommand;
108     PrefDescripRec copiesOption;
109     PrefDescripRec queueOption;
110     PrefDescripRec nameOption;
111     PrefDescripRec hostOption;
112     PrefDescripRec defaultQueue;
113     PrefDescripRec defaultHost;
114 };
115 
116 /* Function Prototypes */
117 static Widget createForm(Widget parent);
118 static void allowOnlyNumInput(Widget widget, caddr_t client_data,
119 	XmTextVerifyCallbackStruct *call_data);
120 static void noSpaceOrPunct(Widget widget, caddr_t client_data,
121 	XmTextVerifyCallbackStruct *call_data);
122 static void updatePrintCmd(Widget w, caddr_t client_data, caddr_t call_data);
123 static void printCmdModified(Widget w, caddr_t client_data, caddr_t call_data);
124 static void printButtonCB(Widget widget, caddr_t client_data, caddr_t call_data);
125 static void cancelButtonCB(Widget widget, caddr_t client_data, caddr_t call_data);
126 static void setQueueLabelText(void);
127 static int fileInDir(const char *filename, const char *dirpath, unsigned short mode_flags);
128 static int fileInPath(const char *filename, unsigned short mode_flags);
129 static int flprPresent(void);
130 #ifdef USE_LPR_PRINT_CMD
131 static void getLprQueueDefault(char *defqueue);
132 #endif
133 #ifndef USE_LPR_PRINT_CMD
134 static void getLpQueueDefault(char *defqueue);
135 #endif
136 static void setHostLabelText(void);
137 #ifdef VMS
138 static void getVmsQueueDefault(char *defqueue);
139 #else
140 static void getFlprHostDefault(char *defhost);
141 static void getFlprQueueDefault(char *defqueue);
142 #endif
143 
144 /* Module Global Variables */
145 static Boolean  DoneWithDialog;
146 static Boolean	PreferencesLoaded = False;
147 static Widget	Form;
148 static Widget	Label2;
149 static Widget	Label3;
150 static Widget	Text1;
151 static Widget	Text2;
152 static Widget	Text3;
153 static Widget	Text4;
154 static const char *PrintFileName;
155 static const char *PrintJobName;
156 static char PrintCommand[MAX_PCMD_STR];	/* print command string */
157 static char CopiesOption[MAX_OPT_STR];	/* # of copies argument string */
158 static char QueueOption[MAX_OPT_STR];	/* queue name argument string */
159 static char NameOption[MAX_OPT_STR];	/* print job name argument string */
160 static char HostOption[MAX_OPT_STR];	/* host name argument string */
161 static char DefaultQueue[MAX_QUEUE_STR];/* default print queue */
162 static char DefaultHost[MAX_HOST_STR];	/* default host name */
163 static char Copies[MAX_INT_STR] = "";	/* # of copies last entered by user */
164 static char Queue[MAX_QUEUE_STR] = "";	/* queue name last entered by user */
165 static char Host[MAX_HOST_STR] = "";	/* host name last entered by user */
166 static char CmdText[MAX_CMD_STR] = "";	/* print command last entered by user */
167 static int  CmdFieldModified = False;	/* user last changed the print command
168 					   field, so don't trust the rest */
169 #ifdef VMS
170 static int DeleteFile;			/* append /DELETE to VMS print command*/
171 #endif /*VMS*/
172 
173 static struct printPrefDescrip PrintPrefDescrip = {
174     {"printCommand", "PrintCommand", PREF_STRING, NULL,
175     	PrintCommand, (void *)MAX_PCMD_STR, False},
176     {"printCopiesOption", "PrintCopiesOption", PREF_STRING, NULL,
177     	CopiesOption, (void *)MAX_OPT_STR, False},
178     {"printQueueOption", "PrintQueueOption", PREF_STRING, NULL,
179     	QueueOption, (void *)MAX_OPT_STR, False},
180     {"printNameOption", "PrintNameOption", PREF_STRING, NULL,
181     	NameOption, (void *)MAX_OPT_STR, False},
182     {"printHostOption", "PrintHostOption", PREF_STRING, NULL,
183     	HostOption, (void *)MAX_OPT_STR, False},
184     {"printDefaultQueue", "PrintDefaultQueue", PREF_STRING, NULL,
185     	DefaultQueue, (void *)MAX_QUEUE_STR, False},
186     {"printDefaultHost", "PrintDefaultHost", PREF_STRING, NULL,
187     	DefaultHost, (void *)MAX_HOST_STR, False},
188 };
189 
190 /*
191 ** PrintFile(Widget parent, char *printFile, char *jobName);
192 **
193 ** function to put up an application-modal style Print Panel dialog
194 ** box.
195 **
196 **	parent		Parent widget for displaying dialog
197 **	printFile	File to print (assumed to be a temporary file
198 **			and not revealed to the user)
199 **	jobName		Title for the print banner page
200 */
201 #ifdef VMS
PrintFile(Widget parent,const char * printFile,const char * jobName,int delete)202 void PrintFile(Widget parent, const char *printFile, const char *jobName, int delete)
203 #else
204 void PrintFile(Widget parent, const char *printFile, const char *jobName)
205 #endif /*VMS*/
206 {
207     /* In case the program hasn't called LoadPrintPreferences, set up the
208        default values for the print preferences */
209     if (!PreferencesLoaded)
210     	LoadPrintPreferences(NULL, "", "", True);
211 
212     /* Make the PrintFile information available to the callback routines */
213     PrintFileName = printFile;
214     PrintJobName = jobName;
215 #ifdef VMS
216     DeleteFile = delete;
217 #endif /*VMS*/
218 
219     /* Create and display the print dialog */
220     DoneWithDialog = False;
221     Form = createForm(parent);
222     ManageDialogCenteredOnPointer(Form);
223 
224     /* Process events until the user is done with the print dialog */
225     while (!DoneWithDialog)
226         XtAppProcessEvent(XtWidgetToApplicationContext(Form), XtIMAll);
227 
228     /* Destroy the dialog.  Print dialogs are not preserved across calls
229        to PrintFile so that it may be called with different parents and
230        to generally simplify the call (this, of course, makes it slower) */
231     XtDestroyWidget(Form);
232 }
233 
234 /*
235 ** LoadPrintPreferences
236 **
237 ** Read an X database to obtain print dialog preferences.
238 **
239 **	prefDB		X database potentially containing print preferences
240 **	appName		Application name which can be used to qualify
241 **			resource names for database lookup.
242 **	appClass	Application class which can be used to qualify
243 **			resource names for database lookup.
244 **	lookForFlpr	Check if the flpr print command is installed
245 **			and use that for the default if it's found.
246 **			(flpr is a Fermilab utility for printing on
247 **			arbitrary systems that support the lpr protocol)
248 */
LoadPrintPreferences(XrmDatabase prefDB,const char * appName,const char * appClass,int lookForFlpr)249 void LoadPrintPreferences(XrmDatabase prefDB, const char *appName,
250         const char *appClass, int lookForFlpr)
251 {
252     static char defaultQueue[MAX_QUEUE_STR], defaultHost[MAX_HOST_STR];
253 
254 #ifdef VMS
255     /* VMS built-in print command */
256     getVmsQueueDefault(defaultQueue);
257     PrintPrefDescrip.printCommand.defaultString = "print";
258     PrintPrefDescrip.copiesOption.defaultString = "/copies=";
259     PrintPrefDescrip.queueOption.defaultString = "/queue=";
260     PrintPrefDescrip.nameOption.defaultString = "/name=";
261     PrintPrefDescrip.hostOption.defaultString = "";
262     PrintPrefDescrip.defaultQueue.defaultString = defaultQueue;
263     PrintPrefDescrip.defaultHost.defaultString = "";
264 #else
265 
266     /* check if flpr is installed, and otherwise choose appropriate
267        printer per system type */
268     if (lookForFlpr && flprPresent()) {
269     	getFlprQueueDefault(defaultQueue);
270     	getFlprHostDefault(defaultHost);
271     	PrintPrefDescrip.printCommand.defaultString = "flpr";
272     	PrintPrefDescrip.copiesOption.defaultString = "";
273     	PrintPrefDescrip.queueOption.defaultString = "-q";
274     	PrintPrefDescrip.nameOption.defaultString = "-j ";
275     	PrintPrefDescrip.hostOption.defaultString = "-h";
276     	PrintPrefDescrip.defaultQueue.defaultString = defaultQueue;
277     	PrintPrefDescrip.defaultHost.defaultString = defaultHost;
278     } else {
279 #ifdef USE_LPR_PRINT_CMD
280 	getLprQueueDefault(defaultQueue);
281      	PrintPrefDescrip.printCommand.defaultString = "lpr";
282     	PrintPrefDescrip.copiesOption.defaultString = "-# ";
283     	PrintPrefDescrip.queueOption.defaultString = "-P ";
284     	PrintPrefDescrip.nameOption.defaultString = "-J ";
285     	PrintPrefDescrip.hostOption.defaultString = "";
286     	PrintPrefDescrip.defaultQueue.defaultString = defaultQueue;
287     	PrintPrefDescrip.defaultHost.defaultString = "";
288 #else
289      	getLpQueueDefault(defaultQueue);
290      	PrintPrefDescrip.printCommand.defaultString = "lp"; /* was lp -c */
291     	PrintPrefDescrip.copiesOption.defaultString = "-n";
292     	PrintPrefDescrip.queueOption.defaultString = "-d";
293     	PrintPrefDescrip.nameOption.defaultString = "-t";
294     	PrintPrefDescrip.hostOption.defaultString = "";
295     	PrintPrefDescrip.defaultQueue.defaultString = defaultQueue;
296     	PrintPrefDescrip.defaultHost.defaultString = "";
297 #endif
298     }
299 #endif
300 
301     /* Read in the preferences from the X database using the mechanism from
302        prefFile.c (this allows LoadPrintPreferences to work before any
303        widgets are created, which is more convenient than XtGetApplication-
304        Resources for applications which have no main window) */
305     RestorePreferences(NULL, prefDB, appName, appClass,
306     	    (PrefDescripRec *)&PrintPrefDescrip, N_PRINT_PREFS);
307 
308     PreferencesLoaded = True;
309 }
310 
createForm(Widget parent)311 static Widget createForm(Widget parent)
312 {
313     Widget form, printOk, printCancel, label1, separator;
314     Widget topWidget = NULL;
315     XmString st0;
316     Arg args[65];
317     int argcnt;
318     Widget bwidgetarray [30];
319     int bwidgetcnt = 0;
320 
321     /************************ FORM ***************************/
322     argcnt = 0;
323     XtSetArg(args[argcnt], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
324     argcnt++;
325     XtSetArg(args[argcnt], XmNdialogTitle, (st0=XmStringCreateLtoR(
326 		"Print", XmSTRING_DEFAULT_CHARSET))); argcnt++;
327     XtSetArg(args[argcnt], XmNautoUnmanage, False); argcnt++;
328     form = CreateFormDialog(parent, "printForm", args, argcnt);
329     XtVaSetValues(form, XmNshadowThickness, 0, NULL);
330 
331     XmStringFree( st0 );
332 
333     /*********************** LABEL 1 and TEXT BOX 1 *********************/
334     if (CopiesOption[0] != '\0') {
335 	argcnt = 0;
336 	XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR(
337 		"Number of copies (1)", XmSTRING_DEFAULT_CHARSET))); argcnt++;
338 	XtSetArg(args[argcnt], XmNmnemonic, 'N'); argcnt++;
339 	XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++;
340 	XtSetArg(args[argcnt], XmNtopOffset, LABEL_TEXT_DIFF+5); argcnt++;
341 	XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++;
342 	XtSetArg(args[argcnt], XmNleftOffset, 8); argcnt++;
343 	label1 = XmCreateLabelGadget(form, "label1", args, argcnt);
344 	XmStringFree( st0 );
345 	bwidgetarray[bwidgetcnt] = label1; bwidgetcnt++;
346 
347 	argcnt = 0;
348 	XtSetArg(args[argcnt], XmNshadowThickness, (short)2); argcnt++;
349 	XtSetArg(args[argcnt], XmNcolumns, 3); argcnt++;
350 	XtSetArg(args[argcnt], XmNrows, 1); argcnt++;
351 	XtSetArg(args[argcnt], XmNvalue , Copies); argcnt++;
352 	XtSetArg(args[argcnt], XmNmaxLength, 3); argcnt++;
353         XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_FORM); argcnt++;
354 	XtSetArg(args[argcnt], XmNtopOffset, 5); argcnt++;
355 	XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++;
356 	XtSetArg(args[argcnt], XmNleftWidget, label1); argcnt++;
357 	Text1 = XmCreateText(form, "text1", args, argcnt);
358 	bwidgetarray[bwidgetcnt] = Text1; bwidgetcnt++;
359 	XtAddCallback(Text1, XmNmodifyVerifyCallback,
360 		(XtCallbackProc)allowOnlyNumInput, NULL);
361 	XtAddCallback(Text1, XmNvalueChangedCallback,
362 		(XtCallbackProc)updatePrintCmd, NULL);
363 	RemapDeleteKey(Text1);
364 	topWidget = Text1;
365 	XtVaSetValues(label1, XmNuserData, Text1, NULL); /* mnemonic procesing */
366     }
367 
368     /************************ LABEL 2 and TEXT 2 ************************/
369     if (QueueOption[0] != '\0') {
370 	argcnt = 0;
371 	XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR(
372 		    "  ", XmSTRING_DEFAULT_CHARSET))); argcnt++;
373 	XtSetArg(args[argcnt], XmNmnemonic, 'Q'); argcnt++;
374 	XtSetArg(args[argcnt], XmNrecomputeSize, True); argcnt++;
375 	XtSetArg(args[argcnt], XmNtopAttachment,
376 		topWidget==NULL?XmATTACH_FORM:XmATTACH_WIDGET); argcnt++;
377 	XtSetArg(args[argcnt], XmNtopWidget, topWidget); argcnt++;
378 	XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++;
379 	XtSetArg(args[argcnt], XmNtopOffset, LABEL_TEXT_DIFF+4); argcnt++;
380 	XtSetArg(args[argcnt], XmNleftOffset, 8); argcnt++;
381 	Label2 = XmCreateLabelGadget(form, "label2", args, argcnt);
382 	XmStringFree(st0);
383 	bwidgetarray[bwidgetcnt] = Label2; bwidgetcnt++;
384 	setQueueLabelText();
385 
386 	argcnt = 0;
387 	XtSetArg(args[argcnt], XmNshadowThickness, (short)2); argcnt++;
388 	XtSetArg(args[argcnt], XmNcolumns, (short)17); argcnt++;
389 	XtSetArg(args[argcnt], XmNmaxLength, MAX_QUEUE_STR); argcnt++;
390 	XtSetArg(args[argcnt], XmNvalue, Queue); argcnt++;
391 	XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++;
392 	XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++;
393 	XtSetArg(args[argcnt], XmNleftWidget, Label2 ); argcnt++;
394 	XtSetArg(args[argcnt], XmNtopAttachment,
395 		topWidget==NULL?XmATTACH_FORM:XmATTACH_WIDGET); argcnt++;
396 	XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++;
397 	XtSetArg(args[argcnt], XmNrightOffset, 8); argcnt++;
398 	XtSetArg(args[argcnt], XmNtopOffset, 4); argcnt++;
399 	Text2 = XmCreateText(form, "text2", args, argcnt);
400 	XtAddCallback(Text2, XmNmodifyVerifyCallback,
401 		(XtCallbackProc)noSpaceOrPunct, NULL);
402 	XtAddCallback(Text2, XmNvalueChangedCallback,
403 		(XtCallbackProc)updatePrintCmd, NULL);
404 	bwidgetarray[bwidgetcnt] = Text2; bwidgetcnt++;
405 	RemapDeleteKey(Text2);
406 	XtVaSetValues(Label2, XmNuserData, Text2, NULL); /* mnemonic procesing */
407 	topWidget = Text2;
408     }
409 
410     /****************** LABEL 3 and TEXT 3 *********************/
411     if (HostOption[0] != '\0') {
412 	argcnt = 0;
413 	XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR(
414 		   "  ", XmSTRING_DEFAULT_CHARSET))); argcnt++;
415 	XtSetArg(args[argcnt], XmNmnemonic, 'H'); argcnt++;
416 	XtSetArg(args[argcnt], XmNrecomputeSize, True); argcnt++;
417 	XtSetArg(args[argcnt], XmNvalue , ""); argcnt++;
418 	XtSetArg(args[argcnt], XmNtopAttachment,
419 		topWidget==NULL?XmATTACH_FORM:XmATTACH_WIDGET); argcnt++;
420 	XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++;
421 	XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++;
422 	XtSetArg(args[argcnt], XmNleftOffset, 8); argcnt++;
423 	XtSetArg(args[argcnt], XmNtopOffset, LABEL_TEXT_DIFF+4); argcnt++;
424 	Label3 = XmCreateLabelGadget(form, "label3", args, argcnt);
425 	XmStringFree(st0);
426 	bwidgetarray[bwidgetcnt] = Label3; bwidgetcnt++;
427 	setHostLabelText();
428 
429 	argcnt = 0;
430 	XtSetArg(args[argcnt], XmNcolumns, 17); argcnt++;
431 	XtSetArg(args[argcnt], XmNrows, 1); argcnt++;
432 	XtSetArg(args[argcnt], XmNvalue, Host); argcnt++;
433 	XtSetArg(args[argcnt], XmNmaxLength, MAX_HOST_STR); argcnt++;
434 	XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++;
435 	XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_WIDGET); argcnt++;
436 	XtSetArg(args[argcnt], XmNleftWidget, Label3 ); argcnt++;
437 	XtSetArg(args[argcnt], XmNtopAttachment,
438 		topWidget==NULL?XmATTACH_FORM:XmATTACH_WIDGET); argcnt++;
439 	XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++;
440 	XtSetArg(args[argcnt], XmNrightOffset, 8); argcnt++;
441     	XtSetArg(args[argcnt], XmNtopOffset, 4); argcnt++;
442 	Text3 = XmCreateText(form, "Text3", args, argcnt);
443 	XtAddCallback(Text3, XmNmodifyVerifyCallback,
444 		(XtCallbackProc)noSpaceOrPunct, NULL);
445 	XtAddCallback(Text3, XmNvalueChangedCallback,
446 		(XtCallbackProc)updatePrintCmd, NULL);
447 	bwidgetarray[bwidgetcnt] = Text3; bwidgetcnt++;
448     	RemapDeleteKey(Text3);
449 	XtVaSetValues(Label3, XmNuserData, Text3, NULL); /* mnemonic procesing */
450     	topWidget = Text3;
451     }
452 
453     /************************** TEXT 4 ***************************/
454     argcnt = 0;
455     XtSetArg(args[argcnt], XmNvalue, CmdText); argcnt++;
456     XtSetArg(args[argcnt], XmNcolumns, 50); argcnt++;
457     XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++;
458     XtSetArg(args[argcnt], XmNleftOffset, 8); argcnt++;
459     XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++;
460     XtSetArg(args[argcnt], XmNtopOffset, 8); argcnt++;
461     XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++;
462     XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++;
463     XtSetArg(args[argcnt], XmNrightOffset, 8); argcnt++;
464     Text4 = XmCreateText(form, "Text4", args, argcnt);
465     XtAddCallback(Text4, XmNmodifyVerifyCallback,
466 	    (XtCallbackProc)printCmdModified, NULL);
467     bwidgetarray[bwidgetcnt] = Text4; bwidgetcnt++;
468     RemapDeleteKey(Text4);
469     topWidget = Text4;
470     if (!CmdFieldModified)
471     	updatePrintCmd(NULL, NULL, NULL);
472 
473     /*********************** SEPARATOR **************************/
474     argcnt = 0;
475     XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++;
476     XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++;
477     XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++;
478     XtSetArg(args[argcnt], XmNtopOffset, 8); argcnt++;
479     XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++;
480     separator = XmCreateSeparatorGadget(form, "separator", args, argcnt);
481     bwidgetarray[bwidgetcnt] = separator; bwidgetcnt++;
482     topWidget = separator;
483 
484     /********************** CANCEL BUTTON *************************/
485     argcnt = 0;
486     XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR(
487 		"Cancel", XmSTRING_DEFAULT_CHARSET))); argcnt++;
488     XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_POSITION); argcnt++;
489     XtSetArg(args[argcnt], XmNleftPosition, 60); argcnt++;
490     XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++;
491     XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++;
492     XtSetArg(args[argcnt], XmNtopOffset, 7); argcnt++;
493     printCancel = XmCreatePushButton(form, "printCancel", args, argcnt);
494     XmStringFree( st0 );
495     bwidgetarray[bwidgetcnt] = printCancel; bwidgetcnt++;
496     XtAddCallback (printCancel, XmNactivateCallback,
497     	    (XtCallbackProc)cancelButtonCB, NULL);
498 
499     /*********************** PRINT BUTTON **************************/
500     argcnt = 0;
501     XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR(
502 		"Print", XmSTRING_DEFAULT_CHARSET))); argcnt++;
503     XtSetArg(args[argcnt], XmNshowAsDefault, True); argcnt++;
504     XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_POSITION); argcnt++;
505     XtSetArg(args[argcnt], XmNrightPosition, 40); argcnt++;
506     XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++;
507     XtSetArg(args[argcnt], XmNtopWidget, topWidget ); argcnt++;
508     XtSetArg(args[argcnt], XmNtopOffset, 7); argcnt++;
509     printOk = XmCreatePushButton(form, "printOk", args, argcnt);
510     XmStringFree( st0 );
511     bwidgetarray[bwidgetcnt] = printOk; bwidgetcnt++;
512     XtAddCallback (printOk, XmNactivateCallback,
513     	    (XtCallbackProc)printButtonCB, NULL);
514 
515     argcnt = 0;
516     XtSetArg(args[argcnt], XmNcancelButton, printCancel); argcnt++;
517     XtSetArg(args[argcnt], XmNdefaultButton, printOk); argcnt++;
518     XtSetValues(form, args, argcnt);
519 
520     XtManageChildren(bwidgetarray, bwidgetcnt);
521     AddDialogMnemonicHandler(form, FALSE);
522     return form;
523 }
524 
setQueueLabelText(void)525 static void setQueueLabelText(void)
526 {
527     Arg args[15];
528     int	argcnt;
529     XmString	st0;
530     char        tmp_buf[MAX_QUEUE_STR+8];
531 
532     if (DefaultQueue[0] != '\0')
533     	sprintf(tmp_buf, "Queue (%s)", DefaultQueue);
534     else
535     	sprintf(tmp_buf, "Queue");
536     argcnt = 0;
537     XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR(
538 		tmp_buf, XmSTRING_DEFAULT_CHARSET))); argcnt++;
539     XtSetValues (Label2, args, argcnt);
540     XmStringFree( st0 );
541 }
542 
setHostLabelText(void)543 static void setHostLabelText(void)
544 {
545     Arg args[15];
546     int	argcnt;
547     XmString st0;
548     char tmp_buf[MAX_HOST_STR+7];
549 
550     if (strcmp(DefaultHost, ""))
551     	sprintf(tmp_buf, "Host (%s)", DefaultHost);
552     else
553     	sprintf(tmp_buf, "Host");
554     argcnt = 0;
555     XtSetArg(args[argcnt], XmNlabelString, (st0=XmStringCreateLtoR(
556 		tmp_buf, XmSTRING_DEFAULT_CHARSET))); argcnt++;
557 
558     XtSetValues (Label3, args, argcnt);
559     XmStringFree( st0 );
560 }
561 
allowOnlyNumInput(Widget widget,caddr_t client_data,XmTextVerifyCallbackStruct * call_data)562 static void allowOnlyNumInput(Widget widget, caddr_t client_data,
563 			      XmTextVerifyCallbackStruct *call_data)
564 {
565     int i, textInserted, nInserted;
566 
567     nInserted = call_data->text->length;
568     textInserted = (nInserted > 0);
569     if ((call_data->reason == XmCR_MODIFYING_TEXT_VALUE) && textInserted) {
570 	for (i=0; i<nInserted; i++) {
571             if (!isdigit((unsigned char)call_data->text->ptr[i])) {
572             	call_data->doit = False;
573             	return;
574             }
575         }
576     }
577     call_data->doit = True;
578 }
579 
580 /*
581 ** Prohibit a relatively random sampling of characters that will cause
582 ** problems on command lines
583 */
noSpaceOrPunct(Widget widget,caddr_t client_data,XmTextVerifyCallbackStruct * call_data)584 static void noSpaceOrPunct(Widget widget, caddr_t client_data,
585 			      XmTextVerifyCallbackStruct *call_data)
586 {
587     int i, j, textInserted, nInserted;
588 #ifndef VMS
589     static char prohibited[] = " \t,;|<>()[]{}!@?";
590 #else
591     static char prohibited[] = " \t,;|@+";
592 #endif
593 
594     nInserted = call_data->text->length;
595     textInserted = (nInserted > 0);
596     if ((call_data->reason == XmCR_MODIFYING_TEXT_VALUE) && textInserted) {
597 	for (i=0; i<nInserted; i++) {
598             for (j=0; j<(int)XtNumber(prohibited); j++) {
599         	if (call_data->text->ptr[i] == prohibited[j]) {
600             	    call_data->doit = False;
601             	    return;
602         	}
603             }
604         }
605     }
606     call_data->doit = True;
607 }
608 
updatePrintCmd(Widget w,caddr_t client_data,caddr_t call_data)609 static void updatePrintCmd(Widget w, caddr_t client_data, caddr_t call_data)
610 {
611     char command[MAX_CMD_STR], copiesArg[MAX_OPT_STR+MAX_INT_STR];
612     char jobArg[MAX_NAME_STR], hostArg[MAX_OPT_STR+MAX_HOST_STR];
613     char queueArg[MAX_OPT_STR+MAX_QUEUE_STR];
614     char *str;
615     int nCopies;
616 #ifdef VMS
617     char printJobName[VMS_MAX_JOB_NAME_STR+1];
618 #endif /*VMS*/
619 
620     /* read each text field in the dialog and generate the corresponding
621        command argument */
622     if (CopiesOption[0] == '\0') {
623     	copiesArg[0] = '\0';
624     } else {
625 	str = XmTextGetString(Text1);
626 	if (str[0] == '\0') {
627 	    copiesArg[0] = '\0';
628 	} else {
629 	    if (sscanf(str, "%d", &nCopies) != 1) {
630             	copiesArg[0] = '\0';
631             } else {
632             	sprintf(copiesArg, " %s%s", CopiesOption, str);
633             }
634 	}
635 	NEditFree(str);
636     }
637     if (QueueOption[0] == '\0') {
638     	queueArg[0] = '\0';
639     } else {
640 	str = XmTextGetString(Text2);
641 	if (str[0] == '\0')
642 	    queueArg[0] = '\0';
643 	else
644 	    sprintf(queueArg, " %s%s", QueueOption, str);
645 	NEditFree(str);
646     }
647     if (HostOption[0] == '\0') {
648     	hostArg[0] = '\0';
649     } else {
650 	str = XmTextGetString(Text3);
651 	if (str[0] == '\0')
652 	    hostArg[0] = '\0';
653 	else
654 	    sprintf(hostArg, " %s%s", HostOption, str);
655 	NEditFree(str);
656     }
657     if (NameOption[0] == '\0')
658     	jobArg[0] = '\0';
659     else {
660 #ifdef VMS
661     /* truncate job name on VMS systems or it will cause problems */
662         strncpy(printJobName,PrintJobName,VMS_MAX_JOB_NAME_STR);
663         printJobName[VMS_MAX_JOB_NAME_STR] = '\0';
664         sprintf(jobArg, " %s\"%s\"", NameOption, printJobName);
665 #else
666         sprintf(jobArg, " %s\"%s\"", NameOption, PrintJobName);
667 #endif
668     }
669 
670     /* Compose the command from the options determined above */
671     sprintf(command, "%s%s%s%s%s", PrintCommand, copiesArg,
672     	    queueArg, hostArg, jobArg);
673 
674     /* display it in the command text area */
675     XmTextSetString(Text4, command);
676 
677     /* Indicate that the command field was synthesized from the other fields,
678        so future dialog invocations can safely re-generate the command without
679        overwriting commands specifically entered by the user */
680     CmdFieldModified = False;
681 }
682 
printCmdModified(Widget w,caddr_t client_data,caddr_t call_data)683 static void printCmdModified(Widget w, caddr_t client_data, caddr_t call_data)
684 {
685     /* Indicate that the user has specifically modified the print command
686        and that this field should be left as is in subsequent dialogs */
687     CmdFieldModified = True;
688 }
689 
printButtonCB(Widget widget,caddr_t client_data,caddr_t call_data)690 static void printButtonCB(Widget widget, caddr_t client_data, caddr_t call_data)
691 {
692     char *str, command[MAX_CMD_STR];
693 #ifdef VMS
694     int spawn_sts;
695     int spawnFlags=CLI$M_NOCLISYM;
696     struct dsc$descriptor cmdDesc;
697 
698     /* get the print command from the command text area */
699     str = XmTextGetString(Text4);
700 
701     /* add the file name to the print command */
702     sprintf(command, "%s %s", str, PrintFileName);
703 
704     NEditFree(str);
705 
706     /* append /DELETE to print command if requested */
707     if (DeleteFile)
708 	strcat(command, "/DELETE");
709 
710     /* spawn the print command */
711     cmdDesc.dsc$w_length  = strlen(command);
712     cmdDesc.dsc$b_dtype   = DSC$K_DTYPE_T;
713     cmdDesc.dsc$b_class   = DSC$K_CLASS_S;
714     cmdDesc.dsc$a_pointer = command;
715     spawn_sts = lib$spawn(&cmdDesc,0,0,&spawnFlags,0,0,0,0,0,0,0,0);
716 
717     if (spawn_sts != SS$_NORMAL)
718     {
719         DialogF(DF_WARN, widget, 1, "Print Error",
720                 "Unable to Print:\n%d - %s\n  spawnFlags = %d\n", "OK",
721                 spawn_sts, strerror(EVMSERR, spawn_sts), spawnFlags);
722         return;
723     }
724 #else
725     int nRead;
726     FILE *pipe;
727     char errorString[MAX_PRINT_ERROR_LENGTH], discarded[1024];
728 
729     /* get the print command from the command text area */
730     str = XmTextGetString(Text4);
731 
732     /* add the file name and output redirection to the print command */
733     sprintf(command, "cat %s | %s 2>&1", PrintFileName, str);
734     NEditFree(str);
735 
736     /* Issue the print command using a popen call and recover error messages
737        from the output stream of the command. */
738     pipe = popen(command,"r");
739     if (pipe == NULL)
740     {
741         DialogF(DF_WARN, widget, 1, "Print Error", "Unable to Print:\n%s",
742                 "OK", strerror(errno));
743         return;
744     }
745 
746     errorString[0] = 0;
747     nRead = fread(errorString, sizeof(char), MAX_PRINT_ERROR_LENGTH-1, pipe);
748     /* Make sure that the print command doesn't get stuck when trying to
749        write a lot of output on stderr (pipe may fill up). We discard
750        the additional output, though. */
751     while (fread(discarded, sizeof(char), 1024, pipe) > 0);
752 
753     if (!ferror(pipe))
754     {
755         errorString[nRead] = '\0';
756     }
757 
758     if (pclose(pipe))
759     {
760         DialogF(DF_WARN, widget, 1, "Print Error", "Unable to Print:\n%s",
761                 "OK", errorString);
762         return;
763     }
764 #endif /*(VMS)*/
765 
766     /* Print command succeeded, so retain the current print parameters */
767     if (CopiesOption[0] != '\0') {
768     	str = XmTextGetString(Text1);
769     	strcpy(Copies, str);
770     	NEditFree(str);
771     }
772     if (QueueOption[0] != '\0') {
773     	str = XmTextGetString(Text2);
774     	strcpy(Queue, str);
775     	NEditFree(str);
776     }
777     if (HostOption[0] != '\0') {
778     	str = XmTextGetString(Text3);
779     	strcpy(Host, str);
780     	NEditFree(str);
781     }
782     str = XmTextGetString(Text4);
783     strcpy(CmdText, str);
784     NEditFree(str);
785 
786 
787     /* Pop down the dialog */
788     DoneWithDialog = True;
789 }
790 
cancelButtonCB(Widget widget,caddr_t client_data,caddr_t call_data)791 static void cancelButtonCB(Widget widget, caddr_t client_data, caddr_t call_data)
792 {
793     DoneWithDialog = True;
794     CmdFieldModified = False;
795 }
796 
797 #ifndef VMS
798 /*
799 ** Is the filename file in the directory dirpath
800 ** and does it have at least some of the mode_flags enabled ?
801 */
fileInDir(const char * filename,const char * dirpath,unsigned short mode_flags)802 static int fileInDir(const char *filename, const char *dirpath, unsigned short mode_flags)
803 {
804     DIR           *dfile;
805 #ifdef USE_DIRENT
806     struct dirent *DirEntryPtr;
807 #else
808     struct direct *DirEntryPtr;
809 #endif
810     struct stat   statbuf;
811     char          fullname[MAXPATHLEN];
812 
813     dfile = opendir(dirpath);
814     if (dfile != NULL) {
815 	while ((DirEntryPtr=readdir(dfile)) != NULL) {
816             if (!strcmp(DirEntryPtr->d_name, filename)) {
817         	strcpy(fullname,dirpath);
818         	strcat(fullname,"/");
819 		strcat(fullname,filename);
820         	stat(fullname,&statbuf);
821         	closedir(dfile);
822         	return statbuf.st_mode & mode_flags;
823             }
824         }
825     	closedir(dfile);
826     }
827     return False;
828 }
829 
830 /*
831 ** Is the filename file in the environment path directories
832 ** and does it have at least some of the mode_flags enabled ?
833 */
fileInPath(const char * filename,unsigned short mode_flags)834 static int fileInPath(const char *filename, unsigned short mode_flags)
835 {
836     char path[MAXPATHLEN];
837     char *pathstring,*lastchar;
838 
839     /* Get environmental value of PATH */
840     pathstring = getenv("PATH");
841     if (pathstring == NULL)
842     	return False;
843 
844     /* parse the pathstring and search on each directory found */
845     do {
846 	/* if final path in list is empty, don't search it */
847 	if (!strcmp(pathstring, ""))
848             return False;
849 	/* locate address of next : character */
850 	lastchar = strchr(pathstring, SEPARATOR);
851 	if (lastchar != NULL) {
852             /* if more directories remain in pathstring, copy up to : */
853             strncpy(path, pathstring, lastchar-pathstring);
854             path[lastchar-pathstring] = '\0';
855 	} else {
856 	    /* if it's the last directory, just copy it */
857             strcpy(path, pathstring);
858 	}
859 	/* search for the file in this path */
860 	if(fileInDir(filename, path, mode_flags))
861             return True; /* found it !! */
862 	/* point pathstring to start of new dir string */
863 	pathstring = lastchar + 1;
864     } while( lastchar != NULL );
865     return False;
866 }
867 
868 /*
869 ** Is flpr present in the search path and is it executable ?
870 */
flprPresent(void)871 static int flprPresent(void)
872 {
873     /* Is flpr present in the search path and is it executable ? */
874     return fileInPath("flpr",0111);
875 }
876 
foundTag(const char * tagfilename,const char * tagname,char * result)877 static int foundTag(const char *tagfilename, const char *tagname, char *result)
878 {
879     FILE *tfile;
880     char tagformat[512],line[512];
881 
882     strcpy(tagformat, tagname);
883     strcat(tagformat, " %s");
884 
885     tfile = fopen(tagfilename,"r");
886     if (tfile != NULL) {
887 	while (!feof(tfile)) {
888             fgets(line,sizeof(line),tfile);
889             if (sscanf(line,tagformat,result) != 0) {
890 		fclose(tfile);
891         	return True;
892 	    }
893 	}
894 	fclose(tfile);
895     }
896     return False;
897 }
898 
foundEnv(const char * EnvVarName,char * result)899 static int foundEnv(const char *EnvVarName, char *result)
900 {
901     char *dqstr;
902 
903     dqstr = getenv(EnvVarName);
904     if (dqstr != NULL) {
905         strcpy(result,dqstr);
906         return True;
907     }
908     return False;
909 }
910 
getFlprHostDefault(char * defhost)911 static void getFlprHostDefault(char *defhost)
912 {
913     if (!foundEnv("FLPHOST",defhost))
914         if(!foundTag("/usr/local/etc/flp.defaults", "host", defhost))
915             strcpy(defhost,"");
916 }
917 
getFlprQueueDefault(char * defqueue)918 static void getFlprQueueDefault(char *defqueue)
919 {
920     if (!foundEnv("FLPQUE",defqueue))
921 	if (!foundTag("/usr/local/etc/flp.defaults", "queue", defqueue))
922             strcpy(defqueue,"");
923 }
924 
925 #ifdef USE_LPR_PRINT_CMD
getLprQueueDefault(char * defqueue)926 static void getLprQueueDefault(char *defqueue)
927 {
928     if (!foundEnv("PRINTER",defqueue))
929         strcpy(defqueue,"");
930 }
931 #endif
932 
933 #ifndef USE_LPR_PRINT_CMD
getLpQueueDefault(char * defqueue)934 static void getLpQueueDefault(char *defqueue)
935 {
936     if (!foundEnv("LPDEST",defqueue))
937         defqueue[0] = '\0';
938 }
939 #endif
940 #endif
941 
942 #ifdef VMS
getVmsQueueDefault(char * defqueue)943 static void getVmsQueueDefault(char *defqueue)
944 {
945     int translate_sts;
946     short ret_len;
947     char logicl[12], tabl[15];
948     struct itemList {
949         short bufL;
950         short itemCode;
951         char *queName;
952         short *lngth;
953         int end_entry;
954     } translStruct;
955     struct dsc$descriptor tabName;
956     struct dsc$descriptor logName;
957 
958     sprintf(tabl, "LNM$FILE_DEV");
959 
960     tabName.dsc$w_length  = strlen(tabl);
961     tabName.dsc$b_dtype   = DSC$K_DTYPE_T;
962     tabName.dsc$b_class   = DSC$K_CLASS_S;
963     tabName.dsc$a_pointer = tabl;
964 
965     sprintf(logicl, "SYS$PRINT");
966 
967     logName.dsc$w_length  = strlen(logicl);
968     logName.dsc$b_dtype   = DSC$K_DTYPE_T;
969     logName.dsc$b_class   = DSC$K_CLASS_S;
970     logName.dsc$a_pointer = logicl;
971 
972     translStruct.itemCode = LNM$_STRING;
973     translStruct.lngth = &ret_len;
974     translStruct.bufL = 99;
975     translStruct.end_entry = 0;
976     translStruct.queName = defqueue;
977     translate_sts = sys$trnlnm(0,&tabName,&logName,0,&translStruct);
978 
979     if (translate_sts != SS$_NORMAL && translate_sts != SS$_NOLOGNAM){
980        fprintf(stderr, "Error return from sys$trnlnm: %d\n", translate_sts);
981        DialogF(DF_WARN, Label2, 1, "Error", "Error translating SYS$PRINT",
982                "OK");
983        defqueue[0] = '\0';
984     } else
985     {
986 /*    printf("return status from sys$trnlnm = %d\n", translate_sts); */
987         if (translate_sts == SS$_NOLOGNAM)
988         {
989             defqueue[0] = '\0';
990         } else
991         {
992             strncpy(defqueue, translStruct.queName, ret_len);
993             defqueue[ret_len] = '\0';
994 /*  printf("defqueue = %s, length = %d\n", defqueue, ret_len); */
995         }
996     }
997 }
998 #endif /*(VMS)*/
999