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 = 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>
603 ****************************************************************************/
604 static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
609 /* handle the case of "(standard input)" as a filename */
610 string_sub(line,"stdin","STDIN");
611 string_sub(line,"(","\"");
612 string_sub(line,")","\"");
614 for (count=0; count<8 && next_token(&line,tok[count],NULL); count++) ;
616 /* we must get 5 tokens */
620 /* the 4rd must be integer */
621 if (!isdigit(*tok[3])) return(False);
623 /* if the fname contains a space then use STDIN */
624 if (strchr(tok[3],' '))
625 strcpy(tok[3],"STDIN");
627 /* only take the last part of the filename */
630 char *p = strrchr(tok[5],'/');
639 buf->job = atoi(tok[3]);
641 /* calcul de la taille du fichier */
642 if (!isdigit(*tok[7])) { buf->size = atoi(tok[7]) * 1.0 ; }
646 if (strchr(tok[7],'K')) {
647 strncpy(tok[7],tmp,strlen(tmp)-1);
648 buf->size = atoi(tok[7]);
649 buf->size = buf->size * 1024;
651 if (strchr(tok[7],'M')) {
652 strncpy(tok[7],tmp,strlen(tmp)-1);
653 buf->size = atoi(tok[7]);
654 buf->size = buf->size * 1024.0 * 1000.0;
656 if (strchr(tok[7],'G')) {
657 strncpy(tok[7],tmp,strlen(tmp)-1);
658 buf->size = atoi(tok[7]);
659 buf->size = buf->size * 1024.0 * 1000000.0;
663 buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
665 buf->time = time(NULL);
666 StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
667 StrnCpy(buf->file,tok[5],sizeof(buf->file)-1);
673 char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
674 char *stat1_strings[] = { "offline", "disabled", "down", "off", "waiting", "no daemon", NULL };
675 char *stat2_strings[] = { "jam", "paper", "error", "responding", "not accepting", "not running", "turned off", NULL };
677 /****************************************************************************
678 parse a lpq line. Choose printing style
679 ****************************************************************************/
680 static BOOL parse_lpq_entry(int snum,char *line,
681 print_queue_struct *buf,
682 print_status_struct *status,BOOL first)
686 switch (lp_printing())
689 ret = parse_lpq_sysv(line,buf,first);
692 ret = parse_lpq_aix(line,buf,first);
695 ret = parse_lpq_hpux(line,buf,first);
698 ret = parse_lpq_qnx(line,buf,first);
701 ret = parse_lpq_plp(line,buf,first);
704 ret = parse_lpq_bsd(line,buf,first);
708 #ifdef LPQ_GUEST_TO_USER
710 extern pstring sesssetup_user;
711 /* change guest entries to the current logged in user to make
712 them appear deletable to windows */
713 if (sesssetup_user[0] && strequal(buf->user,lp_guestaccount(snum)))
714 strcpy(buf->user,sesssetup_user);
720 /* a few simple checks to see if the line might be a
722 handle them so that most severe condition is shown */
726 switch (status->status) {
728 for (i=0; stat0_strings[i]; i++)
729 if (strstr(line,stat0_strings[i])) {
730 StrnCpy(status->message,line,sizeof(status->message)-1);
731 status->status=LPSTAT_OK;
734 for (i=0; stat1_strings[i]; i++)
735 if (strstr(line,stat1_strings[i])) {
736 StrnCpy(status->message,line,sizeof(status->message)-1);
737 status->status=LPSTAT_STOPPED;
740 for (i=0; stat2_strings[i]; i++)
741 if (strstr(line,stat2_strings[i])) {
742 StrnCpy(status->message,line,sizeof(status->message)-1);
743 status->status=LPSTAT_ERROR;
752 /****************************************************************************
754 ****************************************************************************/
755 int get_printqueue(int snum,int cnum,print_queue_struct **queue,
756 print_status_struct *status)
758 char *lpq_command = lp_lpqcommand(snum);
759 char *printername = PRINTERNAME(snum);
767 int cachetime = lp_lpqcachetime();
771 check_lpq_cache(snum);
773 if (!printername || !*printername)
775 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
776 lp_servicename(snum),snum));
777 printername = lp_servicename(snum);
780 if (!lpq_command || !(*lpq_command))
782 DEBUG(5,("No lpq command\n"));
786 strcpy(syscmd,lpq_command);
787 string_sub(syscmd,"%p",printername);
789 standard_sub(cnum,syscmd);
791 sprintf(outfile,"/tmp/lpq.%08x",str_checksum(syscmd));
793 if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf))
795 if (time(NULL) - sbuf.st_mtime < cachetime) {
796 DEBUG(3,("Using cached lpq output\n"));
801 lfd = file_lock(outfile,LPQ_LOCK_TIMEOUT);
803 (!fstat(lfd,&sbuf) && (time(NULL) - sbuf.st_mtime)<cachetime)) {
804 DEBUG(3,("Using cached lpq output\n"));
806 file_unlock(lfd); lfd = -1;
812 ret = smbrun(syscmd,outfile);
813 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
816 lpq_cache_reset[snum] = False;
818 f = fopen(outfile,"r");
820 if (lfd >= 0) file_unlock(lfd);
825 strcpy(status->message,"");
826 status->status = LPSTAT_OK;
829 while (fgets(line,sizeof(pstring),f))
831 DEBUG(6,("QUEUE2: %s\n",line));
833 *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
840 bzero((char *)&(*queue)[count],sizeof(**queue));
843 if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
851 if (lfd >= 0) file_unlock(lfd);
861 /****************************************************************************
862 delete a printer queue entry
863 ****************************************************************************/
864 void del_printqueue(int cnum,int snum,int jobid)
866 char *lprm_command = lp_lprmcommand(snum);
867 char *printername = PRINTERNAME(snum);
872 if (!printername || !*printername)
874 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
875 lp_servicename(snum),snum));
876 printername = lp_servicename(snum);
879 if (!lprm_command || !(*lprm_command))
881 DEBUG(5,("No lprm command\n"));
885 sprintf(jobstr,"%d",jobid);
887 strcpy(syscmd,lprm_command);
888 string_sub(syscmd,"%p",printername);
889 string_sub(syscmd,"%j",jobstr);
890 standard_sub(cnum,syscmd);
892 ret = smbrun(syscmd,NULL);
893 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
894 lpq_reset(snum); /* queue has changed */
897 /****************************************************************************
898 change status of a printer queue entry
899 ****************************************************************************/
900 void status_printjob(int cnum,int snum,int jobid,int status)
902 char *lpstatus_command =
903 (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
904 char *printername = PRINTERNAME(snum);
909 if (!printername || !*printername)
911 DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
912 lp_servicename(snum),snum));
913 printername = lp_servicename(snum);
916 if (!lpstatus_command || !(*lpstatus_command))
918 DEBUG(5,("No lpstatus command to %s job\n",
919 (status==LPQ_PAUSED?"pause":"resume")));
923 sprintf(jobstr,"%d",jobid);
925 strcpy(syscmd,lpstatus_command);
926 string_sub(syscmd,"%p",printername);
927 string_sub(syscmd,"%j",jobstr);
928 standard_sub(cnum,syscmd);
930 ret = smbrun(syscmd,NULL);
931 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
932 lpq_reset(snum); /* queue has changed */