Bring printing in HEAD inline with 2.2.x and app-head.
authorJeremy Allison <jra@samba.org>
Sat, 9 Feb 2002 04:10:24 +0000 (04:10 +0000)
committerJeremy Allison <jra@samba.org>
Sat, 9 Feb 2002 04:10:24 +0000 (04:10 +0000)
Jeremy.
(This used to be commit 771ef92fc6e43725b7cc351079998a8acb74abef)

source3/include/doserr.h
source3/printing/nt_printing.c
source3/rpc_server/srv_spoolss_nt.c

index c1431117f08442f735463b134483d75fd75c0122..a2c53791cc87e99ffce8a2fe0e83e4ca39dfb5ab 100644 (file)
@@ -1,5 +1,6 @@
 /* 
-   Unix SMB/CIFS implementation.
+   Unix SMB/Netbios implementation.
+   Version 1.9.
    DOS error code constants
    Copyright (C) Andrew Tridgell              1992-2000
    Copyright (C) John H Terpstra              1996-2000
 #define WERR_BADFUNC W_ERROR(1)
 #define WERR_INSUFFICIENT_BUFFER W_ERROR(122)
 #define WERR_NO_SUCH_SHARE W_ERROR(67)
+#define WERR_ALREADY_EXISTS W_ERROR(80)
 #define WERR_INVALID_PARAM W_ERROR(87)
 #define WERR_NOT_SUPPORTED W_ERROR(50)
 #define WERR_BAD_PASSWORD W_ERROR(86)
-#define WERR_FILE_EXISTS W_ERROR(80)
 #define WERR_NOMEM W_ERROR(8)
 #define WERR_INVALID_NAME W_ERROR(123)
 #define WERR_UNKNOWN_LEVEL W_ERROR(124)
index 14d746a50d6dc285b69647823e4a4c9806d7e361..de12e63847273964bcb9cdfa2532bd022972a7cd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Unix SMB/CIFS implementation.
+ *  Unix SMB/Netbios implementation.
  *  RPC Pipe client / server routines
  *  Copyright (C) Andrew Tridgell              1992-2000,
  *  Copyright (C) Jean Fran├žois Micouleau      1998-2000.
@@ -32,6 +32,7 @@ static TDB_CONTEXT *tdb_printers; /* used for printers files */
 #define DRIVER_INIT_PREFIX "DRIVER_INIT/"
 #define PRINTERS_PREFIX "PRINTERS/"
 #define SECDESC_PREFIX "SECDESC/"
+#define GLOBAL_C_SETPRINTER "GLOBALS/c_setprinter"
  
 #define NTDRIVERS_DATABASE_VERSION_1 1
 #define NTDRIVERS_DATABASE_VERSION_2 2
@@ -276,24 +277,93 @@ BOOL nt_printing_init(void)
                }
 
                if (vers_id != NTDRIVERS_DATABASE_VERSION) {
-                       if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) {
+
+                       if ((vers_id == NTDRIVERS_DATABASE_VERSION_1) || (IREV(vers_id) == NTDRIVERS_DATABASE_VERSION_1)) { 
                                if (!upgrade_to_version_3())
                                        return False;
                        } else
                                tdb_traverse(tdb_drivers, tdb_traverse_delete_fn, NULL);
-
+                        
                        tdb_store_int32(tdb_drivers, vstring, NTDRIVERS_DATABASE_VERSION);
                }
        }
        tdb_unlock_bystring(tdb_drivers, vstring);
 
+       update_c_setprinter(True);
+
        return True;
 }
 
+/*******************************************************************
+ tdb traversal function for counting printers.
+********************************************************************/
+
+static int traverse_counting_printers(TDB_CONTEXT *t, TDB_DATA key,
+                                      TDB_DATA data, void *context)
+{
+       int *printer_count = (int*)context;
+       if (memcmp(PRINTERS_PREFIX, key.dptr, sizeof(PRINTERS_PREFIX)-1) == 0) {
+               (*printer_count)++;
+               DEBUG(10,("traverse_counting_printers: printer = [%s]  printer_count = %d\n", key.dptr, *printer_count));
+       }
+       return 0;
+}
+/*******************************************************************
+ Update the spooler global c_setprinter. This variable is initialized
+ when the parent smbd starts with the number of existing printers. It
+ is monotonically increased by the current number of printers *after*
+ each add or delete printer RPC. Only Microsoft knows why... JRR020119
+********************************************************************/
+
+uint32 update_c_setprinter(BOOL initialize)
+{
+       int32 c_setprinter;
+       int32 printer_count = 0;
+       tdb_lock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
+       /* Traverse the tdb, counting the printers */
+       tdb_traverse(tdb_printers, traverse_counting_printers, (void *)&printer_count);
+       /* If initializing, set c_setprinter to current printers count
+        * otherwise, bump it by the current printer count
+        */
+       if (!initialize)
+               c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER) + printer_count;
+       else
+               c_setprinter = printer_count;
+       DEBUG(10,("update_c_setprinter: c_setprinter = %u\n", (unsigned int)c_setprinter));
+       tdb_store_int32(tdb_printers, GLOBAL_C_SETPRINTER, c_setprinter);
+       tdb_unlock_bystring(tdb_printers, GLOBAL_C_SETPRINTER);
+       return (uint32)c_setprinter;
+}
+
+/*******************************************************************
+ Get the spooler global c_setprinter, accounting for initialization.
+********************************************************************/
+
+uint32 get_c_setprinter(void)
+{
+       int32 c_setprinter = tdb_fetch_int32(tdb_printers, GLOBAL_C_SETPRINTER);
+       if (c_setprinter == (int32)-1)
+               c_setprinter = update_c_setprinter(True);
+       DEBUG(10,("get_c_setprinter: c_setprinter = %d\n", c_setprinter));
+       return (uint32)c_setprinter;
+}
+
 /****************************************************************************
- get builtin form struct list
+ Get builtin form struct list.
 ****************************************************************************/
+
 int get_builtin_ntforms(nt_forms_struct **list)
 {
        *list = (nt_forms_struct *)memdup(&default_forms[0], sizeof(default_forms));
@@ -354,7 +424,7 @@ int get_ntforms(nt_forms_struct **list)
                        DEBUG(0,("get_ntforms: Realloc fail.\n"));
                        return 0;
                }
-               *list = tl;
+        *list = tl;
                (*list)[n] = form;
                n++;
        }
@@ -940,7 +1010,7 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
        int               access_mode;
        int               action;
        NTSTATUS          nt_status;
-       pstring           driverpath;
+       pstring           driverpath;
        DATA_BLOB         null_pw;
        files_struct      *fsp = NULL;
        BOOL              bad_path;
@@ -958,11 +1028,14 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
                return 0;
        }
 
-       /* connect to the print$ share under the same account as the user connected to the rpc pipe */  
+       /*
+        * Connect to the print$ share under the same account as the user connected
+        * to the rpc pipe. Note we must still be root to do this.
+        */
+
        /* Null password is ok - we are already an authenticated user... */
        null_pw = data_blob(NULL, 0);
-
-       become_root();
+       become_root();
        conn = make_connection("print$", null_pw, "A:", user->vuid, &nt_status);
        unbecome_root();
 
@@ -1029,8 +1102,8 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
                                  driverpath, major, minor));
        }
 
-       DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
-                 driverpath, cversion));
+    DEBUG(10,("get_correct_cversion: Driver file [%s] cversion = %d\n",
+                       driverpath, cversion));
 
        close_file(fsp, True);
        close_cnum(conn, user->vuid);
@@ -1038,11 +1111,12 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
        *perr = WERR_OK;
        return cversion;
 
+
   error_exit:
 
        if(fsp)
                close_file(fsp, True);
-       
+
        close_cnum(conn, user->vuid);
        unbecome_user();
        return -1;
@@ -1051,7 +1125,7 @@ static uint32 get_correct_cversion(fstring architecture, fstring driverpath_in,
 /****************************************************************************
 ****************************************************************************/
 static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver,
-                                            struct current_user *user)
+                                                                                        struct current_user *user)
 {
        fstring architecture;
        fstring new_name;
@@ -1107,7 +1181,7 @@ static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri
         *      NT2K: cversion=3
         */
        if ((driver->cversion = get_correct_cversion( architecture,
-                                                     driver->driverpath, user, &err)) == -1)
+                                                                       driver->driverpath, user, &err)) == -1)
                return err;
 
        return WERR_OK;
@@ -1116,7 +1190,7 @@ static WERROR clean_up_driver_struct_level_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *dri
 /****************************************************************************
 ****************************************************************************/
 static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *driver,
-                                            struct current_user *user)
+                                                                                        struct current_user *user)
 {
        fstring architecture;
        fstring new_name;
@@ -1172,7 +1246,7 @@ static WERROR clean_up_driver_struct_level_6(NT_PRINTER_DRIVER_INFO_LEVEL_6 *dri
         *      NT2K: cversion=3
         */
        if ((driver->version = get_correct_cversion(architecture,
-                                                   driver->driverpath, user, &err)) == -1)
+                                                                       driver->driverpath, user, &err)) == -1)
                return err;
 
        return WERR_OK;
@@ -1252,9 +1326,13 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        DATA_BLOB null_pw;
        connection_struct *conn;
        NTSTATUS nt_status;
+       pstring inbuf;
+       pstring outbuf;
        int ver = 0;
        int i;
 
+       memset(inbuf, '\0', sizeof(inbuf));
+       memset(outbuf, '\0', sizeof(outbuf));
        *perr = WERR_OK;
 
        if (level==3)
