printjob merge from APP_HEAD regarding device modes
authorGerald Carter <jerry@samba.org>
Wed, 18 Sep 2002 19:06:58 +0000 (19:06 +0000)
committerGerald Carter <jerry@samba.org>
Wed, 18 Sep 2002 19:06:58 +0000 (19:06 +0000)
source/include/includes.h
source/include/printing.h
source/printing/nt_printing.c
source/printing/printfsp.c
source/printing/printing.c
source/rpc_server/srv_spoolss_nt.c

index bdf5bbcef3697115a44abfef6894a5c03ba63a8e..56b8357831268b454c332e907819ae219903c709 100644 (file)
@@ -803,6 +803,11 @@ struct functable {
 
 #include "nsswitch/nss.h"
 
+/* forward declaration from printing.h to get around 
+   header file dependencies */
+
+struct printjob;
+
 /***** automatically generated prototypes *****/
 #include "proto.h"
 
index ecf603b8fcc9f35db321db98c6be88285f757a60..9774a6acd95d401c4195e910d2abed79cbcd5880 100644 (file)
@@ -43,6 +43,7 @@ struct printjob {
        fstring jobname; /* the job name given to us by the client */
        fstring user; /* the user who started the job */
        fstring queuename; /* service number of printer for this job */
+       NT_DEVICEMODE *nt_devmode;
 };
 
 /* Information for print interfaces */
index 2a96f9a83e01f1708e8e0f8bb769f057f75eed78..58eba9d87e8cd4ef014965b54c20c85222d4583b 100644 (file)
@@ -1905,7 +1905,7 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32
 
 /****************************************************************************
 ****************************************************************************/
-static int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
+int pack_devicemode(NT_DEVICEMODE *nt_devmode, char *buf, int buflen)
 {
        int len = 0;
 
@@ -2282,7 +2282,7 @@ static void free_nt_printer_info_level_2(NT_PRINTER_INFO_LEVEL_2 **info_ptr)
 
 /****************************************************************************
 ****************************************************************************/
-static int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
+int unpack_devicemode(NT_DEVICEMODE **nt_devmode, char *buf, int buflen)
 {
        int len = 0;
        int extra_len = 0;
index ff50ac47c492e18d6e939935e55ccc6705c49bd2..8a4e7ea073b0cda26b10d6df9c7574d25da72290 100644 (file)
@@ -46,7 +46,7 @@ files_struct *print_fsp_open(connection_struct *conn, char *fname)
                fstrcat(name, p);
        }
 
-       jobid = print_job_start(&current_user, SNUM(conn), name);
+       jobid = print_job_start(&current_user, SNUM(conn), name, NULL);
        if (jobid == -1) {
                file_free(fsp);
                return NULL;
index 035d4d383afca476c69c93e6769513b33787c19a..208da5b78b554ecd8dc5422dacdf11fc52dd379c 100644 (file)
@@ -311,15 +311,49 @@ static TDB_DATA print_key(uint32 jobid)
        return ret;
 }
 
+/***********************************************************************
+ unpack a pjob from a tdb buffer 
+***********************************************************************/
+int unpack_pjob( char* buf, int buflen, struct printjob *pjob )
+{
+       int     len = 0;
+       
+       if ( !buf || !pjob )
+               return -1;
+               
+       len += tdb_unpack(buf+len, buflen-len, "dddddddddffff",
+                               &pjob->pid,
+                               &pjob->sysjob,
+                               &pjob->fd,
+                               &pjob->starttime,
+                               &pjob->status,
+                               &pjob->size,
+                               &pjob->page_count,
+                               &pjob->spooled,
+                               &pjob->smbjob,
+                               pjob->filename,
+                               pjob->jobname,
+                               pjob->user,
+                               pjob->queuename);
+
+
+       len += unpack_devicemode(&pjob->nt_devmode, buf+len, buflen-len);
+       
+       return len;
+
+}
+
 /****************************************************************************
  Useful function to find a print job in the database.
 ****************************************************************************/
 
 static struct printjob *print_job_find(int snum, uint32 jobid)
 {
-       static struct printjob pjob;
-       TDB_DATA ret;
-       struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+       static struct printjob  pjob;
+       TDB_DATA                ret;
+       struct tdb_print_db     *pdb = get_print_db_byname(lp_const_servicename(snum));
+       
 
        if (!pdb)
                return NULL;
@@ -327,11 +361,17 @@ static struct printjob *print_job_find(int snum, uint32 jobid)
        ret = tdb_fetch(pdb->tdb, print_key(jobid));
        release_print_db(pdb);
 
-       if (!ret.dptr || ret.dsize != sizeof(pjob))
+       if (!ret.dptr)
                return NULL;
-
-       memcpy(&pjob, ret.dptr, sizeof(pjob));
-       SAFE_FREE(ret.dptr);
+       
+       if ( pjob.nt_devmode )
+               free_nt_devicemode( &pjob.nt_devmode );
+               
+       ZERO_STRUCT( pjob );
+       
+       unpack_pjob( ret.dptr, ret.dsize, &pjob );
+       
+       SAFE_FREE(ret.dptr);    
        return &pjob;
 }
 
@@ -462,9 +502,12 @@ static void pjob_store_notify(int snum, uint32 jobid, struct printjob *old_data,
 
 static BOOL pjob_store(int snum, uint32 jobid, struct printjob *pjob)
 {
-       TDB_DATA old_data, new_data;
-       BOOL ret;
-       struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum));
+       TDB_DATA                old_data, new_data;
+       BOOL                    ret = False;
+       struct tdb_print_db     *pdb = get_print_db_byname(lp_const_servicename(snum));
+       char                    *buf = NULL;
+       int                     len, newlen, buflen;
+       
 
        if (!pdb)
                return False;
@@ -473,22 +516,63 @@ static BOOL pjob_store(int snum, uint32 jobid, struct printjob *pjob)
 
        old_data = tdb_fetch(pdb->tdb, print_key(jobid));
 
+       /* Doh!  Now we have to pack/unpack data since the NT_DEVICEMODE was added */
+
+       newlen = 0;
+       
+       do {
+               len = 0;
+               buflen = newlen;
+               len += tdb_pack(buf+len, buflen-len, "dddddddddffff",
+                               pjob->pid,
+                               pjob->sysjob,
+                               pjob->fd,
+                               pjob->starttime,
+                               pjob->status,
+                               pjob->size,
+                               pjob->page_count,
+                               pjob->spooled,
+                               pjob->smbjob,
+                               pjob->filename,
+                               pjob->jobname,
+                               pjob->user,
+                               pjob->queuename);
+
+               len += pack_devicemode(pjob->nt_devmode, buf+len, buflen-len);
+       
+               if (buflen != len) 
+               {
+                       char *tb;
+
+                       tb = (char *)Realloc(buf, len);
+                       if (!tb) {
+                               DEBUG(0,("pjob_store: failed to enlarge buffer!\n"));
+                               goto done;
+                       }
+                       else 
+                               buf = tb;
+                       newlen = len;
+               }
+       }
+       while ( buflen != len );
+               
+       
        /* Store new data */
 
-       new_data.dptr = (void *)pjob;
-       new_data.dsize = sizeof(*pjob);
+       new_data.dptr = buf;
+       new_data.dsize = len;
        ret = (tdb_store(pdb->tdb, print_key(jobid), new_data, TDB_REPLACE) == 0);
 
        release_print_db(pdb);
 
        /* Send notify updates for what has changed */
 
-       if (ret && (old_data.dsize == 0 || old_data.dsize == sizeof(*pjob))) {
-               pjob_store_notify(
-                       snum, jobid, (struct printjob *)old_data.dptr,
-                       (struct printjob *)new_data.dptr);
-               free(old_data.dptr);
-       }
+       if ( ret && (old_data.dsize == 0 || old_data.dsize == sizeof(*pjob)) )
+               pjob_store_notify( snum, jobid, (struct printjob *)old_data.dptr, pjob );
+
+done:
+       SAFE_FREE( old_data.dptr );
+       SAFE_FREE( buf );
 
        return ret;
 }
@@ -956,6 +1040,23 @@ char *print_job_fname(int snum, uint32 jobid)
        return pjob->filename;
 }
 
