'The mother of all checkins' :-). Jeremy Allison (jallison@whistle.com)
[Samba.git] / source / printing / printing.c
blobc4dd9803ebe742f1e36079d17dd8919be1aa02f0
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 printing routines
5 Copyright (C) Andrew Tridgell 1992-1997
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.
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.
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.
22 #include "includes.h"
23 extern int DEBUGLEVEL;
24 extern connection_struct Connections[];
25 extern files_struct Files[];
27 static BOOL * lpq_cache_reset=NULL;
29 static int check_lpq_cache(int snum) {
30 static int lpq_caches=0;
32 if (lpq_caches <= snum) {
33 BOOL * p;
34 p = (BOOL *) Realloc(lpq_cache_reset,(snum+1)*sizeof(BOOL));
35 if (p) {
36 lpq_cache_reset=p;
37 lpq_caches = snum+1;
40 return lpq_caches;
43 void lpq_reset(int snum)
45 if (check_lpq_cache(snum) > snum) lpq_cache_reset[snum]=True;
49 /****************************************************************************
50 Build the print command in the supplied buffer. This means getting the
51 print command for the service and inserting the printer name and the
52 print file name. Return NULL on error, else the passed buffer pointer.
53 ****************************************************************************/
54 static char *build_print_command(int cnum, char *command, char *syscmd, char *filename1)
56 int snum = SNUM(cnum);
57 char *tstr;
58 pstring filename;
60 /* get the print command for the service. */
61 tstr = command;
62 if (!syscmd || !tstr) {
63 DEBUG(0,("No print command for service `%s'\n", SERVICE(snum)));
64 return (NULL);
67 /* copy the command into the buffer for extensive meddling. */
68 StrnCpy(syscmd, tstr, sizeof(pstring) - 1);
70 /* look for "%s" in the string. If there is no %s, we cannot print. */
71 if (!strstr(syscmd, "%s") && !strstr(syscmd, "%f")) {
72 DEBUG(2,("WARNING! No placeholder for the filename in the print command for service %s!\n", SERVICE(snum)));
75 if (strstr(syscmd,"%s")) {
76 int iOffset = PTR_DIFF(strstr(syscmd, "%s"),syscmd);
78 /* construct the full path for the filename, shouldn't be necessary unless
79 the subshell causes a "cd" to be executed.
80 Only use the full path if there isn't a / preceding the %s */
81 if (iOffset==0 || syscmd[iOffset-1] != '/') {
82 StrnCpy(filename,Connections[cnum].connectpath,sizeof(filename)-1);
83 trim_string(filename,"","/");
84 strcat(filename,"/");
85 strcat(filename,filename1);
87 else
88 strcpy(filename,filename1);
90 string_sub(syscmd, "%s", filename);
93 string_sub(syscmd, "%f", filename1);
95 /* Does the service have a printername? If not, make a fake and empty */
96 /* printer name. That way a %p is treated sanely if no printer */
97 /* name was specified to replace it. This eventuality is logged. */
98 tstr = PRINTERNAME(snum);
99 if (tstr == NULL || tstr[0] == '\0') {
100 DEBUG(3,( "No printer name - using %s.\n", SERVICE(snum)));
101 tstr = SERVICE(snum);
104 string_sub(syscmd, "%p", tstr);
106 standard_sub(cnum,syscmd);
108 return (syscmd);
112 /****************************************************************************
113 print a file - called on closing the file
114 ****************************************************************************/
115 void print_file(int fnum)
117 pstring syscmd;
118 int cnum = Files[fnum].cnum;
119 int snum=SNUM(cnum);
120 char *tempstr;
122 *syscmd = 0;
124 if (file_size(Files[fnum].name) <= 0) {
125 DEBUG(3,("Discarding null print job %s\n",Files[fnum].name));
126 sys_unlink(Files[fnum].name);
127 return;
130 tempstr = build_print_command(cnum, PRINTCOMMAND(snum), syscmd, Files[fnum].name);
131 if (tempstr != NULL)
133 int ret = smbrun(syscmd,NULL,False);
134 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
136 else
137 DEBUG(0,("Null print command?\n"));
139 lpq_reset(snum);
142 static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
143 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
146 /*******************************************************************
147 process time fields
148 ********************************************************************/
149 static time_t EntryTime(string tok[], int ptr, int count, int minimum)
151 time_t jobtime,jobtime1;
153 jobtime = time(NULL); /* default case: take current time */
154 if (count >= minimum) {
155 struct tm *t;
156 int i, day, hour, min, sec;
157 char *c;
159 for (i=0; i<13; i++) if (!strncmp(tok[ptr], Months[i],3)) break; /* Find month */
160 if (i<12) {
161 t = localtime(&jobtime);
162 day = atoi(tok[ptr+1]);
163 c=(char *)(tok[ptr+2]);
164 *(c+2)=0;
165 hour = atoi(c);
166 *(c+5)=0;
167 min = atoi(c+3);
168 if(*(c+6) != 0)sec = atoi(c+6);
169 else sec=0;
171 if ((t->tm_mon < i)||
172 ((t->tm_mon == i)&&
173 ((t->tm_mday < day)||
174 ((t->tm_mday == day)&&
175 (t->tm_hour*60+t->tm_min < hour*60+min)))))
176 t->tm_year--; /* last year's print job */
178 t->tm_mon = i;
179 t->tm_mday = day;
180 t->tm_hour = hour;
181 t->tm_min = min;
182 t->tm_sec = sec;
183 jobtime1 = mktime(t);
184 if (jobtime1 != (time_t)-1)
185 jobtime = jobtime1;
188 return jobtime;
192 /****************************************************************************
193 parse a lpq line
195 here is an example of lpq output under bsd
197 Warning: no daemon present
198 Rank Owner Job Files Total Size
199 1st tridge 148 README 8096 bytes
201 here is an example of lpq output under osf/1
203 Warning: no daemon present
204 Rank Pri Owner Job Files Total Size
205 1st 0 tridge 148 README 8096 bytes
206 ****************************************************************************/
207 static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
209 #ifdef OSF1
210 #define RANKTOK 0
211 #define PRIOTOK 1
212 #define USERTOK 2
213 #define JOBTOK 3
214 #define FILETOK 4
215 #define TOTALTOK 5
216 #define NTOK 6
217 #else /* OSF1 */
218 #define RANKTOK 0
219 #define USERTOK 1
220 #define JOBTOK 2
221 #define FILETOK 3
222 #define TOTALTOK 4
223 #define NTOK 5
224 #endif /* OSF1 */
226 string tok[NTOK];
227 int count=0;
229 #ifdef OSF1
230 int length;
231 length = strlen(line);
232 if (line[length-3] == ':')
233 return(False);
234 #endif /* OSF1 */
236 /* handle the case of "(standard input)" as a filename */
237 string_sub(line,"standard input","STDIN");
238 string_sub(line,"(","\"");
239 string_sub(line,")","\"");
241 for (count=0; count<NTOK && next_token(&line,tok[count],NULL); count++) ;
243 /* we must get NTOK tokens */
244 if (count < NTOK)
245 return(False);
247 /* the Job and Total columns must be integer */
248 if (!isdigit(*tok[JOBTOK]) || !isdigit(*tok[TOTALTOK])) return(False);
250 /* if the fname contains a space then use STDIN */
251 if (strchr(tok[FILETOK],' '))
252 strcpy(tok[FILETOK],"STDIN");
254 /* only take the last part of the filename */
256 string tmp;
257 char *p = strrchr(tok[FILETOK],'/');
258 if (p)
260 strcpy(tmp,p+1);
261 strcpy(tok[FILETOK],tmp);
266 buf->job = atoi(tok[JOBTOK]);
267 buf->size = atoi(tok[TOTALTOK]);
268 buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
269 buf->time = time(NULL);
270 StrnCpy(buf->user,tok[USERTOK],sizeof(buf->user)-1);
271 StrnCpy(buf->file,tok[FILETOK],sizeof(buf->file)-1);
272 #ifdef PRIOTOK
273 buf->priority = atoi(tok[PRIOTOK]);
274 #else
275 buf->priority = 1;
276 #endif
277 return(True);
281 <magnus@hum.auc.dk>
282 LPRng_time modifies the current date by inserting the hour and minute from
283 the lpq output. The lpq time looks like "23:15:07"
285 static time_t LPRng_time(string tok[],int pos)
287 time_t jobtime;
288 struct tm *t;
289 char tmp_time[9];
291 jobtime = time(NULL); /* default case: take current time */
292 t = localtime(&jobtime);
293 t->tm_hour = atoi(tok[pos]);
294 StrnCpy(tmp_time,tok[pos],sizeof(tmp_time));
295 t->tm_min = atoi(tmp_time+3);
296 t->tm_sec = atoi(tmp_time+6);
297 jobtime = mktime(t);
299 return jobtime;
303 /****************************************************************************
304 parse a lpq line
305 <magnus@hum.auc.dk>
306 Most of the code is directly reused from parse_lpq_bsd()
308 here are two examples of lpq output under lprng (LPRng-2.3.0)
310 Printer: humprn@hum-fak
311 Queue: 1 printable job
312 Server: pid 4840 active, Unspooler: pid 4841 active
313 Status: job 'cfA659hum-fak', closing device at Fri Jun 21 10:10:21 1996
314 Rank Owner Class Job Files Size Time
315 active magnus@hum-fak A 659 /var/spool/smb/Notesblok-ikke-na4024 10:03:31
317 Printer: humprn@hum-fak (printing disabled)
318 Queue: 1 printable job
319 Warning: no server present
320 Status: finished operations at Fri Jun 21 10:10:32 1996
321 Rank Owner Class Job Files Size Time
322 1 magnus@hum-fak A 387 /var/spool/smb/netbudget.xls 21230 10:50:53
324 ****************************************************************************/
325 static BOOL parse_lpq_lprng(char *line,print_queue_struct *buf,BOOL first)
327 #define LPRNG_RANKTOK 0
328 #define LPRNG_USERTOK 1
329 #define LPRNG_PRIOTOK 2
330 #define LPRNG_JOBTOK 3
331 #define LPRNG_FILETOK 4
332 #define LPRNG_TOTALTOK 5
333 #define LPRNG_TIMETOK 6
334 #define LPRNG_NTOK 7
336 /****************************************************************************
337 From lpd_status.c in LPRng source.
338 0 1 2 3 4 5 6 7
339 12345678901234567890123456789012345678901234567890123456789012345678901234
340 " Rank Owner Class Job Files Size Time"
341 plp_snprintf( msg, sizeof(msg), "%-6s %-19s %c %03d %-32s",
342 number, line, priority, cfp->number, error );
343 plp_snprintf( msg + len, sizeof(msg)-len, "%4d",
344 cfp->jobsize );
345 plp_snprintf( msg+len, sizeof(msg)-len, " %s",
346 Time_str( 1, cfp->statb.st_ctime ) );
347 ****************************************************************************/
348 /* The following define's are to be able to adjust the values if the
349 LPRng source changes. This is from version 2.3.0. Magnus */
350 #define SPACE_W 1
351 #define RANK_W 6
352 #define OWNER_W 19
353 #define CLASS_W 1
354 #define JOB_W 3
355 #define FILE_W 32
356 /* The JOBSIZE_W is too small for big jobs, so time is pushed to the right */
357 #define JOBSIZE_W 4
359 #define RANK_POS 0
360 #define OWNER_POS RANK_POS+RANK_W+SPACE_W
361 #define CLASS_POS OWNER_POS+OWNER_W+SPACE_W
362 #define JOB_POS CLASS_POS+CLASS_W+SPACE_W
363 #define FILE_POS JOB_POS+JOB_W+SPACE_W
364 #define JOBSIZE_POS FILE_POS+FILE_W
367 string tok[LPRNG_NTOK];
368 int count=0;
371 Need to insert one space in front of the size, to be able to use
372 next_token() unchanged. I would have liked to be able to insert a
373 space instead, to prevent losing that one char, but perl has spoiled
374 me :-\ So I did it the easiest way.
376 HINT: Use as short a path as possible for the samba spool directory.
377 A long spool-path will just waste significant chars of the file name.
380 line[JOBSIZE_POS-1]=' ';
382 /* handle the case of "(stdin)" as a filename */
383 string_sub(line,"stdin","STDIN");
384 string_sub(line,"(","\"");
385 string_sub(line,")","\"");
387 for (count=0; count<LPRNG_NTOK && next_token(&line,tok[count],NULL); count++) ;
389 /* we must get LPRNG_NTOK tokens */
390 if (count < LPRNG_NTOK)
391 return(False);
393 /* the Job and Total columns must be integer */
394 if (!isdigit(*tok[LPRNG_JOBTOK]) || !isdigit(*tok[LPRNG_TOTALTOK])) return(False);
396 /* if the fname contains a space then use STDIN */
397 /* I do not understand how this would be possible. Magnus. */
398 if (strchr(tok[LPRNG_FILETOK],' '))
399 strcpy(tok[LPRNG_FILETOK],"STDIN");
401 /* only take the last part of the filename */
403 string tmp;
404 char *p = strrchr(tok[LPRNG_FILETOK],'/');
405 if (p)
407 strcpy(tmp,p+1);
408 strcpy(tok[LPRNG_FILETOK],tmp);
413 buf->job = atoi(tok[LPRNG_JOBTOK]);
414 buf->size = atoi(tok[LPRNG_TOTALTOK]);
415 buf->status = strequal(tok[LPRNG_RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
416 /* buf->time = time(NULL); */
417 buf->time = LPRng_time(tok,LPRNG_TIMETOK);
418 DEBUG(3,("Time reported for job %d is %s", buf->job, ctime(&buf->time)));
419 StrnCpy(buf->user,tok[LPRNG_USERTOK],sizeof(buf->user)-1);
420 StrnCpy(buf->file,tok[LPRNG_FILETOK],sizeof(buf->file)-1);
421 #ifdef LPRNG_PRIOTOK
422 /* Here I try to map the CLASS char to a number, but the number
423 is never shown in Print Manager under NT anyway... Magnus. */
424 buf->priority = atoi(tok[LPRNG_PRIOTOK]-('A'-1));
425 #else
426 buf->priority = 1;
427 #endif
428 return(True);
433 /*******************************************************************
434 parse lpq on an aix system
436 Queue Dev Status Job Files User PP % Blks Cp Rnk
437 ------- ----- --------- --- ------------------ ---------- ---- -- ----- --- ---
438 lazer lazer READY
439 lazer lazer RUNNING 537 6297doc.A kvintus@IE 0 10 2445 1 1
440 QUEUED 538 C.ps root@IEDVB 124 1 2
441 QUEUED 539 E.ps root@IEDVB 28 1 3
442 QUEUED 540 L.ps root@IEDVB 172 1 4
443 QUEUED 541 P.ps root@IEDVB 22 1 5
444 ********************************************************************/
445 static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
447 string tok[11];
448 int count=0;
450 /* handle the case of "(standard input)" as a filename */
451 string_sub(line,"standard input","STDIN");
452 string_sub(line,"(","\"");
453 string_sub(line,")","\"");
455 for (count=0; count<10 && next_token(&line,tok[count],NULL); count++) ;
457 /* we must get 6 tokens */
458 if (count < 10)
460 if ((count == 7) && (strcmp(tok[0],"QUEUED") == 0))
462 /* the 2nd and 5th columns must be integer */
463 if (!isdigit(*tok[1]) || !isdigit(*tok[4])) return(False);
464 buf->size = atoi(tok[4]) * 1024;
465 /* if the fname contains a space then use STDIN */
466 if (strchr(tok[2],' '))
467 strcpy(tok[2],"STDIN");
469 /* only take the last part of the filename */
471 string tmp;
472 char *p = strrchr(tok[2],'/');
473 if (p)
475 strcpy(tmp,p+1);
476 strcpy(tok[2],tmp);
481 buf->job = atoi(tok[1]);
482 buf->status = LPQ_QUEUED;
483 buf->priority = 0;
484 buf->time = time(NULL);
485 StrnCpy(buf->user,tok[3],sizeof(buf->user)-1);
486 StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
488 else
490 DEBUG(6,("parse_lpq_aix count=%d\n", count));
491 return(False);
494 else
496 /* the 4th and 9th columns must be integer */
497 if (!isdigit(*tok[3]) || !isdigit(*tok[8])) return(False);
498 buf->size = atoi(tok[8]) * 1024;
499 /* if the fname contains a space then use STDIN */
500 if (strchr(tok[4],' '))
501 strcpy(tok[4],"STDIN");
503 /* only take the last part of the filename */
505 string tmp;
506 char *p = strrchr(tok[4],'/');
507 if (p)
509 strcpy(tmp,p+1);
510 strcpy(tok[4],tmp);
515 buf->job = atoi(tok[3]);
516 buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED;
517 buf->priority = 0;
518 buf->time = time(NULL);
519 StrnCpy(buf->user,tok[5],sizeof(buf->user)-1);
520 StrnCpy(buf->file,tok[4],sizeof(buf->file)-1);
524 return(True);
528 /****************************************************************************
529 parse a lpq line
530 here is an example of lpq output under hpux; note there's no space after -o !
531 $> lpstat -oljplus
532 ljplus-2153 user priority 0 Jan 19 08:14 on ljplus
533 util.c 125697 bytes
534 server.c 110712 bytes
535 ljplus-2154 user priority 0 Jan 19 08:14 from client
536 (standard input) 7551 bytes
537 ****************************************************************************/
538 static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
540 /* must read two lines to process, therefore keep some values static */
541 static BOOL header_line_ok=False, base_prio_reset=False;
542 static string jobuser;
543 static int jobid;
544 static int jobprio;
545 static time_t jobtime;
546 static int jobstat=LPQ_QUEUED;
547 /* to store minimum priority to print, lpstat command should be invoked
548 with -p option first, to work */
549 static int base_prio;
551 int count;
552 char TAB = '\011';
553 string tok[12];
555 /* If a line begins with a horizontal TAB, it is a subline type */
557 if (line[0] == TAB) { /* subline */
558 /* check if it contains the base priority */
559 if (!strncmp(line,"\tfence priority : ",18)) {
560 base_prio=atoi(&line[18]);
561 DEBUG(4, ("fence priority set at %d\n", base_prio));
563 if (!header_line_ok) return (False); /* incorrect header line */
564 /* handle the case of "(standard input)" as a filename */
565 string_sub(line,"standard input","STDIN");
566 string_sub(line,"(","\"");
567 string_sub(line,")","\"");
569 for (count=0; count<2 && next_token(&line,tok[count],NULL); count++) ;
570 /* we must get 2 tokens */
571 if (count < 2) return(False);
573 /* the 2nd column must be integer */
574 if (!isdigit(*tok[1])) return(False);
576 /* if the fname contains a space then use STDIN */
577 if (strchr(tok[0],' '))
578 strcpy(tok[0],"STDIN");
580 buf->size = atoi(tok[1]);
581 StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
583 /* fill things from header line */
584 buf->time = jobtime;
585 buf->job = jobid;
586 buf->status = jobstat;
587 buf->priority = jobprio;
588 StrnCpy(buf->user,jobuser,sizeof(buf->user)-1);
590 return(True);
592 else { /* header line */
593 header_line_ok=False; /* reset it */
594 if (first) {
595 if (!base_prio_reset) {
596 base_prio=0; /* reset it */
597 base_prio_reset=True;
600 else if (base_prio) base_prio_reset=False;
602 /* handle the dash in the job id */
603 string_sub(line,"-"," ");
605 for (count=0; count<12 && next_token(&line,tok[count],NULL); count++) ;
607 /* we must get 8 tokens */
608 if (count < 8) return(False);
610 /* first token must be printer name (cannot check ?) */
611 /* the 2nd, 5th & 7th column must be integer */
612 if (!isdigit(*tok[1]) || !isdigit(*tok[4]) || !isdigit(*tok[6])) return(False);
613 jobid = atoi(tok[1]);
614 StrnCpy(jobuser,tok[2],sizeof(buf->user)-1);
615 jobprio = atoi(tok[4]);
617 /* process time */
618 jobtime=EntryTime(tok, 5, count, 8);
619 if (jobprio < base_prio) {
620 jobstat = LPQ_PAUSED;
621 DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n", jobid, jobprio, base_prio, jobstat));
623 else {
624 jobstat = LPQ_QUEUED;
625 if ((count >8) && (((strequal(tok[8],"on")) ||
626 ((strequal(tok[8],"from")) &&
627 ((count > 10)&&(strequal(tok[10],"on")))))))
628 jobstat = LPQ_PRINTING;
631 header_line_ok=True; /* information is correct */
632 return(False); /* need subline info to include into queuelist */
637 /****************************************************************************
638 parse a lpq line
640 here is an example of "lpstat -o dcslw" output under sysv
642 dcslw-896 tridge 4712 Dec 20 10:30:30 on dcslw
643 dcslw-897 tridge 4712 Dec 20 10:30:30 being held
645 ****************************************************************************/
646 static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
648 string tok[9];
649 int count=0;
650 char *p;
652 /* handle the dash in the job id */
653 string_sub(line,"-"," ");
655 for (count=0; count<9 && next_token(&line,tok[count],NULL); count++) ;
657 /* we must get 7 tokens */
658 if (count < 7)
659 return(False);
661 /* the 2nd and 4th, 6th columns must be integer */
662 if (!isdigit(*tok[1]) || !isdigit(*tok[3])) return(False);
663 if (!isdigit(*tok[5])) return(False);
665 /* if the user contains a ! then trim the first part of it */
666 if ((p=strchr(tok[2],'!')))
668 string tmp;
669 strcpy(tmp,p+1);
670 strcpy(tok[2],tmp);
674 buf->job = atoi(tok[1]);
675 buf->size = atoi(tok[3]);
676 if (count > 7 && strequal(tok[7],"on"))
677 buf->status = LPQ_PRINTING;
678 else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held"))
679 buf->status = LPQ_PAUSED;
680 else
681 buf->status = LPQ_QUEUED;
682 buf->priority = 0;
683 buf->time = EntryTime(tok, 4, count, 7);
684 StrnCpy(buf->user,tok[2],sizeof(buf->user)-1);
685 StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
686 return(True);
689 /****************************************************************************
690 parse a lpq line
692 here is an example of lpq output under qnx
693 Spooler: /qnx/spooler, on node 1
694 Printer: txt (ready)
695 0000: root [job #1 ] active 1146 bytes /etc/profile
696 0001: root [job #2 ] ready 2378 bytes /etc/install
697 0002: root [job #3 ] ready 1146 bytes -- standard input --
698 ****************************************************************************/
699 static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
701 string tok[7];
702 int count=0;
704 DEBUG(0,("antes [%s]\n", line));
706 /* handle the case of "-- standard input --" as a filename */
707 string_sub(line,"standard input","STDIN");
708 DEBUG(0,("despues [%s]\n", line));
709 string_sub(line,"-- ","\"");
710 string_sub(line," --","\"");
711 DEBUG(0,("despues 1 [%s]\n", line));
713 string_sub(line,"[job #","");
714 string_sub(line,"]","");
715 DEBUG(0,("despues 2 [%s]\n", line));
719 for (count=0; count<7 && next_token(&line,tok[count],NULL); count++) ;
721 /* we must get 7 tokens */
722 if (count < 7)
723 return(False);
725 /* the 3rd and 5th columns must be integer */
726 if (!isdigit(*tok[2]) || !isdigit(*tok[4])) return(False);
728 /* only take the last part of the filename */
730 string tmp;
731 char *p = strrchr(tok[6],'/');
732 if (p)
734 strcpy(tmp,p+1);
735 strcpy(tok[6],tmp);
740 buf->job = atoi(tok[2]);
741 buf->size = atoi(tok[4]);
742 buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED;
743 buf->priority = 0;
744 buf->time = time(NULL);
745 StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
746 StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
747 return(True);
751 /****************************************************************************
752 parse a lpq line for the plp printing system
753 Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
755 redone by tridge. Here is a sample queue:
757 Local Printer 'lp2' (fjall):
758 Printing (started at Jun 15 13:33:58, attempt 1).
759 Rank Owner Pr Opt Job Host Files Size Date
760 active tridge X - 6 fjall /etc/hosts 739 Jun 15 13:33
761 3rd tridge X - 7 fjall /etc/hosts 739 Jun 15 13:33
763 ****************************************************************************/
764 static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
766 string tok[11];
767 int count=0;
769 /* handle the case of "(standard input)" as a filename */
770 string_sub(line,"stdin","STDIN");
771 string_sub(line,"(","\"");
772 string_sub(line,")","\"");
774 for (count=0; count<11 && next_token(&line,tok[count],NULL); count++) ;
776 /* we must get 11 tokens */
777 if (count < 11)
778 return(False);
780 /* the first must be "active" or begin with an integer */
781 if (strcmp(tok[0],"active") && !isdigit(tok[0][0]))
782 return(False);
784 /* the 5th and 8th must be integer */
785 if (!isdigit(*tok[4]) || !isdigit(*tok[7]))
786 return(False);
788 /* if the fname contains a space then use STDIN */
789 if (strchr(tok[6],' '))
790 strcpy(tok[6],"STDIN");
792 /* only take the last part of the filename */
794 string tmp;
795 char *p = strrchr(tok[6],'/');
796 if (p)
798 strcpy(tmp,p+1);
799 strcpy(tok[6],tmp);
804 buf->job = atoi(tok[4]);
806 buf->size = atoi(tok[7]);
807 if (strchr(tok[7],'K'))
808 buf->size *= 1024;
809 if (strchr(tok[7],'M'))
810 buf->size *= 1024*1024;
812 buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
813 buf->priority = 0;
814 buf->time = time(NULL);
815 StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
816 StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
817 return(True);
822 char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
823 char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
824 char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
826 /****************************************************************************
827 parse a lpq line. Choose printing style
828 ****************************************************************************/
829 static BOOL parse_lpq_entry(int snum,char *line,
830 print_queue_struct *buf,
831 print_status_struct *status,BOOL first)
833 BOOL ret;
835 switch (lp_printing())
837 case PRINT_SYSV:
838 ret = parse_lpq_sysv(line,buf,first);
839 break;
840 case PRINT_AIX:
841 ret = parse_lpq_aix(line,buf,first);
842 break;
843 case PRINT_HPUX:
844 ret = parse_lpq_hpux(line,buf,first);
845 break;
846 case PRINT_QNX:
847 ret = parse_lpq_qnx(line,buf,first);
848 break;
849 case PRINT_LPRNG:
850 ret = parse_lpq_lprng(line,buf,first);
851 break;
852 case PRINT_PLP:
853 ret = parse_lpq_plp(line,buf,first);
854 break;
855 default:
856 ret = parse_lpq_bsd(line,buf,first);
857 break;
860 #ifdef LPQ_GUEST_TO_USER
861 if (ret) {
862 extern pstring sesssetup_user;
863 /* change guest entries to the current logged in user to make
864 them appear deletable to windows */
865 if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
866 strcpy(buf->user,sesssetup_user);
868 #endif
870 /* We don't want the newline in the status message. */
872 char *p = strchr(line,'\n');
873 if (p) *p = 0;
876 if (status && !ret)
878 /* a few simple checks to see if the line might be a
879 printer status line:
880 handle them so that most severe condition is shown */
881 int i;
882 strlower(line);
884 switch (status->status) {
885 case LPSTAT_OK:
886 for (i=0; stat0_strings[i]; i++)
887 if (strstr(line,stat0_strings[i])) {
888 StrnCpy(status->message,line,sizeof(status->message)-1);
889 status->status=LPSTAT_OK;
891 case LPSTAT_STOPPED:
892 for (i=0; stat1_strings[i]; i++)
893 if (strstr(line,stat1_strings[i])) {
894 StrnCpy(status->message,line,sizeof(status->message)-1);
895 status->status=LPSTAT_STOPPED;
897 case LPSTAT_ERROR:
898 for (i=0; stat2_strings[i]; i++)
899 if (strstr(line,stat2_strings[i])) {
900 StrnCpy(status->message,line,sizeof(status->message)-1);
901 status->status=LPSTAT_ERROR;
903 break;
907 return(ret);
910 /****************************************************************************
911 get a printer queue
912 ****************************************************************************/
913 int get_printqueue(int snum,int cnum,print_queue_struct **queue,
914 print_status_struct *status)
916 char *lpq_command = lp_lpqcommand(snum);
917 char *printername = PRINTERNAME(snum);
918 int ret=0,count=0;
919 pstring syscmd;
920 fstring outfile;
921 pstring line;
922 FILE *f;
923 struct stat sbuf;
924 BOOL dorun=True;
925 int cachetime = lp_lpqcachetime();
927 *line = 0;
928 check_lpq_cache(snum);
930 if (!printername || !*printername)
932 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
933 lp_servicename(snum),snum));
934 printername = lp_servicename(snum);
937 if (!lpq_command || !(*lpq_command))
939 DEBUG(5,("No lpq command\n"));
940 return(0);
943 strcpy(syscmd,lpq_command);
944 string_sub(syscmd,"%p",printername);
946 standard_sub(cnum,syscmd);
948 sprintf(outfile,"%s/lpq.%08x",tmpdir(),str_checksum(syscmd));
950 if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf))
952 if (time(NULL) - sbuf.st_mtime < cachetime) {
953 DEBUG(3,("Using cached lpq output\n"));
954 dorun = False;
958 if (dorun) {
959 ret = smbrun(syscmd,outfile,True);
960 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
963 lpq_cache_reset[snum] = False;
965 f = fopen(outfile,"r");
966 if (!f) {
967 return(0);
970 if (status) {
971 strcpy(status->message,"");
972 status->status = LPSTAT_OK;
975 while (fgets(line,sizeof(pstring),f))
977 DEBUG(6,("QUEUE2: %s\n",line));
979 *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
980 if (! *queue)
982 count = 0;
983 break;
986 bzero((char *)&(*queue)[count],sizeof(**queue));
988 /* parse it */
989 if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
990 continue;
992 count++;
995 fclose(f);
997 if (!cachetime) {
998 unlink(outfile);
999 } else {
1000 /* we only expect this to succeed on trapdoor systems, on normal systems
1001 the file is owned by root */
1002 chmod(outfile,0666);
1004 return(count);
1008 /****************************************************************************
1009 delete a printer queue entry
1010 ****************************************************************************/
1011 void del_printqueue(int cnum,int snum,int jobid)
1013 char *lprm_command = lp_lprmcommand(snum);
1014 char *printername = PRINTERNAME(snum);
1015 pstring syscmd;
1016 char jobstr[20];
1017 int ret;
1019 if (!printername || !*printername)
1021 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
1022 lp_servicename(snum),snum));
1023 printername = lp_servicename(snum);
1026 if (!lprm_command || !(*lprm_command))
1028 DEBUG(5,("No lprm command\n"));
1029 return;
1032 sprintf(jobstr,"%d",jobid);
1034 strcpy(syscmd,lprm_command);
1035 string_sub(syscmd,"%p",printername);
1036 string_sub(syscmd,"%j",jobstr);
1037 standard_sub(cnum,syscmd);
1039 ret = smbrun(syscmd,NULL,False);
1040 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
1041 lpq_reset(snum); /* queue has changed */
1044 /****************************************************************************
1045 change status of a printer queue entry
1046 ****************************************************************************/
1047 void status_printjob(int cnum,int snum,int jobid,int status)
1049 char *lpstatus_command =
1050 (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
1051 char *printername = PRINTERNAME(snum);
1052 pstring syscmd;
1053 char jobstr[20];
1054 int ret;
1056 if (!printername || !*printername)
1058 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
1059 lp_servicename(snum),snum));
1060 printername = lp_servicename(snum);
1063 if (!lpstatus_command || !(*lpstatus_command))
1065 DEBUG(5,("No lpstatus command to %s job\n",
1066 (status==LPQ_PAUSED?"pause":"resume")));
1067 return;
1070 sprintf(jobstr,"%d",jobid);
1072 strcpy(syscmd,lpstatus_command);
1073 string_sub(syscmd,"%p",printername);
1074 string_sub(syscmd,"%j",jobstr);
1075 standard_sub(cnum,syscmd);
1077 ret = smbrun(syscmd,NULL,False);
1078 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
1079 lpq_reset(snum); /* queue has changed */