@@ -1269,10 +1347,15 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
 
        get_short_archi(architecture, driver->environment);
 
-       /* connect to the print$ share under the same account as the user connected to the rpc pipe */  
-       /* Null password is ok - we are already an authenticated user... */
+       /*
+        * Connect to the print$ share under the same account as the user connected to the rpc pipe.
+        * Note we must be root to do this.
+        */
+
+       become_root();
        null_pw = data_blob(NULL, 0);
        conn = make_connection("print$", null_pw, "A:", user->vuid, &nt_status);
+       unbecome_root();
 
        if (conn == NULL) {
                DEBUG(0,("move_driver_to_download_area: Unable to connect\n"));
@@ -1284,11 +1367,8 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
         * Save who we are - we are temporarily becoming the connection user.
         */
 
-       push_sec_ctx();
-
        if (!become_user(conn, conn->vuid)) {
                DEBUG(0,("move_driver_to_download_area: Can't become user!\n"));
-               pop_sec_ctx();
                return False;
        }
 
@@ -1434,7 +1514,7 @@ BOOL move_driver_to_download_area(NT_PRINTER_DRIVER_INFO_LEVEL driver_abstract,
        }
 
        close_cnum(conn, user->vuid);
-       pop_sec_ctx();
+       unbecome_user();
 
        return ver == -1 ? False : True;
 }
@@ -1461,36 +1541,36 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
 
        slprintf(directory, sizeof(directory)-1, "\\print$\\%s\\%d\\", architecture, driver->cversion);
 
-    /* .inf files do not always list a file for each of the four standard files. 
-     * Don't prepend a path to a null filename, or client claims:
-     *   "The server on which the printer resides does not have a suitable 
-     *   <printer driver name> printer driver installed. Click OK if you 
-     *   wish to install the driver on your local machine."
-     */
+       /* .inf files do not always list a file for each of the four standard files. 
+        * Don't prepend a path to a null filename, or client claims:
+        *   "The server on which the printer resides does not have a suitable 
+        *   <printer driver name> printer driver installed. Click OK if you 
+        *   wish to install the driver on your local machine."
+        */
        if (strlen(driver->driverpath)) {
-       fstrcpy(temp_name, driver->driverpath);
-       slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
-    }
+               fstrcpy(temp_name, driver->driverpath);
+               slprintf(driver->driverpath, sizeof(driver->driverpath)-1, "%s%s", directory, temp_name);
+       }
 
        if (strlen(driver->datafile)) {
-       fstrcpy(temp_name, driver->datafile);
-       slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
-    }
+               fstrcpy(temp_name, driver->datafile);
+               slprintf(driver->datafile, sizeof(driver->datafile)-1, "%s%s", directory, temp_name);
+       }
 
        if (strlen(driver->configfile)) {
-       fstrcpy(temp_name, driver->configfile);
-       slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
-    }
+               fstrcpy(temp_name, driver->configfile);
+               slprintf(driver->configfile, sizeof(driver->configfile)-1, "%s%s", directory, temp_name);
+       }
 
        if (strlen(driver->helpfile)) {
-       fstrcpy(temp_name, driver->helpfile);
-       slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
-    }
+               fstrcpy(temp_name, driver->helpfile);
+               slprintf(driver->helpfile, sizeof(driver->helpfile)-1, "%s%s", directory, temp_name);
+       }
 
        if (driver->dependentfiles) {
                for (i=0; *driver->dependentfiles[i]; i++) {
-            fstrcpy(temp_name, driver->dependentfiles[i]);
-            slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
+                       fstrcpy(temp_name, driver->dependentfiles[i]);
+                       slprintf(driver->dependentfiles[i], sizeof(driver->dependentfiles[i])-1, "%s%s", directory, temp_name);
                }
        }
 