+
+/****************************************************************************
+ Give the filename used for a jobid.
+ Only valid for the process doing the spooling and when the job
+ has not been spooled.
+****************************************************************************/
+
+NT_DEVICEMODE *print_job_devmode(int snum, uint32 jobid)
+{
+       struct printjob *pjob = print_job_find(snum, jobid);
+       
+       if ( !pjob )
+               return NULL;
+               
+       return pjob->nt_devmode;
+}
+
 /****************************************************************************
  Set the place in the queue for a job.
 ****************************************************************************/
@@ -1297,7 +1398,7 @@ int print_queue_length(int snum, print_status_struct *pstatus)
  Start spooling a job - return the jobid.
 ***************************************************************************/
 
-uint32 print_job_start(struct current_user *user, int snum, char *jobname)
+uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DEVICEMODE *nt_devmode )
 {
        uint32 jobid;
        char *path;
@@ -1357,7 +1458,9 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname)
        }
 
        /* create the database entry */
+       
        ZERO_STRUCT(pjob);
+       
        pjob.pid = local_pid;
        pjob.sysjob = -1;
        pjob.fd = -1;
@@ -1366,7 +1469,8 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname)
        pjob.size = 0;
        pjob.spooled = False;
        pjob.smbjob = True;
-
+       pjob.nt_devmode = nt_devmode;
+       
        fstrcpy(pjob.jobname, jobname);
 
        if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
