don't allow newlines in printer status messages
[bbaumbach/samba-autobuild/.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 = PTR_DIFF(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   /* We don't want the newline in the status message. */
717   {
718     char *p = strchr(line,'\n');
719     if (p) *p = 0;
720   }
721
722   if (status && !ret)
723     {
724       /* a few simple checks to see if the line might be a
725          printer status line: 
726          handle them so that most severe condition is shown */
727       int i;
728       strlower(line);
729       
730       switch (status->status) {
731       case LPSTAT_OK:
732         for (i=0; stat0_strings[i]; i++)
733           if (strstr(line,stat0_strings[i])) {
734             StrnCpy(status->message,line,sizeof(status->message)-1);
735             status->status=LPSTAT_OK;
736           }
737       case LPSTAT_STOPPED:
738         for (i=0; stat1_strings[i]; i++)
739           if (strstr(line,stat1_strings[i])) {
740             StrnCpy(status->message,line,sizeof(status->message)-1);
741             status->status=LPSTAT_STOPPED;
742           }
743       case LPSTAT_ERROR:
744         for (i=0; stat2_strings[i]; i++)
745           if (strstr(line,stat2_strings[i])) {
746             StrnCpy(status->message,line,sizeof(status->message)-1);
747             status->status=LPSTAT_ERROR;
748           }
749         break;
750       }
751     }
752
753   return(ret);
754 }
755
756 /****************************************************************************
757 get a printer queue
758 ****************************************************************************/
759 int get_printqueue(int snum,int cnum,print_queue_struct **queue,
760                    print_status_struct *status)
761 {
762   char *lpq_command = lp_lpqcommand(snum);
763   char *printername = PRINTERNAME(snum);
764   int ret=0,count=0;
765   pstring syscmd;
766   fstring outfile;
767   pstring line;
768   FILE *f;
769   struct stat sbuf;
770   BOOL dorun=True;
771   int cachetime = lp_lpqcachetime();
772   int lfd = -1;
773
774   *line = 0;
775   check_lpq_cache(snum);
776   
777   if (!printername || !*printername)
778     {
779       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
780             lp_servicename(snum),snum));
781       printername = lp_servicename(snum);
782     }
783     
784   if (!lpq_command || !(*lpq_command))
785     {
786       DEBUG(5,("No lpq command\n"));
787       return(0);
788     }
789     
790   strcpy(syscmd,lpq_command);
791   string_sub(syscmd,"%p",printername);
792
793   standard_sub(cnum,syscmd);
794
795   sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
796   
797   if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf)) 
798     {
799       if (time(NULL) - sbuf.st_mtime < cachetime) {
800         DEBUG(3,("Using cached lpq output\n"));
801         dorun = False;
802       }
803
804       if (dorun) {
805         lfd = file_lock(outfile,LPQ_LOCK_TIMEOUT);
806         if (lfd<0 || 
807             (!fstat(lfd,&sbuf) && (time(NULL) - sbuf.st_mtime)<cachetime)) {
808           DEBUG(3,("Using cached lpq output\n"));
809           dorun = False;
810           file_unlock(lfd); lfd = -1;
811         }
812       }
813     }
814
815   if (dorun) {
816     ret = smbrun(syscmd,outfile);
817     DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
818   }
819
820   lpq_cache_reset[snum] = False;
821
822   f = fopen(outfile,"r");
823   if (!f) {
824     if (lfd >= 0) file_unlock(lfd);
825     return(0);
826   }
827
828   if (status) {
829     strcpy(status->message,"");
830     status->status = LPSTAT_OK;
831   }
832       
833   while (fgets(line,sizeof(pstring),f))
834     {
835       DEBUG(6,("QUEUE2: %s\n",line));
836
837       *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
838       if (! *queue)
839         {
840           count = 0;
841           break;
842         }
843
844       bzero((char *)&(*queue)[count],sizeof(**queue));
845           
846       /* parse it */
847       if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
848         continue;
849           
850       count++;
851     }         
852
853   fclose(f);
854
855   if (lfd >= 0) file_unlock(lfd);
856
857   if (!cachetime) 
858     unlink(outfile);
859   else
860     chmod(outfile,0666);
861   return(count);
862 }
863
864
865 /****************************************************************************
866 delete a printer queue entry
867 ****************************************************************************/
868 void del_printqueue(int cnum,int snum,int jobid)
869 {
870   char *lprm_command = lp_lprmcommand(snum);
871   char *printername = PRINTERNAME(snum);
872   pstring syscmd;
873   char jobstr[20];
874   int ret;
875
876   if (!printername || !*printername)
877     {
878       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
879             lp_servicename(snum),snum));
880       printername = lp_servicename(snum);
881     }
882     
883   if (!lprm_command || !(*lprm_command))
884     {
885       DEBUG(5,("No lprm command\n"));
886       return;
887     }
888     
889   sprintf(jobstr,"%d",jobid);
890
891   strcpy(syscmd,lprm_command);
892   string_sub(syscmd,"%p",printername);
893   string_sub(syscmd,"%j",jobstr);
894   standard_sub(cnum,syscmd);
895
896   ret = smbrun(syscmd,NULL);
897   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
898   lpq_reset(snum); /* queue has changed */
899 }
900
901 /****************************************************************************
902 change status of a printer queue entry
903 ****************************************************************************/
904 void status_printjob(int cnum,int snum,int jobid,int status)
905 {
906   char *lpstatus_command = 
907     (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
908   char *printername = PRINTERNAME(snum);
909   pstring syscmd;
910   char jobstr[20];
911   int ret;
912
913   if (!printername || !*printername)
914     {
915       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
916             lp_servicename(snum),snum));
917       printername = lp_servicename(snum);
918     }
919     
920   if (!lpstatus_command || !(*lpstatus_command))
921     {
922       DEBUG(5,("No lpstatus command to %s job\n",
923                (status==LPQ_PAUSED?"pause":"resume")));
924       return;
925     }
926     
927   sprintf(jobstr,"%d",jobid);
928
929   strcpy(syscmd,lpstatus_command);
930   string_sub(syscmd,"%p",printername);
931   string_sub(syscmd,"%j",jobstr);
932   standard_sub(cnum,syscmd);
933
934   ret = smbrun(syscmd,NULL);
935   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
936   lpq_reset(snum); /* queue has changed */
937 }
938
939