Changed calls to strncat() to safe_strcat(). Fix from SAMBA_2_0 branch.
[samba.git] / source3 / printing / printing.c
index bf49a372030188f2c4fe9bcaa13f669f44908cb8..dc28f176159450047e6caa6c82758227c5638702 100644 (file)
@@ -21,8 +21,6 @@
 
 #include "includes.h"
 extern int DEBUGLEVEL;
-extern connection_struct Connections[];
-extern files_struct Files[];
 
 static BOOL * lpq_cache_reset=NULL;
 
@@ -51,92 +49,84 @@ Build the print command in the supplied buffer. This means getting the
 print command for the service and inserting the printer name and the
 print file name. Return NULL on error, else the passed buffer pointer.
 ****************************************************************************/
-static char *build_print_command(int cnum, char *command, char *syscmd, char *filename1)
+static char *build_print_command(connection_struct *conn,
+                                char *command, 
+                                char *syscmd, char *filename1)
 {
-  int snum = SNUM(cnum);
-  char *tstr;
-  pstring filename;
+       int snum = SNUM(conn);
+       char *tstr;
+       pstring filename;
   
-  /* get the print command for the service. */
-  tstr = command;
-  if (!syscmd || !tstr) {
-    DEBUG(0,("No print command for service `%s'\n", SERVICE(snum)));
-    return (NULL);
-  }
+       /* get the print command for the service. */
+       tstr = command;
+       if (!syscmd || !tstr) {
+               DEBUG(0,("No print command for service `%s'\n", 
+                        SERVICE(snum)));
+               return (NULL);
+       }
 
-  /* copy the command into the buffer for extensive meddling. */
-  StrnCpy(syscmd, tstr, sizeof(pstring) - 1);
+       /* copy the command into the buffer for extensive meddling. */
+       StrnCpy(syscmd, tstr, sizeof(pstring) - 1);
   
-  /* look for "%s" in the string. If there is no %s, we cannot print. */   
-  if (!strstr(syscmd, "%s") && !strstr(syscmd, "%f")) {
-    DEBUG(2,("WARNING! No placeholder for the filename in the print command for service %s!\n", SERVICE(snum)));
-  }
+       /* look for "%s" in the string. If there is no %s, we cannot print. */   
+       if (!strstr(syscmd, "%s") && !strstr(syscmd, "%f")) {
+               DEBUG(2,("WARNING! No placeholder for the filename in the print command for service %s!\n", SERVICE(snum)));
+       }
   
-  if (strstr(syscmd,"%s")) {
-    int iOffset = PTR_DIFF(strstr(syscmd, "%s"),syscmd);
-    
-    /* construct the full path for the filename, shouldn't be necessary unless
-       the subshell causes a "cd" to be executed.
-       Only use the full path if there isn't a / preceding the %s */
-    if (iOffset==0 || syscmd[iOffset-1] != '/') {
-      StrnCpy(filename,Connections[cnum].connectpath,sizeof(filename)-1);
-      trim_string(filename,"","/");
-      strcat(filename,"/");
-      strcat(filename,filename1);
-    }
-    else
-      pstrcpy(filename,filename1);
+       if (strstr(syscmd,"%s")) {
+               pstrcpy(filename,filename1);
     
-    string_sub(syscmd, "%s", filename);
-  }
+               string_sub(syscmd, "%s", filename);
+       }
   
-  string_sub(syscmd, "%f", filename1);
+       string_sub(syscmd, "%f", filename1);
   
-  /* Does the service have a printername? If not, make a fake and empty    */
-  /* printer name. That way a %p is treated sanely if no printer */
-  /* name was specified to replace it. This eventuality is logged.         */
-  tstr = PRINTERNAME(snum);
-  if (tstr == NULL || tstr[0] == '\0') {
-    DEBUG(3,( "No printer name - using %s.\n", SERVICE(snum)));
-    tstr = SERVICE(snum);
-  }
+       /* Does the service have a printername? If not, make a fake
+           and empty */
+       /* printer name. That way a %p is treated sanely if no printer */
+       /* name was specified to replace it. This eventuality is logged.  */
+       tstr = PRINTERNAME(snum);
+       if (tstr == NULL || tstr[0] == '\0') {
+               DEBUG(3,( "No printer name - using %s.\n", SERVICE(snum)));
+               tstr = SERVICE(snum);
+       }
   
-  string_sub(syscmd, "%p", tstr);
+       string_sub(syscmd, "%p", tstr);
   
-  standard_sub(cnum,syscmd);
+       standard_sub(conn,syscmd);
   
-  return (syscmd);
+       return (syscmd);
 }
 
 
 /****************************************************************************
 print a file - called on closing the file
 ****************************************************************************/
-void print_file(int fnum)
+void print_file(connection_struct *conn, files_struct *file)
 {
-  pstring syscmd;
-  int cnum = Files[fnum].cnum;
-  int snum=SNUM(cnum);
-  char *tempstr;
+       pstring syscmd;
+       int snum = SNUM(conn);
+       char *tempstr;
 
-  *syscmd = 0;
+       *syscmd = 0;
 
-  if (file_size(Files[fnum].name) <= 0) {
-    DEBUG(3,("Discarding null print job %s\n",Files[fnum].name));
-    sys_unlink(Files[fnum].name);
-    return;
-  }
+       if (dos_file_size(file->fsp_name) <= 0) {
+               DEBUG(3,("Discarding null print job %s\n",file->fsp_name));
+               dos_unlink(file->fsp_name);
+               return;
+       }
 
-  tempstr = build_print_command(cnum, PRINTCOMMAND(snum), syscmd, Files[fnum].name);
-  if (tempstr != NULL)
-    {
-      int ret = smbrun(syscmd,NULL,False);
-      DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
-    }
-  else
-    DEBUG(0,("Null print command?\n"));
+       tempstr = build_print_command(conn, 
+                                     PRINTCOMMAND(snum), 
+                                     syscmd, file->fsp_name);
+       if (tempstr != NULL) {
+               int ret = smbrun(syscmd,NULL,False);
+               DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
+       } else {
+               DEBUG(0,("Null print command?\n"));
+       }
   
-  lpq_reset(snum);
+       lpq_reset(snum);
 }
 
 static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