@@ -1554,10 +1658,10 @@ static int traverse_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *
        int i;
        uint32 jobid;
 
-       if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int))
-               return 0;
        memcpy(&jobid, key.dptr, sizeof(jobid));
-       memcpy(&pjob,  data.dptr, sizeof(pjob));
+       
+       if ( !unpack_pjob( data.dptr, data.dsize, &pjob ) )
+               return 0;
 
        /* maybe it isn't for this queue */
        if (ts->snum != lp_servicenumber(pjob.queuename))
@@ -1596,10 +1700,10 @@ static int traverse_count_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data,
        struct printjob pjob;
        uint32 jobid;
 
-       if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int))
-               return 0;
        memcpy(&jobid, key.dptr, sizeof(jobid));
-       memcpy(&pjob,  data.dptr, sizeof(pjob));
+       
+       if ( !unpack_pjob( data.dptr, data.dsize, &pjob ) )
+               return 0;
 
        /* maybe it isn't for this queue - this cannot happen with the tdb/printer code. JRA */
        if (ts->snum != lp_servicenumber(pjob.queuename))
index bcba89c2cc1665fccfa173486d888349cd98c835..6953ec366313ca47b3ae509fbed3e6edae4e4ece 100644 (file)
@@ -87,6 +87,10 @@ typedef struct _Printer{
                fstring machine;
                fstring user;
        } client;
+       
+       /* devmode sent in the OpenPrinter() call */
+       NT_DEVICEMODE   *nt_devmode;
+       
 } Printer_entry;
 
 static Printer_entry *printers_list;
@@ -224,6 +228,8 @@ static void free_printer_entry(void *ptr)
        free_spool_notify_option(&Printer->notify.option);
        Printer->notify.option=NULL;
        Printer->notify.client_connected=False;
+       
+       free_nt_devicemode( &Printer->nt_devmode );
 
        /* Remove from the internal list. */
        DLIST_REMOVE(printers_list, Printer);
