home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Wtestowe / Clico / UNIX / SAMBA / SOURCE / SAMBA.TAR / samba-1.9.17 / source / printing.c < prev    next >
C/C++ Source or Header  |  1997-05-08  |  32KB  |  1,083 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    printing routines
  5.    Copyright (C) Andrew Tridgell 1992-1997
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #include "includes.h"
  23. extern int DEBUGLEVEL;
  24. extern connection_struct Connections[];
  25. extern files_struct Files[];
  26.  
  27. static BOOL * lpq_cache_reset=NULL;
  28.  
  29. static int check_lpq_cache(int snum) {
  30.   static int lpq_caches=0;
  31.   
  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;
  38.       }
  39.   }
  40.   return lpq_caches;
  41. }
  42.  
  43. void lpq_reset(int snum)
  44. {
  45.   if (check_lpq_cache(snum) > snum) lpq_cache_reset[snum]=True;
  46. }
  47.  
  48.  
  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)
  55. {
  56.   int snum = SNUM(cnum);
  57.   char *tstr;
  58.   pstring filename;
  59.   
  60.   /* get the print command for the service. */
  61.   tstr = command;
  62.   if (!syscmd || !tstr) {
  63.     DEBUG(0,("No print command for service `%s'\n", SERVICE(snum)));
  64.     return (NULL);
  65.   }
  66.  
  67.   /* copy the command into the buffer for extensive meddling. */
  68.   StrnCpy(syscmd, tstr, sizeof(pstring) - 1);
  69.   
  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)));
  73.   }
  74.   
  75.   if (strstr(syscmd,"%s")) {
  76.     int iOffset = PTR_DIFF(strstr(syscmd, "%s"),syscmd);
  77.     
  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);
  86.     }
  87.     else
  88.       strcpy(filename,filename1);
  89.     
  90.     string_sub(syscmd, "%s", filename);
  91.   }
  92.   
  93.   string_sub(syscmd, "%f", filename1);
  94.   
  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);
  102.   }
  103.   
  104.   string_sub(syscmd, "%p", tstr);
  105.   
  106.   standard_sub(cnum,syscmd);
  107.   
  108.   return (syscmd);
  109. }
  110.  
  111.  
  112. /****************************************************************************
  113. print a file - called on closing the file
  114. ****************************************************************************/
  115. void print_file(int fnum)
  116. {
  117.   pstring syscmd;
  118.   int cnum = Files[fnum].cnum;
  119.   int snum=SNUM(cnum);
  120.   char *tempstr;
  121.  
  122.   *syscmd = 0;
  123.  
  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;
  128.   }
  129.  
  130.   tempstr = build_print_command(cnum, PRINTCOMMAND(snum), syscmd, Files[fnum].name);
  131.   if (tempstr != NULL)
  132.     {
  133.       int ret = smbrun(syscmd,NULL,False);
  134.       DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
  135.     }
  136.   else
  137.     DEBUG(0,("Null print command?\n"));
  138.   
  139.   lpq_reset(snum);
  140. }
  141.  
  142. static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  143.                   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Err"};
  144.  
  145.  
  146. /*******************************************************************
  147. process time fields
  148. ********************************************************************/
  149. static time_t EntryTime(string tok[], int ptr, int count, int minimum)
  150. {
  151.   time_t jobtime,jobtime1;
  152.  
  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;
  158.  
  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;
  170.  
  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 */
  177.  
  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;
  186.     }
  187.   }
  188.   return jobtime;
  189. }
  190.  
  191.  
  192. /****************************************************************************
  193. parse a lpq line
  194.  
  195. here is an example of lpq output under bsd
  196.  
  197. Warning: no daemon present
  198. Rank   Owner      Job  Files                                 Total Size
  199. 1st    tridge     148  README                                8096 bytes
  200.  
  201. here is an example of lpq output under osf/1
  202.  
  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)
  208. {
  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 */
  225.  
  226.   string tok[NTOK];
  227.   int count=0;
  228.  
  229. #ifdef    OSF1
  230.   int length;
  231.   length = strlen(line);
  232.   if (line[length-3] == ':')
  233.     return(False);
  234. #endif    /* OSF1 */
  235.  
  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,")","\"");
  240.   
  241.   for (count=0; count<NTOK && next_token(&line,tok[count],NULL); count++) ;
  242.  
  243.   /* we must get NTOK tokens */
  244.   if (count < NTOK)
  245.     return(False);
  246.  
  247.   /* the Job and Total columns must be integer */
  248.   if (!isdigit(*tok[JOBTOK]) || !isdigit(*tok[TOTALTOK])) return(False);
  249.  
  250.   /* if the fname contains a space then use STDIN */
  251.   if (strchr(tok[FILETOK],' '))
  252.     strcpy(tok[FILETOK],"STDIN");
  253.  
  254.   /* only take the last part of the filename */
  255.   {
  256.     string tmp;
  257.     char *p = strrchr(tok[FILETOK],'/');
  258.     if (p)
  259.       {
  260.     strcpy(tmp,p+1);
  261.     strcpy(tok[FILETOK],tmp);
  262.       }
  263.   }
  264.     
  265.  
  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);
  278. }
  279.  
  280. /*
  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"
  284. */
  285. static time_t LPRng_time(string tok[],int pos)
  286. {
  287.   time_t jobtime;
  288.   struct tm *t;
  289.   char tmp_time[9];
  290.  
  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);
  298.  
  299.   return jobtime;
  300. }
  301.  
  302.  
  303. /****************************************************************************
  304.   parse a lpq line
  305.   <magnus@hum.auc.dk>
  306.   Most of the code is directly reused from parse_lpq_bsd()
  307.  
  308. here are two examples of lpq output under lprng (LPRng-2.3.0)
  309.  
  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
  316.  
  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
  323.  
  324. ****************************************************************************/
  325. static BOOL parse_lpq_lprng(char *line,print_queue_struct *buf,BOOL first)
  326. {
  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
  335.  
  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
  358.  
  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
  365.  
  366.   
  367.   string tok[LPRNG_NTOK];
  368.   int count=0;
  369.  
  370. /* 
  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.
  375.  
  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.
  378. */
  379.  
  380.   line[JOBSIZE_POS-1]=' ';
  381.  
  382.   /* handle the case of "(stdin)" as a filename */
  383.   string_sub(line,"stdin","STDIN");
  384.   string_sub(line,"(","\"");
  385.   string_sub(line,")","\"");
  386.   
  387.   for (count=0; count<LPRNG_NTOK && next_token(&line,tok[count],NULL); count++) ;
  388.  
  389.   /* we must get LPRNG_NTOK tokens */
  390.   if (count < LPRNG_NTOK)
  391.     return(False);
  392.  
  393.   /* the Job and Total columns must be integer */
  394.   if (!isdigit(*tok[LPRNG_JOBTOK]) || !isdigit(*tok[LPRNG_TOTALTOK])) return(False);
  395.  
  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");
  400.  
  401.   /* only take the last part of the filename */
  402.   {
  403.     string tmp;
  404.     char *p = strrchr(tok[LPRNG_FILETOK],'/');
  405.     if (p)
  406.       {
  407.        strcpy(tmp,p+1);
  408.        strcpy(tok[LPRNG_FILETOK],tmp);
  409.       }
  410.   }
  411.        
  412.  
  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);
  429. }
  430.  
  431.  
  432.  
  433. /*******************************************************************
  434. parse lpq on an aix system
  435.  
  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)
  446. {
  447.   string tok[11];
  448.   int count=0;
  449.  
  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,")","\"");
  454.  
  455.   for (count=0; count<10 && next_token(&line,tok[count],NULL); count++) ;
  456.  
  457.   /* we must get 6 tokens */
  458.   if (count < 10)
  459.   {
  460.       if ((count == 7) && (strcmp(tok[0],"QUEUED") == 0))
  461.       {
  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");
  468.  
  469.           /* only take the last part of the filename */
  470.           {
  471.             string tmp;
  472.             char *p = strrchr(tok[2],'/');
  473.             if (p)
  474.               {
  475.                 strcpy(tmp,p+1);
  476.                 strcpy(tok[2],tmp);
  477.               }
  478.           }
  479.  
  480.  
  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);
  487.       }
  488.       else
  489.       {
  490.           DEBUG(6,("parse_lpq_aix count=%d\n", count));
  491.           return(False);
  492.       }
  493.   }
  494.   else
  495.   {
  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");
  502.  
  503.       /* only take the last part of the filename */
  504.       {
  505.         string tmp;
  506.         char *p = strrchr(tok[4],'/');
  507.         if (p)
  508.           {
  509.             strcpy(tmp,p+1);
  510.             strcpy(tok[4],tmp);
  511.           }
  512.       }
  513.  
  514.  
  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);
  521.   }
  522.  
  523.  
  524.   return(True);
  525. }
  526.  
  527.  
  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)
  539. {
  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;
  550.  
  551.   int count;
  552.   char TAB = '\011';  
  553.   string tok[12];
  554.  
  555.   /* If a line begins with a horizontal TAB, it is a subline type */
  556.   
  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));
  562.     }
  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,")","\"");
  568.     
  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);
  572.     
  573.     /* the 2nd column must be integer */
  574.     if (!isdigit(*tok[1])) return(False);
  575.     
  576.     /* if the fname contains a space then use STDIN */
  577.     if (strchr(tok[0],' '))
  578.       strcpy(tok[0],"STDIN");
  579.     
  580.     buf->size = atoi(tok[1]);
  581.     StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
  582.     
  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);
  589.     
  590.     return(True);
  591.   }
  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;
  598.        }
  599.     }
  600.     else if (base_prio) base_prio_reset=False;
  601.     
  602.     /* handle the dash in the job id */
  603.     string_sub(line,"-"," ");
  604.     
  605.     for (count=0; count<12 && next_token(&line,tok[count],NULL); count++) ;
  606.       
  607.     /* we must get 8 tokens */
  608.     if (count < 8) return(False);
  609.     
  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]);
  616.     
  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));
  622.     }
  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;
  629.     }
  630.     
  631.     header_line_ok=True; /* information is correct */
  632.     return(False); /* need subline info to include into queuelist */
  633.   }
  634. }
  635.  
  636.  
  637. /****************************************************************************
  638. parse a lpq line
  639.  
  640. here is an example of "lpstat -o dcslw" output under sysv
  641.  
  642. dcslw-896               tridge            4712   Dec 20 10:30:30 on dcslw
  643. dcslw-897               tridge            4712   Dec 20 10:30:30 being held
  644.  
  645. ****************************************************************************/
  646. static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
  647. {
  648.   string tok[9];
  649.   int count=0;
  650.   char *p;
  651.  
  652.   /* handle the dash in the job id */
  653.   string_sub(line,"-"," ");
  654.   
  655.   for (count=0; count<9 && next_token(&line,tok[count],NULL); count++) ;
  656.  
  657.   /* we must get 7 tokens */
  658.   if (count < 7)
  659.     return(False);
  660.  
  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);
  664.  
  665.   /* if the user contains a ! then trim the first part of it */  
  666.   if ((p=strchr(tok[2],'!')))
  667.     {
  668.       string tmp;
  669.       strcpy(tmp,p+1);
  670.       strcpy(tok[2],tmp);
  671.     }
  672.     
  673.  
  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);
  687. }
  688.  
  689. /****************************************************************************
  690. parse a lpq line
  691.  
  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)
  700. {
  701.   string tok[7];
  702.   int count=0;
  703.  
  704.   DEBUG(0,("antes [%s]\n", line));
  705.  
  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));
  712.  
  713.   string_sub(line,"[job #","");
  714.   string_sub(line,"]","");
  715.   DEBUG(0,("despues 2 [%s]\n", line));
  716.  
  717.   
  718.   
  719.   for (count=0; count<7 && next_token(&line,tok[count],NULL); count++) ;
  720.  
  721.   /* we must get 7 tokens */
  722.   if (count < 7)
  723.     return(False);
  724.  
  725.   /* the 3rd and 5th columns must be integer */
  726.   if (!isdigit(*tok[2]) || !isdigit(*tok[4])) return(False);
  727.  
  728.   /* only take the last part of the filename */
  729.   {
  730.     string tmp;
  731.     char *p = strrchr(tok[6],'/');
  732.     if (p)
  733.       {
  734.     strcpy(tmp,p+1);
  735.     strcpy(tok[6],tmp);
  736.       }
  737.   }
  738.     
  739.  
  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);
  748. }
  749.  
  750.  
  751. /****************************************************************************
  752.   parse a lpq line for the plp printing system
  753.   Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
  754.  
  755. redone by tridge. Here is a sample queue:
  756.  
  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
  762.  
  763. ****************************************************************************/
  764. static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
  765. {
  766.   string tok[11];
  767.   int count=0;
  768.  
  769.   /* handle the case of "(standard input)" as a filename */
  770.   string_sub(line,"stdin","STDIN");
  771.   string_sub(line,"(","\"");
  772.   string_sub(line,")","\"");
  773.   
  774.   for (count=0; count<11 && next_token(&line,tok[count],NULL); count++) ;
  775.  
  776.   /* we must get 11 tokens */
  777.   if (count < 11)
  778.     return(False);
  779.  
  780.   /* the first must be "active" or begin with an integer */
  781.   if (strcmp(tok[0],"active") && !isdigit(tok[0][0]))
  782.     return(False);
  783.  
  784.   /* the 5th and 8th must be integer */
  785.   if (!isdigit(*tok[4]) || !isdigit(*tok[7])) 
  786.     return(False);
  787.  
  788.   /* if the fname contains a space then use STDIN */
  789.   if (strchr(tok[6],' '))
  790.     strcpy(tok[6],"STDIN");
  791.  
  792.   /* only take the last part of the filename */
  793.   {
  794.     string tmp;
  795.     char *p = strrchr(tok[6],'/');
  796.     if (p)
  797.       {
  798.         strcpy(tmp,p+1);
  799.         strcpy(tok[6],tmp);
  800.       }
  801.   }
  802.  
  803.  
  804.   buf->job = atoi(tok[4]);
  805.  
  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;
  811.  
  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);
  818. }
  819.  
  820.  
  821.  
  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 };
  825.  
  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)
  832. {
  833.   BOOL ret;
  834.  
  835.   switch (lp_printing())
  836.     {
  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;
  858.     }
  859.  
  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);
  867.   }
  868. #endif
  869.  
  870.   /* We don't want the newline in the status message. */
  871.   {
  872.     char *p = strchr(line,'\n');
  873.     if (p) *p = 0;
  874.   }
  875.  
  876.   if (status && !ret)
  877.     {
  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);
  883.       
  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;
  890.       }
  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;
  896.       }
  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;
  902.       }
  903.     break;
  904.       }
  905.     }
  906.  
  907.   return(ret);
  908. }
  909.  
  910. /****************************************************************************
  911. get a printer queue
  912. ****************************************************************************/
  913. int get_printqueue(int snum,int cnum,print_queue_struct **queue,
  914.            print_status_struct *status)
  915. {
  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();
  926.  
  927.   *line = 0;
  928.   check_lpq_cache(snum);
  929.   
  930.   if (!printername || !*printername)
  931.     {
  932.       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
  933.         lp_servicename(snum),snum));
  934.       printername = lp_servicename(snum);
  935.     }
  936.     
  937.   if (!lpq_command || !(*lpq_command))
  938.     {
  939.       DEBUG(5,("No lpq command\n"));
  940.       return(0);
  941.     }
  942.     
  943.   strcpy(syscmd,lpq_command);
  944.   string_sub(syscmd,"%p",printername);
  945.  
  946.   standard_sub(cnum,syscmd);
  947.  
  948.   sprintf(outfile,"%s/lpq.%08x",tmpdir(),str_checksum(syscmd));
  949.   
  950.   if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf)) 
  951.     {
  952.       if (time(NULL) - sbuf.st_mtime < cachetime) {
  953.     DEBUG(3,("Using cached lpq output\n"));
  954.     dorun = False;
  955.       }
  956.     }
  957.  
  958.   if (dorun) {
  959.     ret = smbrun(syscmd,outfile,True);
  960.     DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
  961.   }
  962.  
  963.   lpq_cache_reset[snum] = False;
  964.  
  965.   f = fopen(outfile,"r");
  966.   if (!f) {
  967.     return(0);
  968.   }
  969.  
  970.   if (status) {
  971.     strcpy(status->message,"");
  972.     status->status = LPSTAT_OK;
  973.   }
  974.       
  975.   while (fgets(line,sizeof(pstring),f))
  976.     {
  977.       DEBUG(6,("QUEUE2: %s\n",line));
  978.  
  979.       *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
  980.       if (! *queue)
  981.     {
  982.       count = 0;
  983.       break;
  984.     }
  985.  
  986.       bzero((char *)&(*queue)[count],sizeof(**queue));
  987.       
  988.       /* parse it */
  989.       if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
  990.     continue;
  991.       
  992.       count++;
  993.     }          
  994.  
  995.   fclose(f);
  996.  
  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);
  1003.   }
  1004.   return(count);
  1005. }
  1006.  
  1007.  
  1008. /****************************************************************************
  1009. delete a printer queue entry
  1010. ****************************************************************************/
  1011. void del_printqueue(int cnum,int snum,int jobid)
  1012. {
  1013.   char *lprm_command = lp_lprmcommand(snum);
  1014.   char *printername = PRINTERNAME(snum);
  1015.   pstring syscmd;
  1016.   char jobstr[20];
  1017.   int ret;
  1018.  
  1019.   if (!printername || !*printername)
  1020.     {
  1021.       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
  1022.         lp_servicename(snum),snum));
  1023.       printername = lp_servicename(snum);
  1024.     }
  1025.     
  1026.   if (!lprm_command || !(*lprm_command))
  1027.     {
  1028.       DEBUG(5,("No lprm command\n"));
  1029.       return;
  1030.     }
  1031.     
  1032.   sprintf(jobstr,"%d",jobid);
  1033.  
  1034.   strcpy(syscmd,lprm_command);
  1035.   string_sub(syscmd,"%p",printername);
  1036.   string_sub(syscmd,"%j",jobstr);
  1037.   standard_sub(cnum,syscmd);
  1038.  
  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 */
  1042. }
  1043.  
  1044. /****************************************************************************
  1045. change status of a printer queue entry
  1046. ****************************************************************************/
  1047. void status_printjob(int cnum,int snum,int jobid,int status)
  1048. {
  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;
  1055.  
  1056.   if (!printername || !*printername)
  1057.     {
  1058.       DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
  1059.         lp_servicename(snum),snum));
  1060.       printername = lp_servicename(snum);
  1061.     }
  1062.     
  1063.   if (!lpstatus_command || !(*lpstatus_command))
  1064.     {
  1065.       DEBUG(5,("No lpstatus command to %s job\n",
  1066.            (status==LPQ_PAUSED?"pause":"resume")));
  1067.       return;
  1068.     }
  1069.     
  1070.   sprintf(jobstr,"%d",jobid);
  1071.  
  1072.   strcpy(syscmd,lpstatus_command);
  1073.   string_sub(syscmd,"%p",printername);
  1074.   string_sub(syscmd,"%j",jobstr);
  1075.   standard_sub(cnum,syscmd);
  1076.  
  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 */
  1080. }
  1081.  
  1082.  
  1083.