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