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