Takes print spooler functions out of win16drv.
[wine] / misc / spooler.c
1 /*
2  * Print spooler and PQ functions
3  *
4  * Copyright 1996 John Harvey
5  *           1998 Huw Davies
6  *
7  */
8
9 #include <ctype.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include "callback.h"
16 #include "dc.h"
17 #include "debug.h"
18 #include "gdi.h"
19 #include "options.h"
20 #include "windows.h"
21 #include "xmalloc.h"
22
23 /**********************************************************************
24  *           QueryAbort   (GDI.155)
25  *
26  *  Calls the app's AbortProc function if avail.
27  *
28  * RETURNS
29  * TRUE if no AbortProc avail or AbortProc wants to continue printing.
30  * FALSE if AbortProc wants to abort printing.
31  */
32 BOOL16 WINAPI QueryAbort(HDC16 hdc, INT16 reserved)
33 {
34     DC *dc = DC_GetDCPtr( hdc );
35
36     if ((!dc) || (!dc->w.lpfnPrint))
37         return TRUE;
38     return Callbacks->CallDrvAbortProc(dc->w.lpfnPrint, hdc, 0);
39 }
40
41 /**********************************************************************
42  *           SetAbortProc   (GDI.381)
43  *
44  */
45 INT16 WINAPI SetAbortProc(HDC16 hdc, FARPROC16 abrtprc)
46 {
47     DC *dc = DC_GetDCPtr( hdc );
48
49     if (dc) {
50         dc->w.lpfnPrint = abrtprc;
51         return 1;
52     }
53     return -1;
54
55
56 /****************** misc. printer related functions */
57
58 /*
59  * The following function should implement a queing system
60  */
61 #ifndef HPQ 
62 #define HPQ WORD
63 #endif
64 struct hpq 
65 {
66     struct hpq  *next;
67     int          tag;
68     int          key;
69 };
70
71 static struct hpq *hpqueue;
72
73 /**********************************************************************
74  *           CreatePQ   (GDI.230)
75  *
76  */
77 HPQ WINAPI CreatePQ(int size) 
78 {
79 #if 0
80     HGLOBAL16 hpq = 0;
81     WORD tmp_size;
82     LPWORD pPQ;
83
84     tmp_size = size << 2;
85     if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8)))
86        return 0xffff;
87     pPQ = GlobalLock16(hpq);
88     *pPQ++ = 0;
89     *pPQ++ = tmp_size;
90     *pPQ++ = 0;
91     *pPQ++ = 0;
92     GlobalUnlock16(hpq);
93
94     return (HPQ)hpq;
95 #else
96     FIXME(print, "(%d): stub\n",size);
97     return 1;
98 #endif
99 }
100
101 /**********************************************************************
102  *           DeletePQ   (GDI.235)
103  *
104  */
105 int WINAPI DeletePQ(HPQ hPQ) 
106 {
107     return GlobalFree16((HGLOBAL16)hPQ);
108 }
109
110 /**********************************************************************
111  *           ExtractPQ   (GDI.232)
112  *
113  */
114 int WINAPI ExtractPQ(HPQ hPQ) 
115
116     struct hpq *queue, *prev, *current, *currentPrev;
117     int key = 0, tag = -1;
118     currentPrev = prev = NULL;
119     queue = current = hpqueue;
120     if (current)
121         key = current->key;
122     
123     while (current)
124     {
125         currentPrev = current;
126         current = current->next;
127         if (current)
128         {
129             if (current->key < key)
130             {
131                 queue = current;
132                 prev = currentPrev;
133             }
134         }
135     }
136     if (queue)
137     {
138         tag = queue->tag;
139         
140         if (prev)
141             prev->next = queue->next;
142         else
143             hpqueue = queue->next;
144         free(queue);
145     }
146     
147     TRACE(print, "%x got tag %d key %d\n", hPQ, tag, key); 
148
149     return tag;
150 }
151
152 /**********************************************************************
153  *           InsertPQ   (GDI.233)
154  *
155  */
156 int WINAPI InsertPQ(HPQ hPQ, int tag, int key) 
157 {
158     struct hpq *queueItem = xmalloc(sizeof(struct hpq));
159     queueItem->next = hpqueue;
160     hpqueue = queueItem;
161     queueItem->key = key;
162     queueItem->tag = tag;
163     
164     FIXME(print, "(%x %d %d): stub???\n", hPQ, tag, key);
165     return TRUE;
166 }
167
168 /**********************************************************************
169  *           MinPQ   (GDI.231)
170  *
171  */
172 int WINAPI MinPQ(HPQ hPQ) 
173 {
174     FIXME(print, "(%x): stub\n", hPQ); 
175     return 0;
176 }
177
178 /**********************************************************************
179  *           SizePQ   (GDI.234)
180  *
181  */
182 int WINAPI SizePQ(HPQ hPQ, int sizechange) 
183 {  
184     FIXME(print, "(%x %d): stub\n", hPQ, sizechange); 
185     return -1; 
186 }
187
188
189
190 /* 
191  * The following functions implement part of the spooling process to 
192  * print manager.  I would like to see wine have a version of print managers
193  * that used LPR/LPD.  For simplicity print jobs will be sent to a file for
194  * now.
195  */
196 typedef struct PRINTJOB
197 {
198     char        *pszOutput;
199     char        *pszTitle;
200     HDC16       hDC;
201     HANDLE16    hHandle;
202     int         nIndex;
203     int         fd;
204 } PRINTJOB, *PPRINTJOB;
205
206 #define MAX_PRINT_JOBS 1
207 #define SP_OK 1
208
209 PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS];
210
211
212 static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle)
213 {
214     return gPrintJobsTable[0];
215 }
216
217 /* TTD Need to do some DOS->UNIX file conversion here */
218 static int CreateSpoolFile(LPSTR pszOutput)
219 {
220     int fd=-1;
221     char psCmd[1024];
222     char *psCmdP = psCmd;
223
224     /* TTD convert the 'output device' into a spool file name */
225
226     if (pszOutput == NULL || *pszOutput == '\0')
227       return -1;
228
229     PROFILE_GetWineIniString( "spooler", pszOutput, "", psCmd, sizeof(psCmd) );
230     TRACE(print, "Got printerSpoolCommand '%s' for output device '%s'\n",
231           psCmd, pszOutput);
232     if (!*psCmd)
233         psCmdP = pszOutput;
234     else
235     {
236         while (*psCmdP && isspace(*psCmdP))
237         {
238             psCmdP++;
239         };
240         if (!*psCmdP)
241             return -1;
242     }
243     if (*psCmdP == '|')
244     {
245         int fds[2];
246         if (pipe(fds))
247             return -1;
248         if (fork() == 0)
249         {
250             psCmdP++;
251
252             TRACE(print, "In child need to exec %s\n",psCmdP);
253             close(0);
254             dup2(fds[0],0);
255             close (fds[1]);
256             system(psCmdP);
257             exit(0);
258             
259         }
260         close (fds[0]);
261         fd = fds[1];
262         TRACE(print,"Need to execute a cmnd and pipe the output to it\n");
263     }
264     else
265     {
266         TRACE(print, "Just assume its a file\n");
267
268         if ((fd = open(psCmdP, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0)
269         {
270             ERR(print, "Failed to create spool file %s, errno = %d\n", 
271                 psCmdP, errno);
272         }
273     }
274     return fd;
275 }
276
277 static int FreePrintJob(HANDLE16 hJob)
278 {
279     int nRet = SP_ERROR;
280     PPRINTJOB pPrintJob;
281
282     pPrintJob = FindPrintJobFromHandle(hJob);
283     if (pPrintJob != NULL)
284     {
285         gPrintJobsTable[pPrintJob->nIndex] = NULL;
286         free(pPrintJob->pszOutput);
287         free(pPrintJob->pszTitle);
288         if (pPrintJob->fd >= 0) close(pPrintJob->fd);
289         free(pPrintJob);
290         nRet = SP_OK;
291     }
292     return nRet;
293 }
294
295 /**********************************************************************
296  *           OpenJob   (GDI.240)
297  *
298  */
299 HANDLE16 WINAPI OpenJob(LPSTR lpOutput, LPSTR lpTitle, HDC16 hDC)
300 {
301     HANDLE16 hHandle = (HANDLE16)SP_ERROR;
302     PPRINTJOB pPrintJob;
303
304     TRACE(print, "'%s' '%s' %04x\n", lpOutput, lpTitle, hDC);
305
306     pPrintJob = gPrintJobsTable[0];
307     if (pPrintJob == NULL)
308     {
309         int fd;
310
311         /* Try an create a spool file */
312         fd = CreateSpoolFile(lpOutput);
313         if (fd >= 0)
314         {
315             hHandle = 1;
316
317             pPrintJob = xmalloc(sizeof(PRINTJOB));
318             memset(pPrintJob, 0, sizeof(PRINTJOB));
319
320             pPrintJob->pszOutput = strdup(lpOutput);
321             if(lpTitle)
322                 pPrintJob->pszTitle = strdup(lpTitle);
323             pPrintJob->hDC = hDC;
324             pPrintJob->fd = fd;
325             pPrintJob->nIndex = 0;
326             pPrintJob->hHandle = hHandle; 
327             gPrintJobsTable[pPrintJob->nIndex] = pPrintJob; 
328         }
329     }
330     TRACE(print, "return %04x\n", hHandle);
331     return hHandle;
332 }
333
334 /**********************************************************************
335  *           CloseJob   (GDI.243)
336  *
337  */
338 int WINAPI CloseJob(HANDLE16 hJob)
339 {
340     int nRet = SP_ERROR;
341     PPRINTJOB pPrintJob = NULL;
342
343     TRACE(print, "%04x\n", hJob);
344
345     pPrintJob = FindPrintJobFromHandle(hJob);
346     if (pPrintJob != NULL)
347     {
348         /* Close the spool file */
349         close(pPrintJob->fd);
350         FreePrintJob(hJob);
351         nRet  = 1;
352     }
353     return nRet;
354 }
355
356 /**********************************************************************
357  *           WriteSpool   (GDI.241)
358  *
359  */
360 int WINAPI WriteSpool(HANDLE16 hJob, LPSTR lpData, WORD cch)
361 {
362     int nRet = SP_ERROR;
363     PPRINTJOB pPrintJob = NULL;
364
365     TRACE(print, "%04x %08lx %04x\n", hJob, (DWORD)lpData, cch);
366
367     pPrintJob = FindPrintJobFromHandle(hJob);
368     if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch)
369     {
370         if (write(pPrintJob->fd, lpData, cch) != cch)
371           nRet = SP_OUTOFDISK;
372         else
373           nRet = cch;
374         if (pPrintJob->hDC == 0) {
375             TRACE(print, "hDC == 0 so no QueryAbort\n");
376         }
377         else if (!(QueryAbort(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 )))
378         {
379             CloseJob(hJob); /* printing aborted */
380             nRet = SP_APPABORT;
381         }
382     }
383     return nRet;
384 }
385
386 /**********************************************************************
387  *           WriteDialog   (GDI.242)
388  *
389  */
390 int WINAPI WriteDialog(HANDLE16 hJob, LPSTR lpMsg, WORD cchMsg)
391 {
392     int nRet = 0;
393
394     TRACE(print, "%04x %04x '%s'\n", hJob,  cchMsg, lpMsg);
395
396     nRet = MessageBox16(0, lpMsg, "Printing Error", MB_OKCANCEL);
397     return nRet;
398 }
399
400
401 /**********************************************************************
402  *           DeleteJob  (GDI.244)
403  *
404  */
405 int WINAPI DeleteJob(HANDLE16 hJob, WORD wNotUsed)
406 {
407     int nRet;
408
409     TRACE(print, "%04x\n", hJob);
410
411     nRet = FreePrintJob(hJob);
412     return nRet;
413 }
414
415 /* 
416  * The following two function would allow a page to be sent to the printer
417  * when it has been processed.  For simplicity they havn't been implemented.
418  * This means a whole job has to be processed before it is sent to the printer.
419  */
420
421 /**********************************************************************
422  *           StartSpoolPage   (GDI.246)
423  *
424  */
425 int WINAPI StartSpoolPage(HANDLE16 hJob)
426 {
427     FIXME(print, "StartSpoolPage GDI.246 unimplemented\n");
428     return 1;
429
430 }
431
432
433 /**********************************************************************
434  *           EndSpoolPage   (GDI.247)
435  *
436  */
437 int WINAPI EndSpoolPage(HANDLE16 hJob)
438 {
439     FIXME(print, "EndSpoolPage GDI.247 unimplemented\n");
440     return 1;
441 }
442
443
444 /**********************************************************************
445  *           GetSpoolJob   (GDI.245)
446  *
447  */
448 DWORD WINAPI GetSpoolJob(int nOption, LONG param)
449 {
450     DWORD retval = 0;
451     TRACE(print, "In GetSpoolJob param 0x%lx noption %d\n",param, nOption);
452     return retval;
453 }