s3: Lift the server_messaging_context from get_stored_queue_info
[amitay/samba.git] / source3 / printing / printing.c
index bb293800078d1204b39238591325b4a83b8d0918..72e388fda744296f7d7625f95b3d9467cd22fbfd 100644 (file)
@@ -1,39 +1,41 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    Version 3.0
    printing backend routines
    Copyright (C) Andrew Tridgell 1992-2000
    Copyright (C) Jeremy Allison 2002
    Unix SMB/Netbios implementation.
    Version 3.0
    printing backend routines
    Copyright (C) Andrew Tridgell 1992-2000
    Copyright (C) Jeremy Allison 2002
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "printing.h"
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "printing.h"
+#include "librpc/gen_ndr/messaging.h"
+#include "../librpc/gen_ndr/ndr_spoolss.h"
+#include "nt_printing.h"
+#include "../librpc/gen_ndr/netlogon.h"
 
 
-extern SIG_ATOMIC_T got_sig_term;
-extern SIG_ATOMIC_T reload_after_sighup;
 extern struct current_user current_user;
 extern userdom_struct current_user_info;
 
 /* Current printer interface */
 static bool remove_from_jobs_changed(const char* sharename, uint32 jobid);
 
 extern struct current_user current_user;
 extern userdom_struct current_user_info;
 
 /* Current printer interface */
 static bool remove_from_jobs_changed(const char* sharename, uint32 jobid);
 
-/* 
+/*
    the printing backend revolves around a tdb database that stores the
    the printing backend revolves around a tdb database that stores the
-   SMB view of the print queue 
-   
+   SMB view of the print queue
+
    The key for this database is a jobid - a internally generated number that
    uniquely identifies a print job
 
    The key for this database is a jobid - a internally generated number that
    uniquely identifies a print job
 
@@ -41,7 +43,7 @@ static bool remove_from_jobs_changed(const char* sharename, uint32 jobid);
      - possibly running lpq and updating the internal database from that
      - reading entries from the database
 
      - possibly running lpq and updating the internal database from that
      - reading entries from the database
 
-   jobids are assigned when a job starts spooling. 
+   jobids are assigned when a job starts spooling.
 */
 
 static TDB_CONTEXT *rap_tdb;
 */
 
 static TDB_CONTEXT *rap_tdb;
@@ -116,10 +118,12 @@ bool rap_to_pjobid(uint16 rap_jobid, fstring sharename, uint32 *pjobid)
        key.dptr = buf;
        key.dsize = sizeof(rap_jobid);
        data = tdb_fetch(rap_tdb, key);
        key.dptr = buf;
        key.dsize = sizeof(rap_jobid);
        data = tdb_fetch(rap_tdb, key);
-       if ( data.dptr && data.dsize == sizeof(struct rap_jobid_key) ) 
+       if ( data.dptr && data.dsize == sizeof(struct rap_jobid_key) )
        {
                struct rap_jobid_key *jinfo = (struct rap_jobid_key*)data.dptr;
        {
                struct rap_jobid_key *jinfo = (struct rap_jobid_key*)data.dptr;
-               fstrcpy( sharename, jinfo->sharename );
+               if (sharename != NULL) {
+                       fstrcpy( sharename, jinfo->sharename );
+               }
                *pjobid = jinfo->jobid;
                DEBUG(10,("rap_to_pjobid: jobid %u maps to RAP jobid %u\n",
                        (unsigned int)*pjobid, (unsigned int)rap_jobid));
                *pjobid = jinfo->jobid;
                DEBUG(10,("rap_to_pjobid: jobid %u maps to RAP jobid %u\n",
                        (unsigned int)*pjobid, (unsigned int)rap_jobid));
@@ -133,7 +137,7 @@ bool rap_to_pjobid(uint16 rap_jobid, fstring sharename, uint32 *pjobid)
        return False;
 }
 
        return False;
 }
 
-static void rap_jobid_delete(const char* sharename, uint32 jobid)
+void rap_jobid_delete(const char* sharename, uint32 jobid)
 {
        TDB_DATA key, data;
        uint16 rap_jobid;
 {
        TDB_DATA key, data;
        uint16 rap_jobid;
@@ -225,10 +229,10 @@ void printing_end(void)
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
- Retrieve the set of printing functions for a given service.  This allows 
+ Retrieve the set of printing functions for a given service.  This allows
  us to set the printer function table based on the value of the 'printing'
  service parameter.
  us to set the printer function table based on the value of the 'printing'
  service parameter.
+
  Use the generic interface as the default and only use cups interface only
  when asked for (and only when supported)
 ****************************************************************************/
  Use the generic interface as the default and only use cups interface only
  when asked for (and only when supported)
 ****************************************************************************/
@@ -250,7 +254,7 @@ static struct printif *get_printer_fns_from_type( enum printing_types type )
 #endif /* HAVE_IPRINT */
 
        printer_fns->type = type;
 #endif /* HAVE_IPRINT */
 
        printer_fns->type = type;
-       
+
        return printer_fns;
 }
 
        return printer_fns;
 }
 
@@ -274,10 +278,93 @@ static TDB_DATA print_key(uint32 jobid, uint32 *tmp)
        return ret;
 }
 
        return ret;
 }
 
+/****************************************************************************
+ Pack the devicemode to store it in a tdb.
+****************************************************************************/
+static int pack_devicemode(struct spoolss_DeviceMode *devmode, uint8 *buf, int buflen)
+{
+       enum ndr_err_code ndr_err;
+       DATA_BLOB blob;
+       int len = 0;
+
+       if (devmode) {
+               ndr_err = ndr_push_struct_blob(&blob, talloc_tos(),
+                                              devmode,
+                                              (ndr_push_flags_fn_t)
+                                              ndr_push_spoolss_DeviceMode);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       DEBUG(10, ("pack_devicemode: "
+                                  "error encoding spoolss_DeviceMode\n"));
+                       goto done;
+               }
+       } else {
+               ZERO_STRUCT(blob);
+       }
+
+       len = tdb_pack(buf, buflen, "B", blob.length, blob.data);
+
+       if (devmode) {
+               DEBUG(8, ("Packed devicemode [%s]\n", devmode->formname));
+       }
+
+done:
+       return len;
+}
+
+/****************************************************************************
+ Unpack the devicemode to store it in a tdb.
+****************************************************************************/
+static int unpack_devicemode(TALLOC_CTX *mem_ctx,
+                     const uint8 *buf, int buflen,
+                     struct spoolss_DeviceMode **devmode)
+{
+       struct spoolss_DeviceMode *dm;
+       enum ndr_err_code ndr_err;
+       char *data = NULL;
+       int data_len = 0;
+       DATA_BLOB blob;
+       int len = 0;
+
+       *devmode = NULL;
+
+       len = tdb_unpack(buf, buflen, "B", &data_len, &data);
+       if (!data) {
+               return len;
+       }
+
+       dm = talloc_zero(mem_ctx, struct spoolss_DeviceMode);
+       if (!dm) {
+               goto done;
+       }
+
+       blob = data_blob_const(data, data_len);
+
+       ndr_err = ndr_pull_struct_blob(&blob, dm, dm,
+                       (ndr_pull_flags_fn_t)ndr_pull_spoolss_DeviceMode);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(10, ("unpack_devicemode: "
+                          "error parsing spoolss_DeviceMode\n"));
+               goto done;
+       }
+
+       DEBUG(8, ("Unpacked devicemode [%s](%s)\n",
+                 dm->devicename, dm->formname));
+       if (dm->driverextra_data.data) {
+               DEBUG(8, ("with a private section of %d bytes\n",
+                         dm->__driverextra_length));
+       }
+
+       *devmode = dm;
+
+done:
+       SAFE_FREE(data);
+       return len;
+}
+
 /***********************************************************************
 /***********************************************************************
- unpack a pjob from a tdb buffer 
+ unpack a pjob from a tdb buffer
 ***********************************************************************/
 ***********************************************************************/
+
 int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
 {
        int     len = 0;
 int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
 {
        int     len = 0;
@@ -287,7 +374,7 @@ int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
 
        if ( !buf || !pjob )
                return -1;
 
        if ( !buf || !pjob )
                return -1;
-               
+
        len += tdb_unpack(buf+len, buflen-len, "dddddddddffff",
                                &pjpid,
                                &pjsysjob,
        len += tdb_unpack(buf+len, buflen-len, "dddddddddffff",
                                &pjpid,
                                &pjsysjob,
@@ -302,13 +389,15 @@ int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
                                pjob->jobname,
                                pjob->user,
                                pjob->queuename);
                                pjob->jobname,
                                pjob->user,
                                pjob->queuename);
-                               
+
        if ( len == -1 )
                return -1;
        if ( len == -1 )
                return -1;
-               
-       if ( (used = unpack_devicemode(&pjob->nt_devmode, buf+len, buflen-len)) == -1 )
+
+        used = unpack_devicemode(NULL, buf+len, buflen-len, &pjob->devmode);
+        if (used == -1) {
                return -1;
                return -1;
-       
+        }
+
        len += used;
 
        pjob->pid = pjpid;
        len += used;
 
        pjob->pid = pjpid;
@@ -320,7 +409,7 @@ int unpack_pjob( uint8 *buf, int buflen, struct printjob *pjob )
        pjob->page_count = pjpage_count;
        pjob->spooled = pjspooled;
        pjob->smbjob = pjsmbjob;
        pjob->page_count = pjpage_count;
        pjob->spooled = pjspooled;
        pjob->smbjob = pjsmbjob;
-       
+
        return len;
 
 }
        return len;
 
 }
@@ -351,9 +440,7 @@ static struct printjob *print_job_find(const char *sharename, uint32 jobid)
                return NULL;
        }
 
                return NULL;
        }
 
-       if ( pjob.nt_devmode ) {
-               free_nt_devicemode( &pjob.nt_devmode );
-       }
+       talloc_free(pjob.devmode);
 
        ZERO_STRUCT( pjob );
 
 
        ZERO_STRUCT( pjob );
 
@@ -449,7 +536,7 @@ static const struct {
        { LPQ_PAPEROUT, JOB_STATUS_PAPEROUT },
        { LPQ_PRINTED, JOB_STATUS_PRINTED },
        { LPQ_DELETED, JOB_STATUS_DELETED },
        { LPQ_PAPEROUT, JOB_STATUS_PAPEROUT },
        { LPQ_PRINTED, JOB_STATUS_PRINTED },
        { LPQ_DELETED, JOB_STATUS_DELETED },
-       { LPQ_BLOCKED, JOB_STATUS_BLOCKED },
+       { LPQ_BLOCKED, JOB_STATUS_BLOCKED_DEVQ },
        { LPQ_USER_INTERVENTION, JOB_STATUS_USER_INTERVENTION },
        { -1, 0 }
 };
        { LPQ_USER_INTERVENTION, JOB_STATUS_USER_INTERVENTION },
        { -1, 0 }
 };
