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