- change date as a demo for john
[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 redone by tridge. Here is a sample queue:
605
606 Local  Printer 'lp2' (fjall):
607   Printing (started at Jun 15 13:33:58, attempt 1).
608     Rank Owner       Pr Opt  Job Host        Files           Size     Date
609   active tridge      X  -    6   fjall       /etc/hosts      739      Jun 15 13:33
610      3rd tridge      X  -    7   fjall       /etc/hosts      739      Jun 15 13:33
611
612 ****************************************************************************/
613 static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
614 {
615   string tok[11];
616   int count=0;
617
618   /* handle the case of "(standard input)" as a filename */
619   string_sub(line,"stdin","STDIN");
620   string_sub(line,"(","\"");
621   string_sub(line,")","\"");
622   
623   for (count=0; count<11 && next_token(&line,tok[count],NULL); count++) ;
624
625   /* we must get 11 tokens */
626   if (count < 11)
627     return(False);
628
629   /* the first must be "active" or begin with an integer */
630   if (strcmp(tok[0],"active") && !isdigit(tok[0][0]))
631     return(False);
632
633   /* the 5th and 8th must be integer */
634   if (!isdigit(*tok[4]) || !isdigit(*tok[7])) 
635     return(False);
636
637   /* if the fname contains a space then use STDIN */
638   if (strchr(tok[6],' '))
639     strcpy(tok[6],"STDIN");
640
641   /* only take the last part of the filename */
642   {
643     string tmp;
644     char *p = strrchr(tok[6],'/');
645     if (p)
646       {
647         strcpy(tmp,p+1);
648         strcpy(tok[6],tmp);
649       }
650   }
651
652
653   buf->job = atoi(tok[4]);
654
655   buf->size = atoi(tok[7]);
656   if (strchr(tok[7],'K'))
657     buf->size *= 1024;
658   if (strchr(tok[7],'M'))
659     buf->size *= 1024*1024;
660
661   buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
662   buf->priority = 0;
663   buf->time = time(NULL);
664   StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
665   StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
666   return(True);
667 }
668
669
670
671 char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
672 char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
673 char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
674
675 /****************************************************************************
676 parse a lpq line. Choose printing style
677 ****************************************************************************/
678 static BOOL parse_lpq_entry(int snum,char *line,
679                             print_queue_struct *buf,
680                             print_status_struct *status,BOOL first)
681 {
682   BOOL ret;
683
684   switch (lp_printing())
685     {
686     case PRINT_SYSV:
687       ret = parse_lpq_sysv(line,buf,first);
688       break;
689     case PRINT_AIX:      
690       ret = parse_lpq_aix(line,buf,first);
691       break;
692     case PRINT_HPUX:
693       ret = parse_lpq_hpux(line,buf,first);
694       break;
695     case PRINT_QNX:
696       ret = parse_lpq_qnx(line,buf,first);
697       break;
698     case PRINT_PLP:
699       ret = parse_lpq_plp(line,buf,first);
700       break;
701     default:
702       ret = parse_lpq_bsd(line,buf,first);
703       break;
704     }
705
706 #ifdef LPQ_GUEST_TO_USER
707   if (ret) {
708     extern pstring sesssetup_user;
709     /* change guest entries to the current logged in user to make
710        them appear deletable to windows */
711     if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
712       strcpy(buf->user,sesssetup_user);
713   }
714 #endif
715
716   if (status && !ret)
717     {
718       /* a few simple checks to see if the line might be a
719          printer status line: 
720          handle them so that most severe condition is shown */
721       int i;
722       strlower(line);
723       
724       switch (status->status) {
725       case LPSTAT_OK:
726         for (i=0; stat0_strings[i]; i++)
727           if (strstr(line,stat0_strings[i])) {
728             StrnCpy(status->message,line,sizeof(status->message)-1);
729             status->status=LPSTAT_OK;
730           }
731       case LPSTAT_STOPPED:
732         for (i=0; stat1_strings[i]; i++)
733           if (strstr(line,stat1_strings[i])) {
734             StrnCpy(status->message,line,sizeof(status->message)-1);
735             status->status=LPSTAT_STOPPED;
736           }
737       case LPSTAT_ERROR:
738         for (i=0; stat2_strings[i]; i++)
739           if (strstr(line,stat2_strings[i])) {
740             StrnCpy(status->message,line,sizeof(status->message)-1);
741             status->status=LPSTAT_ERROR;
742           }
743         break;
744       }
745     }
746
747   return(ret);
748 }
749
750 /****************************************************************************
751 get a printer queue
752 ****************************************************************************/
753 int get_printqueue(int snum,int cnum,print_queue_struct **queue,
754                    print_status_struct *status)
755 {
756   char *lpq_command = lp_lpqcommand(snum);
757   char *printername = PRINTERNAME(snum);
758   int ret=0,count=0;
759   pstring syscmd;
760   fstring outfile;
761   pstring line;
762   FILE *f;
763   struct stat sbuf;
764   BOOL dorun=True;
765   int cachetime = lp_lpqcachetime();
766   int lfd = -1;
767
768   *line = 0;
769   check_lpq_cache(snum);
770   
771   if (!printername || !*printername)
772     {
773       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
774             lp_servicename(snum),snum));
775       printername = lp_servicename(snum);
776     }
777     
778   if (!lpq_command || !(*lpq_command))
779     {
780       DEBUG(5,("No lpq command\n"));
781       return(0);
782     }
783     
784   strcpy(syscmd,lpq_command);
785   string_sub(syscmd,"%p",printername);
786
787   standard_sub(cnum,syscmd);
788
789   sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
790   
791   if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf)) 
792     {
793       if (time(NULL) - sbuf.st_mtime < cachetime) {
794         DEBUG(3,("Using cached lpq output\n"));
795         dorun = False;
796       }
797
798       if (dorun) {
799         lfd = file_lock(outfile,LPQ_LOCK_TIMEOUT);
800         if (lfd<0 || 
801             (!fstat(lfd,&sbuf) && (time(NULL) - sbuf.st_mtime)<cachetime)) {
802           DEBUG(3,("Using cached lpq output\n"));
803           dorun = False;
804           file_unlock(lfd); lfd = -1;
805         }
806       }
807     }
808
809   if (dorun) {
810     ret = smbrun(syscmd,outfile);
811     DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
812   }
813
814   lpq_cache_reset[snum] = False;
815
816   f = fopen(outfile,"r");
817   if (!f) {
818     if (lfd >= 0) file_unlock(lfd);
819     return(0);
820   }
821
822   if (status) {
823     strcpy(status->message,"");
824     status->status = LPSTAT_OK;
825   }
826       
827   while (fgets(line,sizeof(pstring),f))
828     {
829       DEBUG(6,("QUEUE2: %s\n",line));
830
831       *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
832       if (! *queue)
833         {
834           count = 0;
835           break;
836         }
837
838       bzero((char *)&(*queue)[count],sizeof(**queue));
839           
840       /* parse it */
841       if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
842         continue;
843           
844       count++;
845     }         
846
847   fclose(f);
848
849   if (lfd >= 0) file_unlock(lfd);
850
851   if (!cachetime) 
852     unlink(outfile);
853   else
854     chmod(outfile,0666);
855   return(count);
856 }
857
858
859 /****************************************************************************
860 delete a printer queue entry
861 ****************************************************************************/
862 void del_printqueue(int cnum,int snum,int jobid)
863 {
864   char *lprm_command = lp_lprmcommand(snum);
865   char *printername = PRINTERNAME(snum);
866   pstring syscmd;
867   char jobstr[20];
868   int ret;
869
870   if (!printername || !*printername)
871     {
872       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
873             lp_servicename(snum),snum));
874       printername = lp_servicename(snum);
875     }
876     
877   if (!lprm_command || !(*lprm_command))
878     {
879       DEBUG(5,("No lprm command\n"));
880       return;
881     }
882     
883   sprintf(jobstr,"%d",jobid);
884
885   strcpy(syscmd,lprm_command);
886   string_sub(syscmd,"%p",printername);
887   string_sub(syscmd,"%j",jobstr);
888   standard_sub(cnum,syscmd);
889
890   ret = smbrun(syscmd,NULL);
891   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
892   lpq_reset(snum); /* queue has changed */
893 }
894
895 /****************************************************************************
896 change status of a printer queue entry
897 ****************************************************************************/
898 void status_printjob(int cnum,int snum,int jobid,int status)
899 {
900   char *lpstatus_command = 
901     (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
902   char *printername = PRINTERNAME(snum);
903   pstring syscmd;
904   char jobstr[20];
905   int ret;
906
907   if (!printername || !*printername)
908     {
909       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
910             lp_servicename(snum),snum));
911       printername = lp_servicename(snum);
912     }
913     
914   if (!lpstatus_command || !(*lpstatus_command))
915     {
916       DEBUG(5,("No lpstatus command to %s job\n",
917                (status==LPQ_PAUSED?"pause":"resume")));
918       return;
919     }
920     
921   sprintf(jobstr,"%d",jobid);
922
923   strcpy(syscmd,lpstatus_command);
924   string_sub(syscmd,"%p",printername);
925   string_sub(syscmd,"%j",jobstr);
926   standard_sub(cnum,syscmd);
927
928   ret = smbrun(syscmd,NULL);
929   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
930   lpq_reset(snum); /* queue has changed */
931 }
932
933