@@ -481,13 +568,13 @@ static void pjob_store_notify(const char* sharename, uint32 jobid, struct printj
        /* Job attributes that can't be changed.  We only send
           notification for these on a new job. */
 
        /* Job attributes that can't be changed.  We only send
           notification for these on a new job. */
 
-       /* ACHTUNG!  Due to a bug in Samba's spoolss parsing of the 
-          NOTIFY_INFO_DATA buffer, we *have* to send the job submission 
-          time first or else we'll end up with potential alignment 
-          errors.  I don't think the systemtime should be spooled as 
-          a string, but this gets us around that error.   
-          --jerry (i'll feel dirty for this) */
+       /* ACHTUNG!  Due to a bug in Samba's spoolss parsing of the
+          NOTIFY_INFO_DATA buffer, we *have* to send the job submission
+          time first or else we'll end up with potential alignment
+          errors.  I don't think the systemtime should be spooled as
+          a string, but this gets us around that error.
+          --jerry (i'll feel dirty for this) */
+
        if (new_job) {
                notify_job_submitted(sharename, jobid, new_data->starttime);
                notify_job_username(sharename, jobid, new_data->user);
        if (new_job) {
                notify_job_submitted(sharename, jobid, new_data->starttime);
                notify_job_username(sharename, jobid, new_data->user);
@@ -524,7 +611,7 @@ static bool pjob_store(const char* sharename, uint32 jobid, struct printjob *pjo
        struct tdb_print_db     *pdb = get_print_db_byname(sharename);
        uint8                   *buf = NULL;
        int                     len, newlen, buflen;
        struct tdb_print_db     *pdb = get_print_db_byname(sharename);
        uint8                   *buf = NULL;
        int                     len, newlen, buflen;
-       
+
 
        if (!pdb)
                return False;
 
        if (!pdb)
                return False;
@@ -536,7 +623,7 @@ static bool pjob_store(const char* sharename, uint32 jobid, struct printjob *pjo
        /* Doh!  Now we have to pack/unpack data since the NT_DEVICEMODE was added */
 
        newlen = 0;
        /* Doh!  Now we have to pack/unpack data since the NT_DEVICEMODE was added */
 
        newlen = 0;
-       
+
        do {
                len = 0;
                buflen = newlen;
        do {
                len = 0;
                buflen = newlen;
@@ -555,8 +642,8 @@ static bool pjob_store(const char* sharename, uint32 jobid, struct printjob *pjo
                                pjob->user,
                                pjob->queuename);
 
                                pjob->user,
                                pjob->queuename);
 
-               len += pack_devicemode(pjob->nt_devmode, buf+len, buflen-len);
-       
+               len += pack_devicemode(pjob->devmode, buf+len, buflen-len);
+
                if (buflen != len) {
                        buf = (uint8 *)SMB_REALLOC(buf, len);
                        if (!buf) {
                if (buflen != len) {
                        buf = (uint8 *)SMB_REALLOC(buf, len);
                        if (!buf) {
@@ -566,8 +653,8 @@ static bool pjob_store(const char* sharename, uint32 jobid, struct printjob *pjo
                        newlen = len;
                }
        } while ( buflen != len );
                        newlen = len;
                }
        } while ( buflen != len );
-               
-       
+
+
        /* Store new data */
 
        new_data.dptr = buf;
        /* Store new data */
 
        new_data.dptr = buf;
@@ -587,7 +674,7 @@ static bool pjob_store(const char* sharename, uint32 jobid, struct printjob *pjo
                        if ( unpack_pjob( old_data.dptr, old_data.dsize, &old_pjob ) != -1 )
                        {
                                pjob_store_notify( sharename, jobid, &old_pjob , pjob );
                        if ( unpack_pjob( old_data.dptr, old_data.dsize, &old_pjob ) != -1 )
                        {
                                pjob_store_notify( sharename, jobid, &old_pjob , pjob );
-                               free_nt_devicemode( &old_pjob.nt_devmode );
+                               talloc_free(old_pjob.devmode);
                        }
                }
                else {
                        }
                }
                else {
@@ -631,10 +718,10 @@ void pjob_delete(const char* sharename, uint32 jobid)
        /* We must cycle through JOB_STATUS_DELETING and
            JOB_STATUS_DELETED for the port monitor to delete the job
            properly. */
        /* We must cycle through JOB_STATUS_DELETING and
            JOB_STATUS_DELETED for the port monitor to delete the job
            properly. */
-       
+
        job_status = JOB_STATUS_DELETING|JOB_STATUS_DELETED;
        notify_job_status(sharename, jobid, job_status);
        job_status = JOB_STATUS_DELETING|JOB_STATUS_DELETED;
        notify_job_status(sharename, jobid, job_status);
-       
+
        /* Remove from printing.tdb */
 
        tdb_delete(pdb->tdb, print_key(jobid, &tmp));
        /* Remove from printing.tdb */
 
        tdb_delete(pdb->tdb, print_key(jobid, &tmp));
@@ -643,25 +730,6 @@ void pjob_delete(const char* sharename, uint32 jobid)
        rap_jobid_delete(sharename, jobid);
 }
 
        rap_jobid_delete(sharename, jobid);
 }
 
-/****************************************************************************
- Parse a file name from the system spooler to generate a jobid.
-****************************************************************************/
-
-static uint32 print_parse_jobid(char *fname)
-{
-       int jobid;
-
-       if (strncmp(fname,PRINT_SPOOL_PREFIX,strlen(PRINT_SPOOL_PREFIX)) != 0)
-               return (uint32)-1;
-       fname += strlen(PRINT_SPOOL_PREFIX);
-
-       jobid = atoi(fname);
-       if (jobid <= 0)
-               return (uint32)-1;
-
-       return (uint32)jobid;
-}
-
 /****************************************************************************
  List a unix job in the print database.
 ****************************************************************************/
 /****************************************************************************
  List a unix job in the print database.
 ****************************************************************************/
@@ -670,7 +738,7 @@ static void print_unix_job(const char *sharename, print_queue_struct *q, uint32
 {
        struct printjob pj, *old_pj;
 
 {
        struct printjob pj, *old_pj;
 
-       if (jobid == (uint32)-1) 
+       if (jobid == (uint32)-1)
                jobid = q->job + UNIX_JOB_START;
 
        /* Preserve the timestamp on an existing unix print job */
                jobid = q->job + UNIX_JOB_START;
 
        /* Preserve the timestamp on an existing unix print job */
@@ -723,11 +791,11 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
 
        if (  key.dsize != sizeof(jobid) )
                return 0;
 
        if (  key.dsize != sizeof(jobid) )
                return 0;
-               
+
        jobid = IVAL(key.dptr, 0);
        if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 )
                return 0;
        jobid = IVAL(key.dptr, 0);
        if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 )
                return 0;
-       free_nt_devicemode( &pjob.nt_devmode );
+       talloc_free(pjob.devmode);
 
 
        if (!pjob.smbjob) {
 
 
        if (!pjob.smbjob) {
@@ -743,7 +811,7 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
                                                (unsigned int)jobid ));
                        pjob_delete(ts->sharename, jobid);
                        return 0;
                                                (unsigned int)jobid ));
                        pjob_delete(ts->sharename, jobid);
                        return 0;
-               } 
+               }
 
                /* need to continue the the bottom of the function to
                   save the correct attributes */
 
                /* need to continue the the bottom of the function to
                   save the correct attributes */
@@ -764,7 +832,7 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
        }
 
        /* this check only makes sense for jobs submitted from Windows clients */
        }
 
        /* this check only makes sense for jobs submitted from Windows clients */
-       
+
        if ( pjob.smbjob ) {
                for (i=0;i<ts->qcount;i++) {
                        uint32 curr_jobid;
        if ( pjob.smbjob ) {
                for (i=0;i<ts->qcount;i++) {
                        uint32 curr_jobid;
@@ -781,7 +849,7 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
                                if ( pjob.status == LPQ_DELETING ) {
                                        int result;
 
                                if ( pjob.status == LPQ_DELETING ) {
                                        int result;
 
-                                       result = (*(ts->print_if->job_delete))( 
+                                       result = (*(ts->print_if->job_delete))(
                                                ts->sharename, ts->lprm_command, &pjob );
 
                                        if ( result != 0 ) {
                                                ts->sharename, ts->lprm_command, &pjob );
 
                                        if ( result != 0 ) {
@@ -794,14 +862,14 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
                                                pjob_delete(ts->sharename, jobid);
                                                pjob.status = LPQ_DELETED;
                                        }
                                                pjob_delete(ts->sharename, jobid);
                                                pjob.status = LPQ_DELETED;
                                        }
-                                               
+
                                }
 
                                break;
                        }
                }
        }
                                }
 
                                break;
                        }
                }
        }
-       
+
        /* The job isn't in the system queue - we have to assume it has
           completed, so delete the database entry. */
 
        /* The job isn't in the system queue - we have to assume it has
           completed, so delete the database entry. */
 
@@ -825,11 +893,11 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
                return 0;
        }
 
                return 0;
        }
 
-       /* Save the pjob attributes we will store. 
-          FIXME!!! This is the only place where queue->job 
+       /* Save the pjob attributes we will store.
+          FIXME!!! This is the only place where queue->job
           represents the SMB jobid      --jerry */
 
           represents the SMB jobid      --jerry */
 
-       ts->queue[i].job = jobid;               
+       ts->queue[i].job = jobid;
        ts->queue[i].size = pjob.size;
        ts->queue[i].page_count = pjob.page_count;
        ts->queue[i].status = pjob.status;
        ts->queue[i].size = pjob.size;
        ts->queue[i].page_count = pjob.page_count;
        ts->queue[i].status = pjob.status;
@@ -903,7 +971,7 @@ static void set_updating_pid(const fstring sharename, bool updating)
        TDB_DATA data;
        pid_t updating_pid = sys_getpid();
        uint8 buffer[4];
        TDB_DATA data;
        pid_t updating_pid = sys_getpid();
        uint8 buffer[4];
-       
+
        struct tdb_print_db *pdb = get_print_db_byname(sharename);
 
        if (!pdb)
        struct tdb_print_db *pdb = get_print_db_byname(sharename);
 
        if (!pdb)
@@ -911,8 +979,8 @@ static void set_updating_pid(const fstring sharename, bool updating)
 
        slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
        key = string_tdb_data(keystr);
 
        slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", sharename);
        key = string_tdb_data(keystr);
-       
-       DEBUG(5, ("set_updating_pid: %s updating lpq cache for print share %s\n", 
+
+       DEBUG(5, ("set_updating_pid: %s updating lpq cache for print share %s\n",
                updating ? "" : "not ",
                sharename ));
 
                updating ? "" : "not ",
                sharename ));
 
@@ -921,12 +989,12 @@ static void set_updating_pid(const fstring sharename, bool updating)
                release_print_db(pdb);
                return;
        }
                release_print_db(pdb);
                return;
        }
-       
+
        SIVAL( buffer, 0, updating_pid);
        data.dptr = buffer;
        data.dsize = 4;         /* we always assume this is a 4 byte value */
 
        SIVAL( buffer, 0, updating_pid);
        data.dptr = buffer;
        data.dsize = 4;         /* we always assume this is a 4 byte value */
 
-       tdb_store(pdb->tdb, key, data, TDB_REPLACE);    
+       tdb_store(pdb->tdb, key, data, TDB_REPLACE);
        release_print_db(pdb);
 }
 
        release_print_db(pdb);
 }
 
@@ -1072,36 +1140,36 @@ static bool print_cache_expired(const char *sharename, bool check_pending)
         * that last lpq scan would stay around for a loooong loooong time... :-). JRA.
         */
 
         * that last lpq scan would stay around for a loooong loooong time... :-). JRA.
         */
 
