09a574c2c9afe350dd7b0a85e4b624f92af9c234
[kai/samba.git] / source / printing / printing.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    printing routines
5    Copyright (C) Andrew Tridgell 1992-1998
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
25 static BOOL * lpq_cache_reset=NULL;
26
27 static int check_lpq_cache(int snum) {
28   static int lpq_caches=0;
29   
30   if (lpq_caches <= snum) {
31       BOOL * p;
32       p = (BOOL *) Realloc(lpq_cache_reset,(snum+1)*sizeof(BOOL));
33       if (p) {
34          lpq_cache_reset=p;
35          lpq_caches = snum+1;
36       }
37   }
38   return lpq_caches;
39 }
40
41 void lpq_reset(int snum)
42 {
43   if (check_lpq_cache(snum) > snum) lpq_cache_reset[snum]=True;
44 }
45
46
47 /****************************************************************************
48 Build the print command in the supplied buffer. This means getting the
49 print command for the service and inserting the printer name and the
50 print file name. Return NULL on error, else the passed buffer pointer.
51 ****************************************************************************/
52 static char *build_print_command(connection_struct *conn,
53                                  char *command, 
54                                  char *syscmd, char *filename1)
55 {
56         int snum = SNUM(conn);
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", 
64                          SERVICE(snum)));
65                 return (NULL);
66         }
67
68         /* copy the command into the buffer for extensive meddling. */
69         StrnCpy(syscmd, tstr, sizeof(pstring) - 1);
70   
71         /* look for "%s" in the string. If there is no %s, we cannot print. */   
72         if (!strstr(syscmd, "%s") && !strstr(syscmd, "%f")) {
73                 DEBUG(2,("WARNING! No placeholder for the filename in the print command for service %s!\n", SERVICE(snum)));
74         }
75   
76         if (strstr(syscmd,"%s")) {
77                 pstrcpy(filename,filename1);
78     
79                 string_sub(syscmd, "%s", filename);
80         }
81   
82         string_sub(syscmd, "%f", filename1);
83   
84         /* Does the service have a printername? If not, make a fake
85            and empty */
86         /* printer name. That way a %p is treated sanely if no printer */
87         /* name was specified to replace it. This eventuality is logged.  */
88         tstr = PRINTERNAME(snum);
89         if (tstr == NULL || tstr[0] == '\0') {
90                 DEBUG(3,( "No printer name - using %s.\n", SERVICE(snum)));
91                 tstr = SERVICE(snum);
92         }
93   
94         string_sub(syscmd, "%p", tstr);
95   
96         standard_sub(conn,syscmd);
97   
98         return (syscmd);
99 }
100
101
102 /****************************************************************************
103 print a file - called on closing the file
104 ****************************************************************************/
105 void print_file(connection_struct *conn, files_struct *file)
106 {
107         pstring syscmd;
108         int snum = SNUM(conn);
109         char *tempstr;
110
111         *syscmd = 0;
112
113         if (file_size(file->fsp_name) <= 0) {
114                 DEBUG(3,("Discarding null print job %s\n",file->fsp_name));
115                 dos_unlink(file->fsp_name);
116                 return;
117         }
118
119         tempstr = build_print_command(conn, 
120                                       PRINTCOMMAND(snum), 
121                                       syscmd, file->fsp_name);
122         if (tempstr != NULL) {
123                 int ret = smbrun(syscmd,NULL,False);
124                 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
125         } else {
126                 DEBUG(0,("Null print command?\n"));
127         }
128   
129         lpq_reset(snum);
130 }
131
132 static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
133                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
134
135
136 /*******************************************************************
137 process time fields
138 ********************************************************************/
139 static time_t EntryTime(fstring tok[], int ptr, int count, int minimum)
140 {
141   time_t jobtime,jobtime1;
142
143   jobtime = time(NULL);         /* default case: take current time */
144   if (count >= minimum) {
145     struct tm *t;
146     int i, day, hour, min, sec;
147     char   *c;
148
149     for (i=0; i<13; i++) if (!strncmp(tok[ptr], Months[i],3)) break; /* Find month */
150     if (i<12) {
151       t = localtime(&jobtime);
152       day = atoi(tok[ptr+1]);
153       c=(char *)(tok[ptr+2]);
154       *(c+2)=0;
155       hour = atoi(c);
156       *(c+5)=0;
157       min = atoi(c+3);
158       if(*(c+6) != 0)sec = atoi(c+6);
159       else  sec=0;
160
161       if ((t->tm_mon < i)||
162           ((t->tm_mon == i)&&
163            ((t->tm_mday < day)||
164             ((t->tm_mday == day)&&
165              (t->tm_hour*60+t->tm_min < hour*60+min)))))
166         t->tm_year--;           /* last year's print job */
167
168       t->tm_mon = i;
169       t->tm_mday = day;
170       t->tm_hour = hour;
171       t->tm_min = min;
172       t->tm_sec = sec;
173       jobtime1 = mktime(t);
174       if (jobtime1 != (time_t)-1)
175         jobtime = jobtime1;
176     }
177   }
178   return jobtime;
179 }
180
181
182 /****************************************************************************
183 parse a lpq line
184
185 here is an example of lpq output under bsd
186
187 Warning: no daemon present
188 Rank   Owner      Job  Files                                 Total Size
189 1st    tridge     148  README                                8096 bytes
190
191 here is an example of lpq output under osf/1
192
193 Warning: no daemon present
194 Rank   Pri Owner      Job  Files                             Total Size
195 1st    0   tridge     148  README                            8096 bytes
196
197
198 <allan@umich.edu> June 30, 1998.
199 Modified to handle file names with spaces, like the parse_lpq_lprng code
200 further below.
201 ****************************************************************************/
202 static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
203 {
204 #ifdef  OSF1
205 #define RANKTOK 0
206 #define PRIOTOK 1
207 #define USERTOK 2
208 #define JOBTOK  3
209 #define FILETOK 4
210 #define TOTALTOK (count - 2)
211 #define NTOK    6
212 #define MAXTOK  128
213 #else   /* OSF1 */
214 #define RANKTOK 0
215 #define USERTOK 1
216 #define JOBTOK  2
217 #define FILETOK 3
218 #define TOTALTOK (count - 2)
219 #define NTOK    5
220 #define MAXTOK  128
221 #endif  /* OSF1 */
222
223   char *tok[MAXTOK];
224   int  count = 0;
225   pstring line2;
226
227   pstrcpy(line2,line);
228
229 #ifdef  OSF1
230   int length;
231   length = strlen(line2);
232   if (line2[length-3] == ':')
233         return(False);
234 #endif  /* OSF1 */
235
236   tok[0] = strtok(line2," \t");
237   count++;
238
239   while (((tok[count] = strtok(NULL," \t")) != NULL) && (count < MAXTOK)) {
240     count++;
241   }
242
243   /* we must get at least 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   buf->job = atoi(tok[JOBTOK]);
251   buf->size = atoi(tok[TOTALTOK]);
252   buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
253   buf->time = time(NULL);
254   StrnCpy(buf->user,tok[USERTOK],sizeof(buf->user)-1);
255   StrnCpy(buf->file,tok[FILETOK],sizeof(buf->file)-1);
256
257   if ((FILETOK + 1) != TOTALTOK) {
258     int bufsize;
259     int i;
260
261     bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
262
263     for (i = (FILETOK + 1); i < TOTALTOK; i++) {
264       strncat(buf->file," ",bufsize);
265       strncat(buf->file,tok[i],bufsize - 1);
266       bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
267       if (bufsize <= 0) {
268         break;
269       }
270     }
271   }
272
273 #ifdef PRIOTOK
274   buf->priority = atoi(tok[PRIOTOK]);
275 #else
276   buf->priority = 1;
277 #endif
278   return(True);
279 }
280
281 /*
282 <magnus@hum.auc.dk>
283 LPRng_time modifies the current date by inserting the hour and minute from
284 the lpq output.  The lpq time looks like "23:15:07"
285
286 <allan@umich.edu> June 30, 1998.
287 Modified to work with the re-written parse_lpq_lprng routine.
288 */
289 static time_t LPRng_time(char *time_string)
290 {
291   time_t jobtime;
292   struct tm *t;
293
294   jobtime = time(NULL);         /* default case: take current time */
295   t = localtime(&jobtime);
296   t->tm_hour = atoi(time_string);
297   t->tm_min = atoi(time_string+3);
298   t->tm_sec = atoi(time_string+6);
299   jobtime = mktime(t);
300
301   return jobtime;
302 }
303
304
305 /****************************************************************************
306   parse a lprng lpq line
307   <allan@umich.edu> June 30, 1998.
308   Re-wrote this to handle file names with spaces, multiple file names on one
309   lpq line, etc;
310 ****************************************************************************/
311 static BOOL parse_lpq_lprng(char *line,print_queue_struct *buf,BOOL first)
312 {
313 #define LPRNG_RANKTOK   0
314 #define LPRNG_USERTOK   1
315 #define LPRNG_PRIOTOK   2
316 #define LPRNG_JOBTOK    3
317 #define LPRNG_FILETOK   4
318 #define LPRNG_TOTALTOK  (num_tok - 2)
319 #define LPRNG_TIMETOK   (num_tok - 1)
320 #define LPRNG_NTOK      7
321 #define LPRNG_MAXTOK    128 /* PFMA just to keep us from running away. */
322
323   char *tokarr[LPRNG_MAXTOK];
324   char *cptr;
325   int  num_tok = 0;
326   pstring line2;
327
328   pstrcpy(line2,line);
329   tokarr[0] = strtok(line2," \t");
330   num_tok++;
331   while (((tokarr[num_tok] = strtok(NULL," \t")) != NULL)
332          && (num_tok < LPRNG_MAXTOK)) {
333     num_tok++;
334   }
335
336   /* We must get at least LPRNG_NTOK tokens. */
337   if (num_tok < LPRNG_NTOK) {
338     return(False);
339   }
340
341   if (!isdigit(*tokarr[LPRNG_JOBTOK]) || !isdigit(*tokarr[LPRNG_TOTALTOK])) {
342     return(False);
343   }
344
345   buf->job  = atoi(tokarr[LPRNG_JOBTOK]);
346   buf->size = atoi(tokarr[LPRNG_TOTALTOK]);
347
348   if (strequal(tokarr[LPRNG_RANKTOK],"active")) {
349     buf->status = LPQ_PRINTING;
350   } else if (isdigit(*tokarr[LPRNG_RANKTOK])) {
351     buf->status = LPQ_QUEUED;
352   } else {
353     buf->status = LPQ_PAUSED;
354   }
355
356   buf->priority = *tokarr[LPRNG_PRIOTOK] -'A';
357
358   buf->time = LPRng_time(tokarr[LPRNG_TIMETOK]);
359
360   StrnCpy(buf->user,tokarr[LPRNG_USERTOK],sizeof(buf->user)-1);
361
362   /* The '@hostname' prevents windows from displaying the printing icon
363    * for the current user on the taskbar.  Plop in a null.
364    */
365
366   if ((cptr = strchr(buf->user,'@')) != NULL) {
367     *cptr = '\0';
368   }
369
370   StrnCpy(buf->file,tokarr[LPRNG_FILETOK],sizeof(buf->file)-1);
371
372   if ((LPRNG_FILETOK + 1) != LPRNG_TOTALTOK) {
373     int bufsize;
374     int i;
375
376     bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
377
378     for (i = (LPRNG_FILETOK + 1); i < LPRNG_TOTALTOK; i++) {
379       strncat(buf->file," ",bufsize);
380       strncat(buf->file,tokarr[i],bufsize - 1);
381       bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
382       if (bufsize <= 0) {
383         break;
384       }
385     }
386   }
387
388   return(True);
389 }
390
391
392
393 /*******************************************************************
394 parse lpq on an aix system
395
396 Queue   Dev   Status    Job Files              User         PP %   Blks  Cp Rnk
397 ------- ----- --------- --- ------------------ ---------- ---- -- ----- --- ---
398 lazer   lazer READY
399 lazer   lazer RUNNING   537 6297doc.A          kvintus@IE    0 10  2445   1   1
400               QUEUED    538 C.ps               root@IEDVB           124   1   2
401               QUEUED    539 E.ps               root@IEDVB            28   1   3
402               QUEUED    540 L.ps               root@IEDVB           172   1   4
403               QUEUED    541 P.ps               root@IEDVB            22   1   5
404 ********************************************************************/
405 static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
406 {
407   fstring tok[11];
408   int count=0;
409
410   /* handle the case of "(standard input)" as a filename */
411   string_sub(line,"standard input","STDIN");
412   string_sub(line,"(","\"");
413   string_sub(line,")","\"");
414
415   for (count=0; 
416        count<10 && 
417                next_token(&line,tok[count],NULL, sizeof(tok[count])); 
418        count++) ;
419
420   /* we must get 6 tokens */
421   if (count < 10)
422   {
423       if ((count == 7) && ((strcmp(tok[0],"QUEUED") == 0) || (strcmp(tok[0],"HELD") == 0)))
424       {
425           /* the 2nd and 5th columns must be integer */
426           if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4])) return(False);
427           buf->size = atoi(tok[4]) * 1024;
428           /* if the fname contains a space then use STDIN */
429           if (strchr(tok[2],' '))
430             fstrcpy(tok[2],"STDIN");
431
432           /* only take the last part of the filename */
433           {
434             fstring tmp;
435             char *p = strrchr(tok[2],'/');
436             if (p)
437               {
438                 fstrcpy(tmp,p+1);
439                 fstrcpy(tok[2],tmp);
440               }
441           }
442
443
444           buf->job = atoi(tok[1]);
445           buf->status = strequal(tok[0],"HELD")?LPQ_PAUSED:LPQ_QUEUED;
446           buf->priority = 0;
447           buf->time = time(NULL);
448           StrnCpy(buf->user,tok[3],sizeof(buf->user)-1);
449           StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
450       }
451       else
452       {
453           DEBUG(6,("parse_lpq_aix count=%d\n", count));
454           return(False);
455       }
456   }
457   else
458   {
459       /* the 4th and 9th columns must be integer */
460       if (!isdigit((int)*tok[3]) || !isdigit((int)*tok[8])) return(False);
461       buf->size = atoi(tok[8]) * 1024;
462       /* if the fname contains a space then use STDIN */
463       if (strchr(tok[4],' '))
464         fstrcpy(tok[4],"STDIN");
465
466       /* only take the last part of the filename */
467       {
468         fstring tmp;
469         char *p = strrchr(tok[4],'/');
470         if (p)
471           {
472             fstrcpy(tmp,p+1);
473             fstrcpy(tok[4],tmp);
474           }
475       }
476
477
478       buf->job = atoi(tok[3]);
479       buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED;
480       buf->priority = 0;
481       buf->time = time(NULL);
482       StrnCpy(buf->user,tok[5],sizeof(buf->user)-1);
483       StrnCpy(buf->file,tok[4],sizeof(buf->file)-1);
484   }
485
486
487   return(True);
488 }
489
490
491 /****************************************************************************
492 parse a lpq line
493 here is an example of lpq output under hpux; note there's no space after -o !
494 $> lpstat -oljplus
495 ljplus-2153         user           priority 0  Jan 19 08:14 on ljplus
496       util.c                                  125697 bytes
497       server.c                                110712 bytes
498 ljplus-2154         user           priority 0  Jan 19 08:14 from client
499       (standard input)                          7551 bytes
500 ****************************************************************************/
501 static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
502 {
503   /* must read two lines to process, therefore keep some values static */
504   static BOOL header_line_ok=False, base_prio_reset=False;
505   static fstring jobuser;
506   static int jobid;
507   static int jobprio;
508   static time_t jobtime;
509   static int jobstat=LPQ_QUEUED;
510   /* to store minimum priority to print, lpstat command should be invoked
511      with -p option first, to work */
512   static int base_prio;
513  
514   int count;
515   char htab = '\011';  
516   fstring tok[12];
517
518   /* If a line begins with a horizontal TAB, it is a subline type */
519   
520   if (line[0] == htab) { /* subline */
521     /* check if it contains the base priority */
522     if (!strncmp(line,"\tfence priority : ",18)) {
523        base_prio=atoi(&line[18]);
524        DEBUG(4, ("fence priority set at %d\n", base_prio));
525     }
526     if (!header_line_ok) return (False); /* incorrect header line */
527     /* handle the case of "(standard input)" as a filename */
528     string_sub(line,"standard input","STDIN");
529     string_sub(line,"(","\"");
530     string_sub(line,")","\"");
531     
532     for (count=0; count<2 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
533     /* we must get 2 tokens */
534     if (count < 2) return(False);
535     
536     /* the 2nd column must be integer */
537     if (!isdigit((int)*tok[1])) return(False);
538     
539     /* if the fname contains a space then use STDIN */
540     if (strchr(tok[0],' '))
541       fstrcpy(tok[0],"STDIN");
542     
543     buf->size = atoi(tok[1]);
544     StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
545     
546     /* fill things from header line */
547     buf->time = jobtime;
548     buf->job = jobid;
549     buf->status = jobstat;
550     buf->priority = jobprio;
551     StrnCpy(buf->user,jobuser,sizeof(buf->user)-1);
552     
553     return(True);
554   }
555   else { /* header line */
556     header_line_ok=False; /* reset it */
557     if (first) {
558        if (!base_prio_reset) {
559           base_prio=0; /* reset it */
560           base_prio_reset=True;
561        }
562     }
563     else if (base_prio) base_prio_reset=False;
564     
565     /* handle the dash in the job id */
566     string_sub(line,"-"," ");
567     
568     for (count=0; count<12 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
569       
570     /* we must get 8 tokens */
571     if (count < 8) return(False);
572     
573     /* first token must be printer name (cannot check ?) */
574     /* the 2nd, 5th & 7th column must be integer */
575     if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4]) || !isdigit((int)*tok[6])) return(False);
576     jobid = atoi(tok[1]);
577     StrnCpy(jobuser,tok[2],sizeof(buf->user)-1);
578     jobprio = atoi(tok[4]);
579     
580     /* process time */
581     jobtime=EntryTime(tok, 5, count, 8);
582     if (jobprio < base_prio) {
583        jobstat = LPQ_PAUSED;
584        DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n", jobid, jobprio, base_prio, jobstat));
585     }
586     else {
587        jobstat = LPQ_QUEUED;
588        if ((count >8) && (((strequal(tok[8],"on")) ||
589                            ((strequal(tok[8],"from")) && 
590                             ((count > 10)&&(strequal(tok[10],"on")))))))
591          jobstat = LPQ_PRINTING;
592     }
593     
594     header_line_ok=True; /* information is correct */
595     return(False); /* need subline info to include into queuelist */
596   }
597 }
598
599
600 /****************************************************************************
601 parse a lpq line
602
603 here is an example of "lpstat -o dcslw" output under sysv
604
605 dcslw-896               tridge            4712   Dec 20 10:30:30 on dcslw
606 dcslw-897               tridge            4712   Dec 20 10:30:30 being held
607
608 ****************************************************************************/
609 static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
610 {
611   fstring tok[9];
612   int count=0;
613   char *p;
614
615   /* handle the dash in the job id */
616   string_sub(line,"-"," ");
617   
618   for (count=0; count<9 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
619
620   /* we must get 7 tokens */
621   if (count < 7)
622     return(False);
623
624   /* the 2nd and 4th, 6th columns must be integer */
625   if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[3])) return(False);
626   if (!isdigit((int)*tok[5])) return(False);
627
628   /* if the user contains a ! then trim the first part of it */  
629   if ((p=strchr(tok[2],'!')))
630     {
631       fstring tmp;
632       fstrcpy(tmp,p+1);
633       fstrcpy(tok[2],tmp);
634     }
635     
636
637   buf->job = atoi(tok[1]);
638   buf->size = atoi(tok[3]);
639   if (count > 7 && strequal(tok[7],"on"))
640     buf->status = LPQ_PRINTING;
641   else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held"))
642     buf->status = LPQ_PAUSED;
643   else
644     buf->status = LPQ_QUEUED;
645   buf->priority = 0;
646   buf->time = EntryTime(tok, 4, count, 7);
647   StrnCpy(buf->user,tok[2],sizeof(buf->user)-1);
648   StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
649   return(True);
650 }
651
652 /****************************************************************************
653 parse a lpq line
654
655 here is an example of lpq output under qnx
656 Spooler: /qnx/spooler, on node 1
657 Printer: txt        (ready) 
658 0000:     root  [job #1    ]   active 1146 bytes        /etc/profile
659 0001:     root  [job #2    ]    ready 2378 bytes        /etc/install
660 0002:     root  [job #3    ]    ready 1146 bytes        -- standard input --
661 ****************************************************************************/
662 static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
663 {
664   fstring tok[7];
665   int count=0;
666
667   DEBUG(0,("antes [%s]\n", line));
668
669   /* handle the case of "-- standard input --" as a filename */
670   string_sub(line,"standard input","STDIN");
671   DEBUG(0,("despues [%s]\n", line));
672   string_sub(line,"-- ","\"");
673   string_sub(line," --","\"");
674   DEBUG(0,("despues 1 [%s]\n", line));
675
676   string_sub(line,"[job #","");
677   string_sub(line,"]","");
678   DEBUG(0,("despues 2 [%s]\n", line));
679
680   
681   
682   for (count=0; count<7 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
683
684   /* we must get 7 tokens */
685   if (count < 7)
686     return(False);
687
688   /* the 3rd and 5th columns must be integer */
689   if (!isdigit((int)*tok[2]) || !isdigit((int)*tok[4])) return(False);
690
691   /* only take the last part of the filename */
692   {
693     fstring tmp;
694     char *p = strrchr(tok[6],'/');
695     if (p)
696       {
697         fstrcpy(tmp,p+1);
698         fstrcpy(tok[6],tmp);
699       }
700   }
701         
702
703   buf->job = atoi(tok[2]);
704   buf->size = atoi(tok[4]);
705   buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED;
706   buf->priority = 0;
707   buf->time = time(NULL);
708   StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
709   StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
710   return(True);
711 }
712
713
714 /****************************************************************************
715   parse a lpq line for the plp printing system
716   Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
717
718 redone by tridge. Here is a sample queue:
719
720 Local  Printer 'lp2' (fjall):
721   Printing (started at Jun 15 13:33:58, attempt 1).
722     Rank Owner       Pr Opt  Job Host        Files           Size     Date
723   active tridge      X  -    6   fjall       /etc/hosts      739      Jun 15 13:33
724      3rd tridge      X  -    7   fjall       /etc/hosts      739      Jun 15 13:33
725
726 ****************************************************************************/
727 static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
728 {
729   fstring tok[11];
730   int count=0;
731
732   /* handle the case of "(standard input)" as a filename */
733   string_sub(line,"stdin","STDIN");
734   string_sub(line,"(","\"");
735   string_sub(line,")","\"");
736   
737   for (count=0; count<11 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
738
739   /* we must get 11 tokens */
740   if (count < 11)
741     return(False);
742
743   /* the first must be "active" or begin with an integer */
744   if (strcmp(tok[0],"active") && !isdigit((int)tok[0][0]))
745     return(False);
746
747   /* the 5th and 8th must be integer */
748   if (!isdigit((int)*tok[4]) || !isdigit((int)*tok[7])) 
749     return(False);
750
751   /* if the fname contains a space then use STDIN */
752   if (strchr(tok[6],' '))
753     fstrcpy(tok[6],"STDIN");
754
755   /* only take the last part of the filename */
756   {
757     fstring tmp;
758     char *p = strrchr(tok[6],'/');
759     if (p)
760       {
761         fstrcpy(tmp,p+1);
762         fstrcpy(tok[6],tmp);
763       }
764   }
765
766
767   buf->job = atoi(tok[4]);
768
769   buf->size = atoi(tok[7]);
770   if (strchr(tok[7],'K'))
771     buf->size *= 1024;
772   if (strchr(tok[7],'M'))
773     buf->size *= 1024*1024;
774
775   buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
776   buf->priority = 0;
777   buf->time = time(NULL);
778   StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
779   StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
780   return(True);
781 }
782
783 /****************************************************************************
784 parse a qstat line
785
786 here is an example of "qstat -l -d qms" output under softq
787
788 Queue qms: 2 jobs; daemon active (313); enabled; accepting;
789  job-ID   submission-time     pri     size owner      title 
790 205980: H 98/03/09 13:04:05     0    15733 stephenf   chap1.ps
791 206086:>  98/03/12 17:24:40     0      659 chris      -
792 206087:   98/03/12 17:24:45     0     4876 chris      -
793 Total:      21268 bytes in queue
794
795
796 ****************************************************************************/
797 static BOOL parse_lpq_softq(char *line,print_queue_struct *buf,BOOL first)
798 {
799   fstring tok[10];
800   int count=0;
801
802   /* mung all the ":"s to spaces*/
803   string_sub(line,":"," ");
804   
805   for (count=0; count<10 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
806
807   /* we must get 9 tokens */
808   if (count < 9)
809     return(False);
810
811   /* the 1st and 7th columns must be integer */
812   if (!isdigit((int)*tok[0]) || !isdigit((int)*tok[6]))  return(False);
813   /* if the 2nd column is either '>' or 'H' then the 7th and 8th must be
814    * integer, else it's the 6th and 7th that must be
815    */
816   if (*tok[1] == 'H' || *tok[1] == '>')
817     {
818       if (!isdigit((int)*tok[7]))
819         return(False);
820       buf->status = *tok[1] == '>' ? LPQ_PRINTING : LPQ_PAUSED;
821       count = 1;
822     }
823   else
824     {
825       if (!isdigit((int)*tok[5]))
826         return(False);
827       buf->status = LPQ_QUEUED;
828       count = 0;
829     }
830         
831
832   buf->job = atoi(tok[0]);
833   buf->size = atoi(tok[count+6]);
834   buf->priority = atoi(tok[count+5]);
835   StrnCpy(buf->user,tok[count+7],sizeof(buf->user)-1);
836   StrnCpy(buf->file,tok[count+8],sizeof(buf->file)-1);
837   buf->time = time(NULL);               /* default case: take current time */
838   {
839     time_t jobtime;
840     struct tm *t;
841
842     t = localtime(&buf->time);
843     t->tm_mday = atoi(tok[count+2]+6);
844     t->tm_mon  = atoi(tok[count+2]+3);
845     switch (*tok[count+2])
846     {
847     case 7: case 8: case 9: t->tm_year = atoi(tok[count+2]) + 1900; break;
848     default:                t->tm_year = atoi(tok[count+2]) + 2000; break;
849     }
850
851     t->tm_hour = atoi(tok[count+3]);
852     t->tm_min = atoi(tok[count+4]);
853     t->tm_sec = atoi(tok[count+5]);
854     jobtime = mktime(t);
855     if (jobtime != (time_t)-1)
856       buf->time = jobtime; 
857   }
858
859   return(True);
860 }
861
862
863 char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
864 char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
865 char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
866
867 /****************************************************************************
868 parse a lpq line. Choose printing style
869 ****************************************************************************/
870 static BOOL parse_lpq_entry(int snum,char *line,
871                             print_queue_struct *buf,
872                             print_status_struct *status,BOOL first)
873 {
874   BOOL ret;
875
876   switch (lp_printing(snum))
877     {
878     case PRINT_SYSV:
879       ret = parse_lpq_sysv(line,buf,first);
880       break;
881     case PRINT_AIX:      
882       ret = parse_lpq_aix(line,buf,first);
883       break;
884     case PRINT_HPUX:
885       ret = parse_lpq_hpux(line,buf,first);
886       break;
887     case PRINT_QNX:
888       ret = parse_lpq_qnx(line,buf,first);
889       break;
890     case PRINT_LPRNG:
891       ret = parse_lpq_lprng(line,buf,first);
892       break;
893     case PRINT_PLP:
894       ret = parse_lpq_plp(line,buf,first);
895       break;
896     case PRINT_SOFTQ:
897       ret = parse_lpq_softq(line,buf,first);
898       break;
899     default:
900       ret = parse_lpq_bsd(line,buf,first);
901       break;
902     }
903
904 #ifdef LPQ_GUEST_TO_USER
905   if (ret) {
906     extern pstring sesssetup_user;
907     /* change guest entries to the current logged in user to make
908        them appear deletable to windows */
909     if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
910       pstrcpy(buf->user,sesssetup_user);
911   }
912 #endif
913
914   /* We don't want the newline in the status message. */
915   {
916     char *p = strchr(line,'\n');
917     if (p) *p = 0;
918   }
919
920   if (status && !ret)
921     {
922       /* a few simple checks to see if the line might be a
923          printer status line: 
924          handle them so that most severe condition is shown */
925       int i;
926       strlower(line);
927       
928       switch (status->status) {
929       case LPSTAT_OK:
930         for (i=0; stat0_strings[i]; i++)
931           if (strstr(line,stat0_strings[i])) {
932             StrnCpy(status->message,line,sizeof(status->message)-1);
933             status->status=LPSTAT_OK;
934             return ret;
935           }
936       case LPSTAT_STOPPED:
937         for (i=0; stat1_strings[i]; i++)
938           if (strstr(line,stat1_strings[i])) {
939             StrnCpy(status->message,line,sizeof(status->message)-1);
940             status->status=LPSTAT_STOPPED;
941             return ret;
942           }
943       case LPSTAT_ERROR:
944         for (i=0; stat2_strings[i]; i++)
945           if (strstr(line,stat2_strings[i])) {
946             StrnCpy(status->message,line,sizeof(status->message)-1);
947             status->status=LPSTAT_ERROR;
948             return ret;
949           }
950         break;
951       }
952     }
953
954   return(ret);
955 }
956
957 /****************************************************************************
958 get a printer queue
959 ****************************************************************************/
960 int get_printqueue(int snum, 
961                    connection_struct *conn,print_queue_struct **queue,
962                    print_status_struct *status)
963 {
964         char *lpq_command = lp_lpqcommand(snum);
965         char *printername = PRINTERNAME(snum);
966         int ret=0,count=0;
967         pstring syscmd;
968         fstring outfile;
969         pstring line;
970         FILE *f;
971         SMB_STRUCT_STAT sbuf;
972         BOOL dorun=True;
973         int cachetime = lp_lpqcachetime();
974         
975         *line = 0;
976         check_lpq_cache(snum);
977         
978         if (!printername || !*printername) {
979                 DEBUG(6,("xx replacing printer name with service (snum=(%s,%d))\n",
980                          lp_servicename(snum),snum));
981                 printername = lp_servicename(snum);
982         }
983     
984         if (!lpq_command || !(*lpq_command)) {
985                 DEBUG(5,("No lpq command\n"));
986                 return(0);
987         }
988     
989         pstrcpy(syscmd,lpq_command);
990         string_sub(syscmd,"%p",printername);
991
992         standard_sub(conn,syscmd);
993
994         slprintf(outfile,sizeof(outfile)-1, "%s/lpq.%08x",tmpdir(),str_checksum(syscmd));
995   
996         if (!lpq_cache_reset[snum] && cachetime && !sys_stat(outfile,&sbuf)) {
997                 if (time(NULL) - sbuf.st_mtime < cachetime) {
998                         DEBUG(3,("Using cached lpq output\n"));
999                         dorun = False;
1000                 }
1001         }
1002
1003         if (dorun) {
1004                 ret = smbrun(syscmd,outfile,True);
1005                 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
1006         }
1007
1008         lpq_cache_reset[snum] = False;
1009
1010         f = fopen(outfile,"r");
1011         if (!f) {
1012                 return(0);
1013         }
1014
1015         if (status) {
1016                 fstrcpy(status->message,"");
1017                 status->status = LPSTAT_OK;
1018         }
1019         
1020         while (fgets(line,sizeof(pstring),f)) {
1021                 DEBUG(6,("QUEUE2: %s\n",line));
1022                 
1023                 *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
1024                 if (! *queue) {
1025                         count = 0;
1026                         break;
1027                 }
1028
1029                 bzero((char *)&(*queue)[count],sizeof(**queue));
1030           
1031                 /* parse it */
1032                 if (!parse_lpq_entry(snum,line,
1033                                      &(*queue)[count],status,count==0))
1034                         continue;
1035                 
1036                 count++;
1037         }             
1038
1039         fclose(f);
1040         
1041         if (!cachetime) {
1042                 unlink(outfile);
1043         } else {
1044                 /* we only expect this to succeed on trapdoor systems,
1045                    on normal systems the file is owned by root */
1046                 chmod(outfile,0666);
1047         }
1048         return(count);
1049 }
1050
1051
1052 /****************************************************************************
1053 delete a printer queue entry
1054 ****************************************************************************/
1055 void del_printqueue(connection_struct *conn,int snum,int jobid)
1056 {
1057   char *lprm_command = lp_lprmcommand(snum);
1058   char *printername = PRINTERNAME(snum);
1059   pstring syscmd;
1060   char jobstr[20];
1061   int ret;
1062
1063   if (!printername || !*printername)
1064     {
1065       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
1066             lp_servicename(snum),snum));
1067       printername = lp_servicename(snum);
1068     }
1069     
1070   if (!lprm_command || !(*lprm_command))
1071     {
1072       DEBUG(5,("No lprm command\n"));
1073       return;
1074     }
1075     
1076   slprintf(jobstr,sizeof(jobstr)-1,"%d",jobid);
1077
1078   pstrcpy(syscmd,lprm_command);
1079   string_sub(syscmd,"%p",printername);
1080   string_sub(syscmd,"%j",jobstr);
1081   standard_sub(conn,syscmd);
1082
1083   ret = smbrun(syscmd,NULL,False);
1084   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
1085   lpq_reset(snum); /* queue has changed */
1086 }
1087
1088 /****************************************************************************
1089 change status of a printer queue entry
1090 ****************************************************************************/
1091 void status_printjob(connection_struct *conn,int snum,int jobid,int status)
1092 {
1093   char *lpstatus_command = 
1094     (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
1095   char *printername = PRINTERNAME(snum);
1096   pstring syscmd;
1097   char jobstr[20];
1098   int ret;
1099
1100   if (!printername || !*printername)
1101     {
1102       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
1103             lp_servicename(snum),snum));
1104       printername = lp_servicename(snum);
1105     }
1106     
1107   if (!lpstatus_command || !(*lpstatus_command))
1108     {
1109       DEBUG(5,("No lpstatus command to %s job\n",
1110                (status==LPQ_PAUSED?"pause":"resume")));
1111       return;
1112     }
1113     
1114   slprintf(jobstr,sizeof(jobstr)-1,"%d",jobid);
1115
1116   pstrcpy(syscmd,lpstatus_command);
1117   string_sub(syscmd,"%p",printername);
1118   string_sub(syscmd,"%j",jobstr);
1119   standard_sub(conn,syscmd);
1120
1121   ret = smbrun(syscmd,NULL,False);
1122   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
1123   lpq_reset(snum); /* queue has changed */
1124 }
1125
1126
1127
1128 /****************************************************************************
1129 we encode print job numbers over the wire so that when we get them back we can
1130 tell not only what print job they are but also what service it belongs to,
1131 this is to overcome the problem that windows clients tend to send the wrong
1132 service number when doing print queue manipulation!
1133 ****************************************************************************/
1134 int printjob_encode(int snum, int job)
1135 {
1136         return ((snum&0xFF)<<8) | (job & 0xFF);
1137 }
1138
1139 /****************************************************************************
1140 and now decode them again ...
1141 ****************************************************************************/
1142 void printjob_decode(int jobid, int *snum, int *job)
1143 {
1144         (*snum) = (jobid >> 8) & 0xFF;
1145         (*job) = jobid & 0xFF;
1146 }
1147
1148 /****************************************************************************
1149  Change status of a printer queue
1150 ****************************************************************************/
1151
1152 void status_printqueue(connection_struct *conn,int snum,int status)
1153 {
1154   char *queuestatus_command = (status==LPSTAT_STOPPED ? 
1155                                lp_queuepausecommand(snum):lp_queueresumecommand(snum));
1156   char *printername = PRINTERNAME(snum);
1157   pstring syscmd;
1158   int ret;
1159
1160   if (!printername || !*printername) {
1161     DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
1162           lp_servicename(snum),snum));
1163     printername = lp_servicename(snum);
1164   }
1165
1166   if (!queuestatus_command || !(*queuestatus_command)) {
1167     DEBUG(5,("No queuestatus command to %s job\n",
1168           (status==LPSTAT_STOPPED?"pause":"resume")));
1169     return;
1170   }
1171
1172   pstrcpy(syscmd,queuestatus_command);
1173   string_sub(syscmd,"%p",printername);
1174   standard_sub(conn,syscmd);
1175
1176   ret = smbrun(syscmd,NULL,False);
1177   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
1178   lpq_reset(snum); /* queue has changed */
1179 }
1180
1181
1182
1183 /***************************************************************************
1184 auto-load printer services
1185 ***************************************************************************/
1186 static void add_all_printers(void)
1187 {
1188         int printers = lp_servicenumber(PRINTERS_NAME);
1189
1190         if (printers < 0) return;
1191
1192         pcap_printer_fn(lp_add_one_printer);
1193 }
1194
1195 /***************************************************************************
1196 auto-load some homes and printer services
1197 ***************************************************************************/
1198 static void add_auto_printers(void)
1199 {
1200         char *p;
1201         int printers;
1202         char *str = lp_auto_services();
1203
1204         if (!str) return;
1205
1206         printers = lp_servicenumber(PRINTERS_NAME);
1207
1208         if (printers < 0) return;
1209         
1210         for (p=strtok(str,LIST_SEP);p;p=strtok(NULL,LIST_SEP)) {
1211                 if (lp_servicenumber(p) >= 0) continue;
1212                 
1213                 if (pcap_printername_ok(p,NULL)) {
1214                         lp_add_printer(p,printers);
1215                 }
1216         }
1217 }
1218
1219 /***************************************************************************
1220 load automatic printer services
1221 ***************************************************************************/
1222 void load_printers(void)
1223 {
1224         add_auto_printers();
1225         if (lp_load_printers())
1226                 add_all_printers();
1227 }