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.
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) {
34 p = (BOOL *) Realloc(lpq_cache_reset,(snum+1)*sizeof(BOOL));
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);
60 /* get the print command for the service. */
62 if (!syscmd || !tstr) {
63 DEBUG(0,("No print command for service `%s'\n", SERVICE(snum)));
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,"","/");
85 strcat(filename,filename1);
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);
112 /****************************************************************************
113 print a file - called on closing the file
114 ****************************************************************************/
115 void print_file(int fnum)
118 int cnum = Files[fnum].cnum;
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);
130 tempstr = build_print_command(cnum, PRINTCOMMAND(snum), syscmd, Files[fnum].name);
133 int ret = smbrun(syscmd,NULL);
134 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
137 DEBUG(0,("Null print command?\n"));
142 static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
143 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
146 /*******************************************************************
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) {
156 int i, day, hour, min, sec;
159 for (i=0; i<13; i++) if (!strncmp(tok[ptr], Months[i],3)) break; /* Find month */
161 t = localtime(&jobtime);
162 day = atoi(tok[ptr+1]);
163 c=(char *)(tok[ptr+2]);
168 if(*(c+6) != 0)sec = atoi(c+6);
171 if ((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 */
183 jobtime1 = mktime(t);
184 if (jobtime1 != (time_t)-1)
192 /****************************************************************************
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)
231 length = strlen(line);
232 if (line[length-3] == ':')
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 */
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 */
257 char *p = strrchr(tok[FILETOK],'/');
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);
273 buf->priority = atoi(tok[PRIOTOK]);
282 /*******************************************************************
283 parse lpq on an aix system
285 Queue Dev Status Job Files User PP % Blks Cp Rnk
286 ------- ----- --------- --- ------------------ ---------- ---- -- ----- --- ---
288 lazer lazer RUNNING 537 6297doc.A kvintus@IE 0 10 2445 1 1
289 QUEUED 538 C.ps root@IEDVB 124 1 2
290 QUEUED 539 E.ps root@IEDVB 28 1 3
291 QUEUED 540 L.ps root@IEDVB 172 1 4
292 QUEUED 541 P.ps root@IEDVB 22 1 5
293 ********************************************************************/
294 static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
299 /* handle the case of "(standard input)" as a filename */
300 string_sub(line,"standard input","STDIN");
301 string_sub(line,"(","\"");
302 string_sub(line,")","\"");
304 for (count=0; count<10 && next_token(&line,tok[count],NULL); count++) ;
306 /* we must get 6 tokens */
309 if ((count == 7) && (strcmp(tok[0],"QUEUED") == 0))
311 /* the 2nd and 5th columns must be integer */
312 if (!isdigit(*tok[1]) || !isdigit(*tok[4])) return(False);
313 buf->size = atoi(tok[4]) * 1024;
314 /* if the fname contains a space then use STDIN */
315 if (strchr(tok[2],' '))
316 strcpy(tok[2],"STDIN");
318 /* only take the last part of the filename */
321 char *p = strrchr(tok[2],'/');
330 buf->job = atoi(tok[1]);
331 buf->status = LPQ_QUEUED;
333 buf->time = time(NULL);
334 StrnCpy(buf->user,tok[3],sizeof(buf->user)-1);
335 StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
339 DEBUG(6,("parse_lpq_aix count=%d\n", count));
345 /* the 4th and 9th columns must be integer */
346 if (!isdigit(*tok[3]) || !isdigit(*tok[8])) return(False);
347 buf->size = atoi(tok[8]) * 1024;
348 /* if the fname contains a space then use STDIN */
349 if (strchr(tok[4],' '))
350 strcpy(tok[4],"STDIN");
352 /* only take the last part of the filename */
355 char *p = strrchr(tok[4],'/');
364 buf->job = atoi(tok[3]);
365 buf->status = strequal(tok[2],"RUNNING")?LPQ_PRINTING:LPQ_QUEUED;
367 buf->time = time(NULL);
368 StrnCpy(buf->user,tok[5],sizeof(buf->user)-1);
369 StrnCpy(buf->file,tok[4],sizeof(buf->file)-1);
377 /****************************************************************************
379 here is an example of lpq output under hpux; note there's no space after -o !
381 ljplus-2153 user priority 0 Jan 19 08:14 on ljplus
383 server.c 110712 bytes
384 ljplus-2154 user priority 0 Jan 19 08:14 from client
385 (standard input) 7551 bytes
386 ****************************************************************************/
387 static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
389 /* must read two lines to process, therefore keep some values static */
390 static BOOL header_line_ok=False, base_prio_reset=False;
391 static string jobuser;
394 static time_t jobtime;
395 static int jobstat=LPQ_QUEUED;
396 /* to store minimum priority to print, lpstat command should be invoked
397 with -p option first, to work */
398 static int base_prio;
404 /* If a line begins with a horizontal TAB, it is a subline type */
406 if (line[0] == TAB) { /* subline */
407 /* check if it contains the base priority */
408 if (!strncmp(line,"\tfence priority : ",18)) {
409 base_prio=atoi(&line[18]);
410 DEBUG(4, ("fence priority set at %d\n", base_prio));
412 if (!header_line_ok) return (False); /* incorrect header line */
413 /* handle the case of "(standard input)" as a filename */
414 string_sub(line,"standard input","STDIN");
415 string_sub(line,"(","\"");
416 string_sub(line,")","\"");
418 for (count=0; count<2 && next_token(&line,tok[count],NULL); count++) ;
419 /* we must get 2 tokens */
420 if (count < 2) return(False);
422 /* the 2nd column must be integer */
423 if (!isdigit(*tok[1])) return(False);
425 /* if the fname contains a space then use STDIN */
426 if (strchr(tok[0],' '))
427 strcpy(tok[0],"STDIN");
429 buf->size = atoi(tok[1]);
430 StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
432 /* fill things from header line */
435 buf->status = jobstat;
436 buf->priority = jobprio;
437 StrnCpy(buf->user,jobuser,sizeof(buf->user)-1);
441 else { /* header line */
442 header_line_ok=False; /* reset it */
444 if (!base_prio_reset) {
445 base_prio=0; /* reset it */
446 base_prio_reset=True;
449 else if (base_prio) base_prio_reset=False;
451 /* handle the dash in the job id */
452 string_sub(line,"-"," ");
454 for (count=0; count<12 && next_token(&line,tok[count],NULL); count++) ;
456 /* we must get 8 tokens */
457 if (count < 8) return(False);
459 /* first token must be printer name (cannot check ?) */
460 /* the 2nd, 5th & 7th column must be integer */
461 if (!isdigit(*tok[1]) || !isdigit(*tok[4]) || !isdigit(*tok[6])) return(False);
462 jobid = atoi(tok[1]);
463 StrnCpy(jobuser,tok[2],sizeof(buf->user)-1);
464 jobprio = atoi(tok[4]);
467 jobtime=EntryTime(tok, 5, count, 8);
468 if (jobprio < base_prio) {
469 jobstat = LPQ_PAUSED;
470 DEBUG (4, ("job %d is paused: prio %d < %d; jobstat=%d\n", jobid, jobprio, base_prio, jobstat));
473 jobstat = LPQ_QUEUED;
474 if ((count >8) && (((strequal(tok[8],"on")) ||
475 ((strequal(tok[8],"from")) &&
476 ((count > 10)&&(strequal(tok[10],"on")))))))
477 jobstat = LPQ_PRINTING;
480 header_line_ok=True; /* information is correct */
481 return(False); /* need subline info to include into queuelist */
486 /****************************************************************************
489 here is an example of "lpstat -o dcslw" output under sysv
491 dcslw-896 tridge 4712 Dec 20 10:30:30 on dcslw
492 dcslw-897 tridge 4712 Dec 20 10:30:30 being held
494 ****************************************************************************/
495 static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
501 /* handle the dash in the job id */
502 string_sub(line,"-"," ");
504 for (count=0; count<9 && next_token(&line,tok[count],NULL); count++) ;
506 /* we must get 7 tokens */
510 /* the 2nd and 4th, 6th columns must be integer */
511 if (!isdigit(*tok[1]) || !isdigit(*tok[3])) return(False);
512 if (!isdigit(*tok[5])) return(False);
514 /* if the user contains a ! then trim the first part of it */
515 if ((p=strchr(tok[2],'!')))
523 buf->job = atoi(tok[1]);
524 buf->size = atoi(tok[3]);
525 if (count > 7 && strequal(tok[7],"on"))
526 buf->status = LPQ_PRINTING;
527 else if (count > 8 && strequal(tok[7],"being") && strequal(tok[8],"held"))
528 buf->status = LPQ_PAUSED;
530 buf->status = LPQ_QUEUED;
532 buf->time = EntryTime(tok, 4, count, 7);
533 StrnCpy(buf->user,tok[2],sizeof(buf->user)-1);
534 StrnCpy(buf->file,tok[2],sizeof(buf->file)-1);
538 /****************************************************************************
541 here is an example of lpq output under qnx
542 Spooler: /qnx/spooler, on node 1
544 0000: root [job #1 ] active 1146 bytes /etc/profile
545 0001: root [job #2 ] ready 2378 bytes /etc/install
546 0002: root [job #3 ] ready 1146 bytes -- standard input --
547 ****************************************************************************/
548 static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
553 DEBUG(0,("antes [%s]\n", line));
555 /* handle the case of "-- standard input --" as a filename */
556 string_sub(line,"standard input","STDIN");
557 DEBUG(0,("despues [%s]\n", line));
558 string_sub(line,"-- ","\"");
559 string_sub(line," --","\"");
560 DEBUG(0,("despues 1 [%s]\n", line));
562 string_sub(line,"[job #","");
563 string_sub(line,"]","");
564 DEBUG(0,("despues 2 [%s]\n", line));
568 for (count=0; count<7 && next_token(&line,tok[count],NULL); count++) ;
570 /* we must get 7 tokens */
574 /* the 3rd and 5th columns must be integer */
575 if (!isdigit(*tok[2]) || !isdigit(*tok[4])) return(False);
577 /* only take the last part of the filename */
580 char *p = strrchr(tok[6],'/');
589 buf->job = atoi(tok[2]);
590 buf->size = atoi(tok[4]);
591 buf->status = strequal(tok[3],"active")?LPQ_PRINTING:LPQ_QUEUED;
593 buf->time = time(NULL);
594 StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
595 StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
600 /****************************************************************************
601 parse a lpq line for the plp printing system
602 Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
604 redone by tridge. Here is a sample queue:
606 Local Printer 'lp2' (fjall):
607 Printing (started at Jun 15 13:33:58, attempt 1).
608 Rank Owner Pr Opt Job Host Files Size Date
609 active tridge X - 6 fjall /etc/hosts 739 Jun 15 13:33
610 3rd tridge X - 7 fjall /etc/hosts 739 Jun 15 13:33
612 ****************************************************************************/
613 static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
618 /* handle the case of "(standard input)" as a filename */
619 string_sub(line,"stdin","STDIN");
620 string_sub(line,"(","\"");
621 string_sub(line,")","\"");
623 for (count=0; count<11 && next_token(&line,tok[count],NULL); count++) ;
625 /* we must get 11 tokens */
629 /* the first must be "active" or begin with an integer */
630 if (strcmp(tok[0],"active") && !isdigit(tok[0][0]))
633 /* the 5th and 8th must be integer */
634 if (!isdigit(*tok[4]) || !isdigit(*tok[7]))
637 /* if the fname contains a space then use STDIN */
638 if (strchr(tok[6],' '))
639 strcpy(tok[6],"STDIN");
641 /* only take the last part of the filename */
644 char *p = strrchr(tok[6],'/');
653 buf->job = atoi(tok[4]);
655 buf->size = atoi(tok[7]);
656 if (strchr(tok[7],'K'))
658 if (strchr(tok[7],'M'))
659 buf->size *= 1024*1024;
661 buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
663 buf->time = time(NULL);
664 StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
665 StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
671 char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
672 char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
673 char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
675 /****************************************************************************
676 parse a lpq line. Choose printing style
677 ****************************************************************************/
678 static BOOL parse_lpq_entry(int snum,char *line,
679 print_queue_struct *buf,
680 print_status_struct *status,BOOL first)
684 switch (lp_printing())
687 ret = parse_lpq_sysv(line,buf,first);
690 ret = parse_lpq_aix(line,buf,first);
693 ret = parse_lpq_hpux(line,buf,first);
696 ret = parse_lpq_qnx(line,buf,first);
699 ret = parse_lpq_plp(line,buf,first);
702 ret = parse_lpq_bsd(line,buf,first);
706 #ifdef LPQ_GUEST_TO_USER
708 extern pstring sesssetup_user;
709 /* change guest entries to the current logged in user to make
710 them appear deletable to windows */
711 if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
712 strcpy(buf->user,sesssetup_user);
716 /* We don't want the newline in the status message. */
718 char *p = strchr(line,'\n');
724 /* a few simple checks to see if the line might be a
726 handle them so that most severe condition is shown */
730 switch (status->status) {
732 for (i=0; stat0_strings[i]; i++)
733 if (strstr(line,stat0_strings[i])) {
734 StrnCpy(status->message,line,sizeof(status->message)-1);
735 status->status=LPSTAT_OK;
738 for (i=0; stat1_strings[i]; i++)
739 if (strstr(line,stat1_strings[i])) {
740 StrnCpy(status->message,line,sizeof(status->message)-1);
741 status->status=LPSTAT_STOPPED;
744 for (i=0; stat2_strings[i]; i++)
745 if (strstr(line,stat2_strings[i])) {
746 StrnCpy(status->message,line,sizeof(status->message)-1);
747 status->status=LPSTAT_ERROR;
756 /****************************************************************************
758 ****************************************************************************/
759 int get_printqueue(int snum,int cnum,print_queue_struct **queue,
760 print_status_struct *status)
762 char *lpq_command = lp_lpqcommand(snum);
763 char *printername = PRINTERNAME(snum);
771 int cachetime = lp_lpqcachetime();
775 check_lpq_cache(snum);
777 if (!printername || !*printername)
779 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
780 lp_servicename(snum),snum));
781 printername = lp_servicename(snum);
784 if (!lpq_command || !(*lpq_command))
786 DEBUG(5,("No lpq command\n"));
790 strcpy(syscmd,lpq_command);
791 string_sub(syscmd,"%p",printername);
793 standard_sub(cnum,syscmd);
795 sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
797 if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf))
799 if (time(NULL) - sbuf.st_mtime < cachetime) {
800 DEBUG(3,("Using cached lpq output\n"));
805 lfd = file_lock(outfile,LPQ_LOCK_TIMEOUT);
807 (!fstat(lfd,&sbuf) && (time(NULL) - sbuf.st_mtime)<cachetime)) {
808 DEBUG(3,("Using cached lpq output\n"));
810 file_unlock(lfd); lfd = -1;
816 ret = smbrun(syscmd,outfile);
817 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
820 lpq_cache_reset[snum] = False;
822 f = fopen(outfile,"r");
824 if (lfd >= 0) file_unlock(lfd);
829 strcpy(status->message,"");
830 status->status = LPSTAT_OK;
833 while (fgets(line,sizeof(pstring),f))
835 DEBUG(6,("QUEUE2: %s\n",line));
837 *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
844 bzero((char *)&(*queue)[count],sizeof(**queue));
847 if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
855 if (lfd >= 0) file_unlock(lfd);
865 /****************************************************************************
866 delete a printer queue entry
867 ****************************************************************************/
868 void del_printqueue(int cnum,int snum,int jobid)
870 char *lprm_command = lp_lprmcommand(snum);
871 char *printername = PRINTERNAME(snum);
876 if (!printername || !*printername)
878 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
879 lp_servicename(snum),snum));
880 printername = lp_servicename(snum);
883 if (!lprm_command || !(*lprm_command))
885 DEBUG(5,("No lprm command\n"));
889 sprintf(jobstr,"%d",jobid);
891 strcpy(syscmd,lprm_command);
892 string_sub(syscmd,"%p",printername);
893 string_sub(syscmd,"%j",jobstr);
894 standard_sub(cnum,syscmd);
896 ret = smbrun(syscmd,NULL);
897 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
898 lpq_reset(snum); /* queue has changed */
901 /****************************************************************************
902 change status of a printer queue entry
903 ****************************************************************************/
904 void status_printjob(int cnum,int snum,int jobid,int status)
906 char *lpstatus_command =
907 (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
908 char *printername = PRINTERNAME(snum);
913 if (!printername || !*printername)
915 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
916 lp_servicename(snum),snum));
917 printername = lp_servicename(snum);
920 if (!lpstatus_command || !(*lpstatus_command))
922 DEBUG(5,("No lpstatus command to %s job\n",
923 (status==LPQ_PAUSED?"pause":"resume")));
927 sprintf(jobstr,"%d",jobid);
929 strcpy(syscmd,lpstatus_command);
930 string_sub(syscmd,"%p",printername);
931 string_sub(syscmd,"%j",jobstr);
932 standard_sub(cnum,syscmd);
934 ret = smbrun(syscmd,NULL);
935 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
936 lpq_reset(snum); /* queue has changed */