-       if (last_qscan_time == ((time_t)-1) 
-               || (time_now - last_qscan_time) >= lp_lpqcachetime() 
-               || last_qscan_time > (time_now + MAX_CACHE_VALID_TIME)) 
+       if (last_qscan_time == ((time_t)-1)
+               || (time_now - last_qscan_time) >= lp_lpqcachetime()
+               || last_qscan_time > (time_now + MAX_CACHE_VALID_TIME))
        {
                uint32 u;
                time_t msg_pending_time;
 
        {
                uint32 u;
                time_t msg_pending_time;
 
-               DEBUG(4, ("print_cache_expired: cache expired for queue %s " 
-                       "(last_qscan_time = %d, time now = %d, qcachetime = %d)\n", 
-                       sharename, (int)last_qscan_time, (int)time_now, 
+               DEBUG(4, ("print_cache_expired: cache expired for queue %s "
+                       "(last_qscan_time = %d, time now = %d, qcachetime = %d)\n",
+                       sharename, (int)last_qscan_time, (int)time_now,
                        (int)lp_lpqcachetime() ));
 
                        (int)lp_lpqcachetime() ));
 
-               /* check if another smbd has already sent a message to update the 
-                  queue.  Give the pending message one minute to clear and 
-                  then send another message anyways.  Make sure to check for 
+               /* check if another smbd has already sent a message to update the
+                  queue.  Give the pending message one minute to clear and
+                  then send another message anyways.  Make sure to check for
                   clocks that have been run forward and then back again. */
 
                snprintf(key, sizeof(key), "MSG_PENDING/%s", sharename);
 
                   clocks that have been run forward and then back again. */
 
                snprintf(key, sizeof(key), "MSG_PENDING/%s", sharename);
 
-               if ( check_pending 
-                       && tdb_fetch_uint32( pdb->tdb, key, &u ) 
+               if ( check_pending
+                       && tdb_fetch_uint32( pdb->tdb, key, &u )
                        && (msg_pending_time=u) > 0
                        && (msg_pending_time=u) > 0
-                       && msg_pending_time <= time_now 
-                       && (time_now - msg_pending_time) < 60 ) 
+                       && msg_pending_time <= time_now
+                       && (time_now - msg_pending_time) < 60 )
                {
                        DEBUG(4,("print_cache_expired: message already pending for %s.  Accepting cache\n",
                                sharename));
                        goto done;
                }
                {
                        DEBUG(4,("print_cache_expired: message already pending for %s.  Accepting cache\n",
                                sharename));
                        goto done;
                }
-               
+
                result = True;
        }
 
                result = True;
        }
 
@@ -1114,7 +1182,7 @@ done:
  main work for updating the lpq cahe for a printer queue
 ****************************************************************************/
 
  main work for updating the lpq cahe for a printer queue
 ****************************************************************************/
 
-static void print_queue_update_internal( const char *sharename, 
+static void print_queue_update_internal( const char *sharename,
                                          struct printif *current_printif,
                                          char *lpq_command, char *lprm_command )
 {
                                          struct printif *current_printif,
                                          char *lpq_command, char *lprm_command )
 {
@@ -1132,7 +1200,7 @@ static void print_queue_update_internal( const char *sharename,
        if (!pdb) {
                return;
        }
        if (!pdb) {
                return;
        }
-       
+
        DEBUG(5,("print_queue_update_internal: printer = %s, type = %d, lpq command = [%s]\n",
                sharename, current_printif->type, lpq_command));
 
        DEBUG(5,("print_queue_update_internal: printer = %s, type = %d, lpq command = [%s]\n",
                sharename, current_printif->type, lpq_command));
 
@@ -1141,32 +1209,31 @@ static void print_queue_update_internal( const char *sharename,
         * attempting to get the lock and doing this
         * if the lpq takes a long time.
         */
         * attempting to get the lock and doing this
         * if the lpq takes a long time.
         */
-        
+
        slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", sharename);
        tdb_store_int32(pdb->tdb, cachestr, (int)time(NULL));
 
         /* get the current queue using the appropriate interface */
        ZERO_STRUCT(status);
 
        slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", sharename);
        tdb_store_int32(pdb->tdb, cachestr, (int)time(NULL));
 
         /* get the current queue using the appropriate interface */
        ZERO_STRUCT(status);
 
-       qcount = (*(current_printif->queue_get))(sharename, 
-               current_printif->type, 
+       qcount = (*(current_printif->queue_get))(sharename,
+               current_printif->type,
                lpq_command, &queue, &status);
 
                lpq_command, &queue, &status);
 
-       DEBUG(3, ("print_queue_update_internal: %d job%s in queue for %s\n", 
+       DEBUG(3, ("print_queue_update_internal: %d job%s in queue for %s\n",
                qcount, (qcount != 1) ? "s" : "", sharename));
 
        /* Sort the queue by submission time otherwise they are displayed
           in hash order. */
 
                qcount, (qcount != 1) ? "s" : "", sharename));
 
        /* Sort the queue by submission time otherwise they are displayed
           in hash order. */
 
-       qsort(queue, qcount, sizeof(print_queue_struct),
-               QSORT_CAST(printjob_comp));
+       TYPESAFE_QSORT(queue, qcount, printjob_comp);
 
        /*
          any job in the internal database that is marked as spooled
          and doesn't exist in the system queue is considered finished
          and removed from the database
 
 
        /*
          any job in the internal database that is marked as spooled
          and doesn't exist in the system queue is considered finished
          and removed from the database
 
-         any job in the system database but not in the internal database 
+         any job in the system database but not in the internal database
          is added as a unix job
 
          fill in any system job numbers as we go
          is added as a unix job
 
          fill in any system job numbers as we go
@@ -1242,7 +1309,7 @@ static void print_queue_update_internal( const char *sharename,
        status.qcount = qcount;
        data.dptr = (uint8 *)&status;
        data.dsize = sizeof(status);
        status.qcount = qcount;
        data.dptr = (uint8 *)&status;
        data.dsize = sizeof(status);
-       tdb_store(pdb->tdb, key, data, TDB_REPLACE);    
+       tdb_store(pdb->tdb, key, data, TDB_REPLACE);
 
        /*
         * Update the cache time again. We want to do this call
 
        /*
         * Update the cache time again. We want to do this call
@@ -1274,7 +1341,7 @@ static void print_queue_update_internal( const char *sharename,
  smbd processes maytry to update the lpq cache concurrently).
 ****************************************************************************/
 
  smbd processes maytry to update the lpq cache concurrently).
 ****************************************************************************/
 
-static void print_queue_update_with_lock( const char *sharename, 
+static void print_queue_update_with_lock( const char *sharename,
                                           struct printif *current_printif,
                                           char *lpq_command, char *lprm_command )
 {
                                           struct printif *current_printif,
                                           char *lpq_command, char *lprm_command )
 {
@@ -1291,7 +1358,7 @@ static void print_queue_update_with_lock( const char *sharename,
                release_print_db(pdb);
                return;
        }
                release_print_db(pdb);
                return;
        }
-       
+
        /*
         * Check to see if someone else is doing this update.
         * This is essentially a mutex on the update.
        /*
         * Check to see if someone else is doing this update.
         * This is essentially a mutex on the update.
@@ -1342,10 +1409,10 @@ static void print_queue_update_with_lock( const char *sharename,
        tdb_unlock_bystring(pdb->tdb, keystr);
 
        /* do the main work now */
        tdb_unlock_bystring(pdb->tdb, keystr);
 
        /* do the main work now */
-       
-       print_queue_update_internal( sharename, current_printif, 
+
+       print_queue_update_internal( sharename, current_printif,
                lpq_command, lprm_command );
                lpq_command, lprm_command );
-       
+
        /* Delete our pid from the db. */
        set_updating_pid(sharename, False);
        release_print_db(pdb);
        /* Delete our pid from the db. */
        set_updating_pid(sharename, False);
        release_print_db(pdb);
@@ -1378,7 +1445,7 @@ static void print_queue_receive(struct messaging_context *msg,
                return;
        }
 
                return;
        }
 
-       print_queue_update_with_lock(sharename, 
+       print_queue_update_with_lock(sharename,
                get_printer_fns_from_type((enum printing_types)printing_type),
                lpqcommand, lprmcommand );
 
                get_printer_fns_from_type((enum printing_types)printing_type),
                lpqcommand, lprmcommand );
 
@@ -1387,12 +1454,42 @@ static void print_queue_receive(struct messaging_context *msg,
        return;
 }
 
        return;
 }
 
+static void printing_pause_fd_handler(struct tevent_context *ev,
+                                     struct tevent_fd *fde,
+                                     uint16_t flags,
+                                     void *private_data)
+{
+       /*
+        * If pause_pipe[1] is closed it means the parent smbd
+        * and children exited or aborted.
+        */
+       exit_server_cleanly(NULL);
+}
+
+extern struct child_pid *children;
+extern int num_children;
+
+static void add_child_pid(pid_t pid)
+{
+       struct child_pid *child;
+
+        child = SMB_MALLOC_P(struct child_pid);
+        if (child == NULL) {
+                DEBUG(0, ("Could not add child struct -- malloc failed\n"));
+                return;
+        }
+        child->pid = pid;
+        DLIST_ADD(children, child);
+        num_children += 1;
+}
+
 static pid_t background_lpq_updater_pid = -1;
 
 /****************************************************************************
 main thread of the background lpq updater
 ****************************************************************************/
 static pid_t background_lpq_updater_pid = -1;
 
 /****************************************************************************
 main thread of the background lpq updater
 ****************************************************************************/
-void start_background_queue(void)
+void start_background_queue(struct tevent_context *ev,
+                           struct messaging_context *msg_ctx)
 {
        /* Use local variables for this as we don't
         * need to save the parent side of this, just
 {
        /* Use local variables for this as we don't
         * need to save the parent side of this, just
@@ -1414,92 +1511,57 @@ void start_background_queue(void)
                exit(1);
        }
 
                exit(1);
        }
 
+       /* Track the printing pid along with other smbd children */
+       add_child_pid(background_lpq_updater_pid);
+
        if(background_lpq_updater_pid == 0) {
        if(background_lpq_updater_pid == 0) {
+               struct tevent_fd *fde;
+               int ret;
+               NTSTATUS status;
+
                /* Child. */
                DEBUG(5,("start_background_queue: background LPQ thread started\n"));
 
                close(pause_pipe[0]);
                pause_pipe[0] = -1;
 
                /* Child. */
                DEBUG(5,("start_background_queue: background LPQ thread started\n"));
 
                close(pause_pipe[0]);
                pause_pipe[0] = -1;
 
-               if (!reinit_after_fork(smbd_messaging_context(),
-                                      smbd_event_context(), true)) {
+               status = reinit_after_fork(msg_ctx, ev, procid_self(), true);
+
+               if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0,("reinit_after_fork() failed\n"));
                        smb_panic("reinit_after_fork() failed");
                }
 
                        DEBUG(0,("reinit_after_fork() failed\n"));
                        smb_panic("reinit_after_fork() failed");
                }
 
-               claim_connection( NULL, "smbd lpq backend",
-                       FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
+               smbd_setup_sig_term_handler();
+               smbd_setup_sig_hup_handler(ev, msg_ctx);
 
 
-               if (!locking_init()) {
+               if (!serverid_register(procid_self(),
+                                      FLAG_MSG_GENERAL|FLAG_MSG_SMBD
+                                      |FLAG_MSG_PRINT_GENERAL)) {
                        exit(1);
                }
 
                        exit(1);
                }
 
-               messaging_register(smbd_messaging_context(), NULL,
-                                  MSG_PRINTER_UPDATE, print_queue_receive);
-
-               DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
-               while (1) {
-                       fd_set r_fds, w_fds;
-                       int ret;
-                       struct timeval to;
-                       int maxfd = 0;
-
-                       /* Process a signal and timed events now... */
-                       if (run_events(smbd_event_context(), 0, NULL, NULL)) {
-                               continue;
-                       }
-
-                       to.tv_sec = SMBD_SELECT_TIMEOUT;
-                       to.tv_usec = 0;
-
-                       /*
-                        * Setup the select fd sets.
-                        */
-
-                       FD_ZERO(&r_fds);
-                       FD_ZERO(&w_fds);
-
-                       /*
-                        * Are there any timed events waiting ? If so, ensure we don't
-                        * select for longer than it would take to wait for them.
-                        */
-
-                       {
-                               struct timeval now;
-                               GetTimeOfDay(&now);
-
-                               event_add_to_select_args(smbd_event_context(), &now,
-                                                        &r_fds, &w_fds, &to, &maxfd);
-                       }
-
-                       FD_SET(pause_pipe[1], &r_fds);
-                       maxfd = MAX(pause_pipe[1], maxfd);
-
-                       ret = sys_select(maxfd, &r_fds, &w_fds, NULL, &to);
-
-                       /* If pause_pipe[1] is closed it means the parent smbd
-                        * and children exited or aborted. */
-                       if (ret == 1 && FD_ISSET(pause_pipe[1], &r_fds)) {
-                                exit_server_cleanly(NULL);
-                       }
-
-                       /* check for some essential signals first */
-
-                        if (got_sig_term) {
-                                exit_server_cleanly(NULL);
-                        }
+               if (!locking_init()) {
+                       exit(1);
+               }
 
 
-                        if (reload_after_sighup) {
-                                change_to_root_user();
-                                DEBUG(1,("Reloading services after SIGHUP\n"));
-                                reload_services(False);
-                                reload_after_sighup = 0;
-                        }
+               messaging_register(msg_ctx, NULL, MSG_PRINTER_UPDATE,
+                                  print_queue_receive);
 
 
-                       if (run_events(smbd_event_context(), ret, &r_fds, &w_fds)) {
-                               continue;
-                       }
+               fde = tevent_add_fd(ev, ev, pause_pipe[1], TEVENT_FD_READ,
+                                   printing_pause_fd_handler,
+                                   NULL);
+               if (!fde) {
+                       DEBUG(0,("tevent_add_fd() failed for pause_pipe\n"));
+                       smb_panic("tevent_add_fd() failed for pause_pipe");
                }
                }
+
+               DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
+               ret = tevent_loop_wait(ev);
+               /* should not be reached */
+               DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
+                        ret, (ret == 0) ? "out of events" : strerror(errno)));
+               exit(1);
        }
 
        close(pause_pipe[1]);
        }
 
        close(pause_pipe[1]);
