2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1992-1995
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.
24 extern int DEBUGLEVEL;
25 extern connection_struct Connections[];
26 extern files_struct Files[];
28 static BOOL * lpq_cache_reset=NULL;
30 static int check_lpq_cache(int snum) {
31 static int lpq_caches=0;
33 if (lpq_caches <= snum) {
35 p = (BOOL *) Realloc(lpq_cache_reset,(snum+1)*sizeof(BOOL));
44 void lpq_reset(int snum)
46 if (check_lpq_cache(snum) > snum) lpq_cache_reset[snum]=True;
50 /****************************************************************************
51 Build the print command in the supplied buffer. This means getting the
52 print command for the service and inserting the printer name and the
53 print file name. Return NULL on error, else the passed buffer pointer.
54 ****************************************************************************/
55 static char *build_print_command(int cnum, char *command, char *syscmd, char *filename1)
57 int snum = SNUM(cnum);
61 /* get the print command for the service. */
63 if (!syscmd || !tstr) {
64 DEBUG(0,("No print command for service `%s'\n", SERVICE(snum)));
68 /* copy the command into the buffer for extensive meddling. */
69 StrnCpy(syscmd, tstr, sizeof(pstring) - 1);
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)));
76 if (strstr(syscmd,"%s")) {
77 int iOffset = strstr(syscmd, "%s") - syscmd;
79 /* construct the full path for the filename, shouldn't be necessary unless
80 the subshell causes a "cd" to be executed.
81 Only use the full path if there isn't a / preceding the %s */
82 if (iOffset==0 || syscmd[iOffset-1] != '/') {
83 StrnCpy(filename,Connections[cnum].connectpath,sizeof(filename)-1);
84 trim_string(filename,"","/");
86 strcat(filename,filename1);
89 strcpy(filename,filename1);
91 string_sub(syscmd, "%s", filename);
94 string_sub(syscmd, "%f", filename1);
96 /* Does the service have a printername? If not, make a fake and empty */
97 /* printer name. That way a %p is treated sanely if no printer */
98 /* name was specified to replace it. This eventuality is logged. */
99 tstr = PRINTERNAME(snum);
100 if (tstr == NULL || tstr[0] == '\0') {
101 DEBUG(3,( "No printer name - using %s.\n", SERVICE(snum)));
102 tstr = SERVICE(snum);
105 string_sub(syscmd, "%p", tstr);
107 standard_sub(cnum,syscmd);
113 /****************************************************************************
114 print a file - called on closing the file
115 ****************************************************************************/
116 void print_file(int fnum)
119 int cnum = Files[fnum].cnum;
125 if (file_size(Files[fnum].name) <= 0) {
126 DEBUG(3,("Discarding null print job %s\n",Files[fnum].name));
127 sys_unlink(Files[fnum].name);
131 tempstr = build_print_command(cnum, PRINTCOMMAND(snum), syscmd, Files[fnum].name);
134 int ret = smbrun(syscmd,NULL);
135 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
138 DEBUG(0,("Null print command?\n"));
143 static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
144 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
147 /*******************************************************************
149 ********************************************************************/
150 static time_t EntryTime(string tok[], int ptr, int count, int minimum)
154 jobtime = time(NULL); /* default case: take current time */
155 if (count >= minimum) {
157 int i, day, hour, min, sec;
160 for (i=0; i<13; i++) if (!strncmp(tok[ptr], Months[i],3)) break; /* Find month */
162 t = localtime(&jobtime);
163 day = atoi(tok[ptr+1]);
164 c=(char *)(tok[ptr+2]);
169 if(*(c+6) != 0)sec = atoi(c+6);
172 if ((t->tm_mon < i)||
174 ((t->tm_mday < day)||
175 ((t->tm_mday == day)&&
176 (t->tm_hour*60+t->tm_min < hour*60+min)))))
177 t->tm_year--; /* last year's print job */
191 /****************************************************************************
194 here is an example of lpq output under bsd
196 Warning: no daemon present
197 Rank Owner Job Files Total Size
198 1st tridge 148 README 8096 bytes
200 here is an example of lpq output under osf/1
202 Warning: no daemon present
203 Rank Pri Owner Job Files Total Size
204 1st 0 tridge 148 README 8096 bytes
205 ****************************************************************************/
206 static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
230 length = strlen(line);
231 if (line[length-3] == ':')
235 /* handle the case of "(standard input)" as a filename */
236 string_sub(line,"standard input","STDIN");
237 string_sub(line,"(","\"");
238 string_sub(line,")","\"");
240 for (count=0; count<NTOK && next_token(&line,tok[count],NULL); count++) ;
242 /* we must get NTOK tokens */
246 /* the Job and Total columns must be integer */
247 if (!isdigit(*tok[JOBTOK]) || !isdigit(*tok[TOTALTOK])) return(False);
249 /* if the fname contains a space then use STDIN */
250 if (strchr(tok[FILETOK],' '))
251 strcpy(tok[FILETOK],"STDIN");
253 /* only take the last part of the filename */
256 char *p = strrchr(tok[FILETOK],'/');
260 strcpy(tok[FILETOK],tmp);
265 buf->job = atoi(tok[JOBTOK]);
266 buf->size = atoi(tok[TOTALTOK]);
267 buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
268 buf->time = time(NULL);
269 StrnCpy(buf->user,tok[USERTOK],sizeof(buf->user)-1);
270 StrnCpy(buf->file,tok[FILETOK],sizeof(buf->file)-1);
272 buf->priority = atoi(tok[PRIOTOK]);
281 /*******************************************************************
282 parse lpq on an aix system
284 Queue Dev Status Job Files User PP % Blks Cp Rnk
285 ------- ----- --------- --- ------------------ ---------- ---- -- ----- --- ---
287 lazer lazer RUNNING 537 6297doc.A kvintus@IE 0 10 2445 1 1
288 QUEUED 538 C.ps root@IEDVB 124 1 2
289 QUEUED 539 E.ps root@IEDVB 28 1 3
290 QUEUED 540 L.ps root@IEDVB 172 1 4
291 QUEUED 541 P.ps root@IEDVB 22 1 5
292 ********************************************************************/
293 static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
298 /* handle the case of "(standard input)" as a filename */
299 string_sub(line,"standard input","STDIN");
300 string_sub(line,"(","\"");
301 string_sub(line,")","\"");
303 for (count=0; count<10 && next_token(&line,tok[count],NULL); count++) ;
305 /* we must get 6 tokens */
308 if ((count == 7) && (strcmp(tok[0],"QUEUED") == 0))
310 /* the 2nd and 5th columns must be integer */
311 if (!isdigit(*tok[1]) || !isdigit(*tok[4])) return(False);
312 buf->size = atoi(tok[4]) * 1024;
313 /* if the fname contains a space then use STDIN */
314 if (strchr(tok[2],' '))
315 strcpy(tok[2],"STDIN");
317 /* only take the last part of the filename */
320 char *p = strrchr(tok[2],'/');
329 buf->job = atoi(tok[1]);
330 buf->status = LPQ_QUEUED;
332 buf->time = time(NULL);
333 StrnCpy(buf->user,tok[3],sizeof(buf->user)-1);
334 StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
338 DEBUG(6,("parse_lpq_aix count=%d\n", count));
344 /* the 4th and 9th columns must be integer */
345 if (!isdigit(*tok[3]) || !isdigit(*tok[8])) return(False);
346 buf->size = atoi(tok[8]) * 1024;
347 /* if the fname contains a space then use STDIN */
348 if (strchr(tok[4],' '))
349 strcpy(tok[4],"STDIN");
351 /* only take the last part of the filename */
354 char *p = strrchr(tok[4],'/');
363 buf->job = atoi(tok[3]);
364 buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED;
366 buf->time = time(NULL);
367 StrnCpy(buf->user,tok[5],sizeof(buf->user)-1);
368 StrnCpy(buf->file,tok[4],sizeof(buf->file)-1);
376 /****************************************************************************
378 here is an example of lpq output under hpux; note there's no space after -o !
380 ljplus-2153 user priority 0 Jan 19 08:14 on ljplus
382 server.c 110712 bytes
383 ljplus-2154 user priority 0 Jan 19 08:14 from client
384 (standard input) 7551 bytes
385 ****************************************************************************/
386 static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
388 /* must read two lines to process, therefore keep some values static */
389 static BOOL header_line_ok=False, base_prio_reset=False;
390 static string jobuser;
393 static time_t jobtime;
394 static int jobstat=LPQ_QUEUED;
395 /* to store minimum priority to print, lpstat command should be invoked
396 with -p option first, to work */
397 static int base_prio;
403 /* If a line begins with a horizontal TAB, it is a subline type */
405 if (line[0] == TAB) { /* subline */
406 /* check if it contains the base priority */
407 if (!strncmp(line,"\tfence priority : ",18)) {
408 base_prio=atoi(&line[18]);
409 DEBUG(4, ("fence priority set at %d\n", base_prio));
411 if (!header_line_ok) return (False); /* incorrect header line */
412 /* handle the case of "(standard input)" as a filename */
413 string_sub(line,"standard input","STDIN");
414 string_sub(line,"(","\"");
415 string_sub(line,")","\"");
417 for (count=0; count<2 && next_token(&line,tok[count],NULL); count++) ;
418 /* we must get 2 tokens */
419 if (count < 2) return(False);
421 /* the 2nd column must be integer */
422 if (!isdigit(*tok[1])) return(False);
424 /* if the fname contains a space then use STDIN */
425 if (strchr(tok[0],' '))
426 strcpy(tok[0],"STDIN");
428 buf->size = atoi(tok[1]);
429 StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
431 /* fill things from header line */
434 buf->status = jobstat;
435 buf->priority = jobprio;
436 StrnCpy(buf->user,jobuser,sizeof(buf->user)-1);
440 else { /* header line */
441 header_line_ok=False; /* reset it */
443 if (!base_prio_reset) {
444 base_prio=0; /* reset it */
445 base_prio_reset=True;
448 else if (base_prio) base_prio_reset=False;
450 /* handle the dash in the job id */
451 string_sub(line,"-"," ");
453 for (count=0; count<12 && next_token(&line,tok[count],NULL); count++) ;
455 /* we must get 8 tokens */
456 if (count < 8) return(False);
458 /* first token must be printer name (cannot check ?) */
459 /* the 2nd, 5th & 7th column must be integer */
460 if (!isdigit(*tok[1]) || !isdigit(*tok[4]) || !isdigit(*tok[6])) return(False);
461 jobid = atoi(tok[1]);
462 StrnCpy(jobuser,tok[2],sizeof(buf->user)-1);
463 jobprio = atoi(tok[4]);
466 jobtime=EntryTime(tok, 5, count, 8);
467 if (jobprio < base_prio) {
468 jobstat = LPQ_PAUSED;
469 DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n", jobid, jobprio, base_prio, jobstat));
472 jobstat = LPQ_QUEUED;
473 if ((count >8) && (((strequal(tok[8],"on")) ||
474 ((strequal(tok[8],"from")) &&
475 ((count > 10)&&(strequal(tok[10],"on")))))))
476 jobstat = LPQ_PRINTING;
479 header_line_ok=True; /* information is correct */
480 return(False); /* need subline info to include into queuelist */
485 /****************************************************************************
488 here is an example of "lpstat -o dcslw" output under sysv
490 dcslw-896 tridge 4712 Dec 20 10:30:30 on dcslw
491 dcslw-897 tridge 4712 Dec 20 10:30:30 being held
493 ****************************************************************************/
494 static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
500 /* handle the dash in the job id */
501 string_sub(line,"-"," ");
503 for (count=0; count<9 && next_token(&line,tok[count],NULL); count++) ;
505 /* we must get 7 tokens */
509 /* the 2nd and 4th, 6th columns must be integer */
510 if (!isdigit(*tok[1]) || !isdigit(*tok[3])) return(False);
511 if (!isdigit(*tok[5])) return(False);
513 /* if the user contains a ! then trim the first part of it */
514 if ((p=strchr(tok[2],'!')))
522 buf->job = atoi(tok[1]);
523 buf->size = atoi(tok[3]);
524 if (count > 7 && strequal(tok[7],"on"))
525 buf->status = LPQ_PRINTING;
526 else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held"))
527 buf->status = LPQ_PAUSED;
529 buf->status = LPQ_QUEUED;
531 buf->time = EntryTime(tok, 4, count, 7);
532 StrnCpy(buf->user,tok[2],sizeof(buf->user)-1);
533 StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
537 /****************************************************************************
540 here is an example of lpq output under qnx
541 Spooler: /qnx/spooler, on node 1
543 0000: root [job #1 ] active 1146 bytes /etc/profile
544 0001: root [job #2 ] ready 2378 bytes /etc/install
545 0002: root [job #3 ] ready 1146 bytes -- standard input --
546 ****************************************************************************/
547 static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
552 DEBUG(0,("antes [%s]\n", line));
554 /* handle the case of "-- standard input --" as a filename */
555 string_sub(line,"standard input","STDIN");
556 DEBUG(0,("despues [%s]\n", line));
557 string_sub(line,"-- ","\"");
558 string_sub(line," --","\"");
559 DEBUG(0,("despues 1 [%s]\n", line));
561 string_sub(line,"[job #","");
562 string_sub(line,"]","");
563 DEBUG(0,("despues 2 [%s]\n", line));
567 for (count=0; count<7 && next_token(&line,tok[count],NULL); count++) ;
569 /* we must get 7 tokens */
573 /* the 3rd and 5th columns must be integer */
574 if (!isdigit(*tok[2]) || !isdigit(*tok[4])) return(False);
576 /* only take the last part of the filename */
579 char *p = strrchr(tok[6],'/');
588 buf->job = atoi(tok[2]);
589 buf->size = atoi(tok[4]);
590 buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED;
592 buf->time = time(NULL);
593 StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
594 StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
600 char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
601 char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
602 char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
604 /****************************************************************************
605 parse a lpq line. Choose printing style
606 ****************************************************************************/
607 static BOOL parse_lpq_entry(int snum,char *line,
608 print_queue_struct *buf,
609 print_status_struct *status,BOOL first)
613 switch (lp_printing())
616 ret = parse_lpq_sysv(line,buf,first);
619 ret = parse_lpq_aix(line,buf,first);
622 ret = parse_lpq_hpux(line,buf,first);
625 ret = parse_lpq_qnx(line,buf,first);
628 ret = parse_lpq_bsd(line,buf,first);
632 #ifdef LPQ_GUEST_TO_USER
634 extern pstring sesssetup_user;
635 /* change guest entries to the current logged in user to make
636 them appear deletable to windows */
637 if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
638 strcpy(buf->user,sesssetup_user);
644 /* a few simple checks to see if the line might be a
646 handle them so that most severe condition is shown */
650 switch (status->status) {
652 for (i=0; stat0_strings[i]; i++)
653 if (strstr(line,stat0_strings[i])) {
654 StrnCpy(status->message,line,sizeof(status->message)-1);
655 status->status=LPSTAT_OK;
658 for (i=0; stat1_strings[i]; i++)
659 if (strstr(line,stat1_strings[i])) {
660 StrnCpy(status->message,line,sizeof(status->message)-1);
661 status->status=LPSTAT_STOPPED;
664 for (i=0; stat2_strings[i]; i++)
665 if (strstr(line,stat2_strings[i])) {
666 StrnCpy(status->message,line,sizeof(status->message)-1);
667 status->status=LPSTAT_ERROR;
676 /****************************************************************************
678 ****************************************************************************/
679 int get_printqueue(int snum,int cnum,print_queue_struct **queue,
680 print_status_struct *status)
682 char *lpq_command = lp_lpqcommand(snum);
683 char *printername = PRINTERNAME(snum);
691 int cachetime = lp_lpqcachetime();
695 check_lpq_cache(snum);
697 if (!printername || !*printername)
699 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
700 lp_servicename(snum),snum));
701 printername = lp_servicename(snum);
704 if (!lpq_command || !(*lpq_command))
706 DEBUG(5,("No lpq command\n"));
710 strcpy(syscmd,lpq_command);
711 string_sub(syscmd,"%p",printername);
713 standard_sub(cnum,syscmd);
715 sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
717 if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf))
719 if (time(NULL) - sbuf.st_mtime < cachetime) {
720 DEBUG(3,("Using cached lpq output\n"));
725 lfd = file_lock(outfile,LPQ_LOCK_TIMEOUT);
727 (!fstat(lfd,&sbuf) && (time(NULL) - sbuf.st_mtime)<cachetime)) {
728 DEBUG(3,("Using cached lpq output\n"));
730 file_unlock(lfd); lfd = -1;
736 ret = smbrun(syscmd,outfile);
737 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
740 lpq_cache_reset[snum] = False;
742 f = fopen(outfile,"r");
744 if (lfd >= 0) file_unlock(lfd);
749 strcpy(status->message,"");
750 status->status = LPSTAT_OK;
753 while (fgets(line,sizeof(pstring),f))
755 DEBUG(6,("QUEUE2: %s\n",line));
757 *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
764 bzero((char *)&(*queue)[count],sizeof(**queue));
767 if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
775 if (lfd >= 0) file_unlock(lfd);
785 /****************************************************************************
786 delete a printer queue entry
787 ****************************************************************************/
788 void del_printqueue(int cnum,int snum,int jobid)
790 char *lprm_command = lp_lprmcommand(snum);
791 char *printername = PRINTERNAME(snum);
796 if (!printername || !*printername)
798 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
799 lp_servicename(snum),snum));
800 printername = lp_servicename(snum);
803 if (!lprm_command || !(*lprm_command))
805 DEBUG(5,("No lprm command\n"));
809 sprintf(jobstr,"%d",jobid);
811 strcpy(syscmd,lprm_command);
812 string_sub(syscmd,"%p",printername);
813 string_sub(syscmd,"%j",jobstr);
814 standard_sub(cnum,syscmd);
816 ret = smbrun(syscmd,NULL);
817 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
818 lpq_reset(snum); /* queue has changed */
821 /****************************************************************************
822 change status of a printer queue entry
823 ****************************************************************************/
824 void status_printjob(int cnum,int snum,int jobid,int status)
826 char *lpstatus_command =
827 (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
828 char *printername = PRINTERNAME(snum);
833 if (!printername || !*printername)
835 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
836 lp_servicename(snum),snum));
837 printername = lp_servicename(snum);
840 if (!lpstatus_command || !(*lpstatus_command))
842 DEBUG(5,("No lpstatus command to %s job\n",
843 (status==LPQ_PAUSED?"pause":"resume")));
847 sprintf(jobstr,"%d",jobid);
849 strcpy(syscmd,lpstatus_command);
850 string_sub(syscmd,"%p",printername);
851 string_sub(syscmd,"%j",jobstr);
852 standard_sub(cnum,syscmd);
854 ret = smbrun(syscmd,NULL);
855 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
856 lpq_reset(snum); /* queue has changed */