@@ -1446,9 +1452,9 @@ WERROR _spoolss_open_printer(pipes_struct *p, SPOOL_Q_OPEN_PRINTER *q_u, SPOOL_R
 
 WERROR _spoolss_open_printer_ex( pipes_struct *p, SPOOL_Q_OPEN_PRINTER_EX *q_u, SPOOL_R_OPEN_PRINTER_EX *r_u)
 {
-       UNISTR2 *printername = NULL;
-       PRINTER_DEFAULT *printer_default = &q_u->printer_default;
-       POLICY_HND *handle = &r_u->handle;
+       UNISTR2                 *printername = NULL;
+       PRINTER_DEFAULT         *printer_default = &q_u->printer_default;
+       POLICY_HND              *handle = &r_u->handle;
 
        fstring name;
        int snum;
@@ -1606,6 +1612,18 @@ Can't find printer handle we created for printer %s\n", name ));
        }
        
        Printer->access_granted = printer_default->access_required;
+       
+       /* 
+        * If the client sent a devmode in the OpenPrinter() call, then
+        * save it here in case we get a job submission on this handle
+        */
+       
+        if ( (Printer->printer_type != PRINTER_HANDLE_IS_PRINTSERVER)
+               && q_u->printer_default.devmode_cont.devmode_ptr )
+        { 
+               convert_devicemode( Printer->dev.handlename, q_u->printer_default.devmode_cont.devmode,
+                       &Printer->nt_devmode );
+        }
 
        return WERR_OK;
 }
@@ -3784,47 +3802,20 @@ static void free_dev_mode(DEVICEMODE *dev)
        SAFE_FREE(dev); 
 }
 
+
 /****************************************************************************
- Create a DEVMODE struct. Returns malloced memory.
+ Convert an NT_DEVICEMODE to a DEVICEMODE structure.  Both pointers 
+ should be valid upon entry
 ****************************************************************************/
 
-DEVICEMODE *construct_dev_mode(int snum)
+static BOOL convert_nt_devicemode( DEVICEMODE *devmode, NT_DEVICEMODE *ntdevmode )
 {
-       char adevice[32];
-       char aform[32];
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
-       NT_DEVICEMODE *ntdevmode = NULL;
-       DEVICEMODE *devmode = NULL;
-
-       DEBUG(7,("construct_dev_mode\n"));
-       
-       DEBUGADD(8,("getting printer characteristics\n"));
-
-       if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) == NULL) {
-               DEBUG(2,("construct_dev_mode: malloc fail.\n"));
-               return NULL;
-       }
-
-       ZERO_STRUCTP(devmode);  
-
-       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
-               goto fail;
-
-       if (printer->info_2->devmode)
-               ntdevmode = dup_nt_devicemode(printer->info_2->devmode);
-
-       if (ntdevmode == NULL) {
-               DEBUG(5, ("BONG! There was no device mode!\n"));
-               goto fail;
-       }
-
-       DEBUGADD(8,("loading DEVICEMODE\n"));
-
-       slprintf(adevice, sizeof(adevice)-1, printer->info_2->printername);
-       init_unistr(&devmode->devicename, adevice);
+       if ( !devmode || !ntdevmode )
+               return False;
+               
+       init_unistr(&devmode->devicename, ntdevmode->devicename);
 
-       slprintf(aform, sizeof(aform)-1, ntdevmode->formname);
-       init_unistr(&devmode->formname, aform);
+       init_unistr(&devmode->formname, ntdevmode->formname);
 
        devmode->specversion      = ntdevmode->specversion;
        devmode->driverversion    = ntdevmode->driverversion;
@@ -3852,23 +3843,51 @@ DEVICEMODE *construct_dev_mode(int snum)
 
        if (ntdevmode->private != NULL) {
                if ((devmode->private=(uint8 *)memdup(ntdevmode->private, ntdevmode->driverextra)) == NULL)
-                       goto fail;
+                       return False;
        }
+       
+       return True;
+}
 
-       free_nt_devicemode(&ntdevmode);
-       free_a_printer(&printer,2);
+/****************************************************************************
+ Create a DEVMODE struct. Returns malloced memory.
+****************************************************************************/
 