@@ -1509,7 +1571,8 @@ void start_background_queue(void)
 update the internal database from the system print queue for a queue
 ****************************************************************************/
 
 update the internal database from the system print queue for a queue
 ****************************************************************************/
 
-static void print_queue_update(int snum, bool force)
+static void print_queue_update(struct messaging_context *msg_ctx,
+                              int snum, bool force)
 {
        fstring key;
        fstring sharename;
 {
        fstring key;
        fstring sharename;
@@ -1530,7 +1593,7 @@ static void print_queue_update(int snum, bool force)
        lpqcommand = talloc_string_sub2(ctx,
                        lp_lpqcommand(snum),
                        "%p",
        lpqcommand = talloc_string_sub2(ctx,
                        lp_lpqcommand(snum),
                        "%p",
-                       PRINTERNAME(snum),
+                       lp_printername(snum),
                        false, false, false);
        if (!lpqcommand) {
                return;
                        false, false, false);
        if (!lpqcommand) {
                return;
@@ -1550,7 +1613,7 @@ static void print_queue_update(int snum, bool force)
        lprmcommand = talloc_string_sub2(ctx,
                        lp_lprmcommand(snum),
                        "%p",
        lprmcommand = talloc_string_sub2(ctx,
                        lp_lprmcommand(snum),
                        "%p",
-                       PRINTERNAME(snum),
+                       lp_printername(snum),
                        false, false, false);
        if (!lprmcommand) {
                return;
                        false, false, false);
        if (!lprmcommand) {
                return;
@@ -1602,10 +1665,10 @@ static void print_queue_update(int snum, bool force)
        SMB_ASSERT( newlen == len );
 
        DEBUG(10,("print_queue_update: Sending message -> printer = %s, "
        SMB_ASSERT( newlen == len );
 
        DEBUG(10,("print_queue_update: Sending message -> printer = %s, "
-               "type = %d, lpq command = [%s] lprm command = [%s]\n", 
+               "type = %d, lpq command = [%s] lprm command = [%s]\n",
                sharename, type, lpqcommand, lprmcommand ));
 
                sharename, type, lpqcommand, lprmcommand ));
 
-       /* here we set a msg pending record for other smbd processes 
+       /* here we set a msg pending record for other smbd processes
           to throttle the number of duplicate print_queue_update msgs
           sent.  */
 
           to throttle the number of duplicate print_queue_update msgs
           sent.  */
 
@@ -1627,9 +1690,8 @@ static void print_queue_update(int snum, bool force)
        release_print_db( pdb );
 
        /* finally send the message */
        release_print_db( pdb );
 
        /* finally send the message */
-       
-       messaging_send_buf(smbd_messaging_context(),
-                          pid_to_procid(background_lpq_updater_pid),
+
+       messaging_send_buf(msg_ctx, pid_to_procid(background_lpq_updater_pid),
                           MSG_PRINTER_UPDATE, (uint8 *)buffer, len);
 
        SAFE_FREE( buffer );
                           MSG_PRINTER_UPDATE, (uint8 *)buffer, len);
 
        SAFE_FREE( buffer );
@@ -1639,7 +1701,7 @@ static void print_queue_update(int snum, bool force)
 
 /****************************************************************************
  Create/Update an entry in the print tdb that will allow us to send notify
 
 /****************************************************************************
  Create/Update an entry in the print tdb that will allow us to send notify
- updates only to interested smbd's. 
+ updates only to interested smbd's.
 ****************************************************************************/
 
 bool print_notify_register_pid(int snum)
 ****************************************************************************/
 
 bool print_notify_register_pid(int snum)
@@ -1655,17 +1717,17 @@ bool print_notify_register_pid(int snum)
        /* if (snum == -1), then the change notify request was
           on a print server handle and we need to register on
           all print queus */
        /* if (snum == -1), then the change notify request was
           on a print server handle and we need to register on
           all print queus */
-          
-       if (snum == -1) 
+
+       if (snum == -1)
        {
                int num_services = lp_numservices();
                int idx;
        {
                int num_services = lp_numservices();
                int idx;
-               
+
                for ( idx=0; idx<num_services; idx++ ) {
                        if (lp_snum_ok(idx) && lp_print_ok(idx) )
                                print_notify_register_pid(idx);
                }
                for ( idx=0; idx<num_services; idx++ ) {
                        if (lp_snum_ok(idx) && lp_print_ok(idx) )
                                print_notify_register_pid(idx);
                }
-               
+
                return True;
        }
        else /* register for a specific printer */
                return True;
        }
        else /* register for a specific printer */
@@ -1730,7 +1792,7 @@ list for printer %s\n", printername));
 
 /****************************************************************************
  Update an entry in the print tdb that will allow us to send notify
 
 /****************************************************************************
  Update an entry in the print tdb that will allow us to send notify
- updates only to interested smbd's. 
+ updates only to interested smbd's.
 ****************************************************************************/
 
 bool print_notify_deregister_pid(int snum)
 ****************************************************************************/
 
 bool print_notify_deregister_pid(int snum)
@@ -1745,17 +1807,17 @@ bool print_notify_deregister_pid(int snum)
 
        /* if ( snum == -1 ), we are deregister a print server handle
           which means to deregister on all print queues */
 
        /* if ( snum == -1 ), we are deregister a print server handle
           which means to deregister on all print queues */
-          
-       if (snum == -1) 
+
+       if (snum == -1)
        {
                int num_services = lp_numservices();
                int idx;
        {
                int num_services = lp_numservices();
                int idx;
-               
+
                for ( idx=0; idx<num_services; idx++ ) {
                        if ( lp_snum_ok(idx) && lp_print_ok(idx) )
                                print_notify_deregister_pid(idx);
                }
                for ( idx=0; idx<num_services; idx++ ) {
                        if ( lp_snum_ok(idx) && lp_print_ok(idx) )
                                print_notify_deregister_pid(idx);
                }
-               
+
                return True;
        }
        else /* deregister a specific printer */
                return True;
        }
        else /* deregister a specific printer */
@@ -1835,21 +1897,6 @@ bool print_job_exists(const char* sharename, uint32 jobid)
        return ret;
 }
 
        return ret;
 }
 
-/****************************************************************************
- Give the fd used for a jobid.
-****************************************************************************/
-
-int print_job_fd(const char* sharename, uint32 jobid)
-{
-       struct printjob *pjob = print_job_find(sharename, jobid);
-       if (!pjob)
-               return -1;
-       /* don't allow another process to get this info - it is meaningless */
-       if (pjob->pid != sys_getpid())
-               return -1;
-       return pjob->fd;
-}
-
 /****************************************************************************
  Give the filename used for a jobid.
  Only valid for the process doing the spooling and when the job
 /****************************************************************************
  Give the filename used for a jobid.
  Only valid for the process doing the spooling and when the job
@@ -1871,31 +1918,21 @@ char *print_job_fname(const char* sharename, uint32 jobid)
  has not been spooled.
 ****************************************************************************/
 
  has not been spooled.
 ****************************************************************************/
 
-NT_DEVICEMODE *print_job_devmode(const char* sharename, uint32 jobid)
+struct spoolss_DeviceMode *print_job_devmode(const char* sharename, uint32 jobid)
 {
        struct printjob *pjob = print_job_find(sharename, jobid);
 {
        struct printjob *pjob = print_job_find(sharename, jobid);
-       
+
        if ( !pjob )
                return NULL;
        if ( !pjob )
                return NULL;
-               
-       return pjob->nt_devmode;
-}
 
 
-/****************************************************************************
- Set the place in the queue for a job.
-****************************************************************************/
-
-bool print_job_set_place(const char *sharename, uint32 jobid, int place)
-{
-       DEBUG(2,("print_job_set_place not implemented yet\n"));
-       return False;
+       return pjob->devmode;
 }
 
 /****************************************************************************
  Set the name of a job. Only possible for owner.
 ****************************************************************************/
 
 }
 
 /****************************************************************************
  Set the name of a job. Only possible for owner.
 ****************************************************************************/
 
-bool print_job_set_name(const char *sharename, uint32 jobid, char *name)
+bool print_job_set_name(const char *sharename, uint32 jobid, const char *name)
 {
        struct printjob *pjob;
 
 {
        struct printjob *pjob;
 
@@ -1907,6 +1944,28 @@ bool print_job_set_name(const char *sharename, uint32 jobid, char *name)
        return pjob_store(sharename, jobid, pjob);
 }
 
        return pjob_store(sharename, jobid, pjob);
 }
 
+/****************************************************************************
+ Get the name of a job. Only possible for owner.
+****************************************************************************/
+
+bool print_job_get_name(TALLOC_CTX *mem_ctx, const char *sharename, uint32_t jobid, char **name)
+{
+       struct printjob *pjob;
+
+       pjob = print_job_find(sharename, jobid);
+       if (!pjob || pjob->pid != sys_getpid()) {
+               return false;
+       }
+
+       *name = talloc_strdup(mem_ctx, pjob->jobname);
+       if (!*name) {
+               return false;
+       }
+
+       return true;
+}
+
+
 /***************************************************************************
  Remove a jobid from the 'jobs changed' list.
 ***************************************************************************/
 /***************************************************************************
  Remove a jobid from the 'jobs changed' list.
 ***************************************************************************/
@@ -1988,9 +2047,9 @@ static bool print_job_delete1(int snum, uint32 jobid)
                return True;
 
        /* Hrm - we need to be able to cope with deleting a job before it
                return True;
 
        /* Hrm - we need to be able to cope with deleting a job before it
-          has reached the spooler.  Just mark it as LPQ_DELETING and 
+          has reached the spooler.  Just mark it as LPQ_DELETING and
           let the print_queue_update() code rmeove the record */
           let the print_queue_update() code rmeove the record */
-          
+
 
        if (pjob->sysjob == -1) {
                DEBUG(5, ("attempt to delete job %u not seen by lpr\n", (unsigned int)jobid));
 
        if (pjob->sysjob == -1) {
                DEBUG(5, ("attempt to delete job %u not seen by lpr\n", (unsigned int)jobid));
@@ -2001,11 +2060,11 @@ static bool print_job_delete1(int snum, uint32 jobid)
        pjob->status = LPQ_DELETING;
        pjob_store(sharename, jobid, pjob);
 
        pjob->status = LPQ_DELETING;
        pjob_store(sharename, jobid, pjob);
 
-       if (pjob->spooled && pjob->sysjob != -1) 
+       if (pjob->spooled && pjob->sysjob != -1)
        {
                result = (*(current_printif->job_delete))(
        {
                result = (*(current_printif->job_delete))(
-                       PRINTERNAME(snum),
-                       lp_lprmcommand(snum), 
+                       lp_printername(snum),
+                       lp_lprmcommand(snum),
                        pjob);
 
                /* Delete the tdb entry if the delete succeeded or the job hasn't
                        pjob);
 
                /* Delete the tdb entry if the delete succeeded or the job hasn't
@@ -2049,77 +2108,77 @@ static bool is_owner(struct auth_serversupplied_info *server_info,
  Delete a print job.
 ****************************************************************************/
 
  Delete a print job.
 ****************************************************************************/
 
-bool print_job_delete(struct auth_serversupplied_info *server_info, int snum,
-                     uint32 jobid, WERROR *errcode)
+WERROR print_job_delete(struct auth_serversupplied_info *server_info,
+                       struct messaging_context *msg_ctx,
+                       int snum, uint32_t jobid)
 {
 {
-       const char* sharename = lp_const_servicename( snum );
+       const char* sharename = lp_const_servicename(snum);
        struct printjob *pjob;
        bool    owner;
        char    *fname;
 
        struct printjob *pjob;
        bool    owner;
        char    *fname;
 
-       *errcode = WERR_OK;
-               
        owner = is_owner(server_info, lp_const_servicename(snum), jobid);
        owner = is_owner(server_info, lp_const_servicename(snum), jobid);
-       
+
        /* Check access against security descriptor or whether the user
           owns their job. */
 
        /* Check access against security descriptor or whether the user
           owns their job. */
 
-       if (!owner && 
-           !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+       if (!owner &&
+           !print_access_check(server_info, msg_ctx, snum,
+                               JOB_ACCESS_ADMINISTER)) {
                DEBUG(3, ("delete denied by security descriptor\n"));
                DEBUG(3, ("delete denied by security descriptor\n"));
-               *errcode = WERR_ACCESS_DENIED;
 
                /* BEGIN_ADMIN_LOG */
 
                /* BEGIN_ADMIN_LOG */
-               sys_adminlog( LOG_ERR, 
+               sys_adminlog( LOG_ERR,
                              "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
                              uidtoname(server_info->utok.uid),
                              "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
                              uidtoname(server_info->utok.uid),
-                             PRINTERNAME(snum) );
+                             lp_printername(snum) );
                /* END_ADMIN_LOG */
 
                /* END_ADMIN_LOG */
 
-               return False;
+               return WERR_ACCESS_DENIED;
        }
 
        }
 
-       /* 
+       /*
         * get the spooled filename of the print job
         * if this works, then the file has not been spooled
         * get the spooled filename of the print job
         * if this works, then the file has not been spooled
-        * to the underlying print system.  Just delete the 
+        * to the underlying print system.  Just delete the
         * spool file & return.
         */
         * spool file & return.
         */
-        
-       if ( (fname = print_job_fname( sharename, jobid )) != NULL )
-       {
+
+       fname = print_job_fname(sharename, jobid);
+       if (fname != NULL) {
                /* remove the spool file */
                /* remove the spool file */
-               DEBUG(10,("print_job_delete: Removing spool file [%s]\n", fname ));
-               if ( unlink( fname ) == -1 ) {
-                       *errcode = map_werror_from_unix(errno);
-                       return False;
+               DEBUG(10, ("print_job_delete: "
+                          "Removing spool file [%s]\n", fname));
+               if (unlink(fname) == -1) {
+                       return map_werror_from_unix(errno);
                }
        }
                }
        }
-       
+
        if (!print_job_delete1(snum, jobid)) {
        if (!print_job_delete1(snum, jobid)) {
-               *errcode = WERR_ACCESS_DENIED;
-               return False;
+               return WERR_ACCESS_DENIED;
        }
 
        /* force update the database and say the delete failed if the
            job still exists */
 
        }
 
        /* force update the database and say the delete failed if the
            job still exists */
 
-       print_queue_update(snum, True);
-       
+       print_queue_update(msg_ctx, snum, True);
+
        pjob = print_job_find(sharename, jobid);
        pjob = print_job_find(sharename, jobid);
-       if ( pjob && (pjob->status != LPQ_DELETING) )
-               *errcode = WERR_ACCESS_DENIED;
+       if (pjob && (pjob->status != LPQ_DELETING)) {
+               return WERR_ACCESS_DENIED;
+       }
 
 
-       return (pjob == NULL );
+       return WERR_PRINTER_HAS_JOBS_QUEUED;
 }
 
 /****************************************************************************
  Pause a job.
 ****************************************************************************/
 
 }
 
 /****************************************************************************
  Pause a job.
 ****************************************************************************/
 
-bool print_job_pause(struct auth_serversupplied_info *server_info, int snum,
-                    uint32 jobid, WERROR *errcode)
+bool print_job_pause(struct auth_serversupplied_info *server_info,
+                    struct messaging_context *msg_ctx,
+                    int snum, uint32 jobid, WERROR *errcode)
 {
        const char* sharename = lp_const_servicename(snum);
        struct printjob *pjob;
 {
        const char* sharename = lp_const_servicename(snum);
        struct printjob *pjob;
@@ -2127,7 +2186,7 @@ bool print_job_pause(struct auth_serversupplied_info *server_info, int snum,
        struct printif *current_printif = get_printer_fns( snum );
 
        pjob = print_job_find(sharename, jobid);
        struct printif *current_printif = get_printer_fns( snum );
 
        pjob = print_job_find(sharename, jobid);
-       
+
        if (!pjob || !server_info) {
                DEBUG(10, ("print_job_pause: no pjob or user for jobid %u\n",
                        (unsigned int)jobid ));
        if (!pjob || !server_info) {
                DEBUG(10, ("print_job_pause: no pjob or user for jobid %u\n",
                        (unsigned int)jobid ));
@@ -2141,15 +2200,16 @@ bool print_job_pause(struct auth_serversupplied_info *server_info, int snum,
        }
 
        if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
        }
 
        if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
-           !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+           !print_access_check(server_info, msg_ctx, snum,
+                               JOB_ACCESS_ADMINISTER)) {
                DEBUG(3, ("pause denied by security descriptor\n"));
 
                /* BEGIN_ADMIN_LOG */
                DEBUG(3, ("pause denied by security descriptor\n"));
 
                /* BEGIN_ADMIN_LOG */
-               sys_adminlog( LOG_ERR, 
+               sys_adminlog( LOG_ERR,
                        "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
                              uidtoname(server_info->utok.uid),
                        "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
                              uidtoname(server_info->utok.uid),
-                             PRINTERNAME(snum) );
+                             lp_printername(snum) );
                /* END_ADMIN_LOG */
 
                *errcode = WERR_ACCESS_DENIED;
                /* END_ADMIN_LOG */
 
                *errcode = WERR_ACCESS_DENIED;
@@ -2180,8 +2240,9 @@ pause, or resume print job. User name: %s. Printer name: %s.",
  Resume a job.
 ****************************************************************************/
 
  Resume a job.
 ****************************************************************************/
 
-bool print_job_resume(struct auth_serversupplied_info *server_info, int snum,
-                     uint32 jobid, WERROR *errcode)
+bool print_job_resume(struct auth_serversupplied_info *server_info,
+                     struct messaging_context *msg_ctx,
+                     int snum, uint32 jobid, WERROR *errcode)
 {
        const char *sharename = lp_const_servicename(snum);
        struct printjob *pjob;
 {
        const char *sharename = lp_const_servicename(snum);
        struct printjob *pjob;
@@ -2203,16 +2264,17 @@ bool print_job_resume(struct auth_serversupplied_info *server_info, int snum,
        }
 
        if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
        }
 
        if (!is_owner(server_info, lp_const_servicename(snum), jobid) &&
-           !print_access_check(server_info, snum, JOB_ACCESS_ADMINISTER)) {
+           !print_access_check(server_info, msg_ctx, snum,
+                               JOB_ACCESS_ADMINISTER)) {
                DEBUG(3, ("resume denied by security descriptor\n"));
                *errcode = WERR_ACCESS_DENIED;
 
                /* BEGIN_ADMIN_LOG */
                DEBUG(3, ("resume denied by security descriptor\n"));
                *errcode = WERR_ACCESS_DENIED;
 
                /* BEGIN_ADMIN_LOG */
-               sys_adminlog( LOG_ERR, 
+               sys_adminlog( LOG_ERR,
                         "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
                              uidtoname(server_info->utok.uid),
                         "Permission denied-- user not allowed to delete, \
 pause, or resume print job. User name: %s. Printer name: %s.",
                              uidtoname(server_info->utok.uid),
-                             PRINTERNAME(snum) );
+                             lp_printername(snum) );
                /* END_ADMIN_LOG */
                return False;
        }
                /* END_ADMIN_LOG */
                return False;
        }
@@ -2241,7 +2303,7 @@ pause, or resume print job. User name: %s. Printer name: %s.",
 ssize_t print_job_write(int snum, uint32 jobid, const char *buf, SMB_OFF_T pos, size_t size)
 {
        const char* sharename = lp_const_servicename(snum);
 ssize_t print_job_write(int snum, uint32 jobid, const char *buf, SMB_OFF_T pos, size_t size)
 {
        const char* sharename = lp_const_servicename(snum);
-       int return_code;
+       ssize_t return_code;
        struct printjob *pjob;
 
        pjob = print_job_find(sharename, jobid);
        struct printjob *pjob;
 
        pjob = print_job_find(sharename, jobid);
@@ -2252,6 +2314,11 @@ ssize_t print_job_write(int snum, uint32 jobid, const char *buf, SMB_OFF_T pos,
        if (pjob->pid != sys_getpid())
                return -1;
 
        if (pjob->pid != sys_getpid())
                return -1;
 
+       /* if SMBD is spooling this can't be allowed */
+       if (pjob->status == PJOB_SMBD_SPOOLING) {
+               return -1;
+       }
+
        return_code = write_data_at_offset(pjob->fd, buf, size, pos);
 
        if (return_code>0) {
        return_code = write_data_at_offset(pjob->fd, buf, size, pos);
 
        if (return_code>0) {
@@ -2284,7 +2351,7 @@ static int get_queue_status(const char* sharename, print_status_struct *status)
                data = tdb_fetch(pdb->tdb, string_tdb_data(keystr));
                if (data.dptr) {
                        if (data.dsize == sizeof(print_status_struct))
                data = tdb_fetch(pdb->tdb, string_tdb_data(keystr));
                if (data.dptr) {
                        if (data.dsize == sizeof(print_status_struct))
-                               /* this memcpy is ok since the status struct was 
+                               /* this memcpy is ok since the status struct was
                                   not packed before storing it in the tdb */
                                memcpy(status, data.dptr, sizeof(print_status_struct));
                        SAFE_FREE(data.dptr);
                                   not packed before storing it in the tdb */
                                memcpy(status, data.dptr, sizeof(print_status_struct));
                        SAFE_FREE(data.dptr);
@@ -2299,18 +2366,19 @@ static int get_queue_status(const char* sharename, print_status_struct *status)
  Determine the number of jobs in a queue.
 ****************************************************************************/
 
  Determine the number of jobs in a queue.
 ****************************************************************************/
 
-int print_queue_length(int snum, print_status_struct *pstatus)
+int print_queue_length(struct messaging_context *msg_ctx, int snum,
+                      print_status_struct *pstatus)
 {
        const char* sharename = lp_const_servicename( snum );
        print_status_struct status;
        int len;
 
        ZERO_STRUCT( status );
 {
        const char* sharename = lp_const_servicename( snum );
        print_status_struct status;
        int len;
 
        ZERO_STRUCT( status );
+
        /* make sure the database is up to date */
        if (print_cache_expired(lp_const_servicename(snum), True))
        /* make sure the database is up to date */
        if (print_cache_expired(lp_const_servicename(snum), True))
-               print_queue_update(snum, False);
+               print_queue_update(msg_ctx, snum, False);
+
        /* also fetch the queue status */
        memset(&status, 0, sizeof(status));
        len = get_queue_status(sharename, &status);
        /* also fetch the queue status */
        memset(&status, 0, sizeof(status));
        len = get_queue_status(sharename, &status);
@@ -2325,50 +2393,72 @@ int print_queue_length(int snum, print_status_struct *pstatus)
  Allocate a jobid. Hold the lock for as short a time as possible.
 ***************************************************************************/
 
  Allocate a jobid. Hold the lock for as short a time as possible.
 ***************************************************************************/
 
-static bool allocate_print_jobid(struct tdb_print_db *pdb, int snum, const char *sharename, uint32 *pjobid)
+static WERROR allocate_print_jobid(struct tdb_print_db *pdb, int snum,
+                                  const char *sharename, uint32 *pjobid)
 {
        int i;
        uint32 jobid;
 {
        int i;
        uint32 jobid;
+       enum TDB_ERROR terr;
+       int ret;
 
        *pjobid = (uint32)-1;
 
        for (i = 0; i < 3; i++) {
                /* Lock the database - only wait 20 seconds. */
 
        *pjobid = (uint32)-1;
 
        for (i = 0; i < 3; i++) {
                /* Lock the database - only wait 20 seconds. */
-               if (tdb_lock_bystring_with_timeout(pdb->tdb, "INFO/nextjob", 20) == -1) {
-                       DEBUG(0,("allocate_print_jobid: failed to lock printing database %s\n", sharename));
-                       return False;
+               ret = tdb_lock_bystring_with_timeout(pdb->tdb,
+                                                    "INFO/nextjob", 20);
+               if (ret == -1) {
+                       DEBUG(0, ("allocate_print_jobid: "
+                                 "Failed to lock printing database %s\n",
+                                 sharename));
+                       terr = tdb_error(pdb->tdb);
+                       return ntstatus_to_werror(map_nt_error_from_tdb(terr));
                }
 
                if (!tdb_fetch_uint32(pdb->tdb, "INFO/nextjob", &jobid)) {
                }
 
                if (!tdb_fetch_uint32(pdb->tdb, "INFO/nextjob", &jobid)) {
-                       if (tdb_error(pdb->tdb) != TDB_ERR_NOEXIST) {
-                               DEBUG(0, ("allocate_print_jobid: failed to fetch INFO/nextjob for print queue %s\n",
-                                       sharename));
-                               return False;
+                       terr = tdb_error(pdb->tdb);
+                       if (terr != TDB_ERR_NOEXIST) {
+                               DEBUG(0, ("allocate_print_jobid: "
+                                         "Failed to fetch INFO/nextjob "
+                                         "for print queue %s\n", sharename));
+                               tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
+                               return ntstatus_to_werror(map_nt_error_from_tdb(terr));
                        }
                        }
+                       DEBUG(10, ("allocate_print_jobid: "
+                                  "No existing jobid in %s\n", sharename));
                        jobid = 0;
                }
 
                        jobid = 0;
                }
 
+               DEBUG(10, ("allocate_print_jobid: "
+                          "Read jobid %u from %s\n", jobid, sharename));
+
                jobid = NEXT_JOBID(jobid);
 
                jobid = NEXT_JOBID(jobid);
 
-               if (tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid)==-1) {
-                       DEBUG(3, ("allocate_print_jobid: failed to store INFO/nextjob.\n"));
+               ret = tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid);
+               if (ret == -1) {
+                       terr = tdb_error(pdb->tdb);
+                       DEBUG(3, ("allocate_print_jobid: "
+                                 "Failed to store INFO/nextjob.\n"));
                        tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
                        tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
-                       return False;
+                       return ntstatus_to_werror(map_nt_error_from_tdb(terr));
                }
 
                /* We've finished with the INFO/nextjob lock. */
                tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
                }
 
                /* We've finished with the INFO/nextjob lock. */
                tdb_unlock_bystring(pdb->tdb, "INFO/nextjob");
-                               
-               if (!print_job_exists(sharename, jobid))
+
+               if (!print_job_exists(sharename, jobid)) {
                        break;
                        break;
+               }
+               DEBUG(10, ("allocate_print_jobid: "
+                          "Found jobid %u in %s\n", jobid, sharename));
        }
 
        if (i > 2) {
        }
 
        if (i > 2) {
-               DEBUG(0, ("allocate_print_jobid: failed to allocate a print job for queue %s\n",
-                       sharename));
+               DEBUG(0, ("allocate_print_jobid: "
+                         "Failed to allocate a print job for queue %s\n",
+                         sharename));
                /* Probably full... */
                /* Probably full... */
-               errno = ENOSPC;
-               return False;
+               return WERR_NO_SPOOL_SPACE;
        }
 
        /* Store a dummy placeholder. */
        }
 
        /* Store a dummy placeholder. */
@@ -2379,14 +2469,16 @@ static bool allocate_print_jobid(struct tdb_print_db *pdb, int snum, const char
                dum.dsize = 0;
                if (tdb_store(pdb->tdb, print_key(jobid, &tmp), dum,
                              TDB_INSERT) == -1) {
                dum.dsize = 0;
                if (tdb_store(pdb->tdb, print_key(jobid, &tmp), dum,
                              TDB_INSERT) == -1) {
-                       DEBUG(3, ("allocate_print_jobid: jobid (%d) failed to store placeholder.\n",
-                               jobid ));
-                       return False;
+                       DEBUG(3, ("allocate_print_jobid: "
+                                 "jobid (%d) failed to store placeholder.\n",
+                                 jobid ));
+                       terr = tdb_error(pdb->tdb);
+                       return ntstatus_to_werror(map_nt_error_from_tdb(terr));
                }
        }
 
        *pjobid = jobid;
                }
        }
 
        *pjobid = jobid;
-       return True;
+       return WERR_OK;
 }
 
 /***************************************************************************
 }
 
 /***************************************************************************
@@ -2408,78 +2500,175 @@ static bool add_to_jobs_changed(struct tdb_print_db *pdb, uint32 jobid)
                           data) == 0);
 }
 
                           data) == 0);
 }
 
+
 /***************************************************************************
 /***************************************************************************
Start spooling a job - return the jobid.
Do all checks needed to determine if we can start a job.
 ***************************************************************************/
 
 ***************************************************************************/
 
-uint32 print_job_start(struct auth_serversupplied_info *server_info, int snum,
-                      char *jobname, NT_DEVICEMODE *nt_devmode )
+static WERROR print_job_checks(struct auth_serversupplied_info *server_info,
+                              struct messaging_context *msg_ctx,
+                              int snum, int *njobs)
 {
 {
-       uint32 jobid;
-       char *path;
-       struct printjob pjob;
        const char *sharename = lp_const_servicename(snum);
        const char *sharename = lp_const_servicename(snum);
-       struct tdb_print_db *pdb = get_print_db_byname(sharename);
-       int njobs;
-
-       errno = 0;
-
-       if (!pdb)
-               return (uint32)-1;
+       uint64_t dspace, dsize;
+       uint64_t minspace;
+       int ret;
 
 
-       if (!print_access_check(server_info, snum, PRINTER_ACCESS_USE)) {
-               DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
-               release_print_db(pdb);
-               return (uint32)-1;
+       if (!print_access_check(server_info, msg_ctx, snum,
+                               PRINTER_ACCESS_USE)) {
+               DEBUG(3, ("print_job_checks: "
+                         "job start denied by security descriptor\n"));
+               return WERR_ACCESS_DENIED;
        }
 
        }
 
-       if (!print_time_access_check(lp_servicename(snum))) {
-               DEBUG(3, ("print_job_start: job start denied by time check\n"));
-               release_print_db(pdb);
-               return (uint32)-1;
+       if (!print_time_access_check(server_info, msg_ctx, sharename)) {
+               DEBUG(3, ("print_job_checks: "
+                         "job start denied by time check\n"));
+               return WERR_ACCESS_DENIED;
        }
 
        }
 
-       path = lp_pathname(snum);
-
        /* see if we have sufficient disk space */
        if (lp_minprintspace(snum)) {
        /* see if we have sufficient disk space */
        if (lp_minprintspace(snum)) {
-               uint64_t dspace, dsize;
-               if (sys_fsusage(path, &dspace, &dsize) == 0 &&
-                   dspace < 2*(uint64_t)lp_minprintspace(snum)) {
-                       DEBUG(3, ("print_job_start: disk space check failed.\n"));
-                       release_print_db(pdb);
-                       errno = ENOSPC;
-                       return (uint32)-1;
+               minspace = lp_minprintspace(snum);
+               ret = sys_fsusage(lp_pathname(snum), &dspace, &dsize);
+               if (ret == 0 && dspace < 2*minspace) {
+                       DEBUG(3, ("print_job_checks: "
+                                 "disk space check failed.\n"));
+                       return WERR_NO_SPOOL_SPACE;
                }
        }
 
        /* for autoloaded printers, check that the printcap entry still exists */
                }
        }
 
        /* for autoloaded printers, check that the printcap entry still exists */
-       if (lp_autoloaded(snum) && !pcap_printername_ok(lp_const_servicename(snum))) {
-               DEBUG(3, ("print_job_start: printer name %s check failed.\n", lp_const_servicename(snum) ));
-               release_print_db(pdb);
-               errno = ENOENT;
-               return (uint32)-1;
+       if (lp_autoloaded(snum) && !pcap_printername_ok(sharename)) {
+               DEBUG(3, ("print_job_checks: printer name %s check failed.\n",
+                         sharename));
+               return WERR_ACCESS_DENIED;
        }
 
        /* Insure the maximum queue size is not violated */
        }
 
        /* Insure the maximum queue size is not violated */
-       if ((njobs = print_queue_length(snum,NULL)) > lp_maxprintjobs(snum)) {
-               DEBUG(3, ("print_job_start: Queue %s number of jobs (%d) larger than max printjobs per queue (%d).\n",
-                       sharename, njobs, lp_maxprintjobs(snum) ));
+       *njobs = print_queue_length(msg_ctx, snum, NULL);
+       if (*njobs > lp_maxprintjobs(snum)) {
+               DEBUG(3, ("print_job_checks: Queue %s number of jobs (%d) "
+                         "larger than max printjobs per queue (%d).\n",
+                         sharename, *njobs, lp_maxprintjobs(snum)));
+               return WERR_NO_SPOOL_SPACE;
+       }
+
+       return WERR_OK;
+}
+
+/***************************************************************************
+ Create a job file.
+***************************************************************************/
+
+static WERROR print_job_spool_file(int snum, uint32_t jobid,
+                                  const char *output_file,
+                                  struct printjob *pjob)
+{
+       WERROR werr;
+       SMB_STRUCT_STAT st;
+       const char *path;
+       int len;
+
+       /* if this file is within the printer path, it means that smbd
+        * is spooling it and will pass us control when it is finished.
+        * Verify that the file name is ok, within path, and it is
+        * already already there */
+       if (output_file) {
+               path = lp_pathname(snum);
+               len = strlen(path);
+               if (strncmp(output_file, path, len) == 0 &&
+                   (output_file[len - 1] == '/' || output_file[len] == '/')) {
+
+                       /* verify path is not too long */
+                       if (strlen(output_file) >= sizeof(pjob->filename)) {
+                               return WERR_INVALID_NAME;
+                       }
+
+                       /* verify that the file exists */
+                       if (sys_stat(output_file, &st, false) != 0) {
+                               return WERR_INVALID_NAME;
+                       }
+
+                       fstrcpy(pjob->filename, output_file);
+
+                       DEBUG(3, ("print_job_spool_file:"
+                                 "External spooling activated"));
+
+                       /* we do not open the file until spooling is done */
+                       pjob->fd = -1;
+                       pjob->status = PJOB_SMBD_SPOOLING;
+
+                       return WERR_OK;
+               }
+       }
+
+       slprintf(pjob->filename, sizeof(pjob->filename)-1,
+                "%s/%s%.8u.XXXXXX", lp_pathname(snum),
+                PRINT_SPOOL_PREFIX, (unsigned int)jobid);
+       pjob->fd = mkstemp(pjob->filename);
+
+       if (pjob->fd == -1) {
+               werr = map_werror_from_unix(errno);
+               if (W_ERROR_EQUAL(werr, WERR_ACCESS_DENIED)) {
+                       /* Common setup error, force a report. */
+                       DEBUG(0, ("print_job_spool_file: "
+                                 "insufficient permissions to open spool "
+                                 "file %s.\n", pjob->filename));
+               } else {
+                       /* Normal case, report at level 3 and above. */
+                       DEBUG(3, ("print_job_spool_file: "
+                                 "can't open spool file %s\n",
+                                 pjob->filename));
+               }
+               return werr;
+       }
+
+       return WERR_OK;
+}
+
+/***************************************************************************
+ Start spooling a job - return the jobid.
+***************************************************************************/
+
+WERROR print_job_start(struct auth_serversupplied_info *server_info,
+                      struct messaging_context *msg_ctx,
+                      int snum, const char *docname, const char *filename,
+                      struct spoolss_DeviceMode *devmode, uint32_t *_jobid)
+{
+       uint32_t jobid;
+       char *path;
+       struct printjob pjob;
+       const char *sharename = lp_const_servicename(snum);
+       struct tdb_print_db *pdb = get_print_db_byname(sharename);
+       int njobs;
+       WERROR werr;
+
+       if (!pdb) {
+               return WERR_INTERNAL_DB_CORRUPTION;
+       }
+
+       path = lp_pathname(snum);
+
+       werr = print_job_checks(server_info, msg_ctx, snum, &njobs);
+       if (!W_ERROR_IS_OK(werr)) {
                release_print_db(pdb);
                release_print_db(pdb);
-               errno = ENOSPC;
-               return (uint32)-1;
+               return werr;
        }
 
        }
 
-       DEBUG(10,("print_job_start: Queue %s number of jobs (%d), max printjobs = %d\n",
-               sharename, njobs, lp_maxprintjobs(snum) ));
+       DEBUG(10, ("print_job_start: "
+                  "Queue %s number of jobs (%d), max printjobs = %d\n",
+                  sharename, njobs, lp_maxprintjobs(snum)));
 
 
-       if (!allocate_print_jobid(pdb, snum, sharename, &jobid))
+       werr = allocate_print_jobid(pdb, snum, sharename, &jobid);
+       if (!W_ERROR_IS_OK(werr)) {
                goto fail;
                goto fail;
+       }
 
        /* create the database entry */
 
        /* create the database entry */
-       
+
        ZERO_STRUCT(pjob);
        ZERO_STRUCT(pjob);
-       
+
        pjob.pid = sys_getpid();
        pjob.sysjob = -1;
        pjob.fd = -1;
        pjob.pid = sys_getpid();
        pjob.sysjob = -1;
        pjob.fd = -1;
@@ -2488,15 +2677,15 @@ uint32 print_job_start(struct auth_serversupplied_info *server_info, int snum,
        pjob.size = 0;
        pjob.spooled = False;
        pjob.smbjob = True;
        pjob.size = 0;
        pjob.spooled = False;
        pjob.smbjob = True;
-       pjob.nt_devmode = nt_devmode;
-       
-       fstrcpy(pjob.jobname, jobname);
+       pjob.devmode = devmode;
+
+       fstrcpy(pjob.jobname, docname);
 
        fstrcpy(pjob.user, lp_printjob_username(snum));
        standard_sub_advanced(sharename, server_info->sanitized_username,
 
        fstrcpy(pjob.user, lp_printjob_username(snum));
        standard_sub_advanced(sharename, server_info->sanitized_username,
-                             path, server_info->utok.gid, 
+                             path, server_info->utok.gid,
                              server_info->sanitized_username,
                              server_info->sanitized_username,
-                             pdb_get_domain(server_info->sam_account),
+                             server_info->info3->base.domain.string,
                              pjob.user, sizeof(pjob.user)-1);
        /* ensure NULL termination */
        pjob.user[sizeof(pjob.user)-1] = '\0';
                              pjob.user, sizeof(pjob.user)-1);
        /* ensure NULL termination */
        pjob.user[sizeof(pjob.user)-1] = '\0';
@@ -2504,20 +2693,8 @@ uint32 print_job_start(struct auth_serversupplied_info *server_info, int snum,
        fstrcpy(pjob.queuename, lp_const_servicename(snum));
 
        /* we have a job entry - now create the spool file */
        fstrcpy(pjob.queuename, lp_const_servicename(snum));
 
        /* we have a job entry - now create the spool file */
-       slprintf(pjob.filename, sizeof(pjob.filename)-1, "%s/%s%.8u.XXXXXX", 
-                path, PRINT_SPOOL_PREFIX, (unsigned int)jobid);
-       pjob.fd = smb_mkstemp(pjob.filename);
-
-       if (pjob.fd == -1) {
-               if (errno == EACCES) {
-                       /* Common setup error, force a report. */
-                       DEBUG(0, ("print_job_start: insufficient permissions \
-to open spool file %s.\n", pjob.filename));
-               } else {
-                       /* Normal case, report at level 3 and above. */
-                       DEBUG(3, ("print_job_start: can't open spool file %s,\n", pjob.filename));
-                       DEBUGADD(3, ("errno = %d (%s).\n", errno, strerror(errno)));
-               }
+       werr = print_job_spool_file(snum, jobid, filename, &pjob);
+       if (!W_ERROR_IS_OK(werr)) {
                goto fail;
        }
 
                goto fail;
        }
 
@@ -2531,16 +2708,19 @@ to open spool file %s.\n", pjob.filename));
 
        release_print_db(pdb);
 
 
        release_print_db(pdb);
 
-       return jobid;
+       *_jobid = jobid;
+       return WERR_OK;
 
 
- fail:
-       if (jobid != -1)
+fail:
+       if (jobid != -1) {
                pjob_delete(sharename, jobid);
                pjob_delete(sharename, jobid);
+       }
 
        release_print_db(pdb);
 
 
        release_print_db(pdb);
 
-       DEBUG(3, ("print_job_start: returning fail. Error = %s\n", strerror(errno) ));
-       return (uint32)-1;
+       DEBUG(3, ("print_job_start: returning fail. "
+                 "Error = %s\n", win_errstr(werr)));
+       return werr;
 }
 
 /****************************************************************************
 }
 
 /****************************************************************************
@@ -2569,36 +2749,62 @@ void print_job_endpage(int snum, uint32 jobid)
  error.
 ****************************************************************************/
 
  error.
 ****************************************************************************/
 
-bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
+NTSTATUS print_job_end(struct messaging_context *msg_ctx, int snum,
+                      uint32 jobid, enum file_close_type close_type)
 {
        const char* sharename = lp_const_servicename(snum);
        struct printjob *pjob;
        int ret;
        SMB_STRUCT_STAT sbuf;
        struct printif *current_printif = get_printer_fns( snum );
 {
        const char* sharename = lp_const_servicename(snum);
        struct printjob *pjob;
        int ret;
        SMB_STRUCT_STAT sbuf;
        struct printif *current_printif = get_printer_fns( snum );
+       NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 
        pjob = print_job_find(sharename, jobid);
 
 
        pjob = print_job_find(sharename, jobid);
 
-       if (!pjob)
-               return False;
+       if (!pjob) {
+               return NT_STATUS_PRINT_CANCELLED;
+       }
 
 
-       if (pjob->spooled || pjob->pid != sys_getpid())
-               return False;
+       if (pjob->spooled || pjob->pid != sys_getpid()) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       if (close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) {
+               if (pjob->status == PJOB_SMBD_SPOOLING) {
+                       /* take over the file now, smbd is done */
+                       if (sys_stat(pjob->filename, &sbuf, false) != 0) {
+                               status = map_nt_error_from_unix(errno);
+                               DEBUG(3, ("print_job_end: "
+                                         "stat file failed for jobid %d\n",
+                                         jobid));
+                               goto fail;
+                       }
+
+                       pjob->status = LPQ_SPOOLING;
+
+               } else {
 
 
-       if ((close_type == NORMAL_CLOSE || close_type == SHUTDOWN_CLOSE) &&
-                               (sys_fstat(pjob->fd, &sbuf) == 0)) {
-               pjob->size = sbuf.st_size;
-               close(pjob->fd);
-               pjob->fd = -1;
+                       if ((sys_fstat(pjob->fd, &sbuf, false) != 0)) {
+                               status = map_nt_error_from_unix(errno);
+                               close(pjob->fd);
+                               DEBUG(3, ("print_job_end: "
+                                         "stat file failed for jobid %d\n",
+                                         jobid));
+                               goto fail;
+                       }
+
+                       close(pjob->fd);
+               }
+
+               pjob->size = sbuf.st_ex_size;
        } else {
 
        } else {
 
-               /* 
-                * Not a normal close or we couldn't stat the job file,
-                * so something has gone wrong. Cleanup.
+               /*
+                * Not a normal close, something has gone wrong. Cleanup.
                 */
                 */
-               close(pjob->fd);
-               pjob->fd = -1;
-               DEBUG(3,("print_job_end: failed to stat file for jobid %d\n", jobid ));
+               if (pjob->fd != -1) {
+                       close(pjob->fd);
+               }
                goto fail;
        }
 
                goto fail;
        }
 
@@ -2611,42 +2817,45 @@ bool print_job_end(int snum, uint32 jobid, enum file_close_type close_type)
                        pjob->filename, pjob->size ? "deleted" : "zero length" ));
                unlink(pjob->filename);
                pjob_delete(sharename, jobid);
                        pjob->filename, pjob->size ? "deleted" : "zero length" ));
                unlink(pjob->filename);
                pjob_delete(sharename, jobid);
-               return True;
+               return NT_STATUS_OK;
        }
 
        }
 
-       pjob->smbjob = jobid;
-
        ret = (*(current_printif->job_submit))(snum, pjob);
 
        ret = (*(current_printif->job_submit))(snum, pjob);
 
-       if (ret)
+       if (ret) {
+               status = NT_STATUS_PRINT_CANCELLED;
                goto fail;
                goto fail;
+       }
 
        /* The print job has been successfully handed over to the back-end */
 
        /* The print job has been successfully handed over to the back-end */
-       
+
        pjob->spooled = True;
        pjob->status = LPQ_QUEUED;
        pjob_store(sharename, jobid, pjob);
        pjob->spooled = True;
        pjob->status = LPQ_QUEUED;
        pjob_store(sharename, jobid, pjob);
-       
+
        /* make sure the database is up to date */
        if (print_cache_expired(lp_const_servicename(snum), True))
        /* make sure the database is up to date */
        if (print_cache_expired(lp_const_servicename(snum), True))
-               print_queue_update(snum, False);
-       
-       return True;
+               print_queue_update(msg_ctx, snum, False);
+
+       return NT_STATUS_OK;
 
 fail:
 
        /* The print job was not successfully started. Cleanup */
        /* Still need to add proper error return propagation! 010122:JRR */
 
 fail:
 
        /* The print job was not successfully started. Cleanup */
        /* Still need to add proper error return propagation! 010122:JRR */
+       pjob->fd = -1;
        unlink(pjob->filename);
        pjob_delete(sharename, jobid);
        unlink(pjob->filename);
        pjob_delete(sharename, jobid);
-       return False;
+       return status;
 }
 
 /****************************************************************************
  Get a snapshot of jobs in the system without traversing.
 ****************************************************************************/
 
 }
 
 /****************************************************************************
  Get a snapshot of jobs in the system without traversing.
 ****************************************************************************/
 
-static bool get_stored_queue_info(struct tdb_print_db *pdb, int snum, int *pcount, print_queue_struct **ppqueue)
+static bool get_stored_queue_info(struct messaging_context *msg_ctx,
+                                 struct tdb_print_db *pdb, int snum,
+                                 int *pcount, print_queue_struct **ppqueue)
 {
        TDB_DATA data, cgdata;
        print_queue_struct *queue = NULL;
 {
        TDB_DATA data, cgdata;
        print_queue_struct *queue = NULL;
@@ -2661,8 +2870,8 @@ static bool get_stored_queue_info(struct tdb_print_db *pdb, int snum, int *pcoun
 
        /* make sure the database is up to date */
        if (print_cache_expired(lp_const_servicename(snum), True))
 
        /* make sure the database is up to date */
        if (print_cache_expired(lp_const_servicename(snum), True))
-               print_queue_update(snum, False);
+               print_queue_update(msg_ctx, snum, False);
+
        *pcount = 0;
        *ppqueue = NULL;
 
        *pcount = 0;
        *ppqueue = NULL;
 
@@ -2671,10 +2880,10 @@ static bool get_stored_queue_info(struct tdb_print_db *pdb, int snum, int *pcoun
 
        /* Get the stored queue data. */
        data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/linear_queue_array"));
 
        /* Get the stored queue data. */
        data = tdb_fetch(pdb->tdb, string_tdb_data("INFO/linear_queue_array"));
-       
+
        if (data.dptr && data.dsize >= sizeof(qcount))
                len += tdb_unpack(data.dptr + len, data.dsize - len, "d", &qcount);
        if (data.dptr && data.dsize >= sizeof(qcount))
                len += tdb_unpack(data.dptr + len, data.dsize - len, "d", &qcount);
-               
+
        /* Get the changed jobs list. */
        cgdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
        if (cgdata.dptr != NULL && (cgdata.dsize % 4 == 0))
        /* Get the changed jobs list. */
        cgdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
        if (cgdata.dptr != NULL && (cgdata.dsize % 4 == 0))
@@ -2740,7 +2949,7 @@ static bool get_stored_queue_info(struct tdb_print_db *pdb, int snum, int *pcoun
        /* Sort the queue by submission time otherwise they are displayed
           in hash order. */
 
        /* Sort the queue by submission time otherwise they are displayed
           in hash order. */
 
-       qsort(queue, total_count, sizeof(print_queue_struct), QSORT_CAST(printjob_comp));
+       TYPESAFE_QSORT(queue, total_count, printjob_comp);
 
        DEBUG(5,("get_stored_queue_info: total_count = %u\n", (unsigned int)total_count));
 
 
        DEBUG(5,("get_stored_queue_info: total_count = %u\n", (unsigned int)total_count));
 
@@ -2764,7 +2973,7 @@ static bool get_stored_queue_info(struct tdb_print_db *pdb, int snum, int *pcoun
  set queue = NULL and status = NULL if you just want to update the cache
 ****************************************************************************/
 
  set queue = NULL and status = NULL if you just want to update the cache
 ****************************************************************************/
 
-int print_queue_status(int snum, 
+int print_queue_status(int snum,
                       print_queue_struct **ppqueue,
                       print_status_struct *status)
 {
                       print_queue_struct **ppqueue,
                       print_status_struct *status)
 {
@@ -2777,7 +2986,7 @@ int print_queue_status(int snum,
        /* make sure the database is up to date */
 
        if (print_cache_expired(lp_const_servicename(snum), True))
        /* make sure the database is up to date */
 
        if (print_cache_expired(lp_const_servicename(snum), True))
-               print_queue_update(snum, False);
+               print_queue_update(server_messaging_context(), snum, False);
 
        /* return if we are done */
        if ( !ppqueue || !status )
 
        /* return if we are done */
        if ( !ppqueue || !status )
@@ -2802,7 +3011,7 @@ int print_queue_status(int snum,
        data = tdb_fetch(pdb->tdb, key);
        if (data.dptr) {
                if (data.dsize == sizeof(*status)) {
        data = tdb_fetch(pdb->tdb, key);
        if (data.dptr) {
                if (data.dsize == sizeof(*status)) {
-                       /* this memcpy is ok since the status struct was 
+                       /* this memcpy is ok since the status struct was
                           not packed before storing it in the tdb */
                        memcpy(status, data.dptr, sizeof(*status));
                }
                           not packed before storing it in the tdb */
                        memcpy(status, data.dptr, sizeof(*status));
                }
@@ -2814,7 +3023,8 @@ int print_queue_status(int snum,
         * of entries, and then only retrieve the queue if necessary.
         */
 
         * of entries, and then only retrieve the queue if necessary.
         */
 
-       if (!get_stored_queue_info(pdb, snum, &count, ppqueue)) {
+       if (!get_stored_queue_info(server_messaging_context(), pdb, snum,
+                                  &count, ppqueue)) {
                release_print_db(pdb);
                return 0;
        }
                release_print_db(pdb);
                return 0;
        }
@@ -2827,28 +3037,26 @@ int print_queue_status(int snum,
  Pause a queue.
 ****************************************************************************/
 
  Pause a queue.
 ****************************************************************************/
 
-bool print_queue_pause(struct auth_serversupplied_info *server_info, int snum,
-                      WERROR *errcode)
+WERROR print_queue_pause(struct auth_serversupplied_info *server_info,
+                        struct messaging_context *msg_ctx, int snum)
 {
        int ret;
        struct printif *current_printif = get_printer_fns( snum );
 {
        int ret;
        struct printif *current_printif = get_printer_fns( snum );
-       
-       if (!print_access_check(server_info, snum,
+
+       if (!print_access_check(server_info, msg_ctx, snum,
                                PRINTER_ACCESS_ADMINISTER)) {
                                PRINTER_ACCESS_ADMINISTER)) {
-               *errcode = WERR_ACCESS_DENIED;
-               return False;
+               return WERR_ACCESS_DENIED;
        }
        }
-       
+
 
        become_root();
 
        become_root();
-               
+
        ret = (*(current_printif->queue_pause))(snum);
 
        unbecome_root();
        ret = (*(current_printif->queue_pause))(snum);
 
        unbecome_root();
-               
+
        if (ret != 0) {
        if (ret != 0) {
-               *errcode = WERR_INVALID_PARAM;
-               return False;
+               return WERR_INVALID_PARAM;
        }
 
        /* force update the database */
        }
 
        /* force update the database */
@@ -2858,53 +3066,51 @@ bool print_queue_pause(struct auth_serversupplied_info *server_info, int snum,
 
        notify_printer_status(snum, PRINTER_STATUS_PAUSED);
 
 
        notify_printer_status(snum, PRINTER_STATUS_PAUSED);
 
-       return True;
+       return WERR_OK;
 }
 
 /****************************************************************************
  Resume a queue.
 ****************************************************************************/
 
 }
 
 /****************************************************************************
  Resume a queue.
 ****************************************************************************/
 
-bool print_queue_resume(struct auth_serversupplied_info *server_info, int snum,
-                       WERROR *errcode)
+WERROR print_queue_resume(struct auth_serversupplied_info *server_info,
+                         struct messaging_context *msg_ctx, int snum)
 {
        int ret;
        struct printif *current_printif = get_printer_fns( snum );
 
 {
        int ret;
        struct printif *current_printif = get_printer_fns( snum );
 
-       if (!print_access_check(server_info, snum,
+       if (!print_access_check(server_info, msg_ctx, snum,
                                PRINTER_ACCESS_ADMINISTER)) {
                                PRINTER_ACCESS_ADMINISTER)) {
-               *errcode = WERR_ACCESS_DENIED;
-               return False;
+               return WERR_ACCESS_DENIED;
        }
        }
-       
+
        become_root();
        become_root();
-               
+
        ret = (*(current_printif->queue_resume))(snum);
 
        unbecome_root();
        ret = (*(current_printif->queue_resume))(snum);
 
        unbecome_root();
-               
+
        if (ret != 0) {
        if (ret != 0) {
-               *errcode = WERR_INVALID_PARAM;
-               return False;
+               return WERR_INVALID_PARAM;
        }
 
        /* make sure the database is up to date */
        if (print_cache_expired(lp_const_servicename(snum), True))
        }
 
        /* make sure the database is up to date */
        if (print_cache_expired(lp_const_servicename(snum), True))
-               print_queue_update(snum, True);
+               print_queue_update(msg_ctx, snum, True);
 
        /* Send a printer notify message */
 
        notify_printer_status(snum, PRINTER_STATUS_OK);
 
 
        /* Send a printer notify message */
 
        notify_printer_status(snum, PRINTER_STATUS_OK);
 
-       return True;
+       return WERR_OK;
 }
 
 /****************************************************************************
  Purge a queue - implemented by deleting all jobs that we can delete.
 ****************************************************************************/
 
 }
 
 /****************************************************************************
  Purge a queue - implemented by deleting all jobs that we can delete.
 ****************************************************************************/
 
-bool print_queue_purge(struct auth_serversupplied_info *server_info, int snum,
-                      WERROR *errcode)
+WERROR print_queue_purge(struct auth_serversupplied_info *server_info,
+                        struct messaging_context *msg_ctx, int snum)
 {
        print_queue_struct *queue;
        print_status_struct status;
 {
        print_queue_struct *queue;
        print_status_struct status;
@@ -2912,12 +3118,14 @@ bool print_queue_purge(struct auth_serversupplied_info *server_info, int snum,
        bool can_job_admin;
 
        /* Force and update so the count is accurate (i.e. not a cached count) */
        bool can_job_admin;
 
        /* Force and update so the count is accurate (i.e. not a cached count) */
-       print_queue_update(snum, True);
-       
-       can_job_admin = print_access_check(server_info, snum,
+       print_queue_update(msg_ctx, snum, True);
+
+       can_job_admin = print_access_check(server_info,
+                                          msg_ctx,
+                                          snum,
                                           JOB_ACCESS_ADMINISTER);
        njobs = print_queue_status(snum, &queue, &status);
                                           JOB_ACCESS_ADMINISTER);
        njobs = print_queue_status(snum, &queue, &status);
-       
+
        if ( can_job_admin )
                become_root();
 
        if ( can_job_admin )
                become_root();
 
@@ -2929,14 +3137,14 @@ bool print_queue_purge(struct auth_serversupplied_info *server_info, int snum,
                        print_job_delete1(snum, queue[i].job);
                }
        }
                        print_job_delete1(snum, queue[i].job);
                }
        }
-       
+
        if ( can_job_admin )
                unbecome_root();
 
        /* update the cache */
        if ( can_job_admin )
                unbecome_root();
 
        /* update the cache */
-       print_queue_update( snum, True );
+       print_queue_update(msg_ctx, snum, True);
 
        SAFE_FREE(queue);
 
 
        SAFE_FREE(queue);
 
-       return True;
+       return WERR_OK;
 }
 }