got rid of a lot of redundent header files as we now globally generate
[samba.git] / source3 / printing / printing.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    printing routines
5    Copyright (C) Andrew Tridgell 1992-1995
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 extern int DEBUGLEVEL;
24 extern connection_struct Connections[];
25 extern files_struct Files[];
26
27 static BOOL * lpq_cache_reset=NULL;
28
29 static int check_lpq_cache(int snum) {
30   static int lpq_caches=0;
31   
32   if (lpq_caches <= snum) {
33       BOOL * p;
34       p = (BOOL *) Realloc(lpq_cache_reset,(snum+1)*sizeof(BOOL));
35       if (p) {
36          lpq_cache_reset=p;
37          lpq_caches = snum+1;
38       }
39   }
40   return lpq_caches;
41 }
42
43 void lpq_reset(int snum)
44 {
45   if (check_lpq_cache(snum) > snum) lpq_cache_reset[snum]=True;
46 }
47
48
49 /****************************************************************************
50 Build the print command in the supplied buffer. This means getting the
51 print command for the service and inserting the printer name and the
52 print file name. Return NULL on error, else the passed buffer pointer.
53 ****************************************************************************/
54 static char *build_print_command(int cnum, char *command, char *syscmd, char *filename1)
55 {
56   int snum = SNUM(cnum);
57   char *tstr;
58   pstring filename;
59   
60   /* get the print command for the service. */
61   tstr = command;
62   if (!syscmd || !tstr) {
63     DEBUG(0,("No print command for service `%s'\n", SERVICE(snum)));
64     return (NULL);
65   }
66
67   /* copy the command into the buffer for extensive meddling. */
68   StrnCpy(syscmd, tstr, sizeof(pstring) - 1);
69   
70   /* look for "%s" in the string. If there is no %s, we cannot print. */   
71   if (!strstr(syscmd, "%s") && !strstr(syscmd, "%f")) {
72     DEBUG(2,("WARNING! No placeholder for the filename in the print command for service %s!\n", SERVICE(snum)));
73   }
74   
75   if (strstr(syscmd,"%s")) {
76     int iOffset = strstr(syscmd, "%s") - syscmd;
77     
78     /* construct the full path for the filename, shouldn't be necessary unless
79        the subshell causes a "cd" to be executed.
80        Only use the full path if there isn't a / preceding the %s */
81     if (iOffset==0 || syscmd[iOffset-1] != '/') {
82       StrnCpy(filename,Connections[cnum].connectpath,sizeof(filename)-1);
83       trim_string(filename,"","/");
84       strcat(filename,"/");
85       strcat(filename,filename1);
86     }
87     else
88       strcpy(filename,filename1);
89     
90     string_sub(syscmd, "%s", filename);
91   }
92   
93   string_sub(syscmd, "%f", filename1);
94   
95   /* Does the service have a printername? If not, make a fake and empty    */
96   /* printer name. That way a %p is treated sanely if no printer */
97   /* name was specified to replace it. This eventuality is logged.         */
98   tstr = PRINTERNAME(snum);
99   if (tstr == NULL || tstr[0] == '\0') {
100     DEBUG(3,( "No printer name - using %s.\n", SERVICE(snum)));
101     tstr = SERVICE(snum);
102   }
103   
104   string_sub(syscmd, "%p", tstr);
105   
106   standard_sub(cnum,syscmd);
107   
108   return (syscmd);
109 }
110
111
112 /****************************************************************************
113 print a file - called on closing the file
114 ****************************************************************************/
115 void print_file(int fnum)
116 {
117   pstring syscmd;
118   int cnum = Files[fnum].cnum;
119   int snum=SNUM(cnum);
120   char *tempstr;
121
122   *syscmd = 0;
123
124   if (file_size(Files[fnum].name) <= 0) {
125     DEBUG(3,("Discarding null print job %s\n",Files[fnum].name));
126     sys_unlink(Files[fnum].name);
127     return;
128   }
129
130   tempstr = build_print_command(cnum, PRINTCOMMAND(snum), syscmd, Files[fnum].name);
131   if (tempstr != NULL)
132     {
133       int ret = smbrun(syscmd,NULL);
134       DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
135     }
136   else
137     DEBUG(0,("Null print command?\n"));
138   
139   lpq_reset(snum);
140 }
141
142 static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
143                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
144
145
146 /*******************************************************************
147 process time fields
148 ********************************************************************/
149 static time_t EntryTime(string tok[], int ptr, int count, int minimum)
150 {
151   time_t jobtime,jobtime1;
152
153   jobtime = time(NULL);         /* default case: take current time */
154   if (count >= minimum) {
155     struct tm *t;
156     int i, day, hour, min, sec;
157     char   *c;
158
159     for (i=0; i<13; i++) if (!strncmp(tok[ptr], Months[i],3)) break; /* Find month */
160     if (i<12) {
161       t = localtime(&jobtime);
162       day = atoi(tok[ptr+1]);
163       c=(char *)(tok[ptr+2]);
164       *(c+2)=0;
165       hour = atoi(c);
166       *(c+5)=0;
167       min = atoi(c+3);
168       if(*(c+6) != 0)sec = atoi(c+6);
169       else  sec=0;
170
171       if ((t->tm_mon < i)||
172           ((t->tm_mon == i)&&
173            ((t->tm_mday < day)||
174             ((t->tm_mday == day)&&
175              (t->tm_hour*60+t->tm_min < hour*60+min)))))
176         t->tm_year--;           /* last year's print job */
177
178       t->tm_mon = i;
179       t->tm_mday = day;
180       t->tm_hour = hour;
181       t->tm_min = min;
182       t->tm_sec = sec;
183       jobtime1 = mktime(t);
184       if (jobtime1 != (time_t)-1)
185         jobtime = jobtime1;
186     }
187   }
188   return jobtime;
189 }
190
191
192 /****************************************************************************
193 parse a lpq line
194
195 here is an example of lpq output under bsd
196
197 Warning: no daemon present
198 Rank   Owner      Job  Files                                 Total Size
199 1st    tridge     148  README                                8096 bytes
200
201 here is an example of lpq output under osf/1
202
203 Warning: no daemon present
204 Rank   Pri Owner      Job  Files                             Total Size
205 1st    0   tridge     148  README                            8096 bytes
206 ****************************************************************************/
207 static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
208 {
209 #ifdef  OSF1
210 #define RANKTOK 0
211 #define PRIOTOK 1
212 #define USERTOK 2
213 #define JOBTOK  3
214 #define FILETOK 4
215 #define TOTALTOK 5
216 #define NTOK    6
217 #else   /* OSF1 */
218 #define RANKTOK 0
219 #define USERTOK 1
220 #define JOBTOK  2
221 #define FILETOK 3
222 #define TOTALTOK 4
223 #define NTOK    5
224 #endif  /* OSF1 */
225
226   string tok[NTOK];
227   int count=0;
228
229 #ifdef  OSF1
230   int length;
231   length = strlen(line);
232   if (line[length-3] == ':')
233         return(False);
234 #endif  /* OSF1 */
235
236   /* handle the case of "(standard input)" as a filename */
237   string_sub(line,"standard input","STDIN");
238   string_sub(line,"(","\"");
239   string_sub(line,")","\"");
240   
241   for (count=0; count<NTOK && next_token(&line,tok[count],NULL); count++) ;
242
243   /* we must get NTOK tokens */
244   if (count < NTOK)
245     return(False);
246
247   /* the Job and Total columns must be integer */
248   if (!isdigit(*tok[JOBTOK]) || !isdigit(*tok[TOTALTOK])) return(False);
249
250   /* if the fname contains a space then use STDIN */
251   if (strchr(tok[FILETOK],' '))
252     strcpy(tok[FILETOK],"STDIN");
253
254   /* only take the last part of the filename */
255   {
256     string tmp;
257     char *p = strrchr(tok[FILETOK],'/');
258     if (p)
259       {
260         strcpy(tmp,p+1);
261         strcpy(tok[FILETOK],tmp);
262       }
263   }
264         
265
266   buf->job = atoi(tok[JOBTOK]);
267   buf->size = atoi(tok[TOTALTOK]);
268   buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
269   buf->time = time(NULL);
270   StrnCpy(buf->user,tok[USERTOK],sizeof(buf->user)-1);
271   StrnCpy(buf->file,tok[FILETOK],sizeof(buf->file)-1);
272 #ifdef PRIOTOK
273   buf->priority = atoi(tok[PRIOTOK]);
274 #else
275   buf->priority = 1;
276 #endif
277   return(True);
278 }
279
280
281
282 /*******************************************************************
283 parse lpq on an aix system
284
285 Queue   Dev   Status    Job Files              User         PP %   Blks  Cp Rnk
286 ------- ----- --------- --- ------------------ ---------- ---- -- ----- --- ---
287 lazer   lazer READY
288 lazer   lazer RUNNING   537 6297doc.A          kvintus@IE    0 10  2445   1   1
289               QUEUED    538 C.ps               root@IEDVB           124   1   2
290               QUEUED    539 E.ps               root@IEDVB            28   1   3
291               QUEUED    540 L.ps               root@IEDVB           172   1   4
292               QUEUED    541 P.ps               root@IEDVB            22   1   5
293 ********************************************************************/
294 static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
295 {
296   string tok[11];
297   int count=0;
298
299   /* handle the case of "(standard input)" as a filename */
300   string_sub(line,"standard input","STDIN");
301   string_sub(line,"(","\"");
302   string_sub(line,")","\"");
303
304   for (count=0; count<10 && next_token(&line,tok[count],NULL); count++) ;
305
306   /* we must get 6 tokens */
307   if (count < 10)
308   {
309       if ((count == 7) && (strcmp(tok[0],"QUEUED") == 0))
310       {
311           /* the 2nd and 5th columns must be integer */
312           if (!isdigit(*tok[1]) || !isdigit(*tok[4])) return(False);
313           buf->size = atoi(tok[4]) * 1024;
314           /* if the fname contains a space then use STDIN */
315           if (strchr(tok[2],' '))
316             strcpy(tok[2],"STDIN");
317
318           /* only take the last part of the filename */
319           {
320             string tmp;
321             char *p = strrchr(tok[2],'/');
322             if (p)
323               {
324                 strcpy(tmp,p+1);
325                 strcpy(tok[2],tmp);
326               }
327           }
328
329
330           buf->job = atoi(tok[1]);
331           buf->status = LPQ_QUEUED;
332           buf->priority = 0;
333           buf->time = time(NULL);
334           StrnCpy(buf->user,tok[3],sizeof(buf->user)-1);
335           StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
336       }
337       else
338       {
339           DEBUG(6,("parse_lpq_aix count=%d\n", count));
340           return(False);
341       }
342   }
343   else
344   {
345       /* the 4th and 9th columns must be integer */
346       if (!isdigit(*tok[3]) || !isdigit(*tok[8])) return(False);
347       buf->size = atoi(tok[8]) * 1024;
348       /* if the fname contains a space then use STDIN */
349       if (strchr(tok[4],' '))
350         strcpy(tok[4],"STDIN");
351
352       /* only take the last part of the filename */
353       {
354         string tmp;
355         char *p = strrchr(tok[4],'/');
356         if (p)
357           {
358             strcpy(tmp,p+1);
359             strcpy(tok[4],tmp);
360           }
361       }
362
363
364       buf->job = atoi(tok[3]);
365       buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED;
366       buf->priority = 0;
367       buf->time = time(NULL);
368       StrnCpy(buf->user,tok[5],sizeof(buf->user)-1);
369       StrnCpy(buf->file,tok[4],sizeof(buf->file)-1);
370   }
371
372
373   return(True);
374 }
375
376
377 /****************************************************************************
378 parse a lpq line
379 here is an example of lpq output under hpux; note there's no space after -o !
380 $> lpstat -oljplus
381 ljplus-2153         user           priority 0  Jan 19 08:14 on ljplus
382       util.c                                  125697 bytes
383       server.c                                110712 bytes
384 ljplus-2154         user           priority 0  Jan 19 08:14 from client
385       (standard input)                          7551 bytes
386 ****************************************************************************/
387 static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
388 {
389   /* must read two lines to process, therefore keep some values static */
390   static BOOL header_line_ok=False, base_prio_reset=False;
391   static string jobuser;
392   static int jobid;
393   static int jobprio;
394   static time_t jobtime;
395   static int jobstat=LPQ_QUEUED;
396   /* to store minimum priority to print, lpstat command should be invoked
397      with -p option first, to work */
398   static int base_prio;
399  
400   int count;
401   char TAB = '\011';  
402   string tok[12];
403
404   /* If a line begins with a horizontal TAB, it is a subline type */
405   
406   if (line[0] == TAB) { /* subline */
407     /* check if it contains the base priority */
408     if (!strncmp(line,"\tfence priority : ",18)) {
409        base_prio=atoi(&line[18]);
410        DEBUG(4, ("fence priority set at %d\n", base_prio));
411     }
412     if (!header_line_ok) return (False); /* incorrect header line */
413     /* handle the case of "(standard input)" as a filename */
414     string_sub(line,"standard input","STDIN");
415     string_sub(line,"(","\"");
416     string_sub(line,")","\"");
417     
418     for (count=0; count<2 && next_token(&line,tok[count],NULL); count++) ;
419     /* we must get 2 tokens */
420     if (count < 2) return(False);
421     
422     /* the 2nd column must be integer */
423     if (!isdigit(*tok[1])) return(False);
424     
425     /* if the fname contains a space then use STDIN */
426     if (strchr(tok[0],' '))
427       strcpy(tok[0],"STDIN");
428     
429     buf->size = atoi(tok[1]);
430     StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
431     
432     /* fill things from header line */
433     buf->time = jobtime;
434     buf->job = jobid;
435     buf->status = jobstat;
436     buf->priority = jobprio;
437     StrnCpy(buf->user,jobuser,sizeof(buf->user)-1);
438     
439     return(True);
440   }
441   else { /* header line */
442     header_line_ok=False; /* reset it */
443     if (first) {
444        if (!base_prio_reset) {
445           base_prio=0; /* reset it */
446           base_prio_reset=True;
447        }
448     }
449     else if (base_prio) base_prio_reset=False;
450     
451     /* handle the dash in the job id */
452     string_sub(line,"-"," ");
453     
454     for (count=0; count<12 && next_token(&line,tok[count],NULL); count++) ;
455       
456     /* we must get 8 tokens */
457     if (count < 8) return(False);
458     
459     /* first token must be printer name (cannot check ?) */
460     /* the 2nd, 5th & 7th column must be integer */
461     if (!isdigit(*tok[1]) || !isdigit(*tok[4]) || !isdigit(*tok[6])) return(False);
462     jobid = atoi(tok[1]);
463     StrnCpy(jobuser,tok[2],sizeof(buf->user)-1);
464     jobprio = atoi(tok[4]);
465     
466     /* process time */
467     jobtime=EntryTime(tok, 5, count, 8);
468     if (jobprio < base_prio) {
469        jobstat = LPQ_PAUSED;
470        DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n", jobid, jobprio, base_prio, jobstat));
471     }
472     else {
473        jobstat = LPQ_QUEUED;
474        if ((count >8) && (((strequal(tok[8],"on")) ||
475                            ((strequal(tok[8],"from")) && 
476                             ((count > 10)&&(strequal(tok[10],"on")))))))
477          jobstat = LPQ_PRINTING;
478     }
479     
480     header_line_ok=True; /* information is correct */
481     return(False); /* need subline info to include into queuelist */
482   }
483 }
484
485
486 /****************************************************************************
487 parse a lpq line
488
489 here is an example of "lpstat -o dcslw" output under sysv
490
491 dcslw-896               tridge            4712   Dec 20 10:30:30 on dcslw
492 dcslw-897               tridge            4712   Dec 20 10:30:30 being held
493
494 ****************************************************************************/
495 static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
496 {
497   string tok[9];
498   int count=0;
499   char *p;
500
501   /* handle the dash in the job id */
502   string_sub(line,"-"," ");
503   
504   for (count=0; count<9 && next_token(&line,tok[count],NULL); count++) ;
505
506   /* we must get 7 tokens */
507   if (count < 7)
508     return(False);
509
510   /* the 2nd and 4th, 6th columns must be integer */
511   if (!isdigit(*tok[1]) || !isdigit(*tok[3])) return(False);
512   if (!isdigit(*tok[5])) return(False);
513
514   /* if the user contains a ! then trim the first part of it */  
515   if ((p=strchr(tok[2],'!')))
516     {
517       string tmp;
518       strcpy(tmp,p+1);
519       strcpy(tok[2],tmp);
520     }
521     
522
523   buf->job = atoi(tok[1]);
524   buf->size = atoi(tok[3]);
525   if (count > 7 && strequal(tok[7],"on"))
526     buf->status = LPQ_PRINTING;
527   else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held"))
528     buf->status = LPQ_PAUSED;
529   else
530     buf->status = LPQ_QUEUED;
531   buf->priority = 0;
532   buf->time = EntryTime(tok, 4, count, 7);
533   StrnCpy(buf->user,tok[2],sizeof(buf->user)-1);
534   StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
535   return(True);
536 }
537
538 /****************************************************************************
539 parse a lpq line
540
541 here is an example of lpq output under qnx
542 Spooler: /qnx/spooler, on node 1
543 Printer: txt        (ready) 
544 0000:     root  [job #1    ]   active 1146 bytes        /etc/profile
545 0001:     root  [job #2    ]    ready 2378 bytes        /etc/install
546 0002:     root  [job #3    ]    ready 1146 bytes        -- standard input --
547 ****************************************************************************/
548 static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
549 {
550   string tok[7];
551   int count=0;
552
553   DEBUG(0,("antes [%s]\n", line));
554
555   /* handle the case of "-- standard input --" as a filename */
556   string_sub(line,"standard input","STDIN");
557   DEBUG(0,("despues [%s]\n", line));
558   string_sub(line,"-- ","\"");
559   string_sub(line," --","\"");
560   DEBUG(0,("despues 1 [%s]\n", line));
561
562   string_sub(line,"[job #","");
563   string_sub(line,"]","");
564   DEBUG(0,("despues 2 [%s]\n", line));
565
566   
567   
568   for (count=0; count<7 && next_token(&line,tok[count],NULL); count++) ;
569
570   /* we must get 7 tokens */
571   if (count < 7)
572     return(False);
573
574   /* the 3rd and 5th columns must be integer */
575   if (!isdigit(*tok[2]) || !isdigit(*tok[4])) return(False);
576
577   /* only take the last part of the filename */
578   {
579     string tmp;
580     char *p = strrchr(tok[6],'/');
581     if (p)
582       {
583         strcpy(tmp,p+1);
584         strcpy(tok[6],tmp);
585       }
586   }
587         
588
589   buf->job = atoi(tok[2]);
590   buf->size = atoi(tok[4]);
591   buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED;
592   buf->priority = 0;
593   buf->time = time(NULL);
594   StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
595   StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
596   return(True);
597 }
598
599
600 /****************************************************************************
601   parse a lpq line for the plp printing system
602   Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
603 ****************************************************************************/
604 static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
605 {
606   string tok[5];
607   int count=0;
608
609   /* handle the case of "(standard input)" as a filename */
610   string_sub(line,"stdin","STDIN");
611   string_sub(line,"(","\"");
612   string_sub(line,")","\"");
613   
614   for (count=0; count<8 && next_token(&line,tok[count],NULL); count++) ;
615
616   /* we must get 5 tokens */
617   if (count < 8)
618     return(False);
619
620   /* the 4rd must be integer */
621   if (!isdigit(*tok[3])) return(False);
622
623   /* if the fname contains a space then use STDIN */
624   if (strchr(tok[3],' '))
625     strcpy(tok[3],"STDIN");
626
627   /* only take the last part of the filename */
628   {
629     string tmp;
630     char *p = strrchr(tok[5],'/');
631     if (p)
632       {
633         strcpy(tmp,p+1);
634         strcpy(tok[5],tmp);
635       }
636   }
637
638
639   buf->job = atoi(tok[3]);
640
641   /* calcul de la taille du fichier */
642   if (!isdigit(*tok[7])) {  buf->size = atoi(tok[7]) * 1.0 ; }
643   else {
644     string tmp;
645     strcpy(tmp,tok[7]);
646     if (strchr(tok[7],'K')) {
647       strncpy(tok[7],tmp,strlen(tmp)-1);
648       buf->size = atoi(tok[7]);
649       buf->size = buf->size * 1024;
650     }
651     if (strchr(tok[7],'M')) {
652       strncpy(tok[7],tmp,strlen(tmp)-1);
653       buf->size = atoi(tok[7]);
654       buf->size = buf->size * 1024.0 * 1000.0;
655     }
656     if (strchr(tok[7],'G')) {
657       strncpy(tok[7],tmp,strlen(tmp)-1);
658       buf->size = atoi(tok[7]);
659       buf->size = buf->size * 1024.0 * 1000000.0;
660     }
661
662   }
663   buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
664   buf->priority = 0;
665   buf->time = time(NULL);
666   StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
667   StrnCpy(buf->file,tok[5],sizeof(buf->file)-1);
668   return(True);
669 }
670
671
672
673 char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
674 char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
675 char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
676
677 /****************************************************************************
678 parse a lpq line. Choose printing style
679 ****************************************************************************/
680 static BOOL parse_lpq_entry(int snum,char *line,
681                             print_queue_struct *buf,
682                             print_status_struct *status,BOOL first)
683 {
684   BOOL ret;
685
686   switch (lp_printing())
687     {
688     case PRINT_SYSV:
689       ret = parse_lpq_sysv(line,buf,first);
690       break;
691     case PRINT_AIX:      
692       ret = parse_lpq_aix(line,buf,first);
693       break;
694     case PRINT_HPUX:
695       ret = parse_lpq_hpux(line,buf,first);
696       break;
697     case PRINT_QNX:
698       ret = parse_lpq_qnx(line,buf,first);
699       break;
700     case PRINT_PLP:
701       ret = parse_lpq_plp(line,buf,first);
702       break;
703     default:
704       ret = parse_lpq_bsd(line,buf,first);
705       break;
706     }
707
708 #ifdef LPQ_GUEST_TO_USER
709   if (ret) {
710     extern pstring sesssetup_user;
711     /* change guest entries to the current logged in user to make
712        them appear deletable to windows */
713     if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
714       strcpy(buf->user,sesssetup_user);
715   }
716 #endif
717
718   if (status && !ret)
719     {
720       /* a few simple checks to see if the line might be a
721          printer status line: 
722          handle them so that most severe condition is shown */
723       int i;
724       strlower(line);
725       
726       switch (status->status) {
727       case LPSTAT_OK:
728         for (i=0; stat0_strings[i]; i++)
729           if (strstr(line,stat0_strings[i])) {
730             StrnCpy(status->message,line,sizeof(status->message)-1);
731             status->status=LPSTAT_OK;
732           }
733       case LPSTAT_STOPPED:
734         for (i=0; stat1_strings[i]; i++)
735           if (strstr(line,stat1_strings[i])) {
736             StrnCpy(status->message,line,sizeof(status->message)-1);
737             status->status=LPSTAT_STOPPED;
738           }
739       case LPSTAT_ERROR:
740         for (i=0; stat2_strings[i]; i++)
741           if (strstr(line,stat2_strings[i])) {
742             StrnCpy(status->message,line,sizeof(status->message)-1);
743             status->status=LPSTAT_ERROR;
744           }
745         break;
746       }
747     }
748
749   return(ret);
750 }
751
752 /****************************************************************************
753 get a printer queue
754 ****************************************************************************/
755 int get_printqueue(int snum,int cnum,print_queue_struct **queue,
756                    print_status_struct *status)
757 {
758   char *lpq_command = lp_lpqcommand(snum);
759   char *printername = PRINTERNAME(snum);
760   int ret=0,count=0;
761   pstring syscmd;
762   fstring outfile;
763   pstring line;
764   FILE *f;
765   struct stat sbuf;
766   BOOL dorun=True;
767   int cachetime = lp_lpqcachetime();
768   int lfd = -1;
769
770   *line = 0;
771   check_lpq_cache(snum);
772   
773   if (!printername || !*printername)
774     {
775       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
776             lp_servicename(snum),snum));
777       printername = lp_servicename(snum);
778     }
779     
780   if (!lpq_command || !(*lpq_command))
781     {
782       DEBUG(5,("No lpq command\n"));
783       return(0);
784     }
785     
786   strcpy(syscmd,lpq_command);
787   string_sub(syscmd,"%p",printername);
788
789   standard_sub(cnum,syscmd);
790
791   sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
792   
793   if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf)) 
794     {
795       if (time(NULL) - sbuf.st_mtime < cachetime) {
796         DEBUG(3,("Using cached lpq output\n"));
797         dorun = False;
798       }
799
800       if (dorun) {
801         lfd = file_lock(outfile,LPQ_LOCK_TIMEOUT);
802         if (lfd<0 || 
803             (!fstat(lfd,&sbuf) && (time(NULL) - sbuf.st_mtime)<cachetime)) {
804           DEBUG(3,("Using cached lpq output\n"));
805           dorun = False;
806           file_unlock(lfd); lfd = -1;
807         }
808       }
809     }
810
811   if (dorun) {
812     ret = smbrun(syscmd,outfile);
813     DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
814   }
815
816   lpq_cache_reset[snum] = False;
817
818   f = fopen(outfile,"r");
819   if (!f) {
820     if (lfd >= 0) file_unlock(lfd);
821     return(0);
822   }
823
824   if (status) {
825     strcpy(status->message,"");
826     status->status = LPSTAT_OK;
827   }
828       
829   while (fgets(line,sizeof(pstring),f))
830     {
831       DEBUG(6,("QUEUE2: %s\n",line));
832
833       *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
834       if (! *queue)
835         {
836           count = 0;
837           break;
838         }
839
840       bzero((char *)&(*queue)[count],sizeof(**queue));
841           
842       /* parse it */
843       if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
844         continue;
845           
846       count++;
847     }         
848
849   fclose(f);
850
851   if (lfd >= 0) file_unlock(lfd);
852
853   if (!cachetime) 
854     unlink(outfile);
855   else
856     chmod(outfile,0666);
857   return(count);
858 }
859
860
861 /****************************************************************************
862 delete a printer queue entry
863 ****************************************************************************/
864 void del_printqueue(int cnum,int snum,int jobid)
865 {
866   char *lprm_command = lp_lprmcommand(snum);
867   char *printername = PRINTERNAME(snum);
868   pstring syscmd;
869   char jobstr[20];
870   int ret;
871
872   if (!printername || !*printername)
873     {
874       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
875             lp_servicename(snum),snum));
876       printername = lp_servicename(snum);
877     }
878     
879   if (!lprm_command || !(*lprm_command))
880     {
881       DEBUG(5,("No lprm command\n"));
882       return;
883     }
884     
885   sprintf(jobstr,"%d",jobid);
886
887   strcpy(syscmd,lprm_command);
888   string_sub(syscmd,"%p",printername);
889   string_sub(syscmd,"%j",jobstr);
890   standard_sub(cnum,syscmd);
891
892   ret = smbrun(syscmd,NULL);
893   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
894   lpq_reset(snum); /* queue has changed */
895 }
896
897 /****************************************************************************
898 change status of a printer queue entry
899 ****************************************************************************/
900 void status_printjob(int cnum,int snum,int jobid,int status)
901 {
902   char *lpstatus_command = 
903     (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
904   char *printername = PRINTERNAME(snum);
905   pstring syscmd;
906   char jobstr[20];
907   int ret;
908
909   if (!printername || !*printername)
910     {
911       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
912             lp_servicename(snum),snum));
913       printername = lp_servicename(snum);
914     }
915     
916   if (!lpstatus_command || !(*lpstatus_command))
917     {
918       DEBUG(5,("No lpstatus command to %s job\n",
919                (status==LPQ_PAUSED?"pause":"resume")));
920       return;
921     }
922     
923   sprintf(jobstr,"%d",jobid);
924
925   strcpy(syscmd,lpstatus_command);
926   string_sub(syscmd,"%p",printername);
927   string_sub(syscmd,"%j",jobstr);
928   standard_sub(cnum,syscmd);
929
930   ret = smbrun(syscmd,NULL);
931   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
932   lpq_reset(snum); /* queue has changed */
933 }
934
935