@@ -146,7 +136,7 @@ static char *Months[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
 /*******************************************************************
 process time fields
 ********************************************************************/
-static time_t EntryTime(string tok[], int ptr, int count, int minimum)
+static time_t EntryTime(fstring tok[], int ptr, int count, int minimum)
 {
   time_t jobtime,jobtime1;
 
@@ -203,6 +193,11 @@ here is an example of lpq output under osf/1
 Warning: no daemon present
 Rank   Pri Owner      Job  Files                             Total Size
 1st    0   tridge     148  README                            8096 bytes
+
+
+<allan@umich.edu> June 30, 1998.
+Modified to handle file names with spaces, like the parse_lpq_lprng code
+further below.
 ****************************************************************************/
 static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
 {
@@ -212,63 +207,71 @@ static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
 #define        USERTOK 2
 #define        JOBTOK  3
 #define        FILETOK 4
-#define        TOTALTOK 5
+#define        TOTALTOK (count - 2)
 #define        NTOK    6
+#define        MAXTOK  128
 #else  /* OSF1 */
 #define        RANKTOK 0
 #define        USERTOK 1
 #define        JOBTOK  2
 #define        FILETOK 3
-#define        TOTALTOK 4
+#define        TOTALTOK (count - 2)
 #define        NTOK    5
+#define        MAXTOK  128
 #endif /* OSF1 */
 
-  string tok[NTOK];
-  int count=0;
+  char *tok[MAXTOK];
+  int  count = 0;
+  pstring line2;
+
+  pstrcpy(line2,line);
 
 #ifdef OSF1
-  int length;
-  length = strlen(line);
-  if (line[length-3] == ':')
-       return(False);
+  {
+    size_t length;
+    length = strlen(line2);
+    if (line2[length-3] == ':')
+      return(False);
+  }
 #endif /* OSF1 */
 
-  /* handle the case of "(standard input)" as a filename */
-  string_sub(line,"standard input","STDIN");
-  string_sub(line,"(","\"");
-  string_sub(line,")","\"");
-  
-  for (count=0; count<NTOK && next_token(&line,tok[count],NULL); count++) ;
+  tok[0] = strtok(line2," \t");
+  count++;
 
-  /* we must get NTOK tokens */
+  while (((tok[count] = strtok(NULL," \t")) != NULL) && (count < MAXTOK)) {
+    count++;
+  }
+
+  /* we must get at least NTOK tokens */
   if (count < NTOK)
     return(False);
 
   /* the Job and Total columns must be integer */
   if (!isdigit(*tok[JOBTOK]) || !isdigit(*tok[TOTALTOK])) return(False);
 
-  /* if the fname contains a space then use STDIN */
-  if (strchr(tok[FILETOK],' '))
-    strcpy(tok[FILETOK],"STDIN");
-
-  /* only take the last part of the filename */
-  {
-    string tmp;
-    char *p = strrchr(tok[FILETOK],'/');
-    if (p)
-      {
-       strcpy(tmp,p+1);
-       fstrcpy(tok[FILETOK],tmp);
-      }
-  }
-       
-
   buf->job = atoi(tok[JOBTOK]);
   buf->size = atoi(tok[TOTALTOK]);
   buf->status = strequal(tok[RANKTOK],"active")?LPQ_PRINTING:LPQ_QUEUED;
   buf->time = time(NULL);
   StrnCpy(buf->user,tok[USERTOK],sizeof(buf->user)-1);
   StrnCpy(buf->file,tok[FILETOK],sizeof(buf->file)-1);
+
+  if ((FILETOK + 1) != TOTALTOK) {
+    int bufsize;
+    int i;
+
+    bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
+
+    for (i = (FILETOK + 1); i < TOTALTOK; i++) {
+      safe_strcat(buf->file," ",bufsize);
+      safe_strcat(buf->file,tok[i],bufsize - 1);
+      bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
+      if (bufsize <= 0) {
+        break;
+      }
+    }
+  }
+
 #ifdef PRIOTOK
   buf->priority = atoi(tok[PRIOTOK]);
 #else
@@ -281,19 +284,20 @@ static BOOL parse_lpq_bsd(char *line,print_queue_struct *buf,BOOL first)
 <magnus@hum.auc.dk>
 LPRng_time modifies the current date by inserting the hour and minute from
 the lpq output.  The lpq time looks like "23:15:07"
+
+<allan@umich.edu> June 30, 1998.
+Modified to work with the re-written parse_lpq_lprng routine.
 */
-static time_t LPRng_time(string tok[],int pos)
+static time_t LPRng_time(char *time_string)
 {
   time_t jobtime;
   struct tm *t;
-  char tmp_time[9];
 
   jobtime = time(NULL);         /* default case: take current time */
   t = localtime(&jobtime);
-  t->tm_hour = atoi(tok[pos]);
-  StrnCpy(tmp_time,tok[pos],sizeof(tmp_time));
-  t->tm_min = atoi(tmp_time+3);
-  t->tm_sec = atoi(tmp_time+6);
+  t->tm_hour = atoi(time_string);
+  t->tm_min = atoi(time_string+3);
+  t->tm_sec = atoi(time_string+6);
   jobtime = mktime(t);
 
   return jobtime;
@@ -301,159 +305,88 @@ static time_t LPRng_time(string tok[],int pos)
 
 
 /****************************************************************************
-  parse a lpq line
-  <magnus@hum.auc.dk>
-  Most of the code is directly reused from parse_lpq_bsd()
-
-here are two examples of lpq output under lprng (LPRng-2.3.0)
-
-Printer: humprn@hum-fak
-  Queue: 1 printable job
-  Server: pid 4840 active, Unspooler: pid 4841 active
-  Status: job 'cfA659hum-fak', closing device at Fri Jun 21 10:10:21 1996
- Rank  Owner           Class Job Files                           Size Time
-active magnus@hum-fak      A 659 /var/spool/smb/Notesblok-ikke-na4024 10:03:31
-Printer: humprn@hum-fak (printing disabled)
-  Queue: 1 printable job
-  Warning: no server present
-  Status: finished operations at Fri Jun 21 10:10:32 1996
- Rank  Owner           Class Job Files                           Size Time
-1      magnus@hum-fak      A 387 /var/spool/smb/netbudget.xls    21230 10:50:53
-
-******************************************************************************
-
-NEW FOR LPRng-3.3.5 !
-
-<reinelt@eunet.at> 
-This will not happen anymore: with LPRng-3.3.5 there is always a blank between
-the filename and the size, and the format has changed:
-
-Printer: lj6@lizard  'HP LaserJet 6P'
- Queue: 2 printable jobs
- Server: pid 11941 active
- Unspooler: pid 11942 active
- Status: printed all 1818 bytes at 19:49:59
- Rank   Owner/ID                   Class Job  Files               Size Time
-active  root@lizard+937                A  937 (stdin)            1818 19:49:58
-2       root@lizard+969                A  969 junk.txt           2170 19:50:12
+  parse a lprng lpq line
+  <allan@umich.edu> June 30, 1998.
+  Re-wrote this to handle file names with spaces, multiple file names on one
+  lpq line, etc;
 ****************************************************************************/
 static BOOL parse_lpq_lprng(char *line,print_queue_struct *buf,BOOL first)
 {
-#define        LPRNG_RANKTOK   0
-#define        LPRNG_USERTOK 1
-#define        LPRNG_PRIOTOK 2
-#define        LPRNG_JOBTOK    3
-#define        LPRNG_FILETOK   4
-#define        LPRNG_TOTALTOK 5
-#define LPRNG_TIMETOK 6
-#define        LPRNG_NTOK      7
+#define        LPRNG_RANKTOK   0
+#define        LPRNG_USERTOK   1
+#define        LPRNG_PRIOTOK   2
+#define        LPRNG_JOBTOK    3
+#define        LPRNG_FILETOK   4
+#define        LPRNG_TOTALTOK  (num_tok - 2)
+#define        LPRNG_TIMETOK   (num_tok - 1)
+#define        LPRNG_NTOK      7
+#define        LPRNG_MAXTOK    128 /* PFMA just to keep us from running away. */
+
+  char *tokarr[LPRNG_MAXTOK];
+  char *cptr;
+  int  num_tok = 0;
+  pstring line2;
+
+  pstrcpy(line2,line);
+  tokarr[0] = strtok(line2," \t");
+  num_tok++;
+  while (((tokarr[num_tok] = strtok(NULL," \t")) != NULL)
+         && (num_tok < LPRNG_MAXTOK)) {
+    num_tok++;
+  }
 
-/****************************************************************************
-From lpd_status.c in LPRng source.
-0        1         2         3         4         5         6         7
-12345678901234567890123456789012345678901234567890123456789012345678901234 
-" Rank  Owner           Class Job Files                           Size Time"
-                        plp_snprintf( msg, sizeof(msg), "%-6s %-19s %c %03d %-32s",
-                                number, line, priority, cfp->number, error );
-                                plp_snprintf( msg + len, sizeof(msg)-len, "%4d",
-                                        cfp->jobsize );
-                                plp_snprintf( msg+len, sizeof(msg)-len, " %s",
-                                        Time_str( 1, cfp->statb.st_ctime ) );
-****************************************************************************/
-  /* The following define's are to be able to adjust the values if the
-LPRng source changes.  This is from version 2.3.0.  Magnus  */
-#define SPACE_W 1
-#define RANK_W 6
-#define OWNER_W 19
-#define CLASS_W 1
-#define JOB_W 3
-#define FILE_W 32
-/* The JOBSIZE_W is too small for big jobs, so time is pushed to the right */
-#define JOBSIZE_W 4
-#define RANK_POS 0
-#define OWNER_POS RANK_POS+RANK_W+SPACE_W
-#define CLASS_POS OWNER_POS+OWNER_W+SPACE_W
-#define JOB_POS CLASS_POS+CLASS_W+SPACE_W
-#define FILE_POS JOB_POS+JOB_W+SPACE_W
-#define JOBSIZE_POS FILE_POS+FILE_W
+  /* We must get at least LPRNG_NTOK tokens. */
+  if (num_tok < LPRNG_NTOK) {
+    return(False);
+  }
 
-  
-  string tok[LPRNG_NTOK];
-  int count=0;
+  if (!isdigit(*tokarr[LPRNG_JOBTOK]) || !isdigit(*tokarr[LPRNG_TOTALTOK])) {
+    return(False);
+  }
 
-#ifdef OLD_LPRNG
-/* We only need this bugfix for older versions of lprng - current
-   information is that version 3.3.5 must not have this line
-   in order to work correctly.
-*/
+  buf->job  = atoi(tokarr[LPRNG_JOBTOK]);
+  buf->size = atoi(tokarr[LPRNG_TOTALTOK]);
 
-/* 
-Need to insert one space in front of the size, to be able to use
-next_token() unchanged.  I would have liked to be able to insert a
-space instead, to prevent losing that one char, but perl has spoiled
-me :-\  So I did it the easiest way.
+  if (strequal(tokarr[LPRNG_RANKTOK],"active")) {
+    buf->status = LPQ_PRINTING;
+  } else if (isdigit(*tokarr[LPRNG_RANKTOK])) {
+    buf->status = LPQ_QUEUED;
+  } else {
+    buf->status = LPQ_PAUSED;
+  }
 
-HINT: Use as short a path as possible for the samba spool directory.
-A long spool-path will just waste significant chars of the file name.
-*/
+  buf->priority = *tokarr[LPRNG_PRIOTOK] -'A';
 
-  line[JOBSIZE_POS-1]=' ';
-#endif /* OLD_LPRNG */
+  buf->time = LPRng_time(tokarr[LPRNG_TIMETOK]);
 
-  /* handle the case of "(stdin)" as a filename */
-  string_sub(line,"stdin","STDIN");
-  string_sub(line,"(","\"");
-  string_sub(line,")","\"");
-  
-  for (count=0; count<LPRNG_NTOK && next_token(&line,tok[count],NULL); count++) ;
+  StrnCpy(buf->user,tokarr[LPRNG_USERTOK],sizeof(buf->user)-1);
 
-  /* we must get LPRNG_NTOK tokens */
-  if (count < LPRNG_NTOK)
-    return(False);
+  /* The '@hostname' prevents windows from displaying the printing icon
+   * for the current user on the taskbar.  Plop in a null.
+   */
 
-  /* the Job and Total columns must be integer */
-  if (!isdigit(*tok[LPRNG_JOBTOK]) || !isdigit(*tok[LPRNG_TOTALTOK])) return(False);
+  if ((cptr = strchr(buf->user,'@')) != NULL) {
+    *cptr = '\0';
+  }
 
-  /* if the fname contains a space then use STDIN */
-  /* I do not understand how this would be possible. Magnus. */
-  if (strchr(tok[LPRNG_FILETOK],' '))
-    strcpy(tok[LPRNG_FILETOK],"STDIN");
+  StrnCpy(buf->file,tokarr[LPRNG_FILETOK],sizeof(buf->file)-1);
 
-  /* only take the last part of the filename */
-  {
-    string tmp;
-    char *p = strrchr(tok[LPRNG_FILETOK],'/');
-    if (p)
-      {
-       fstrcpy(tmp,p+1);
-       fstrcpy(tok[LPRNG_FILETOK],tmp);
+  if ((LPRNG_FILETOK + 1) != LPRNG_TOTALTOK) {
+    int bufsize;
+    int i;
+
+    bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
+
+    for (i = (LPRNG_FILETOK + 1); i < LPRNG_TOTALTOK; i++) {
+      safe_strcat(buf->file," ",bufsize);
+      safe_strcat(buf->file,tokarr[i],bufsize - 1);
+      bufsize = sizeof(buf->file) - strlen(buf->file) - 1;
+      if (bufsize <= 0) {
+        break;
       }
+    }
   }
-       
 
-  buf->job = atoi(tok[LPRNG_JOBTOK]);
-  buf->size = atoi(tok[LPRNG_TOTALTOK]);
-  if (strequal(tok[LPRNG_RANKTOK],"active"))
-    buf->status = LPQ_PRINTING;
-  else if (strequal(tok[LPRNG_RANKTOK],"hold"))
-    buf->status = LPQ_PAUSED;
-  else
-    buf->status = LPQ_QUEUED;
-  /*  buf->time = time(NULL); */
-  buf->time = LPRng_time(tok,LPRNG_TIMETOK);
-DEBUG(3,("Time reported for job %d is %s", buf->job, ctime(&buf->time)));
-  StrnCpy(buf->user,tok[LPRNG_USERTOK],sizeof(buf->user)-1);
-  StrnCpy(buf->file,tok[LPRNG_FILETOK],sizeof(buf->file)-1);
-#ifdef LPRNG_PRIOTOK
-  /* Here I try to map the CLASS char to a number, but the number
-     is never shown in Print Manager under NT anyway... Magnus. */
-  buf->priority = atoi(tok[LPRNG_PRIOTOK]-('A'-1));
-#else
-  buf->priority = 1;
-#endif
   return(True);
 }
 
@@ -473,15 +406,18 @@ lazer   lazer RUNNING   537 6297doc.A          kvintus@IE    0 10  2445   1   1
 ********************************************************************/
 static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
 {
-  string tok[11];
+  fstring tok[11];
   int count=0;
 
   /* handle the case of "(standard input)" as a filename */
   string_sub(line,"standard input","STDIN");
-  string_sub(line,"(","\"");
-  string_sub(line,")","\"");
+  all_string_sub(line,"(","\"");
+  all_string_sub(line,")","\"");
 
-  for (count=0; count<10 && next_token(&line,tok[count],NULL); count++) ;
+  for (count=0; 
+       count<10 && 
+              next_token(&line,tok[count],NULL, sizeof(tok[count])); 
+       count++) ;
 
   /* we must get 6 tokens */
   if (count < 10)
@@ -489,15 +425,15 @@ static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
       if ((count == 7) && ((strcmp(tok[0],"QUEUED") == 0) || (strcmp(tok[0],"HELD") == 0)))
       {
           /* the 2nd and 5th columns must be integer */
-          if (!isdigit(*tok[1]) || !isdigit(*tok[4])) return(False);
+          if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4])) return(False);
           buf->size = atoi(tok[4]) * 1024;
           /* if the fname contains a space then use STDIN */
           if (strchr(tok[2],' '))
-            strcpy(tok[2],"STDIN");
+            fstrcpy(tok[2],"STDIN");
 
           /* only take the last part of the filename */
           {
-            string tmp;
+            fstring tmp;
             char *p = strrchr(tok[2],'/');
             if (p)
               {
@@ -523,15 +459,15 @@ static BOOL parse_lpq_aix(char *line,print_queue_struct *buf,BOOL first)
   else
   {
       /* the 4th and 9th columns must be integer */
-      if (!isdigit(*tok[3]) || !isdigit(*tok[8])) return(False);
+      if (!isdigit((int)*tok[3]) || !isdigit((int)*tok[8])) return(False);
       buf->size = atoi(tok[8]) * 1024;
       /* if the fname contains a space then use STDIN */
       if (strchr(tok[4],' '))
-        strcpy(tok[4],"STDIN");
+        fstrcpy(tok[4],"STDIN");
 
       /* only take the last part of the filename */
       {
-        string tmp;
+        fstring tmp;
         char *p = strrchr(tok[4],'/');
         if (p)
           {
@@ -568,7 +504,7 @@ static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
 {
   /* must read two lines to process, therefore keep some values static */
   static BOOL header_line_ok=False, base_prio_reset=False;
-  static string jobuser;
+  static fstring jobuser;
   static int jobid;
   static int jobprio;
   static time_t jobtime;
@@ -578,12 +514,12 @@ static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
   static int base_prio;
  
   int count;
-  char TAB = '\011';  
-  string tok[12];
+  char htab = '\011';  
+  fstring tok[12];
 
   /* If a line begins with a horizontal TAB, it is a subline type */
   
-  if (line[0] == TAB) { /* subline */
+  if (line[0] == htab) { /* subline */
     /* check if it contains the base priority */
     if (!strncmp(line,"\tfence priority : ",18)) {
        base_prio=atoi(&line[18]);
@@ -592,19 +528,19 @@ static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
     if (!header_line_ok) return (False); /* incorrect header line */
     /* handle the case of "(standard input)" as a filename */
     string_sub(line,"standard input","STDIN");
-    string_sub(line,"(","\"");
-    string_sub(line,")","\"");
+    all_string_sub(line,"(","\"");
+    all_string_sub(line,")","\"");
     
-    for (count=0; count<2 && next_token(&line,tok[count],NULL); count++) ;
+    for (count=0; count<2 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
     /* we must get 2 tokens */
     if (count < 2) return(False);
     
     /* the 2nd column must be integer */
-    if (!isdigit(*tok[1])) return(False);
+    if (!isdigit((int)*tok[1])) return(False);
     
     /* if the fname contains a space then use STDIN */
     if (strchr(tok[0],' '))
-      strcpy(tok[0],"STDIN");
+      fstrcpy(tok[0],"STDIN");
     
     buf->size = atoi(tok[1]);
     StrnCpy(buf->file,tok[0],sizeof(buf->file)-1);
@@ -631,14 +567,14 @@ static BOOL parse_lpq_hpux(char * line, print_queue_struct *buf, BOOL first)
     /* handle the dash in the job id */
     string_sub(line,"-"," ");
     
-    for (count=0; count<12 && next_token(&line,tok[count],NULL); count++) ;
+    for (count=0; count<12 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
       
     /* we must get 8 tokens */
     if (count < 8) return(False);
     
     /* first token must be printer name (cannot check ?) */
     /* the 2nd, 5th & 7th column must be integer */
-    if (!isdigit(*tok[1]) || !isdigit(*tok[4]) || !isdigit(*tok[6])) return(False);
+    if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[4]) || !isdigit((int)*tok[6])) return(False);
     jobid = atoi(tok[1]);
     StrnCpy(jobuser,tok[2],sizeof(buf->user)-1);
     jobprio = atoi(tok[4]);
@@ -674,27 +610,27 @@ dcslw-897               tridge            4712   Dec 20 10:30:30 being held
 ****************************************************************************/
 static BOOL parse_lpq_sysv(char *line,print_queue_struct *buf,BOOL first)
 {
-  string tok[9];
+  fstring tok[9];
   int count=0;
   char *p;
 
   /* handle the dash in the job id */
   string_sub(line,"-"," ");
   
-  for (count=0; count<9 && next_token(&line,tok[count],NULL); count++) ;
+  for (count=0; count<9 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
 
   /* we must get 7 tokens */
   if (count < 7)
     return(False);
 
   /* the 2nd and 4th, 6th columns must be integer */
-  if (!isdigit(*tok[1]) || !isdigit(*tok[3])) return(False);
-  if (!isdigit(*tok[5])) return(False);
+  if (!isdigit((int)*tok[1]) || !isdigit((int)*tok[3])) return(False);
+  if (!isdigit((int)*tok[5])) return(False);
 
   /* if the user contains a ! then trim the first part of it */  
   if ((p=strchr(tok[2],'!')))
     {
-      string tmp;
+      fstring tmp;
       fstrcpy(tmp,p+1);
       fstrcpy(tok[2],tmp);
     }
@@ -727,36 +663,36 @@ Printer: txt        (ready)
 ****************************************************************************/
 static BOOL parse_lpq_qnx(char *line,print_queue_struct *buf,BOOL first)
 {
-  string tok[7];
+  fstring tok[7];
   int count=0;
 
-  DEBUG(0,("antes [%s]\n", line));
+  DEBUG(4,("antes [%s]\n", line));
 
   /* handle the case of "-- standard input --" as a filename */
   string_sub(line,"standard input","STDIN");
-  DEBUG(0,("despues [%s]\n", line));
-  string_sub(line,"-- ","\"");
-  string_sub(line," --","\"");
-  DEBUG(0,("despues 1 [%s]\n", line));
+  DEBUG(4,("despues [%s]\n", line));
+  all_string_sub(line,"-- ","\"");
+  all_string_sub(line," --","\"");
+  DEBUG(4,("despues 1 [%s]\n", line));
 
   string_sub(line,"[job #","");
   string_sub(line,"]","");
-  DEBUG(0,("despues 2 [%s]\n", line));
+  DEBUG(4,("despues 2 [%s]\n", line));
 
   
   
-  for (count=0; count<7 && next_token(&line,tok[count],NULL); count++) ;
+  for (count=0; count<7 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
 
   /* we must get 7 tokens */
   if (count < 7)
     return(False);
 
   /* the 3rd and 5th columns must be integer */
-  if (!isdigit(*tok[2]) || !isdigit(*tok[4])) return(False);
+  if (!isdigit((int)*tok[2]) || !isdigit((int)*tok[4])) return(False);
 
   /* only take the last part of the filename */
   {
-    string tmp;
+    fstring tmp;
     char *p = strrchr(tok[6],'/');
     if (p)
       {
@@ -792,35 +728,35 @@ Local  Printer 'lp2' (fjall):
 ****************************************************************************/
 static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
 {
-  string tok[11];
+  fstring tok[11];
   int count=0;
 
   /* handle the case of "(standard input)" as a filename */
   string_sub(line,"stdin","STDIN");
-  string_sub(line,"(","\"");
-  string_sub(line,")","\"");
+  all_string_sub(line,"(","\"");
+  all_string_sub(line,")","\"");
   
-  for (count=0; count<11 && next_token(&line,tok[count],NULL); count++) ;
+  for (count=0; count<11 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
 
   /* we must get 11 tokens */
   if (count < 11)
     return(False);
 
   /* the first must be "active" or begin with an integer */
-  if (strcmp(tok[0],"active") && !isdigit(tok[0][0]))
+  if (strcmp(tok[0],"active") && !isdigit((int)tok[0][0]))
     return(False);
 
   /* the 5th and 8th must be integer */
-  if (!isdigit(*tok[4]) || !isdigit(*tok[7])) 
+  if (!isdigit((int)*tok[4]) || !isdigit((int)*tok[7])) 
     return(False);
 
   /* if the fname contains a space then use STDIN */
   if (strchr(tok[6],' '))
-    strcpy(tok[6],"STDIN");
+    fstrcpy(tok[6],"STDIN");
 
   /* only take the last part of the filename */
   {
-    string tmp;
+    fstring tmp;
     char *p = strrchr(tok[6],'/');
     if (p)
       {
@@ -846,6 +782,84 @@ static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
   return(True);
 }
 
+/****************************************************************************
+parse a qstat line
+
+here is an example of "qstat -l -d qms" output under softq
+
+Queue qms: 2 jobs; daemon active (313); enabled; accepting;
+ job-ID   submission-time     pri     size owner      title 
+205980: H 98/03/09 13:04:05     0    15733 stephenf   chap1.ps
+206086:>  98/03/12 17:24:40     0      659 chris      -
+206087:   98/03/12 17:24:45     0     4876 chris      -
+Total:      21268 bytes in queue
+
+
+****************************************************************************/
+static BOOL parse_lpq_softq(char *line,print_queue_struct *buf,BOOL first)
+{
+  fstring tok[10];
+  int count=0;
+
+  /* mung all the ":"s to spaces*/
+  string_sub(line,":"," ");
+  
+  for (count=0; count<10 && next_token(&line,tok[count],NULL,sizeof(tok[count])); count++) ;
+
+  /* we must get 9 tokens */
+  if (count < 9)
+    return(False);
+
+  /* the 1st and 7th columns must be integer */
+  if (!isdigit((int)*tok[0]) || !isdigit((int)*tok[6]))  return(False);
+  /* if the 2nd column is either '>' or 'H' then the 7th and 8th must be
+   * integer, else it's the 6th and 7th that must be
+   */
+  if (*tok[1] == 'H' || *tok[1] == '>')
+    {
+      if (!isdigit((int)*tok[7]))
+        return(False);
+      buf->status = *tok[1] == '>' ? LPQ_PRINTING : LPQ_PAUSED;
+      count = 1;
+    }
+  else
+    {
+      if (!isdigit((int)*tok[5]))
+        return(False);
+      buf->status = LPQ_QUEUED;
+      count = 0;
+    }
+       
+
+  buf->job = atoi(tok[0]);
+  buf->size = atoi(tok[count+6]);
+  buf->priority = atoi(tok[count+5]);
+  StrnCpy(buf->user,tok[count+7],sizeof(buf->user)-1);
+  StrnCpy(buf->file,tok[count+8],sizeof(buf->file)-1);
+  buf->time = time(NULL);              /* default case: take current time */
+  {
+    time_t jobtime;
+    struct tm *t;
+
+    t = localtime(&buf->time);
+    t->tm_mday = atoi(tok[count+2]+6);
+    t->tm_mon  = atoi(tok[count+2]+3);
+    switch (*tok[count+2])
+    {
+    case 7: case 8: case 9: t->tm_year = atoi(tok[count+2]) + 1900; break;
+    default:                t->tm_year = atoi(tok[count+2]) + 2000; break;
+    }
+
+    t->tm_hour = atoi(tok[count+3]);
+    t->tm_min = atoi(tok[count+4]);
+    t->tm_sec = atoi(tok[count+5]);
+    jobtime = mktime(t);
+    if (jobtime != (time_t)-1)
+      buf->time = jobtime; 
+  }
+
+  return(True);
+}
 
 
 char *stat0_strings[] = { "enabled", "online", "idle", "no entries", "free", "ready", NULL };
@@ -881,6 +895,9 @@ static BOOL parse_lpq_entry(int snum,char *line,
     case PRINT_PLP:
       ret = parse_lpq_plp(line,buf,first);
       break;
+    case PRINT_SOFTQ:
+      ret = parse_lpq_softq(line,buf,first);
+      break;
     default:
       ret = parse_lpq_bsd(line,buf,first);
       break;
@@ -942,105 +959,102 @@ static BOOL parse_lpq_entry(int snum,char *line,
 /****************************************************************************
 get a printer queue
 ****************************************************************************/
-int get_printqueue(int snum,int cnum,print_queue_struct **queue,
+int get_printqueue(int snum, 
+                  connection_struct *conn,print_queue_struct **queue,
                   print_status_struct *status)
 {
-  char *lpq_command = lp_lpqcommand(snum);
-  char *printername = PRINTERNAME(snum);
-  int ret=0,count=0;
-  pstring syscmd;
-  fstring outfile;
-  pstring line;
-  FILE *f;
-  struct stat sbuf;
-  BOOL dorun=True;
-  int cachetime = lp_lpqcachetime();
-
-  *line = 0;
-  check_lpq_cache(snum);
-  
-  if (!printername || !*printername)
-    {
-      DEBUG(6,("xx replacing printer name with service (snum=(%s,%d))\n",
-              lp_servicename(snum),snum));
-      printername = lp_servicename(snum);
-    }
+       char *lpq_command = lp_lpqcommand(snum);
+       char *printername = PRINTERNAME(snum);
+       int ret=0,count=0;
+       pstring syscmd;
+       fstring outfile;
+       pstring line;
+       FILE *f;
+       SMB_STRUCT_STAT sbuf;
+       BOOL dorun=True;
+       int cachetime = lp_lpqcachetime();
+       
+       *line = 0;
+       check_lpq_cache(snum);
+       
+       if (!printername || !*printername) {
+               DEBUG(6,("xx replacing printer name with service (snum=(%s,%d))\n",
+                        lp_servicename(snum),snum));
+               printername = lp_servicename(snum);
+       }
     
-  if (!lpq_command || !(*lpq_command))
-    {
-      DEBUG(5,("No lpq command\n"));
-      return(0);
-    }
+       if (!lpq_command || !(*lpq_command)) {
+               DEBUG(5,("No lpq command\n"));
+               return(0);
+       }
     
-  pstrcpy(syscmd,lpq_command);
-  string_sub(syscmd,"%p",printername);
+       pstrcpy(syscmd,lpq_command);
+       string_sub(syscmd,"%p",printername);
 
-  standard_sub(cnum,syscmd);
+       standard_sub(conn,syscmd);
 
-  sprintf(outfile,"%s/lpq.%08x",tmpdir(),str_checksum(syscmd));
+       slprintf(outfile,sizeof(outfile)-1, "%s/lpq.%08x",tmpdir(),str_checksum(syscmd));
   
-  if (!lpq_cache_reset[snum] && cachetime && !stat(outfile,&sbuf)) 
-    {
-      if (time(NULL) - sbuf.st_mtime < cachetime) {
-       DEBUG(3,("Using cached lpq output\n"));
-       dorun = False;
-      }
-    }
-
-  if (dorun) {
-    ret = smbrun(syscmd,outfile,True);
-    DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
-  }
+       if (!lpq_cache_reset[snum] && cachetime && !sys_stat(outfile,&sbuf)) {
+               if (time(NULL) - sbuf.st_mtime < cachetime) {
+                       DEBUG(3,("Using cached lpq output\n"));
+                       dorun = False;
+               }
+       }
 
-  lpq_cache_reset[snum] = False;
+       if (dorun) {
+               ret = smbrun(syscmd,outfile,True);
+               DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
+       }
 
-  f = fopen(outfile,"r");
-  if (!f) {
-    return(0);
-  }
+       lpq_cache_reset[snum] = False;
 
-  if (status) {
-    strcpy(status->message,"");
-    status->status = LPSTAT_OK;
-  }
-      
-  while (fgets(line,sizeof(pstring),f))
-    {
-      DEBUG(6,("QUEUE2: %s\n",line));
-
-      *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
-      if (! *queue)
-       {
-         count = 0;
-         break;
+       f = sys_fopen(outfile,"r");
+       if (!f) {
+               return(0);
        }
 
-      bzero((char *)&(*queue)[count],sizeof(**queue));
-         
-      /* parse it */
-      if (!parse_lpq_entry(snum,line,&(*queue)[count],status,count==0))
-       continue;
+       if (status) {
+               fstrcpy(status->message,"");
+               status->status = LPSTAT_OK;
+       }
+       
+       while (fgets(line,sizeof(pstring),f)) {
+               DEBUG(6,("QUEUE2: %s\n",line));
+               
+               *queue = Realloc(*queue,sizeof(print_queue_struct)*(count+1));
+               if (! *queue) {
+                       count = 0;
+                       break;
+               }
+
+               bzero((char *)&(*queue)[count],sizeof(**queue));
          
-      count++;
-    }        
-
-  fclose(f);
-
-  if (!cachetime) {
-    unlink(outfile);
-  } else {
-    /* we only expect this to succeed on trapdoor systems, on normal systems
-     the file is owned by root */
-    chmod(outfile,0666);
-  }
-  return(count);
+               /* parse it */
+               if (!parse_lpq_entry(snum,line,
+                                    &(*queue)[count],status,count==0))
+                       continue;
+               
+               count++;
+       }             
+
+       fclose(f);
+       
+       if (!cachetime) {
+               unlink(outfile);
+       } else {
+               /* we only expect this to succeed on trapdoor systems,
+                  on normal systems the file is owned by root */
+               chmod(outfile,0666);
+       }
+       return(count);
 }
 
 
 /****************************************************************************
 delete a printer queue entry
 ****************************************************************************/
-void del_printqueue(int cnum,int snum,int jobid)
+void del_printqueue(connection_struct *conn,int snum,int jobid)
 {
   char *lprm_command = lp_lprmcommand(snum);
   char *printername = PRINTERNAME(snum);
@@ -1061,12 +1075,12 @@ void del_printqueue(int cnum,int snum,int jobid)
       return;
     }
     
-  sprintf(jobstr,"%d",jobid);
+  slprintf(jobstr,sizeof(jobstr)-1,"%d",jobid);
 
   pstrcpy(syscmd,lprm_command);
   string_sub(syscmd,"%p",printername);
   string_sub(syscmd,"%j",jobstr);
-  standard_sub(cnum,syscmd);
+  standard_sub(conn,syscmd);
 
   ret = smbrun(syscmd,NULL,False);
   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
@@ -1076,7 +1090,7 @@ void del_printqueue(int cnum,int snum,int jobid)
 /****************************************************************************
 change status of a printer queue entry
 ****************************************************************************/
-void status_printjob(int cnum,int snum,int jobid,int status)
+void status_printjob(connection_struct *conn,int snum,int jobid,int status)
 {
   char *lpstatus_command = 
     (status==LPQ_PAUSED?lp_lppausecommand(snum):lp_lpresumecommand(snum));
@@ -1099,12 +1113,12 @@ void status_printjob(int cnum,int snum,int jobid,int status)
       return;
     }
     
-  sprintf(jobstr,"%d",jobid);
+  slprintf(jobstr,sizeof(jobstr)-1,"%d",jobid);
 
   pstrcpy(syscmd,lpstatus_command);
   string_sub(syscmd,"%p",printername);
   string_sub(syscmd,"%j",jobstr);
-  standard_sub(cnum,syscmd);
+  standard_sub(conn,syscmd);
 
   ret = smbrun(syscmd,NULL,False);
   DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));  
@@ -1132,3 +1146,84 @@ void printjob_decode(int jobid, int *snum, int *job)
        (*snum) = (jobid >> 8) & 0xFF;
        (*job) = jobid & 0xFF;
 }
+
+/****************************************************************************
+ Change status of a printer queue
+****************************************************************************/
+
+void status_printqueue(connection_struct *conn,int snum,int status)
+{
+  char *queuestatus_command = (status==LPSTAT_STOPPED ? 
+                               lp_queuepausecommand(snum):lp_queueresumecommand(snum));
+  char *printername = PRINTERNAME(snum);
+  pstring syscmd;
+  int ret;
+
+  if (!printername || !*printername) {
+    DEBUG(6,("replacing printer name with service (snum=(%s,%d))\n",
+          lp_servicename(snum),snum));
+    printername = lp_servicename(snum);
+  }
+
+  if (!queuestatus_command || !(*queuestatus_command)) {
+    DEBUG(5,("No queuestatus command to %s job\n",
+          (status==LPSTAT_STOPPED?"pause":"resume")));
+    return;
+  }
+
+  pstrcpy(syscmd,queuestatus_command);
+  string_sub(syscmd,"%p",printername);
+  standard_sub(conn,syscmd);
+
+  ret = smbrun(syscmd,NULL,False);
+  DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
+  lpq_reset(snum); /* queue has changed */
+}
+
+
+
+/***************************************************************************
+auto-load printer services
+***************************************************************************/
+static void add_all_printers(void)
+{
+       int printers = lp_servicenumber(PRINTERS_NAME);
+
+       if (printers < 0) return;
+
+       pcap_printer_fn(lp_add_one_printer);
+}
+
+/***************************************************************************
+auto-load some homes and printer services
+***************************************************************************/
+static void add_auto_printers(void)
+{
+       char *p;
+       int printers;
+       char *str = lp_auto_services();
+
+       if (!str) return;
+
+       printers = lp_servicenumber(PRINTERS_NAME);
+
+       if (printers < 0) return;
+       
+       for (p=strtok(str,LIST_SEP);p;p=strtok(NULL,LIST_SEP)) {
+               if (lp_servicenumber(p) >= 0) continue;
+               
+               if (pcap_printername_ok(p,NULL)) {
+                       lp_add_printer(p,printers);
+               }
+       }
+}
+
+/***************************************************************************
+load automatic printer services
+***************************************************************************/
+void load_printers(void)
+{
+       add_auto_printers();
+       if (lp_load_printers())
+               add_all_printers();
+}