@@ -1523,7 +1603,7 @@ static uint32 add_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 *driver)
 
        if (len != buflen) {
                char *tb;
-               
+
                tb = (char *)Realloc(buf, len);
                if (!tb) {
                        DEBUG(0,("add_a_printer_driver_3: failed to enlarge buffer\n!"));
@@ -1642,7 +1722,7 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
        i=0;
        while (len < dbuf.dsize) {
                fstring *tddfs;
-       
+
                tddfs = (fstring *)Realloc(driver.dependentfiles,
                                                         sizeof(fstring)*(i+2));
                if (tddfs == NULL) {
@@ -1661,7 +1741,7 @@ static WERROR get_a_printer_driver_3(NT_PRINTER_DRIVER_INFO_LEVEL_3 **info_ptr,
        SAFE_FREE(dbuf.dptr);
 
        if (len != dbuf.dsize) {
-               SAFE_FREE(driver.dependentfiles);
+                       SAFE_FREE(driver.dependentfiles);
 
                return get_a_printer_driver_3_default(info_ptr, in_prt, in_arch);
        }
@@ -1686,42 +1766,43 @@ uint32 get_a_printer_driver_9x_compatible(pstring line, fstring model)
        
        kbuf.dptr = key;
        kbuf.dsize = strlen(key)+1;
-       if (!tdb_exists(tdb_drivers, kbuf)) return False;
+       if (!tdb_exists(tdb_drivers, kbuf))
+               return False;
 
        ZERO_STRUCT(info3);
        get_a_printer_driver_3(&info3, model, "Windows 4.0", 0);
        
-    DEBUGADD(10,("info3->name            [%s]\n", info3->name));
-    DEBUGADD(10,("info3->datafile        [%s]\n", info3->datafile));
-    DEBUGADD(10,("info3->helpfile        [%s]\n", info3->helpfile));
-    DEBUGADD(10,("info3->monitorname     [%s]\n", info3->monitorname));
-    DEBUGADD(10,("info3->defaultdatatype [%s]\n", info3->defaultdatatype));
+       DEBUGADD(10,("info3->name            [%s]\n", info3->name));
+       DEBUGADD(10,("info3->datafile        [%s]\n", info3->datafile));
+       DEBUGADD(10,("info3->helpfile        [%s]\n", info3->helpfile));
+       DEBUGADD(10,("info3->monitorname     [%s]\n", info3->monitorname));
+       DEBUGADD(10,("info3->defaultdatatype [%s]\n", info3->defaultdatatype));
        for (i=0; info3->dependentfiles && *info3->dependentfiles[i]; i++) {
-    DEBUGADD(10,("info3->dependentfiles  [%s]\n", info3->dependentfiles[i]));
-    }
-    DEBUGADD(10,("info3->environment     [%s]\n", info3->environment));
-    DEBUGADD(10,("info3->driverpath      [%s]\n", info3->driverpath));
-    DEBUGADD(10,("info3->configfile      [%s]\n", info3->configfile));
+               DEBUGADD(10,("info3->dependentfiles  [%s]\n", info3->dependentfiles[i]));
+       }
+       DEBUGADD(10,("info3->environment     [%s]\n", info3->environment));
+       DEBUGADD(10,("info3->driverpath      [%s]\n", info3->driverpath));
+       DEBUGADD(10,("info3->configfile      [%s]\n", info3->configfile));
 
        /*pstrcat(line, info3->name);             pstrcat(line, ":");*/
        trim_string(info3->configfile, "\\print$\\WIN40\\0\\", 0);
        pstrcat(line, info3->configfile);
-    pstrcat(line, ":");
+       pstrcat(line, ":");
        trim_string(info3->datafile, "\\print$\\WIN40\\0\\", 0);
        pstrcat(line, info3->datafile);
-    pstrcat(line, ":");
+       pstrcat(line, ":");
        trim_string(info3->helpfile, "\\print$\\WIN40\\0\\", 0);
        pstrcat(line, info3->helpfile);
-    pstrcat(line, ":");
+       pstrcat(line, ":");
        trim_string(info3->monitorname, "\\print$\\WIN40\\0\\", 0);
        pstrcat(line, info3->monitorname);
-    pstrcat(line, ":");
+       pstrcat(line, ":");
        pstrcat(line, "RAW");                /*info3->defaultdatatype);*/
-    pstrcat(line, ":");
+       pstrcat(line, ":");
 
-       for (i=0; info3->dependentfiles &&
-                *info3->dependentfiles[i]; i++) {
-               if (i) pstrcat(line, ",");               /* don't end in a "," */
+       for (i=0; info3->dependentfiles && *info3->dependentfiles[i]; i++) {
+               if (i)
+                       pstrcat(line, ",");               /* don't end in a "," */
                trim_string(info3->dependentfiles[i], "\\print$\\WIN40\\0\\", 0);
                pstrcat(line, info3->dependentfiles[i]);
        }
@@ -1732,8 +1813,9 @@ uint32 get_a_printer_driver_9x_compatible(pstring line, fstring model)
 }
 
 /****************************************************************************
-debugging function, dump at level 6 the struct in the logs
+ Debugging function, dump at level 6 the struct in the logs.
 ****************************************************************************/
+
 static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32 level)
 {
        uint32 result;
@@ -1771,7 +1853,7 @@ static uint32 dump_a_printer_driver(NT_PRINTER_DRIVER_INFO_LEVEL driver, uint32
                        break;
                }
                default:
-                       DEBUGADD(1,("Level not implemented\n"));
+                       DEBUGADD(106,("dump_a_printer_driver: Level %u not implemented\n", (unsigned int)level));
                        result=1;
                        break;
        }
@@ -1863,9 +1945,10 @@ static int pack_specifics(NT_PRINTER_PARAM *param, char *buf, int buflen)
 
 
 /****************************************************************************
-delete a printer - this just deletes the printer info file, any open
-handles are not affected
+ Delete a printer - this just deletes the printer info file, any open
+ handles are not affected.
 ****************************************************************************/
+
 uint32 del_a_printer(char *sharename)
 {
        pstring key;
@@ -1953,7 +2036,7 @@ static WERROR update_a_printer_2(NT_PRINTER_INFO_LEVEL_2 *info)
 
        if (buflen != len) {
                char *tb;
-               
+
                tb = (char *)Realloc(buf, len);
                if (!tb) {
                        DEBUG(0,("update_a_printer_2: failed to enlarge buffer!\n"));
@@ -2067,7 +2150,7 @@ void free_nt_printer_param(NT_PRINTER_PARAM **param_ptr)
 
        DEBUG(106,("free_nt_printer_param: deleting param [%s]\n", param->value));
 
-       SAFE_FREE(param->data);
+               SAFE_FREE(param->data);
        SAFE_FREE(*param_ptr);
 }
 
@@ -2176,7 +2259,7 @@ void free_nt_devicemode(NT_DEVICEMODE **devmode_ptr)
 
        DEBUG(106,("free_nt_devicemode: deleting DEVMODE\n"));
 
-       SAFE_FREE(nt_devmode->private);
+               SAFE_FREE(nt_devmode->private);
        SAFE_FREE(*devmode_ptr);
 }
 
@@ -2424,13 +2507,13 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
        fstrcpy(info.printprocessor, "winprint");
        fstrcpy(info.datatype, "RAW");
 
-       info.attributes = (PRINTER_ATTRIBUTE_SHARED | PRINTER_ATTRIBUTE_NETWORK); 
+       info.attributes = PRINTER_ATTRIBUTE_SHARED | PRINTER_ATTRIBUTE_NETWORK;      /* attributes */
 
        info.starttime = 0; /* Minutes since 12:00am GMT */
        info.untiltime = 0; /* Minutes since 12:00am GMT */
        info.priority = 1;
        info.default_priority = 1;
-       info.setuptime = (uint32)time(NULL) - 86400;    /* minus 1 day */
+       info.setuptime = (uint32)time(NULL);
 
        /*
         * I changed this as I think it is better to have a generic
@@ -2465,7 +2548,6 @@ static WERROR get_a_printer_2_default(NT_PRINTER_INFO_LEVEL_2 **info_ptr, fstrin
        return WERR_OK;
 
   fail:
-
        if (info.devmode)
                free_nt_devicemode(&info.devmode);
        return WERR_ACCESS_DENIED;
@@ -2611,7 +2693,7 @@ static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
                        break;
                }
                default:
-                       DEBUGADD(1,("Level not implemented\n"));
+                       DEBUGADD(106,("dump_a_printer: Level %u not implemented\n", (unsigned int)level ));
                        result=1;
                        break;
        }
@@ -2626,7 +2708,7 @@ static uint32 dump_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
 void get_printer_subst_params(int snum, fstring *printername, fstring *sharename, fstring *portname)
 {
        NT_PRINTER_INFO_LEVEL *printer = NULL;
-       
+
        **printername = **sharename = **portname = '\0';
 
        if (!W_ERROR_IS_OK(get_a_printer(&printer, 2, lp_servicename(snum))))
@@ -2652,8 +2734,9 @@ static uint32 rev_changeid(void)
        struct timeval tv;
 
        get_process_uptime(&tv);
-       /* This value is in ms * 100 */
-       return (((tv.tv_sec * 1000000) + tv.tv_usec)/100);
+
+       /* Return changeid as msec since spooler restart */
+       return tv.tv_sec * 1000 + tv.tv_usec / 1000;
 }
 
 /*
@@ -2678,8 +2761,8 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
                {
                        /*
                         * Update the changestamp.  Emperical tests show that the
-                        * ChangeID is always updated,but c_setprinter is only 
-                        * incremented on a SetPrinter() call.
+                        * ChangeID is always updated,but c_setprinter is  
+                        *  global spooler variable (not per printer).
                         */
 
                        /* ChangeID **must** be increasing over the lifetime
@@ -2721,6 +2804,7 @@ WERROR mod_a_printer(NT_PRINTER_INFO_LEVEL printer, uint32 level)
 /****************************************************************************
  Initialize printer devmode & data with previously saved driver init values.
 ****************************************************************************/
+
 static uint32 set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
 {
        int                     len = 0;
@@ -2729,6 +2813,17 @@ static uint32 set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
        NT_PRINTER_PARAM        *current;
        NT_PRINTER_INFO_LEVEL_2 info;
 
+       /*
+        * Delete any printer data 'specifics' already set. When called for driver
+        * replace, there will generally be some, but during an add printer, there
+        * should not be any (if there are delete them).
+        */
+       while ( (current=info_ptr->specific) != NULL ) {
+               info_ptr->specific=current->next;
+               SAFE_FREE(current->data);
+               SAFE_FREE(current);
+       }
+
        ZERO_STRUCT(info);
 
        slprintf(key, sizeof(key)-1, "%s%s", DRIVER_INIT_PREFIX, info_ptr->drivername);
@@ -2737,8 +2832,14 @@ static uint32 set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
        kbuf.dsize = strlen(key)+1;
 
        dbuf = tdb_fetch(tdb_drivers, kbuf);
-       if (!dbuf.dptr)
+    if (!dbuf.dptr) {
+               /*
+                * When changing to a driver that has no init info in the tdb, remove
+                * the previous drivers init info and leave the new on blank.
+                */
+               free_nt_devicemode(&info_ptr->devmode);
                return False;
+       }
 
        /*
         * Get the saved DEVMODE..
@@ -2761,16 +2862,6 @@ static uint32 set_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info_ptr)
        DEBUG(10,("set_driver_init_2: Set printer [%s] init DEVMODE for driver [%s]\n",
                        info_ptr->printername, info_ptr->drivername));
 
-       /* 
-        * There should not be any printer data 'specifics' already set during the
-        * add printer operation, if there are delete them. 
-        */
-       while ( (current=info_ptr->specific) != NULL ) {
-               info_ptr->specific=current->next;
-               SAFE_FREE(current->data);
-               SAFE_FREE(current);
-       }
-
        /* 
         * Add the printer data 'specifics' to the new printer
         */
@@ -2814,6 +2905,7 @@ uint32 set_driver_init(NT_PRINTER_INFO_LEVEL *printer, uint32 level)
  of whether it was installed from NT or 2K. Technically, they should be
  different, but they work out to the same struct.
 ****************************************************************************/
+
 static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
 {
        pstring key;
@@ -2832,7 +2924,7 @@ static uint32 update_driver_init_2(NT_PRINTER_INFO_LEVEL_2 *info)
 
        if (buflen != len) {
                char *tb;
-               
+
                tb = (char *)Realloc(buf, len);
                if (!tb) {
                        DEBUG(0, ("update_driver_init_2: failed to enlarge buffer!\n"));
@@ -2869,7 +2961,7 @@ done:
  Update (i.e. save) the driver init info (DEVMODE and specifics) for a printer
 ****************************************************************************/
 
-static uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
+uint32 update_driver_init(NT_PRINTER_INFO_LEVEL printer, uint32 level)
 {
        uint32 result;
        
@@ -2946,27 +3038,36 @@ static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, NT_PRINTER_PARA
        NT_DEVICEMODE *tmp_devmode = printer->info_2->devmode;
        
        /*
-        * Set devmode on printer info, so entire printer initialization can be 
-        * saved to tdb.
+        * When the DEVMODE is already set on the printer, don't try to unpack it.
         */
-       if ((ctx = talloc_init()) == NULL)
-               return WERR_NOMEM;
 
-       if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
-               status = WERR_NOMEM;
-               goto done;
-       }
+       if (!printer->info_2->devmode) {
+               /*
+                * Set devmode on printer info, so entire printer initialization can be
+                * saved to tdb.
+                */
+
+               if ((ctx = talloc_init()) == NULL)
+                       return WERR_NOMEM;
+
+               if ((nt_devmode = (NT_DEVICEMODE*)malloc(sizeof(NT_DEVICEMODE))) == NULL) {
+                       status = WERR_NOMEM;
+                       goto done;
+               }
        
-       ZERO_STRUCTP(nt_devmode);
+               ZERO_STRUCTP(nt_devmode);
 
-       /*
-        * The DEVMODE is held in the 'data' component of the param in raw binary.
-        * Convert it to to a devmode structure
-        */
-       if (!convert_driver_init(param, ctx, nt_devmode)) {
-               DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
-               status = WERR_INVALID_PARAM;
-               goto done;
+               /*
+                * The DEVMODE is held in the 'data' component of the param in raw binary.
+                * Convert it to to a devmode structure
+                */
+               if (!convert_driver_init(param, ctx, nt_devmode)) {
+                       DEBUG(10,("save_driver_init_2: error converting DEVMODE\n"));
+                       status = WERR_INVALID_PARAM;
+                       goto done;
+               }
+
+               printer->info_2->devmode = nt_devmode;
        }
 
        /*
@@ -2974,7 +3075,7 @@ static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, NT_PRINTER_PARA
         * a 'driver init' element in the tdb
         * 
         */
-       printer->info_2->devmode = nt_devmode;
+
        if (update_driver_init(*printer, 2)!=0) {
                DEBUG(10,("save_driver_init_2: error updating DEVMODE\n"));
                status = WERR_NOMEM;
@@ -2991,6 +3092,10 @@ static WERROR save_driver_init_2(NT_PRINTER_INFO_LEVEL *printer, NT_PRINTER_PARA
                DEBUG(10,("save_driver_init_2: error setting DEVMODE on printer [%s]\n",
                                  printer->info_2->printername));
        }
+       
+#if 0  /* JERRY */
+       srv_spoolss_sendnotify(p, handle);
+#endif
 
   done:
        talloc_destroy(ctx);
@@ -3488,6 +3593,7 @@ WERROR nt_printing_setsec(char *printername, SEC_DESC_BUF *secdesc_ctr)
 
 static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
 {
+       extern DOM_SID global_sam_sid;
        SEC_ACE ace[3];
        SEC_ACCESS sa;
        SEC_ACL *psa = NULL;
@@ -3508,9 +3614,10 @@ static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
        if (secrets_fetch_domain_sid(lp_workgroup(), &owner_sid)) {
                sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
        } else {
+
                /* Backup plan - make printer owned by admins.
-                  This should emulate a lanman printer as security
-                  settings can't be changed. */
+                  This should emulate a lanman printer as security
+                  settings can't be changed. */
 
                sid_copy(&owner_sid, &global_sam_sid);
                sid_append_rid(&owner_sid, DOMAIN_USER_RID_ADMIN);
@@ -3537,7 +3644,7 @@ static SEC_DESC_BUF *construct_default_printer_sdb(TALLOC_CTX *ctx)
        }
 
        if (!psd) {
-               DEBUG(0,("construct_default_printer_sdb: Failed to make SEC_DESC.\n"));
+               DEBUG(0,("construct_default_printer_sd: Failed to make SEC_DESC.\n"));
                return NULL;
        }
 
@@ -3576,22 +3683,21 @@ BOOL nt_printing_getsec(TALLOC_CTX *ctx, char *printername, SEC_DESC_BUF **secde
                        return False;
                }
 
-                /* Save default security descriptor for later */
+               /* Save default security descriptor for later */
 
-                prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
-                         sizeof(SEC_DESC_BUF), ctx, MARSHALL);
+               prs_init(&ps, (uint32)sec_desc_size((*secdesc_ctr)->sec) +
+                               sizeof(SEC_DESC_BUF), ctx, MARSHALL);
 
-                if (sec_io_desc_buf("nt_printing_setsec", secdesc_ctr, &ps, 1))
-                        tdb_prs_store(tdb_printers, key, &ps);
+               if (sec_io_desc_buf("nt_printing_setsec", secdesc_ctr, &ps, 1))
+                       tdb_prs_store(tdb_printers, key, &ps);
 
-                prs_mem_free(&ps);
+               prs_mem_free(&ps);
 
                return True;
        }
 
-       /* If security descriptor is owned by S-1-1-0 and we can now read our 
-           domain sid (from secrets.tdb).  The current security descriptor must of been
-           created under the old code that didn't talk to winbind properly or when winbindd was
+       /* If security descriptor is owned by S-1-1-0 and winbindd is up,
+          this security descriptor has been created when winbindd was
           down.  Take ownership of security descriptor. */
 
        if (sid_equal((*secdesc_ctr)->sec->owner_sid, &global_sid_World)) {
index 69ecf5cc776df6d7cd3eba6f94cf098cb67dd616..f76b78f116843804a00a3a0a0d942d3bbabf2247 100644 (file)
@@ -1,12 +1,12 @@
 /*
- *  Unix SMB/CIFS implementation.
+ *  Unix SMB/Netbios implementation.
+ *  Version 1.9.
  *  RPC Pipe client / server routines
  *  Copyright (C) Andrew Tridgell              1992-2000,
  *  Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
  *  Copyright (C) Jean Fran├žois Micouleau      1998-2000.
  *  Copyright (C) Jeremy Allison                   2001.
  *  Copyright (C) Gerald Carter                       2000-2001.
- *  Copyright (C) Tim Potter                       2001.
  *
  *  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
@@ -32,6 +32,7 @@
 #define MAX_OPEN_PRINTER_EXS 50
 #endif
 
+#define MAGIC_DISPLAY_FREQUENCY 0xfade2bad
 #define PHANTOM_DEVMODE_KEY "_p_f_a_n_t_0_m_"
 #define PRINTER_HANDLE_IS_PRINTER      0
 #define PRINTER_HANDLE_IS_PRINTSERVER  1
@@ -48,9 +49,10 @@ struct table_node {
 /* and the notify info asked about */
 /* that's the central struct */
 typedef struct _Printer{
+       struct _Printer *prev, *next;
        BOOL document_started;
        BOOL page_started;
-    int jobid; /* jobid in printing backend */
+       int jobid; /* jobid in printing backend */
        BOOL printer_type;
        union {
                fstring handlename;
@@ -73,6 +75,8 @@ typedef struct _Printer{
        } client;
 } Printer_entry;
 
+static Printer_entry *printers_list;
+
 typedef struct _counter_printer_0 {
        ubi_dlNode Next;
        ubi_dlNode Prev;
@@ -86,7 +90,8 @@ static ubi_dlList counter_list;
 static struct cli_state cli;
 static uint32 smb_connections=0;
 
-#define OUR_HANDLE(hnd) ((hnd==NULL)?"NULL":(IVAL(hnd->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER"))
+#define OUR_HANDLE(hnd) (((hnd)==NULL)?"NULL":(IVAL((hnd)->data5,4)==(uint32)sys_getpid()?"OURS":"OTHER")), \
+((unsigned int)IVAL((hnd)->data5,4)),((unsigned int)sys_getpid())
 
 /* translate between internal status numbers and NT status numbers */
 static int nt_printj_status(int v)
@@ -193,6 +198,9 @@ static void free_printer_entry(void *ptr)
        Printer->notify.option=NULL;
        Printer->notify.client_connected=False;
 
+       /* Remove from the internal list. */
+       DLIST_REMOVE(printers_list, Printer);
+
        SAFE_FREE(Printer);
 }
 
@@ -234,7 +242,7 @@ static Printer_entry *find_printer_index_by_hnd(pipes_struct *p, POLICY_HND *hnd
        Printer_entry *find_printer = NULL;
 
        if(!find_policy_by_hnd(p,hnd,(void **)&find_printer)) {
-               DEBUG(3,("find_printer_index_by_hnd: Printer handle not found: "));
+               DEBUG(2,("find_printer_index_by_hnd: Printer handle not found: "));
                return NULL;
        }
 
@@ -242,7 +250,7 @@ static Printer_entry *find_printer_index_by_hnd(pipes_struct *p, POLICY_HND *hnd
 }
 
 /****************************************************************************
-  close printer index by handle
+ Close printer index by handle.
 ****************************************************************************/
 
 static BOOL close_printer_handle(pipes_struct *p, POLICY_HND *hnd)
@@ -250,7 +258,7 @@ static BOOL close_printer_handle(pipes_struct *p, POLICY_HND *hnd)
        Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
 
        if (!Printer) {
-               DEBUG(0,("close_printer_handle: Invalid handle (%s)\n", OUR_HANDLE(hnd)));
+               DEBUG(2,("close_printer_handle: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
                return False;
        }
 
@@ -260,14 +268,15 @@ static BOOL close_printer_handle(pipes_struct *p, POLICY_HND *hnd)
 }      
 
 /****************************************************************************
-  delete a printer given a handle
+ Delete a printer given a handle.
 ****************************************************************************/
+
 static WERROR delete_printer_handle(pipes_struct *p, POLICY_HND *hnd)
 {
        Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
 
        if (!Printer) {
-               DEBUG(0,("delete_printer_handle: Invalid handle (%s)\n", OUR_HANDLE(hnd)));
+               DEBUG(2,("delete_printer_handle: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
                return WERR_BADFID;
        }
 
@@ -325,7 +334,7 @@ static BOOL get_printer_snum(pipes_struct *p, POLICY_HND *hnd, int *number)
        Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
                
        if (!Printer) {
-               DEBUG(0,("get_printer_snum: Invalid handle (%s)\n", OUR_HANDLE(hnd)));
+               DEBUG(2,("get_printer_snum: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(hnd)));
                return False;
        }
        
@@ -349,7 +358,7 @@ static BOOL set_printer_hnd_accesstype(pipes_struct *p, POLICY_HND *hnd, uint32
        Printer_entry *Printer = find_printer_index_by_hnd(p, hnd);
 
        if (!Printer) {
-               DEBUG(0,("set_printer_hnd_accesstype: Invalid handle (%s)", OUR_HANDLE(hnd)));
+               DEBUG(2,("set_printer_hnd_accesstype: Invalid handle (%s:%u:%u)", OUR_HANDLE(hnd)));
                return False;
        }
 
@@ -532,6 +541,9 @@ static BOOL open_printer_hnd(pipes_struct *p, POLICY_HND *hnd, char *name)
        
        new_printer->notify.option=NULL;
                                
+       /* Add to the internal list. */
+       DLIST_ADD(printers_list, new_printer);
+
        if (!create_policy_hnd(p, hnd, free_printer_entry, new_printer)) {
                SAFE_FREE(new_printer);
                return False;
@@ -553,7 +565,7 @@ static BOOL open_printer_hnd(pipes_struct *p, POLICY_HND *hnd, char *name)
 }
 
 /********************************************************************
- Return True is the handle is a print server.
+ Return True if the handle is a print server.
  ********************************************************************/
 
 static BOOL handle_is_printserver(pipes_struct *p, POLICY_HND *handle)
@@ -604,91 +616,62 @@ static BOOL alloc_buffer_size(NEW_BUFFER *buffer, uint32 buffer_size)
 }
 
 /***************************************************************************
- receive the notify message
+ Receive the notify message.
 ****************************************************************************/
 
 static void srv_spoolss_receive_message(int msg_type, pid_t src, void *buf, size_t len)
 {
-       fstring printer;
+       Printer_entry *find_printer;
        WERROR status;
-       struct pipes_struct *p;
-       struct policy *pol;
-       struct handle_list *hl;
-
-       *printer = '\0';
-       fstrcpy(printer,buf);
+       char msg[8];
+       uint32 low, high;
 
-       if (len == 0) {
-               DEBUG(0,("srv_spoolss_receive_message: got null message !\n"));
+       if (len != sizeof(msg)) {
+               DEBUG(2,("srv_spoolss_receive_message: got incorrect message size (%u)!\n", (unsigned int)len));
                return;
        }
 
-       DEBUG(10,("srv_spoolss_receive_message: Got message about printer %s\n", printer ));
-
-       /*
-        * We need to enumerate all printers. The handle list is shared
-        * across pipes of the same name, so just find the first open
-        * spoolss pipe.
-        */
-
-       hl = NULL;      
-       for ( p = get_first_internal_pipe(); p; get_next_internal_pipe(p)) {
-               if (strequal(p->name, "spoolss")) {
-                       hl = p->pipe_handles;
-                       break;
-               }
-       }
+       memcpy(msg, buf, len);
+       low = IVAL(msg,0);
+       high = IVAL(msg,4);
 
-       if (!hl) {
-               DEBUG(0,("srv_spoolss_receive_message: no handle list on spoolss pipe !\n"));
-               return;
-       }
+       DEBUG(10,("srv_spoolss_receive_message: Got message printer change low=0x%x  high=0x%x\n", (unsigned int)low,
+               (unsigned int)high ));
 
-       /* Iterate the printer list on this pipe. */
-       for (pol = hl->Policy; pol; pol = pol->next ) {
-               Printer_entry *find_printer = (Printer_entry *)pol->data_ptr;
+       find_printer = printers_list;
 
-               if (!find_printer)
-                       continue;
+       /* Iterate the printer list */
+       for(; find_printer; find_printer = find_printer->next) {
 
                /*
-                * if the entry is the given printer or if it's a printerserver
-                * we send the message
+                * If the entry has a connected client we send the message.
                 */
 
-               if (find_printer->printer_type==PRINTER_HANDLE_IS_PRINTER)
-                       if (strcmp(find_printer->dev.handlename, printer))
-                               continue;
 
-               if (find_printer->notify.client_connected==True)
-                       cli_spoolss_reply_rrpcn(&cli, &find_printer->notify.client_hnd, PRINTER_CHANGE_ALL, 0x0, &status);
+               if (find_printer->notify.client_connected==True) {
+                       DEBUG(10,("srv_spoolss_receive_message: printerserver [%s]\n", find_printer->dev.printerservername ));
+                       if (cli_spoolss_reply_rrpcn(&cli, &find_printer->notify.client_hnd, low, high, &status))
+                               DEBUG(10,("srv_spoolss_receive_message: cli_spoolss_reply_rrpcn status = 0x%x\n",
+                                       (unsigned int)W_ERROR_V(status)));
+                       else
+                               DEBUG(10,("srv_spoolss_receive_message: cli_spoolss_reply_rrpcn failed\n"));
+               }
        }
 }
 
 /***************************************************************************
- send a notify event
+ Send a notify event.
 ****************************************************************************/
-static BOOL srv_spoolss_sendnotify(pipes_struct *p, POLICY_HND *handle)
-{
-       fstring printer;
-
-       Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
-
-       if (!Printer) {
-               DEBUG(0,("srv_spoolss_sendnotify: Invalid handle (%s).\n", OUR_HANDLE(handle)));
-               return False;
-       }
 
-       if (Printer->printer_type==PRINTER_HANDLE_IS_PRINTER)
-               fstrcpy(printer, Printer->dev.handlename);
-       else
-               fstrcpy(printer, "");
-
-       /*srv_spoolss_receive_message(printer);*/
-       DEBUG(10,("srv_spoolss_sendnotify: Sending message about printer %s\n", printer ));
+static BOOL srv_spoolss_sendnotify(uint32 high, uint32 low)
+{
+       char msg[8];
 
-       broadcast_printer_notify(printer);
+       SIVAL(msg,0,low);
+       SIVAL(msg,4,high);
+       DEBUG(10,("srv_spoolss_sendnotify: printer change low=0x%x  high=0x%x\n", low, high));
 
+       message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, msg, sizeof(msg), False, NULL);
        return True;
 }      
 
@@ -1021,7 +1004,7 @@ static WERROR _spoolss_enddocprinter_internal(pipes_struct *p, POLICY_HND *handl
        Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
        
        if (!Printer) {
-               DEBUG(0,("_spoolss_enddocprinter_internal: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_enddocprinter_internal: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
        
@@ -1045,11 +1028,16 @@ WERROR _spoolss_closeprinter(pipes_struct *p, SPOOL_Q_CLOSEPRINTER *q_u, SPOOL_R
        if (Printer && Printer->document_started)
                _spoolss_enddocprinter_internal(p, handle);          /* print job was not closed */
 
-       memcpy(&r_u->handle, &q_u->handle, sizeof(r_u->handle));
-
        if (!close_printer_handle(p, handle))
                return WERR_BADFID;     
                
+       /* clear the returned printer handle.  Observed behavior 
+          from Win2k server.  Don't think this really matters.
+          Previous code just copied the value of the closed
+          handle.    --jerry */
+
+       memset(&r_u->handle, '\0', sizeof(r_u->handle));
+
        return WERR_OK;
 }
 
@@ -1071,8 +1059,10 @@ WERROR _spoolss_deleteprinter(pipes_struct *p, SPOOL_Q_DELETEPRINTER *q_u, SPOOL
 
        result = delete_printer_handle(p, handle);
 
+       update_c_setprinter(FALSE);
+
        if (W_ERROR_IS_OK(result)) {
-               srv_spoolss_sendnotify(p, handle);
+               srv_spoolss_sendnotify(0, PRINTER_CHANGE_DELETE_PRINTER);
        }
                
        return result;
@@ -1160,6 +1150,14 @@ static BOOL getprinterdata_printer_server(TALLOC_CTX *ctx, fstring value, uint32
        
        DEBUG(8,("getprinterdata_printer_server:%s\n", value));
                
+       if (!strcmp(value, "W3SvcInstalled")) {
+               *type = 0x4;
+               if((*data = (uint8 *)talloc_zero(ctx, 4*sizeof(uint8) )) == NULL)
+                       return False;
+               *needed = 0x4;                  
+               return True;
+       }
+
        if (!strcmp(value, "BeepEnabled")) {
                *type = 0x4;
                if((*data = (uint8 *)talloc(ctx, 4*sizeof(uint8) )) == NULL)
@@ -1245,7 +1243,7 @@ static BOOL getprinterdata_printer(pipes_struct *p, TALLOC_CTX *ctx, POLICY_HND
        DEBUG(5,("getprinterdata_printer\n"));
 
        if (!Printer) {
-               DEBUG(0,("getprinterdata_printer: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("getprinterdata_printer: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return False;
        }
 
@@ -1321,7 +1319,7 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO
        if (!Printer) {
                if((*data=(uint8 *)talloc_zero(p->mem_ctx, 4*sizeof(uint8))) == NULL)
                        return WERR_NOMEM;
-               DEBUG(0,("_spoolss_getprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_getprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
        
@@ -1407,7 +1405,7 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE
        Printer_entry *Printer=find_printer_index_by_hnd(p, handle);
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_rffpcnex: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_rffpcnex: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -1448,7 +1446,7 @@ static void spoolss_notify_server_name(int snum,
 
        len = rpcstr_push(temp, temp_name, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
 
        if (!data->notify_data.data.string) {
@@ -1472,7 +1470,7 @@ static void spoolss_notify_printer_name(int snum,
        uint32 len;
                
        /* the notify name should not contain the \\server\ part */
-       char *p = strrchr_m(printer->info_2->printername, '\\');
+       char *p = strrchr(printer->info_2->printername, '\\');
 
        if (!p) {
                p = printer->info_2->printername;
@@ -1481,7 +1479,8 @@ static void spoolss_notify_printer_name(int snum,
        }
 
        len = rpcstr_push(temp, p, sizeof(temp)-2, STR_TERMINATE);
-       data->notify_data.data.length = len / 2;
+
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1506,7 +1505,7 @@ static void spoolss_notify_share_name(int snum,
 
        len = rpcstr_push(temp, lp_servicename(snum), sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1533,7 +1532,7 @@ static void spoolss_notify_port_name(int snum,
 
        len = rpcstr_push(temp, printer->info_2->portname, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1559,7 +1558,7 @@ static void spoolss_notify_driver_name(int snum,
        uint32 len;
 
        len = rpcstr_push(temp, printer->info_2->drivername, sizeof(temp)-2, STR_TERMINATE);
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1584,11 +1583,10 @@ static void spoolss_notify_comment(int snum,
 
        if (*printer->info_2->comment == '\0')
                len = rpcstr_push(temp, lp_comment(snum), sizeof(temp)-2, STR_TERMINATE);
-
        else
                len = rpcstr_push(temp, printer->info_2->comment, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1615,7 +1613,7 @@ static void spoolss_notify_location(int snum,
 
        len = rpcstr_push(temp, printer->info_2->location,sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1654,7 +1652,7 @@ static void spoolss_notify_sepfile(int snum,
 
        len = rpcstr_push(temp, printer->info_2->sepfile, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1680,7 +1678,7 @@ static void spoolss_notify_print_processor(int snum,
 
        len = rpcstr_push(temp,  printer->info_2->printprocessor, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1706,7 +1704,7 @@ static void spoolss_notify_parameters(int snum,
 
        len = rpcstr_push(temp,  printer->info_2->parameters, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1732,7 +1730,7 @@ static void spoolss_notify_datatype(int snum,
 
        len = rpcstr_push(temp, printer->info_2->datatype, sizeof(pstring)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1882,8 +1880,7 @@ static void spoolss_notify_username(int snum,
 
        len = rpcstr_push(temp, queue->user, sizeof(temp)-2, STR_TERMINATE);
 
-
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1920,8 +1917,8 @@ static void spoolss_notify_job_name(int snum,
        uint32 len;
 
        len = rpcstr_push(temp, queue->file, sizeof(temp)-2, STR_TERMINATE);
-       
-       data->notify_data.data.length = len / 2;
+
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1970,7 +1967,7 @@ static void spoolss_notify_job_status_string(int snum,
 
        len = rpcstr_push(temp, p, sizeof(temp) - 2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2;
+       data->notify_data.data.length = len / 2 - 1;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -2248,7 +2245,7 @@ static BOOL construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int
                        continue;
 
                if((tid=(SPOOL_NOTIFY_INFO_DATA *)Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) {
-                       DEBUG(0,("construct_notify_printer_info: failed to enlarge buffer info->data!\n"));
+                       DEBUG(2,("construct_notify_printer_info: failed to enlarge buffer info->data!\n"));
                        return False;
                }
                else info->data = tid;
@@ -2303,7 +2300,7 @@ static BOOL construct_notify_jobs_info(print_queue_struct *queue,
                        continue;
 
                if((tid=Realloc(info->data, (info->count+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) {
-                       DEBUG(0,("construct_notify_jobs_info: failed to enlarg buffer info->data!\n"));
+                       DEBUG(2,("construct_notify_jobs_info: failed to enlarg buffer info->data!\n"));
                        return False;
                }
                else info->data = tid;
@@ -2363,6 +2360,9 @@ static WERROR printserver_notify_info(pipes_struct *p, POLICY_HND *hnd,
 
        DEBUG(4,("printserver_notify_info\n"));
        
+       if (!Printer)
+               return WERR_BADFID;
+
        option=Printer->notify.option;
        id=1;
        info->version=2;
@@ -2420,6 +2420,9 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY
        
        DEBUG(4,("printer_notify_info\n"));
 
+       if (!Printer)
+               return WERR_BADFID;
+
        option=Printer->notify.option;
        id=0xffffffff;
        info->version=2;
@@ -2500,7 +2503,7 @@ WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCN
        r_u->info_ptr=0x1;
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_rfnpcnex: Invalid handle (%s).\n",
+               DEBUG(2,("_spoolss_rfnpcnex: Invalid handle (%s:%u:%u).\n",
                         OUR_HANDLE(handle)));
                goto done;
        }
@@ -2624,7 +2627,7 @@ static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum)
        printer->unknown18 =  0x0;
        printer->status = nt_printq_status(status.status);
        printer->unknown20 =  0x0;
-       printer->c_setprinter = ntprinter->info_2->c_setprinter; /* how many times setprinter has been called */
+       printer->c_setprinter = get_c_setprinter(); /* monotonically increasing sum of delta printer counts */
        printer->unknown22 = 0x0;
        printer->unknown23 = 0x6;               /* 6  ???*/
        printer->unknown24 = 0;                 /* unknown 24 to 26 are always 0 */
@@ -2683,7 +2686,7 @@ static void free_dev_mode(DEVICEMODE *dev)
        if (dev == NULL)
                return;
 
-       SAFE_FREE(dev->private);
+               SAFE_FREE(dev->private);
        SAFE_FREE(dev); 
 }
 
@@ -2704,7 +2707,7 @@ static DEVICEMODE *construct_dev_mode(int snum)
        DEBUGADD(8,("getting printer characteristics\n"));
 
        if ((devmode = (DEVICEMODE *)malloc(sizeof(DEVICEMODE))) == NULL) {
-               DEBUG(0,("construct_dev_mode: malloc fail.\n"));
+               DEBUG(2,("construct_dev_mode: malloc fail.\n"));
                return NULL;
        }
 
@@ -2849,7 +2852,7 @@ static BOOL construct_printer_info_3(PRINTER_INFO_3 **pp_printer, int snum)
 
        *pp_printer = NULL;
        if ((printer = (PRINTER_INFO_3 *)malloc(sizeof(PRINTER_INFO_3))) == NULL) {
-               DEBUG(0,("construct_printer_info_3: malloc fail.\n"));
+               DEBUG(2,("construct_printer_info_3: malloc fail.\n"));
                return False;
        }
 
@@ -2951,7 +2954,7 @@ static WERROR enum_all_printers_info_1(uint32 flags, NEW_BUFFER *buffer, uint32
                                
                        if (construct_printer_info_1(flags, &current_prt, snum)) {
                                if((tp=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_1))) == NULL) {
-                                       DEBUG(0,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
+                                       DEBUG(2,("enum_all_printers_info_1: failed to enlarge printers buffer!\n"));
                                        SAFE_FREE(printers);
                                        *returned=0;
                                        return WERR_NOMEM;
@@ -3007,7 +3010,7 @@ static WERROR enum_all_printers_info_1_name(fstring name, NEW_BUFFER *buffer, ui
        
        if ((name[0] == '\\') && (name[1] == '\\'))
                s = name + 2;
-
+               
        if (is_myname_or_ipaddr(s)) {
                return enum_all_printers_info_1(PRINTER_ENUM_ICON8, buffer, offered, needed, returned);
        }
@@ -3100,7 +3103,7 @@ static WERROR enum_all_printers_info_2(NEW_BUFFER *buffer, uint32 offered, uint3
                                
                        if (construct_printer_info_2(&current_prt, snum)) {
                                if((tp=Realloc(printers, (*returned +1)*sizeof(PRINTER_INFO_2))) == NULL) {
-                                       DEBUG(0,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
+                                       DEBUG(2,("enum_all_printers_info_2: failed to enlarge printers buffer!\n"));
                                        SAFE_FREE(printers);
                                        *returned = 0;
                                        return WERR_NOMEM;
@@ -3613,10 +3616,10 @@ static void init_unistr_array(uint16 **uni_array, fstring *char_array, char *ser
                slprintf(line, sizeof(line)-1, "\\\\%s%s", servername, v);
                DEBUGADD(6,("%d:%s:%d\n", i, line, strlen(line)));
                if((tuary=Realloc(*uni_array, (j+strlen(line)+2)*sizeof(uint16))) == NULL) {
-                       DEBUG(0,("init_unistr_array: Realloc error\n" ));
+                       DEBUG(2,("init_unistr_array: Realloc error\n" ));
                        return;
-               }
-               else *uni_array = tuary;
+               } else
+                       *uni_array = tuary;
                j += (rpcstr_push((*uni_array+j), line, sizeof(uint16)*strlen(line)+2, 0)/ sizeof(uint16));
                i++;
        }
@@ -3692,10 +3695,38 @@ static WERROR construct_printer_driver_info_3(DRIVER_INFO_3 *info, int snum, fst
 
        status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);    
        DEBUG(8,("construct_printer_driver_info_3: status: %s\n", werror_str(status)));
+
+#if 0  /* JERRY */
+
+       /* 
+        * I put this code in during testing.  Helpful when commenting out the 
+        * support for DRIVER_INFO_6 in regards to win2k.  Not needed in general
+        * as win2k always queries the driver using an infor level of 6.
+        * I've left it in (but ifdef'd out) because I'll probably
+        * use it in experimentation again in the future.   --jerry 22/01/2002
+        */
+
        if (!W_ERROR_IS_OK(status)) {
-               free_a_printer(&printer,2);
-               return WERR_UNKNOWN_PRINTER_DRIVER;
+               /*
+                * Is this a W2k client ?
+                */
+               if (version == 3) {
+                       /* Yes - try again with a WinNT driver. */
+                       version = 2;
+                       status=get_a_printer_driver(&driver, 3, printer->info_2->drivername, architecture, version);    
+                       DEBUG(8,("construct_printer_driver_info_3: status: %s\n", werror_str(status)));
+               }
+#endif
+
+               if (!W_ERROR_IS_OK(status)) {
+                       free_a_printer(&printer,2);
+                       return WERR_UNKNOWN_PRINTER_DRIVER;
+               }
+               
+#if 0  /* JERRY */
        }
+#endif
+       
 
        fill_printer_driver_info_3(info, driver, servername);
 
@@ -4046,7 +4077,7 @@ WERROR _spoolss_endpageprinter(pipes_struct *p, SPOOL_Q_ENDPAGEPRINTER *q_u, SPO
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_endpageprinter: Invalid handle (%s).\n",OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_endpageprinter: Invalid handle (%s:%u:%u).\n",OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
        
@@ -4076,7 +4107,7 @@ WERROR _spoolss_startdocprinter(pipes_struct *p, SPOOL_Q_STARTDOCPRINTER *q_u, S
        struct current_user user;
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_startdocprinter: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_startdocprinter: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -4150,7 +4181,7 @@ WERROR _spoolss_writeprinter(pipes_struct *p, SPOOL_Q_WRITEPRINTER *q_u, SPOOL_R
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
        
        if (!Printer) {
-               DEBUG(0,("_spoolss_writeprinter: Invalid handle (%s)\n",OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_writeprinter: Invalid handle (%s:%u:%u)\n",OUR_HANDLE(handle)));
                r_u->buffer_written = q_u->buffer_size2;
                return WERR_BADFID;
        }
@@ -4179,7 +4210,7 @@ static WERROR control_printer(POLICY_HND *handle, uint32 command,
        get_current_user(&user, p);
 
        if (!Printer) {
-               DEBUG(0,("control_printer: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+               DEBUG(2,("control_printer: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -4237,7 +4268,7 @@ static WERROR update_printer_sec(POLICY_HND *handle, uint32 level,
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
 
        if (!Printer || !get_printer_snum(p, handle, &snum)) {
-               DEBUG(0,("update_printer_sec: Invalid handle (%s)\n",
+               DEBUG(2,("update_printer_sec: Invalid handle (%s:%u:%u)\n",
                         OUR_HANDLE(handle)));
 
                result = WERR_BADFID;
@@ -4331,10 +4362,7 @@ static BOOL check_printer_ok(NT_PRINTER_INFO_LEVEL_2 *info, int snum)
        slprintf(info->printername, sizeof(info->printername)-1, "\\\\%s\\%s",
                 get_called_name(), lp_servicename(snum));
        fstrcpy(info->sharename, lp_servicename(snum));
-       info->attributes = PRINTER_ATTRIBUTE_SHARED   \
-               | PRINTER_ATTRIBUTE_LOCAL  \
-               | PRINTER_ATTRIBUTE_RAW_ONLY \
-               | PRINTER_ATTRIBUTE_QUEUED ;
+       info->attributes = PRINTER_ATTRIBUTE_SHARED | PRINTER_ATTRIBUTE_NETWORK;
        
        return True;
 }
@@ -4350,6 +4378,7 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
        int numlines;
        int ret;
        int fd;
+       fstring remote_machine = "%m";
 
        /* build driver path... only 9X architecture is needed for legacy reasons */
        slprintf(driverlocation, sizeof(driverlocation)-1, "\\\\%s\\print$\\WIN40\\0",
@@ -4357,11 +4386,12 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
        /* change \ to \\ for the shell */
        all_string_sub(driverlocation,"\\","\\\\",sizeof(pstring));
 
-       slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
+       slprintf(command, sizeof(command)-1, "%s \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
                        cmd, printer->info_2->printername, printer->info_2->sharename,
                        printer->info_2->portname, printer->info_2->drivername,
-                       printer->info_2->location, driverlocation);
+                       printer->info_2->location, driverlocation, remote_machine);
 
+       /* Convert script args to unix-codepage */
        DEBUG(10,("Running [%s]\n", command));
        ret = smbrun(command, &fd);
        DEBUGADD(10,("returned [%d]\n", ret));
@@ -4633,8 +4663,8 @@ static BOOL nt_printer_info_level_equal(NT_PRINTER_INFO_LEVEL *p1,
 }
 
 /********************************************************************
- * called by spoolss_api_setprinter
- * when updating a printer description
+ * Called by spoolss_api_setprinter
+ * when updating a printer description.
  ********************************************************************/
 
 static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
@@ -4651,7 +4681,7 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
        result = WERR_OK;
 
        if (level!=2) {
-               DEBUG(0,("Send a mail to samba@samba.org\n"));
+               DEBUG(0,("update_printer: Send a mail to samba@samba.org\n"));
                DEBUGADD(0,("with the following message: update_printer: level!=2\n"));
                result = WERR_UNKNOWN_LEVEL;
                goto done;
@@ -4690,7 +4720,7 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
                /* we have a valid devmode
                   convert it and link it*/
 
-               DEBUGADD(8,("Converting the devicemode struct\n"));
+               DEBUGADD(8,("update_printer: Converting the devicemode struct\n"));
                if (!convert_devicemode(printer->info_2->printername, devmode,
                                &printer->info_2->devmode)) {
                        result =  WERR_NOMEM;
@@ -4710,7 +4740,7 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
           annoying permission denied dialog box. */
 
        if (nt_printer_info_level_equal(printer, old_printer)) {
-               DEBUG(3, ("printer info has not changed\n"));
+               DEBUG(3, ("update_printer: printer info has not changed\n"));
                result = WERR_OK;
                goto done;
        }
@@ -4718,8 +4748,7 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
        /* Check calling user has permission to update printer description */
 
        if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
-               DEBUG(3, ("printer property change denied by security "
-                         "descriptor\n"));
+               DEBUG(3, ("update_printer: printer property change denied by security descriptor\n"));
                result = WERR_ACCESS_DENIED;
                goto done;
        }
@@ -4727,12 +4756,38 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
        /* Call addprinter hook */
 
        if (*lp_addprinter_cmd()) {
-               if (!add_printer_hook(printer)) {
+               if ( !add_printer_hook(printer) ) {
                        result = WERR_ACCESS_DENIED;
                        goto done;
                }
        }
        
+       /*
+        * Set the DRIVER_INIT info in the tdb; trigger on magic value for the
+        * DEVMODE.displayfrequency, which is not used for printer drivers. This
+        * requires Win32 client code (see other notes elsewhere in the code).
+        */
+       if (printer->info_2->devmode &&
+               printer->info_2->devmode->displayfrequency == MAGIC_DISPLAY_FREQUENCY) {
+               DEBUG(10,("update_printer: Save printer driver init data\n"));
+               printer->info_2->devmode->displayfrequency = 0;
+               if (update_driver_init(*printer, 2)!=0) {
+                       DEBUG(10,("update_printer: error updating printer driver init DEVMODE\n"));
+                       result = WERR_ACCESS_DENIED;
+                       goto done;
+               }
+       } else {
+               /*
+                * When a *new* driver is bound to a printer, the drivername is used to
+                * lookup previously saved driver initialization info, which is then
+                * bound to the printer, simulating what happens in the Windows arch.
+                */
+               if (strequal(printer->info_2->drivername, old_printer->info_2->drivername))
+                       set_driver_init(printer, 2);
+       }
+
        /* Update printer info */
        result = mod_a_printer(*printer, 2);
 
@@ -4740,7 +4795,7 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
        free_a_printer(&printer, 2);
        free_a_printer(&old_printer, 2);
 
-       srv_spoolss_sendnotify(p, handle);
+       srv_spoolss_sendnotify(0, PRINTER_CHANGE_SET_PRINTER);
 
        return result;
 }
@@ -4760,7 +4815,7 @@ WERROR _spoolss_setprinter(pipes_struct *p, SPOOL_Q_SETPRINTER *q_u, SPOOL_R_SET
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
        
        if (!Printer) {
-               DEBUG(0,("_spoolss_setprinter: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_setprinter: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -4788,7 +4843,7 @@ WERROR _spoolss_fcpn(pipes_struct *p, SPOOL_Q_FCPN *q_u, SPOOL_R_FCPN *r_u)
        Printer_entry *Printer= find_printer_index_by_hnd(p, handle);
        
        if (!Printer) {
-               DEBUG(0,("_spoolss_fcpn: Invalid handle (%s)\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_fcpn: Invalid handle (%s:%u:%u)\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -5902,11 +5957,24 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
                return WERR_INVALID_PARAM;
        }
 
-    /*
+       /*
         * When a printer is created, the drivername bound to the printer is used
         * to lookup previously saved driver initialization info, which is then 
         * bound to the new printer, simulating what happens in the Windows arch.
         */
+
+       if (!devmode)
+               set_driver_init(printer, 2);
+       else {
+               /* A valid devmode was included, convert and link it
+               */
+               DEBUGADD(10, ("spoolss_addprinterex_level_2: devmode included, converting\n"));
+
+               if (!convert_devicemode(printer->info_2->printername, devmode,
+                               &printer->info_2->devmode))
+                       return  WERR_NOMEM;
+       }
+
        set_driver_init(printer, 2);
        
        /* write the ASCII on disk */
@@ -5925,7 +5993,9 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
 
        free_a_printer(&printer,2);
 
-       srv_spoolss_sendnotify(p, handle);
+       update_c_setprinter(False);
+
+       srv_spoolss_sendnotify(0, PRINTER_CHANGE_ADD_PRINTER);
 
        return WERR_OK;
 }
@@ -6016,7 +6086,9 @@ static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environmen
        pstring long_archi;
        pstring short_archi;
        DRIVER_DIRECTORY_1 *info=NULL;
-
+#if 0
+       fstring asc_name, servername;
+#endif
        unistr2_to_ascii(long_archi, uni_environment, sizeof(long_archi)-1);
 
        if (get_short_archi(short_archi, long_archi)==False)
@@ -6025,6 +6097,20 @@ static WERROR getprinterdriverdir_level_1(UNISTR2 *name, UNISTR2 *uni_environmen
        if((info=(DRIVER_DIRECTORY_1 *)malloc(sizeof(DRIVER_DIRECTORY_1))) == NULL)
                return WERR_NOMEM;
 
+#if 0  /* JERRY */
+       /* use the name the client sent us */
+
+       unistr2_to_ascii(asc_name, name, sizeof(asc_name)-1);
+       if (asc_name[0] == '\\' && asc_name[1] == '\\')
+               fstrcpy(servername, asc_name);
+       else {
+               fstrcpy(servername, "\\\\");
+               fstrcat(servername, asc_name);
+       }
+
+       slprintf(path, sizeof(path)-1, "%s\\print$\\%s", servername, short_archi);
+#endif
+
        slprintf(path, sizeof(path)-1, "\\\\%s\\print$\\%s", get_called_name(), short_archi);
 
        DEBUG(4,("printer driver directory: [%s]\n", path));
@@ -6118,7 +6204,7 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
        DEBUG(5,("spoolss_enumprinterdata\n"));
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_enumprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_enumprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -6194,20 +6280,17 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
                   problems unmarshalling the response */
 
                *out_max_value_len=(in_value_len/sizeof(uint16));
-               if((*out_value=(uint16 *)malloc(in_value_len*sizeof(uint8))) == NULL)
+               if((*out_value=(uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL)
                        return WERR_NOMEM;
 
-               ZERO_STRUCTP(*out_value);
                *out_value_len = rpcstr_push((char *)*out_value, "", in_value_len, 0);
 
                /* the data is counted in bytes */
                *out_max_data_len = in_data_len;
                *out_data_len = in_data_len;
-               if((*data_out=(uint8 *)malloc(in_data_len*sizeof(uint8))) == NULL)
+               if((*data_out=(uint8 *)talloc_zero(p->mem_ctx, in_data_len*sizeof(uint8))) == NULL)
                        return WERR_NOMEM;
 
-               memset(*data_out,'\0',in_data_len);
-
                return WERR_NO_MORE_ITEMS;
        }
 
@@ -6269,7 +6352,7 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
        DEBUG(5,("spoolss_setprinterdata\n"));
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_setprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_setprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -6305,6 +6388,8 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
        convert_specific_param(&param, value , type, data, real_len);
 
 #if 0
+       /* JRA. W2K always changes changeid. */
+
        if (get_specific_param(*printer, 2, param->value, &old_param.data,
                               &old_param.type, (uint32 *)&old_param.data_len)) {
 
@@ -6344,6 +6429,11 @@ WERROR _spoolss_setprinterdata( pipes_struct *p, SPOOL_Q_SETPRINTERDATA *q_u, SP
                free_nt_printer_param(&param);
        SAFE_FREE(old_param.data);
 
+#if 0
+       /* Is this correct. JRA ? */
+       srv_spoolss_sendnotify(0, PRINTER_CHANGE_SET_PRINTER); 
+#endif
+
        return status;
 }
 
@@ -6364,7 +6454,7 @@ WERROR _spoolss_deleteprinterdata(pipes_struct *p, SPOOL_Q_DELETEPRINTERDATA *q_
        DEBUG(5,("spoolss_deleteprinterdata\n"));
        
        if (!Printer) {
-               DEBUG(0,("_spoolss_deleteprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_deleteprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -6402,40 +6492,60 @@ WERROR _spoolss_addform( pipes_struct *p, SPOOL_Q_ADDFORM *q_u, SPOOL_R_ADDFORM
 /*     uint32 level = q_u->level; - notused. */
        FORM *form = &q_u->form;
        nt_forms_struct tmpForm;
-       int count=0, snum;
+       int snum;
+       WERROR status = WERR_OK;
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+       int count=0;
        nt_forms_struct *list=NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
 
        DEBUG(5,("spoolss_addform\n"));
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_addform: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_addform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
-       /* Must be administrator to add a form */
-
-       if (!get_printer_snum(p, handle, &snum))
-               return WERR_BADFID;
+       /* 
+        * FIXME!!  Feels like there should be an access check here, but haven't
+        * had time to verify.  --jerry
+        */
 
-       if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
-               DEBUG(0, ("_spoolss_addform: Access denied\n"));
-               return WERR_ACCESS_DENIED;
-       }
 
+       if (!get_printer_snum(p,handle, &snum))
+                return WERR_BADFID;
+               
        /* can't add if builtin */
        if (get_a_builtin_ntform(&form->name,&tmpForm)) {
-               return WERR_FILE_EXISTS;
+               return WERR_ALREADY_EXISTS;
        }
 
        count=get_ntforms(&list);
        if(!add_a_form(&list, form, &count))
                return WERR_NOMEM;
        write_ntforms(&list, count);
+       
+       /*
+        * ChangeID must always be set
+        */
+        
+       if (!get_printer_snum(p,handle, &snum))
+                return WERR_BADFID;
 
+       status = get_a_printer(&printer, 2, lp_servicename(snum));
+        if (!W_ERROR_IS_OK(status))
+               goto done;
+       
+       status = mod_a_printer(*printer, 2);
+        if (!W_ERROR_IS_OK(status))
+               goto done;
+       
+done:
+       free_a_printer(&printer, 2);
        SAFE_FREE(list);
 
-       return WERR_OK;
+       return status;
 }
 
 /****************************************************************************
@@ -6446,25 +6556,27 @@ WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DE
        POLICY_HND *handle = &q_u->handle;
        UNISTR2 *form_name = &q_u->name;
        nt_forms_struct tmpForm;
-       int count=0, snum;
+       int count=0;
        WERROR ret = WERR_OK;
        nt_forms_struct *list=NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
+       int snum;
+       WERROR status = WERR_OK;
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
 
        DEBUG(5,("spoolss_deleteform\n"));
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_deleteform: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_deleteform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
-       /* Must be administrator to set a form */
-
-       if (!get_printer_snum(p, handle, &snum))
+       if (!get_printer_snum(p, handle, &snum))
                return WERR_BADFID;
 
        if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
-               DEBUG(0, ("_spoolss_addform: Access denied\n"));
+               DEBUG(3, ("security descriptor change denied by existing "
+                         "security descriptor\n"));
                return WERR_ACCESS_DENIED;
        }
 
@@ -6477,6 +6589,23 @@ WERROR _spoolss_deleteform( pipes_struct *p, SPOOL_Q_DELETEFORM *q_u, SPOOL_R_DE
        if(!delete_a_form(&list, form_name, &count, &ret))
                return WERR_INVALID_PARAM;
 
+       /*
+        * ChangeID must always be set
+        */
+        
+       if (!get_printer_snum(p,handle, &snum))
+                return WERR_BADFID;
+
+       status = get_a_printer(&printer, 2, lp_servicename(snum));
+        if (!W_ERROR_IS_OK(status))
+               goto done;
+       
+       status = mod_a_printer(*printer, 2);
+        if (!W_ERROR_IS_OK(status))
+               goto done;
+       
+done:
+       free_a_printer(&printer, 2);
        SAFE_FREE(list);
 
        return ret;
@@ -6492,24 +6621,27 @@ WERROR _spoolss_setform(pipes_struct *p, SPOOL_Q_SETFORM *q_u, SPOOL_R_SETFORM *
 /*     uint32 level = q_u->level; - notused. */
        FORM *form = &q_u->form;
        nt_forms_struct tmpForm;
-       int count=0, snum;
+       int snum;
+       WERROR status = WERR_OK;
+       NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+       int count=0;
        nt_forms_struct *list=NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
 
        DEBUG(5,("spoolss_setform\n"));
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_setform: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_setform: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
-       /* Must be administrator to set a form */
-
        if (!get_printer_snum(p, handle, &snum))
                return WERR_BADFID;
 
        if (!print_access_check(NULL, snum, PRINTER_ACCESS_ADMINISTER)) {
-               DEBUG(0, ("_spoolss_addform: Access denied\n"));
+               DEBUG(3, ("security descriptor change denied by existing "
+                         "security descriptor\n"));
                return WERR_ACCESS_DENIED;
        }
 
@@ -6522,6 +6654,23 @@ WERROR _spoolss_setform(pipes_struct *p, SPOOL_Q_SETFORM *q_u, SPOOL_R_SETFORM *
        update_a_form(&list, form, count);
        write_ntforms(&list, count);
 
+       /*
+        * ChangeID must always be set
+        */
+        
+       if (!get_printer_snum(p,handle, &snum))
+                return WERR_BADFID;
+
+       status = get_a_printer(&printer, 2, lp_servicename(snum));
+        if (!W_ERROR_IS_OK(status))
+               goto done;
+       
+       status = mod_a_printer(*printer, 2);
+        if (!W_ERROR_IS_OK(status))
+               goto done;
+       
+done:
+       free_a_printer(&printer, 2);
        SAFE_FREE(list);
 
        return WERR_OK;
@@ -6943,7 +7092,7 @@ WERROR _spoolss_getprinterdataex(pipes_struct *p, SPOOL_Q_GETPRINTERDATAEX *q_u,
        if (!Printer) {
                if((*data=(uint8 *)talloc_zero(p->mem_ctx, 4*sizeof(uint8))) == NULL)
                        return WERR_NOMEM;
-               DEBUG(0,("_spoolss_getprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_getprinterdata: Invalid handle (%s:%u:%u).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -7122,7 +7271,7 @@ WERROR _spoolss_enumprinterdataex(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATAEX *q_
        DEBUG(4,("_spoolss_enumprinterdataex\n"));
 
        if (!Printer) {
-               DEBUG(0,("_spoolss_enumprinterdata: Invalid handle (%s).\n", OUR_HANDLE(handle)));
+               DEBUG(2,("_spoolss_enumprinterdata: Invalid handle (%s:%u:%u1<).\n", OUR_HANDLE(handle)));
                return WERR_BADFID;
        }
 
@@ -7259,7 +7408,7 @@ static WERROR getprintprocessordirectory_level_1(UNISTR2 *name,
 
        unistr2_to_ascii(long_archi, environment, sizeof(long_archi)-1);
 
-       if (get_short_archi(short_archi, long_archi)==False)
+       if (get_short_archi(short_archi, long_archi)==FALSE)
                return WERR_INVALID_ENVIRONMENT;
 
        if((info=(PRINTPROCESSOR_DIRECTORY_1 *)malloc(sizeof(PRINTPROCESSOR_DIRECTORY_1))) == NULL)