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