-       return devmode;
+DEVICEMODE *construct_dev_mode(int snum)
+{
+       NT_PRINTER_INFO_LEVEL   *printer = NULL;
+       DEVICEMODE              *devmode = NULL;
+       
+       DEBUG(7,("construct_dev_mode\n"));
+       
+       DEBUGADD(8,("getting printer characteristics\n"));
 
-  fail:
+       if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum)))) 
+               return NULL;
 
-       if (ntdevmode)
-               free_nt_devicemode(&ntdevmode);
-       if (printer)
-               free_a_printer(&printer,2);
-       free_dev_mode(devmode);
+       if ( !printer->info_2->devmode ) {
+               DEBUG(5, ("BONG! There was no device mode!\n"));
+               goto done;
+       }
+
+       if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) == NULL) {
+               DEBUG(2,("construct_dev_mode: malloc fail.\n"));
+               goto done;
+       }
+
+       ZERO_STRUCTP(devmode);  
+       
+       DEBUGADD(8,("loading DEVICEMODE\n"));
+
+       if ( !convert_nt_devicemode( devmode, printer->info_2->devmode ) ) {
+               free_dev_mode( devmode );
+               devmode = NULL;
+       }
 
-       return NULL;
+done:
+       free_a_printer(&printer,2);
+
+       return devmode;
 }
 
 /********************************************************************
@@ -5286,10 +5305,6 @@ WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, S
         * in EMF format.
         *
         * So I add checks like in NT Server ...
-        *
-        * lkclXXXX jean-francois, i love this kind of thing.  oh, well,
-        * there's a bug in NT client-side code, so we'll fix it in the
-        * server-side code. *nnnnnggggh!*
         */
        
        if (info_1->p_datatype != 0) {
@@ -5307,7 +5322,7 @@ WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, S
 
        unistr2_to_ascii(jobname, &info_1->docname, sizeof(jobname));
        
-       Printer->jobid = print_job_start(&user, snum, jobname);
+       Printer->jobid = print_job_start(&user, snum, jobname, Printer->nt_devmode);
 
        /* An error occured in print_job_start() so return an appropriate
           NT error code. */
@@ -8013,7 +8028,7 @@ static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uin
                return WERR_NOMEM;
        }
                
-       for (i=0; i<count && found==False; i++) {
+       for (i=0; i<count && found==False; i++) { 
                if (queue[i].job==(int)jobid)
                        found=True;
        }
@@ -8049,12 +8064,13 @@ static WERROR getjob_level_1(print_queue_struct *queue, int count, int snum, uin
 
 static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uint32 jobid, NEW_BUFFER *buffer, uint32 offered, uint32 *needed)
 {
-       int i=0;
-       BOOL found=False;
-       JOB_INFO_2 *info_2;
+       int             i = 0;
+       BOOL            found = False;
+       JOB_INFO_2      *info_2;
        NT_PRINTER_INFO_LEVEL *ntprinter = NULL;
-       WERROR ret;
-       DEVICEMODE *devmode = NULL;
+       WERROR          ret;
+       DEVICEMODE      *devmode = NULL;
+       NT_DEVICEMODE   *nt_devmode = NULL;
 
        info_2=(JOB_INFO_2 *)malloc(sizeof(JOB_INFO_2));
 
@@ -8082,8 +8098,22 @@ static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uin
        ret = get_a_printer(&ntprinter, 2, lp_servicename(snum));
        if (!W_ERROR_IS_OK(ret))
                goto done;
-               
-       if (!(devmode = construct_dev_mode(snum)) ) {
+       
+       /* 
+        * if the print job does not have a DEVMODE associated with it, 
+        * just use the one for the printer 
+        */
+        
+       if ( !(nt_devmode=print_job_devmode( snum, jobid )) )
+               devmode = construct_dev_mode(snum);
+       else {
+               if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) != NULL) {
+                       ZERO_STRUCTP( devmode );
+                       convert_nt_devicemode( devmode, nt_devmode );
+               }
+       }
+       
+       if ( !devmode ) {
                ret = WERR_NOMEM;
                goto done;
        }