Proper merge of all the working printing stuff from APPLIANCE_HEAD.
authorJeremy Allison <jra@samba.org>
Fri, 28 Jun 2002 00:17:15 +0000 (00:17 +0000)
committerJeremy Allison <jra@samba.org>
Fri, 28 Jun 2002 00:17:15 +0000 (00:17 +0000)
Now let's keep this in sync !
Jeremy.
(This used to be commit 3603cd4947df2c10df604447dc542932cb9e5d5a)

14 files changed:
source3/Makefile.in
source3/include/doserr.h
source3/include/messages.h
source3/include/nt_printing.h
source3/include/rpc_spoolss.h
source3/libsmb/cli_spoolss.c
source3/libsmb/cli_spoolss_notify.c [new file with mode: 0644]
source3/printing/notify.c [new file with mode: 0644]
source3/printing/printing.c
source3/rpc_client/cli_spoolss_notify.c [deleted file]
source3/rpc_parse/parse_spoolss.c
source3/rpc_server/srv_spoolss_nt.c
source3/rpcclient/cmd_spoolss.c
source3/utils/smbcontrol.c

index 844ad5afe051ffaf1d7beb138395a6dc5a00e80b..2f7e714438e65bcac6e7dc4af02c9d45615adebd 100644 (file)
@@ -171,7 +171,7 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \
 LIBMSRPC_OBJ = libsmb/cli_lsarpc.o libsmb/cli_samr.o libsmb/cli_spoolss.o \
               libsmb/cli_netlogon.o libsmb/cli_srvsvc.o libsmb/cli_wkssvc.o \
               libsmb/cli_dfs.o libsmb/cli_reg.o libsmb/trust_passwd.o\
-              rpc_client/cli_pipe.o
+               rpc_client/cli_pipe.o libsmb/cli_spoolss_notify.o
 
 LIBMSRPC_PICOBJ = $(LIBMSRPC_OBJ:.o=.po)
 
@@ -196,8 +196,7 @@ RPC_PARSE_OBJ = rpc_parse/parse_lsa.o rpc_parse/parse_net.o \
                rpc_parse/parse_spoolss.o rpc_parse/parse_dfs.o
 
 
-RPC_CLIENT_OBJ = rpc_client/cli_pipe.o \
-       rpc_client/cli_spoolss_notify.o
+RPC_CLIENT_OBJ = rpc_client/cli_pipe.o
 
 LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
 
@@ -242,7 +241,6 @@ SMBD_OBJ1 = smbd/server.o smbd/files.o smbd/chgpasswd.o smbd/connection.o \
            printing/printfsp.o lib/util_seaccess.o smbd/srvstr.o \
             smbd/build_options.o \
            smbd/change_trust_pw.o \
-           rpc_client/cli_spoolss_notify.o \
            $(MANGLE_OBJ)
 
 
@@ -250,7 +248,7 @@ PRINTING_OBJ = printing/pcap.o printing/print_svid.o \
                                printing/print_cups.o printing/print_generic.o \
                                printing/lpq_parse.o printing/load.o
 
-PRINTBACKEND_OBJ = printing/printing.o printing/nt_printing.o
+PRINTBACKEND_OBJ = printing/printing.o printing/nt_printing.o printing/notify.o
 
 MSDFS_OBJ = msdfs/msdfs.o 
 
@@ -301,7 +299,7 @@ STATUS_OBJ = utils/status.o $(LOCKING_OBJ) $(PARAM_OBJ) \
              $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ)
 
 SMBCONTROL_OBJ = utils/smbcontrol.o $(LOCKING_OBJ) $(PARAM_OBJ) \
-             $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ)
+             $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) printing/notify.o
 
 SMBTREE_OBJ = utils/smbtree.o $(LOCKING_OBJ) $(PARAM_OBJ) \
              $(UBIQX_OBJ) $(PROFILE_OBJ) $(LIB_OBJ) $(LIBSMB_OBJ) 
index 813e54a6d0c415e8dac93c8c6eca724e512c139c..135d799596c2ce1c01c40709a90446020301e28d 100644 (file)
 #define WERR_INVALID_OWNER W_ERROR(1307)
 #define WERR_CAN_NOT_COMPLETE W_ERROR(1003)
 #define WERR_INVALID_SECURITY_DESCRIPTOR W_ERROR(1338)
+#define WERR_SERVER_UNAVAILABLE W_ERROR(1722)
 #define WERR_UNKNOWN_PRINTER_DRIVER W_ERROR(1797)
 #define WERR_INVALID_PRINTER_NAME W_ERROR(1801)
 #define WERR_PRINTER_ALREADY_EXISTS W_ERROR(1802)
index 3127fc85444aae5cf7920cc5a6913242f99ef359..79a08a754626f7b39f05c8f3313f9b0dd5ee2c02 100644 (file)
 #define MSG_FORCE_ELECTION 1001
 #define MSG_WINS_NEW_ENTRY 1002
 
-/* rpc messages */
-#define MSG_PRINTER_NOTIFY     2001
+/* printing messages */
+/* #define MSG_PRINTER_NOTIFY  2001*/ /* Obsolete */
 #define MSG_PRINTER_DRVUPGRADE 2002
-#define MSG_PRINTER_UPDATE     2003
+#define MSG_PRINTER_NOTIFY2     2003
 
 /* smbd messages */
 #define MSG_SMB_CONF_UPDATED 3001
index 90ac45412d945d91e7cd988dae7704e3aae99418..57181c66591912fcc3f7d38feb992524488e0c93 100644 (file)
@@ -1,5 +1,6 @@
 /*
-   Unix SMB/CIFS implementation.
+   Unix SMB/Netbios implementation.
+   Version 1.9.
    SMB parameters and setup
    Copyright (C) Andrew Tridgell              1992-2000,
    Copyright (C) Jean Francois Micouleau      1998-2000.
@@ -331,4 +332,23 @@ typedef struct _form
 #define VS_VERSION_INFO_SIZE            (sizeof(VS_SIGNATURE)+4+VS_MINOR_OFFSET+4)   /* not true size! */
 #define VS_NE_BUF_SIZE                  4096  /* Must be > 2*VS_VERSION_INFO_SIZE */
 
+/* Notify spoolss clients that something has changed.  The
+   notification data is either stored in two uint32 values or a
+   variable length array. */
+
+#define SPOOLSS_NOTIFY_MSG_UNIX_JOBID 0x0001    /* Job id is unix  */
+
+struct spoolss_notify_msg {
+       fstring printer;        /* Name of printer notified */
+       uint32 type;            /* Printer or job notify */
+       uint32 field;           /* Notify field changed */
+       uint32 id;              /* Job id */
+       uint32 len;             /* Length of data, 0 for two uint32 value */
+       uint32 flags;
+       union {
+               uint32 value[2];
+               char *data;
+       } notify;
+};
+
 #endif /* NT_PRINTING_H_ */
index 1a0898245cf162c2400c1bfecacb1997e01be58c..0b458dc9e0d63950c2da5371d350251ba35929a9 100755 (executable)
@@ -1,5 +1,6 @@
 /* 
-   Unix SMB/CIFS implementation.
+   Unix SMB/Netbios implementation.
+   Version 1.9.
    SMB parameters and setup
    Copyright (C) Andrew Tridgell              1992-2000,
    Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
 #define PRINTER_CONTROL_PURGE          0x00000003
 #define PRINTER_CONTROL_SET_STATUS     0x00000004
 
+#define PRINTER_STATUS_OK               0x00000000
 #define PRINTER_STATUS_PAUSED          0x00000001
 #define PRINTER_STATUS_ERROR           0x00000002
 #define PRINTER_STATUS_PENDING_DELETION        0x00000004
 
 /* JOB status codes. */
 
-#define JOB_STATUS_PAUSED              0x001
-#define JOB_STATUS_ERROR               0x002
-#define JOB_STATUS_DELETING            0x004
-#define JOB_STATUS_SPOOLING            0x008
-#define JOB_STATUS_PRINTING            0x010
-#define JOB_STATUS_OFFLINE             0x020
-#define JOB_STATUS_PAPEROUT            0x040
-#define JOB_STATUS_PRINTED             0x080
-#define JOB_STATUS_DELETED             0x100
-#define JOB_STATUS_BLOCKED             0x200
-#define JOB_STATUS_USER_INTERVENTION   0x400
+#define JOB_STATUS_QUEUED               0x0000
+#define JOB_STATUS_PAUSED              0x0001
+#define JOB_STATUS_ERROR               0x0002
+#define JOB_STATUS_DELETING            0x0004
+#define JOB_STATUS_SPOOLING            0x0008
+#define JOB_STATUS_PRINTING            0x0010
+#define JOB_STATUS_OFFLINE             0x0020
+#define JOB_STATUS_PAPEROUT            0x0040
+#define JOB_STATUS_PRINTED             0x0080
+#define JOB_STATUS_DELETED             0x0100
+#define JOB_STATUS_BLOCKED             0x0200
+#define JOB_STATUS_USER_INTERVENTION   0x0400
 
 /* ACE masks for the various print permissions */
 
 #define JOB_WRITE      STANDARD_RIGHTS_WRITE_ACCESS|JOB_ACCESS_ADMINISTER
 #define JOB_EXECUTE    STANDARD_RIGHTS_EXECUTE_ACCESS|JOB_ACCESS_ADMINISTER
 
-/* Print notification constants */
+/* Notify field types */
 
-#define ONE_VALUE 1
-#define TWO_VALUE 2
-#define POINTER   3
+#define ONE_VALUE 1            /* Notify data is stored in value1 */
+#define TWO_VALUE 2            /* Notify data is stored in value2 */
+#define POINTER   3            /* Data is a pointer to a buffer */
+#define STRING    4            /* Data is a pointer to a buffer w/length */
 
 #define PRINTER_NOTIFY_TYPE 0x00
 #define JOB_NOTIFY_TYPE     0x01
 
 #define PRINTER_NOTIFY_INFO_DISCARDED  0x1
 
-#define PRINTER_NOTIFY_VERSION 0x2
-
 /*
  * Set of macros for flagging what changed in the PRINTER_INFO_2 struct
  * when sending messages to other smbd's
@@ -1203,8 +1205,8 @@ typedef struct job_info_ctr_info
 {
        union
        {
-               JOB_INFO_1 *job_info_1;
-               JOB_INFO_2 *job_info_2;
+               JOB_INFO_1 **job_info_1;
+               JOB_INFO_2 **job_info_2;
                void *info;
        } job;
 
@@ -2118,3 +2120,4 @@ SPOOL_R_GETPRINTPROCESSORDIRECTORY;
 #define PRINTER_DRIVER_ARCHITECTURE "Windows NT x86"
 
 #endif /* _RPC_SPOOLSS_H */
+
index 48094f81796add20ac770f690057f48184c5dcb9..18e17758d6d9c963e9477f562f7625bb62424f2c 100644 (file)
@@ -1556,11 +1556,11 @@ WERROR cli_spoolss_enumjobs(struct cli_state *cli, TALLOC_CTX *mem_ctx,
        switch(level) {
        case 1:
                decode_jobs_1(mem_ctx, r.buffer, r.returned,
-                             &ctr->job.job_info_1);
+                               ctr->job.job_info_1);
                break;
        case 2:
                decode_jobs_2(mem_ctx, r.buffer, r.returned,
-                             &ctr->job.job_info_2);
+                               ctr->job.job_info_2);
                break;
        default:
                DEBUG(3, ("unsupported info level %d", level));
@@ -1669,10 +1669,10 @@ WERROR cli_spoolss_getjob(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 
        switch(level) {
        case 1:
-               decode_jobs_1(mem_ctx, r.buffer, 1, &ctr->job.job_info_1);
+               decode_jobs_1(mem_ctx, r.buffer, 1, ctr->job.job_info_1);
                break;
        case 2:
-               decode_jobs_2(mem_ctx, r.buffer, 1, &ctr->job.job_info_2);
+               decode_jobs_2(mem_ctx, r.buffer, 1, ctr->job.job_info_2);
                break;
        default:
                DEBUG(3, ("unsupported info level %d", level));
diff --git a/source3/libsmb/cli_spoolss_notify.c b/source3/libsmb/cli_spoolss_notify.c
new file mode 100644 (file)
index 0000000..922b0fb
--- /dev/null
@@ -0,0 +1,223 @@
+/* 
+   Unix SMB/CIFS implementation.
+   RPC pipe client
+
+   Copyright (C) Gerald Carter                2001-2002,
+   Copyright (C) Tim Potter                   2000-2002,
+   Copyright (C) Andrew Tridgell              1994-2000,
+   Copyright (C) Luke Kenneth Casson Leighton 1996-2000,
+   Copyright (C) Jean-Francois Micouleau      1999-2000.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ * SPOOLSS Client RPC's used by servers as the notification
+ * back channel.
+ */
+
+/* Send a ReplyOpenPrinter request.  This rpc is made by the printer
+   server to the printer client in response to a rffpcnex request.
+   The rrfpcnex request names a printer and a handle (the printerlocal
+   value) and this rpc establishes a back-channel over which printer
+   notifications are performed. */
+
+WERROR cli_spoolss_reply_open_printer(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                     char *printer, uint32 printerlocal, uint32 type, 
+                                     POLICY_HND *handle)
+{
+       prs_struct qbuf, rbuf;
+       SPOOL_Q_REPLYOPENPRINTER q;
+       SPOOL_R_REPLYOPENPRINTER r;
+       WERROR result = W_ERROR(ERRgeneral);
+       
+       /* Initialise input parameters */
+
+       prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+       prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+       make_spoolss_q_replyopenprinter(&q, printer, printerlocal, type);
+
+       /* Marshall data and send request */
+
+       if (!spoolss_io_q_replyopenprinter("", &q, &qbuf, 0) ||
+           !rpc_api_pipe_req (cli, SPOOLSS_REPLYOPENPRINTER, &qbuf, &rbuf)) 
+               goto done;
+       
+       /* Unmarshall response */
+       
+       if (!spoolss_io_r_replyopenprinter("", &r, &rbuf, 0))
+               goto done;
+               
+       /* Return result */
+
+       memcpy(handle, &r.handle, sizeof(r.handle));
+       result = r.status;
+
+done:
+       prs_mem_free(&qbuf);
+       prs_mem_free(&rbuf);
+
+       return result;
+}
+
+/* Close a back-channel notification connection */
+
+WERROR cli_spoolss_reply_close_printer(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                                      POLICY_HND *handle)
+{
+       prs_struct qbuf, rbuf;
+       SPOOL_Q_REPLYCLOSEPRINTER q;
+       SPOOL_R_REPLYCLOSEPRINTER r;
+       WERROR result = W_ERROR(ERRgeneral);
+
+       /* Initialise input parameters */
+
+       prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+       prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+       make_spoolss_q_reply_closeprinter(&q, handle);
+
+       /* Marshall data and send request */
+
+       if (!spoolss_io_q_replycloseprinter("", &q, &qbuf, 0) ||
+           !rpc_api_pipe_req (cli, SPOOLSS_REPLYCLOSEPRINTER, &qbuf, &rbuf)) 
+               goto done;
+       
+       /* Unmarshall response */
+       
+       if (!spoolss_io_r_replycloseprinter("", &r, &rbuf, 0))
+               goto done;
+               
+       /* Return result */
+
+       result = r.status;
+       
+done:
+       prs_mem_free(&qbuf);
+       prs_mem_free(&rbuf);
+
+       return result;
+}
+
+/*********************************************************************
+ This SPOOLSS_ROUTERREPLYPRINTER function is used to send a change 
+ notification event when the registration **did not** use 
+ SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor.
+ Also see cli_spolss_reply_rrpcn()
+ *********************************************************************/
+WERROR cli_spoolss_routerreplyprinter(struct cli_state *cli, TALLOC_CTX *mem_ctx,
+                                     POLICY_HND *pol, uint32 condition, uint32 change_id)
+{
+       prs_struct qbuf, rbuf;
+       SPOOL_Q_ROUTERREPLYPRINTER q;
+        SPOOL_R_ROUTERREPLYPRINTER r;
+       WERROR result = W_ERROR(ERRgeneral);
+
+       /* Initialise input parameters */
+
+       prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+       prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+       make_spoolss_q_routerreplyprinter(&q, pol, condition, change_id);
+
+       /* Marshall data and send request */
+
+       if (!spoolss_io_q_routerreplyprinter("", &q, &qbuf, 0) ||
+           !rpc_api_pipe_req (cli, SPOOLSS_ROUTERREPLYPRINTER, &qbuf, &rbuf)) 
+               goto done;
+       
+       /* Unmarshall response */
+       
+       if (!spoolss_io_r_routerreplyprinter("", &r, &rbuf, 0))
+               goto done;
+
+       /* Return output parameters */
+
+       result = r.status;
+
+done:
+       prs_mem_free(&qbuf);
+       prs_mem_free(&rbuf);
+
+       return result;  
+}
+
+/*********************************************************************
+ This SPOOLSS_REPLY_RRPCN function is used to send a change 
+ notification event when the registration **did** use 
+ SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor
+ Also see cli_spoolss_routereplyprinter()
+ *********************************************************************/
+
+WERROR cli_spoolss_rrpcn(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+                        POLICY_HND *pol, uint32 notify_data_len,
+                        SPOOL_NOTIFY_INFO_DATA *notify_data,
+                        uint32 change_low, uint32 change_high)
+{
+       prs_struct qbuf, rbuf;
+       SPOOL_Q_REPLY_RRPCN q;
+       SPOOL_R_REPLY_RRPCN r;
+       WERROR result = W_ERROR(ERRgeneral);
+       SPOOL_NOTIFY_INFO       notify_info;
+
+       ZERO_STRUCT(q);
+       ZERO_STRUCT(r);
+
+       /* Initialise parse structures */
+
+       prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
+       prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
+
+       ZERO_STRUCT(notify_info);
+
+       /* Initialise input parameters */
+
+       notify_info.version = 0x2;
+       notify_info.flags   = 0x00020000;       /* ?? */
+       notify_info.count   = notify_data_len;
+       notify_info.data    = notify_data;
+
+       /* create and send a MSRPC command with api  */
+       /* store the parameters */
+
+       make_spoolss_q_reply_rrpcn(&q, pol, change_low, change_high, 
+                                  &notify_info);
+
+       /* Marshall data and send request */
+
+       if(!spoolss_io_q_reply_rrpcn("", &q,  &qbuf, 0) ||
+          !rpc_api_pipe_req(cli, SPOOLSS_RRPCN, &qbuf, &rbuf)) 
+               goto done;
+
+       /* Unmarshall response */
+       
+       if(!spoolss_io_r_reply_rrpcn("", &r, &rbuf, 0))
+               goto done;
+
+       if (r.unknown0 == 0x00080000)
+               DEBUG(8,("cli_spoolss_reply_rrpcn: I think the spooler resonded that the notification was ignored.\n"));
+       
+       result = r.status;
+
+done:
+       prs_mem_free(&qbuf);
+       prs_mem_free(&rbuf);
+
+       return result;
+}
diff --git a/source3/printing/notify.c b/source3/printing/notify.c
new file mode 100644 (file)
index 0000000..5ba7fab
--- /dev/null
@@ -0,0 +1,230 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 2.2
+   printing backend routines
+   Copyright (C) Tim Potter, 2002
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "printing.h"
+
+/*
+ * Print notification routines
+ */
+
+static void send_spoolss_notify2_msg(struct spoolss_notify_msg *msg)
+{
+       char *buf = NULL;
+       int buflen = 0, len;
+       TDB_CONTEXT *tdb;
+
+       /* Let's not waste any time with this */
+
+       if (lp_disable_spoolss())
+               return;
+
+       /* Flatten data into a message */
+
+again:
+       len = 0;
+
+       /* Pack header */
+
+       len += tdb_pack(buf + len, buflen - len, "f", msg->printer);
+
+       len += tdb_pack(buf + len, buflen - len, "ddddd",
+                       msg->type, msg->field, msg->id, msg->len, msg->flags);
+
+       /* Pack data */
+
+       if (msg->len == 0)
+               len += tdb_pack(buf + len, buflen - len, "dd",
+                               msg->notify.value[0], msg->notify.value[1]);
+       else
+               len += tdb_pack(buf + len, buflen - len, "B",
+                               msg->len, msg->notify.data);
+
+       if (buflen != len) {
+               buf = Realloc(buf, len);
+               buflen = len;
+               goto again;
+       }
+
+       /* Send message */
+
+       tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
+
+       if (!tdb) {
+               DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
+               return;
+       }
+
+       message_send_all(tdb, MSG_PRINTER_NOTIFY2, buf,
+                        buflen, False, NULL);
+
+       SAFE_FREE(buf);
+       tdb_close(tdb);
+}
+
+static void send_notify_field_values(const char *printer_name, uint32 type,
+                                    uint32 field, uint32 id, uint32 value1, 
+                                    uint32 value2, uint32 flags)
+{
+       struct spoolss_notify_msg msg;
+
+       ZERO_STRUCT(msg);
+
+       fstrcpy(msg.printer, printer_name);
+       msg.type = type;
+       msg.field = field;
+       msg.id = id;
+       msg.notify.value[0] = value1;
+       msg.notify.value[1] = value2;
+       msg.flags = flags;
+
+       send_spoolss_notify2_msg(&msg);
+}
+
+static void send_notify_field_buffer(const char *printer_name, uint32 type,
+                                    uint32 field, uint32 id, uint32 len,
+                                    char *buffer)
+{
+       struct spoolss_notify_msg msg;
+
+       ZERO_STRUCT(msg);
+
+       fstrcpy(msg.printer, printer_name);
+       msg.type = type;
+       msg.field = field;
+       msg.id = id;
+       msg.len = len;
+       msg.notify.data = buffer;
+
+       send_spoolss_notify2_msg(&msg);
+}
+
+/* Send a message that the printer status has changed */
+
+void notify_printer_status_byname(char *printer_name, uint32 status)
+{
+       /* Printer status stored in value1 */
+
+       send_notify_field_values(printer_name, PRINTER_NOTIFY_TYPE, 
+                                PRINTER_NOTIFY_STATUS, 0, 
+                                status, 0, 0);
+}
+
+void notify_printer_status(int snum, uint32 status)
+{
+       char *printer_name = PRINTERNAME(snum);
+
+       if (printer_name)
+               notify_printer_status_byname(printer_name, status);
+}
+
+void notify_job_status_byname(char *printer_name, uint32 jobid, uint32 status,
+                             uint32 flags)
+{
+       /* Job id stored in id field, status in value1 */
+
+       send_notify_field_values(printer_name, JOB_NOTIFY_TYPE,
+                                JOB_NOTIFY_STATUS, jobid,
+                                status, 0, flags);
+}
+
+void notify_job_status(int snum, uint32 jobid, uint32 status)
+{
+       char *printer_name = PRINTERNAME(snum);
+
+       notify_job_status_byname(printer_name, jobid, status, 0);
+}
+
+void notify_job_total_bytes(int snum, uint32 jobid, uint32 size)
+{
+       char *printer_name = PRINTERNAME(snum);
+
+       /* Job id stored in id field, status in value1 */
+
+       send_notify_field_values(printer_name, JOB_NOTIFY_TYPE,
+                                JOB_NOTIFY_TOTAL_BYTES, jobid,
+                                size, 0, 0);
+}
+
+void notify_job_total_pages(int snum, uint32 jobid, uint32 pages)
+{
+       char *printer_name = PRINTERNAME(snum);
+
+       /* Job id stored in id field, status in value1 */
+
+       send_notify_field_values(printer_name, JOB_NOTIFY_TYPE,
+                                JOB_NOTIFY_TOTAL_PAGES, jobid,
+                                pages, 0, 0);
+}
+
+void notify_job_username(int snum, uint32 jobid, char *name)
+{
+       char *printer_name = PRINTERNAME(snum);
+
+       send_notify_field_buffer(
+               printer_name, JOB_NOTIFY_TYPE, JOB_NOTIFY_USER_NAME,
+               jobid, strlen(name) + 1, name);
+}
+
+void notify_job_name(int snum, uint32 jobid, char *name)
+{
+       char *printer_name = PRINTERNAME(snum);
+
+       send_notify_field_buffer(
+               printer_name, JOB_NOTIFY_TYPE, JOB_NOTIFY_DOCUMENT,
+               jobid, strlen(name) + 1, name);
+}
+
+void notify_job_submitted(int snum, uint32 jobid, time_t submitted)
+{
+       char *printer_name = PRINTERNAME(snum);
+
+       send_notify_field_buffer(
+               printer_name, JOB_NOTIFY_TYPE, JOB_NOTIFY_SUBMITTED,
+               jobid, sizeof(submitted), (char *)&submitted);
+}
+
+void notify_printer_delete(char *printer_name)
+{
+}
+
+void notify_printer_add(char *printer_name)
+{
+}
+
+void notify_printer_driver(int num, char *driver_name)
+{
+}
+
+void notify_printer_comment(int num, char *comment)
+{
+}
+
+void notify_printer_sharename(int num, char *share_name)
+{
+}
+
+void notify_printer_port(int num, char *port_name)
+{
+}
+
+void notify_printer_location(int num, char *location)
+{
+}
index aa9df5e47fffcff3306b66ddbfd331ec2c2ef16e..6ecaf3c9bfa031967f38a556b21209f7ebd78596 100644 (file)
@@ -1,5 +1,6 @@
 /* 
-   Unix SMB/CIFS implementation.
+   Unix SMB/Netbios implementation.
+   Version 3.0
    printing backend routines
    Copyright (C) Andrew Tridgell 1992-2000
    
@@ -56,8 +57,8 @@ BOOL print_backend_init(void)
                return True;
        tdb = tdb_open_log(lock_path("printing.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
        if (!tdb) {
-               DEBUG(0,("print_backend_init: Failed to open printing backend database %s\n",
-                                lock_path("printing.tdb") ));
+               DEBUG(0,("print_backend_init: Failed to open printing backend database %s.\n",
+                                       lock_path("printing.tdb") ));
                return False;
        }
        local_pid = sys_getpid();
@@ -113,21 +114,178 @@ static struct printjob *print_job_find(int jobid)
        return &pjob;
 }
 
+/* Convert a unix jobid to a smb jobid */
+
+static int sysjob_to_jobid_value;
+
+static int unixjob_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key,
+                              TDB_DATA data, void *state)
+{
+       struct printjob *pjob = (struct printjob *)data.dptr;
+       int *sysjob = (int *)state;
+
+       if (key.dsize != sizeof(int))
+               return 0;
+
+       if (*sysjob == pjob->sysjob) {
+               int *jobid = (int *)key.dptr;
+
+               sysjob_to_jobid_value = *jobid;
+               return 1;
+       }
+
+       return 0;
+}
+
+int sysjob_to_jobid(int unix_jobid)
+{
+       sysjob_to_jobid_value = -1;
+       tdb_traverse(tdb, unixjob_traverse_fn, &unix_jobid);
+
+       return sysjob_to_jobid_value;
+}
+
+/****************************************************************************
+send notifications based on what has changed after a pjob_store
+****************************************************************************/
+
+static struct {
+       uint32 lpq_status;
+       uint32 spoolss_status;
+} lpq_to_spoolss_status_map[] = {
+       { LPQ_QUEUED, JOB_STATUS_QUEUED },
+       { LPQ_PAUSED, JOB_STATUS_PAUSED },
+       { LPQ_SPOOLING, JOB_STATUS_SPOOLING },
+       { LPQ_PRINTING, JOB_STATUS_PRINTING },
+       { LPQ_DELETING, JOB_STATUS_DELETING },
+       { LPQ_OFFLINE, JOB_STATUS_OFFLINE },
+       { LPQ_PAPEROUT, JOB_STATUS_PAPEROUT },
+       { LPQ_PRINTED, JOB_STATUS_PRINTED },
+       { LPQ_DELETED, JOB_STATUS_DELETED },
+       { LPQ_BLOCKED, JOB_STATUS_BLOCKED },
+       { LPQ_USER_INTERVENTION, JOB_STATUS_USER_INTERVENTION },
+       { -1, 0 }
+};
+
+/* Convert a lpq status value stored in printing.tdb into the
+   appropriate win32 API constant. */
+
+static uint32 map_to_spoolss_status(uint32 lpq_status)
+{
+       int i = 0;
+
+       while (lpq_to_spoolss_status_map[i].lpq_status != -1) {
+               if (lpq_to_spoolss_status_map[i].lpq_status == lpq_status)
+                       return lpq_to_spoolss_status_map[i].spoolss_status;
+               i++;
+       }
+
+       return 0;
+}
+
+static void pjob_store_notify(int jobid, struct printjob *old_data,
+                             struct printjob *new_data)
+{
+       BOOL new_job = False;
+       int snum = print_job_snum(jobid);
+
+       if (snum == -1)
+               return;
+
+       if (!old_data)
+               new_job = True;
+
+       /* Notify the job name first */
+
+       if (new_job || !strequal(old_data->jobname, new_data->jobname))
+               notify_job_name(snum, jobid, new_data->jobname);
+
+       /* Job attributes that can't be changed.  We only send
+          notification for these on a new job. */
+
+       if (new_job) {
+               notify_job_submitted(snum, jobid, new_data->starttime);
+               notify_job_username(snum, jobid, new_data->user);
+       }
+
+       /* Job attributes of a new job or attributes that can be
+          modified. */
+
+       if (new_job || old_data->status != new_data->status)
+               notify_job_status(snum, jobid, map_to_spoolss_status(new_data->status));
+
+       if (new_job || old_data->size != new_data->size)
+               notify_job_total_bytes(snum, jobid, new_data->size);
+
+       if (new_job || old_data->page_count != new_data->page_count)
+               notify_job_total_pages(snum, jobid, new_data->page_count);
+}
+
 /****************************************************************************
  Store a job structure back to the database.
 ****************************************************************************/
 
-static BOOL print_job_store(int jobid, struct printjob *pjob)
+static BOOL pjob_store(int jobid, struct printjob *pjob)
 {
-       TDB_DATA d;
+       TDB_DATA old_data, new_data;
        BOOL ret;
 
-       d.dptr = (void *)pjob;
-       d.dsize = sizeof(*pjob);
-       ret = (tdb_store(tdb, print_key(jobid), d, TDB_REPLACE) == 0);
+       /* Get old data */
+
+       old_data = tdb_fetch(tdb, print_key(jobid));
+
+       /* Store new data */
+
+       new_data.dptr = (void *)pjob;
+       new_data.dsize = sizeof(*pjob);
+       ret = (tdb_store(tdb, print_key(jobid), new_data, TDB_REPLACE) == 0);
+
+       /* Send notify updates for what has changed */
+
+       if (ret && (old_data.dsize == 0 || old_data.dsize == sizeof(*pjob))) {
+               pjob_store_notify(
+                       jobid, (struct printjob *)old_data.dptr,
+                       (struct printjob *)new_data.dptr);
+               free(old_data.dptr);
+       }
+
        return ret;
 }
 
+/****************************************************************************
+remove a job structure from the database
+****************************************************************************/
+static void pjob_delete(int jobid)
+{
+       int snum;
+       struct printjob *pjob = print_job_find(jobid);
+       uint32 job_status = 0;
+
+       if (!pjob) {
+               DEBUG(5, ("pjob_delete(): we were asked to delete nonexistent job %d\n", jobid));
+               return;
+       }
+
+       /* Send a notification that a job has been deleted */
+
+       job_status = map_to_spoolss_status(pjob->status);
+
+       /* We must cycle through JOB_STATUS_DELETING and
+           JOB_STATUS_DELETED for the port monitor to delete the job
+           properly. */
+       
+       snum = print_job_snum(jobid);
+       job_status |= JOB_STATUS_DELETING;
+       notify_job_status(snum, jobid, job_status);
+       
+       job_status |= JOB_STATUS_DELETED;
+       notify_job_status(snum, jobid, job_status);
+
+       /* Remove from printing.tdb */
+
+       tdb_delete(tdb, print_key(jobid));
+}
+
 /****************************************************************************
  Parse a file name from the system spooler to generate a jobid.
 ****************************************************************************/
@@ -175,7 +333,7 @@ static void print_unix_job(int snum, print_queue_struct *q)
        fstrcpy(pj.user, q->fs_user);
        fstrcpy(pj.queuename, lp_servicename(snum));
 
-       print_job_store(jobid, &pj);
+       pjob_store(jobid, &pj);
 }
 
 
@@ -213,7 +371,7 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
                                break;
                }
                if (i == ts->qcount)
-                       tdb_delete(tdb, key);
+                       pjob_delete(jobid);
                else
                        ts->total_jobs++;
                return 0;
@@ -225,7 +383,7 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
                    exist then kill it. This cleans up after smbd
                    deaths */
                if (!process_exists(pjob.pid))
-                       tdb_delete(tdb, key);
+                       pjob_delete(jobid);
                else
                        ts->total_jobs++;
                return 0;
@@ -252,7 +410,7 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void
                   submitted less than lp_lpqcachetime() seconds ago. */
 
                if ((cur_t - pjob.starttime) > lp_lpqcachetime())
-                       tdb_delete(t, key);
+                       pjob_delete(jobid);
                else
                        ts->total_jobs++;
        }
@@ -328,24 +486,10 @@ static void set_updating_pid(fstring printer_name, BOOL delete)
 }
 
 /****************************************************************************
- Send a message saying the queue changed.
-****************************************************************************/
-
-static void send_queue_message(const char *printer_name, uint32 high, uint32 low)
-{
-       char msg[8 + sizeof(fstring)];
-       SIVAL(msg,0,low);
-       SIVAL(msg,4,high);
-       fstrcpy(&msg[8], printer_name);
-
-       message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, msg, 8 + strlen(printer_name) + 1, False, NULL);
-}
-
-/****************************************************************************
- Update the internal database from the system print queue for a queue in the background
+update the internal database from the system print queue for a queue
 ****************************************************************************/
 
-static void print_queue_update_background(int snum)
+static void print_queue_update(int snum)
 {
        int i, qcount;
        print_queue_struct *queue = NULL;
@@ -356,6 +500,8 @@ static void print_queue_update_background(int snum)
        fstring keystr, printer_name, cachestr;
        TDB_DATA data, key;
 
+       /* Convert printer name (i.e. share name) to unix-codepage for all of the 
+        * following tdb key generation */
        fstrcpy(printer_name, lp_servicename(snum));
        
        /*
@@ -448,7 +594,7 @@ static void print_queue_update_background(int snum)
                pjob->sysjob = queue[i].job;
                pjob->status = queue[i].status;
 
-               print_job_store(jobid, pjob);
+               pjob_store(jobid, pjob);
        }
 
        /* now delete any queued entries that don't appear in the
@@ -460,21 +606,12 @@ static void print_queue_update_background(int snum)
 
        tdb_traverse(tdb, traverse_fn_delete, (void *)&tstruct);
 
-       safe_free(tstruct.queue);
+       SAFE_FREE(tstruct.queue);
 
        tdb_store_int32(tdb, "INFO/total_jobs", tstruct.total_jobs);
 
-       /*
-        * Get the old print status. We will use this to compare the
-        * number of jobs. If they have changed we need to send a
-        * "changed" message to the smbds.
-        */
-
-       if( qcount != get_queue_status(snum, &old_status)) {
-               DEBUG(10,("print_queue_update: queue status change %d jobs -> %d jobs for printer %s\n",
-                               old_status.qcount, qcount, printer_name ));
-               send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB);
-       }
+       if( qcount != get_queue_status(snum, &old_status))
+               DEBUG(10,("print_queue_update: queue status change %d jobs -> %d jobs for printer %s\n", old_status.qcount, qcount, printer_name ));
 
        /* store the new queue status structure */
        slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printer_name);
@@ -492,74 +629,12 @@ static void print_queue_update_background(int snum)
         */
 
        slprintf(keystr, sizeof(keystr)-1, "CACHE/%s", printer_name);
-       tdb_store_int32(tdb, keystr, (int)time(NULL));
+       tdb_store_int32(tdb, keystr, (int32)time(NULL));
 
        /* Delete our pid from the db. */
        set_updating_pid(printer_name, True);
 }
 
-/****************************************************************************
- This is the receive function of the background lpq updater.
-****************************************************************************/
-
-static void print_queue_receive(int msg_type, pid_t src, void *buf, size_t len)
-{
-       int snum;
-       snum=*((int *)buf);
-       print_queue_update_background(snum);
-}
-
-static pid_t background_lpq_updater_pid;
-
-/****************************************************************************
- Main thread of the background lpq updater.
-****************************************************************************/
-
-void start_background_queue(void)
-{
-       DEBUG(3,("start_background_queue: Starting background LPQ thread\n"));
-       background_lpq_updater_pid = sys_fork();
-
-       if (background_lpq_updater_pid == -1) {
-               DEBUG(5,("start_background_queue: background LPQ thread failed to start. %s\n", strerror(errno) ));
-               exit(1);
-       }
-
-       if(background_lpq_updater_pid == 0) {
-               /* Child. */
-               DEBUG(5,("start_background_queue: background LPQ thread started\n"));
-
-               claim_connection(NULL,"smbd lpq backend",0,False);
-
-               if (!locking_init(0))
-                       exit(1);
-
-               if (!print_backend_init())
-                       exit(1);
-
-               message_register(MSG_PRINTER_UPDATE, print_queue_receive);
-               
-               DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
-               while (1) {
-                       pause();
-                       DEBUG(10,("start_background_queue: background LPQ thread got a message\n"));
-                       message_dispatch();
-               }
-       }
-}
-
-/****************************************************************************
- Update the internal database from the system print queue for a queue.
-****************************************************************************/
-
-static void print_queue_update(int snum)
-{
-       if (background_lpq_updater_pid > 0) {
-               message_send_pid(background_lpq_updater_pid, MSG_PRINTER_UPDATE, 
-                                &snum, sizeof(snum), False);
-       }
-}
-
 /****************************************************************************
  Check if a jobid is valid. It is valid if it exists in the database.
 ****************************************************************************/
@@ -634,7 +709,7 @@ BOOL print_job_set_name(int jobid, char *name)
                return False;
 
        fstrcpy(pjob->jobname, name);
-       return print_job_store(jobid, pjob);
+       return pjob_store(jobid, pjob);
 }
 
 /****************************************************************************
@@ -672,7 +747,7 @@ static BOOL print_job_delete1(int jobid)
        /* Set the tdb entry to be deleting. */
 
        pjob->status = LPQ_DELETING;
-       print_job_store(jobid, pjob);
+       pjob_store(jobid, pjob);
 
        if (pjob->spooled && pjob->sysjob != -1)
                result = (*(current_printif->job_delete))(snum, pjob);
@@ -680,9 +755,8 @@ static BOOL print_job_delete1(int jobid)
        /* Delete the tdb entry if the delete suceeded or the job hasn't
           been spooled. */
 
-       if (result == 0) {
-               tdb_delete(tdb, print_key(jobid));
-       }
+       if (result == 0)
+               pjob_delete(jobid);
 
        return (result == 0);
 }
@@ -713,7 +787,6 @@ static BOOL is_owner(struct current_user *user, int jobid)
 BOOL print_job_delete(struct current_user *user, int jobid, WERROR *errcode)
 {
        int snum = print_job_snum(jobid);
-       char *printer_name;
        BOOL owner;
 
        if (snum == -1) {
@@ -733,7 +806,7 @@ BOOL print_job_delete(struct current_user *user, int jobid, WERROR *errcode)
                return False;
        }
 
-       if (!print_job_delete1(jobid))
+       if (!print_job_delete1(jobid)) 
                return False;
 
        /* force update the database and say the delete failed if the
@@ -741,12 +814,6 @@ BOOL print_job_delete(struct current_user *user, int jobid, WERROR *errcode)
 
        print_queue_update(snum);
 
-       /* Send a printer notify message */
-
-       printer_name = PRINTERNAME(snum);
-
-       send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB);
-
        return !print_job_exists(jobid);
 }
 
@@ -758,12 +825,11 @@ BOOL print_job_pause(struct current_user *user, int jobid, WERROR *errcode)
 {
        struct printjob *pjob = print_job_find(jobid);
        int snum, ret = -1;
-       char *printer_name;
        
-       if (!pjob || !user)
+       if (!pjob || !user) 
                return False;
 
-       if (!pjob->spooled || pjob->sysjob == -1)
+       if (!pjob->spooled || pjob->sysjob == -1) 
                return False;
 
        snum = print_job_snum(jobid);
@@ -771,10 +837,6 @@ BOOL print_job_pause(struct current_user *user, int jobid, WERROR *errcode)
                DEBUG(5,("print_job_pause: unknown service number for jobid %d\n", jobid));
                return False;
        }
-       if (snum == -1) {
-               DEBUG(5,("print_job_resume: unknown service number for jobid %d\n", jobid));
-               return False;
-       }
 
        if (!is_owner(user, jobid) &&
            !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
@@ -796,9 +858,7 @@ BOOL print_job_pause(struct current_user *user, int jobid, WERROR *errcode)
 
        /* Send a printer notify message */
 
-       printer_name = PRINTERNAME(snum);
-
-       send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB);
+       notify_job_status(snum, jobid, JOB_STATUS_PAUSED);
 
        /* how do we tell if this succeeded? */
 
@@ -812,7 +872,6 @@ BOOL print_job_pause(struct current_user *user, int jobid, WERROR *errcode)
 BOOL print_job_resume(struct current_user *user, int jobid, WERROR *errcode)
 {
        struct printjob *pjob = print_job_find(jobid);
-       char *printer_name;
        int snum, ret;
        
        if (!pjob || !user)
@@ -822,6 +881,10 @@ BOOL print_job_resume(struct current_user *user, int jobid, WERROR *errcode)
                return False;
 
        snum = print_job_snum(jobid);
+       if (snum == -1) {
+               DEBUG(5,("print_job_resume: unknown service number for jobid %d\n", jobid));
+               return False;
+       }
 
        if (!is_owner(user, jobid) &&
            !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
@@ -842,9 +905,7 @@ BOOL print_job_resume(struct current_user *user, int jobid, WERROR *errcode)
 
        /* Send a printer notify message */
 
-       printer_name = PRINTERNAME(snum);
-
-       send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB);
+       notify_job_status(snum, jobid, JOB_STATUS_QUEUED);
 
        return True;
 }
@@ -867,7 +928,7 @@ int print_job_write(int jobid, const char *buf, int size)
        return_code = write(pjob->fd, buf, size);
        if (return_code>0) {
                pjob->size += size;
-               print_job_store(jobid, pjob);
+               pjob_store(jobid, pjob);
        }
        return return_code;
 }
@@ -1060,8 +1121,8 @@ int print_job_start(struct current_user *user, int snum, char *jobname)
                if (!print_job_exists(jobid))
                        break;
        }
-       if (jobid == next_jobid || !print_job_store(jobid, &pjob)) {
-               DEBUG(3, ("print_job_start: either jobid (%d)==next_jobid(%d) or print_job_store failed.\n",
+       if (jobid == next_jobid || !pjob_store(jobid, &pjob)) {
+               DEBUG(3, ("print_job_start: either jobid (%d)==next_jobid(%d) or pjob_store failed.\n",
                                jobid, next_jobid ));
                jobid = -1;
                goto fail;
@@ -1087,7 +1148,7 @@ to open spool file %s.\n", pjob.filename));
                goto fail;
        }
 
-       print_job_store(jobid, &pjob);
+       pjob_store(jobid, &pjob);
 
        tdb_unlock_bystring(tdb, "INFO/nextjob");
 
@@ -1105,9 +1166,8 @@ to open spool file %s.\n", pjob.filename));
        return jobid;
 
  fail:
-       if (jobid != -1) {
-               tdb_delete(tdb, print_key(jobid));
-       }
+       if (jobid != -1)
+               pjob_delete(jobid);
 
        tdb_unlock_bystring(tdb, "INFO/nextjob");
 
@@ -1129,7 +1189,7 @@ void print_job_endpage(int jobid)
                return;
 
        pjob->page_count++;
-       print_job_store(jobid, pjob);
+       pjob_store(jobid, pjob);
 }
 
 /****************************************************************************
@@ -1180,7 +1240,7 @@ BOOL print_job_end(int jobid, BOOL normal_close)
                DEBUG(5,("print_job_end: canceling spool of %s (%s)\n",
                        pjob->filename, pjob->size ? "deleted" : "zero length" ));
                unlink(pjob->filename);
-               tdb_delete(tdb, print_key(jobid));
+               pjob_delete(jobid);
                return True;
        }
 
@@ -1193,7 +1253,7 @@ BOOL print_job_end(int jobid, BOOL normal_close)
        
        pjob->spooled = True;
        pjob->status = LPQ_QUEUED;
-       print_job_store(jobid, pjob);
+       pjob_store(jobid, pjob);
        
        /* make sure the database is up to date */
        if (print_cache_expired(snum))
@@ -1206,7 +1266,7 @@ fail:
        /* The print job was not succesfully started. Cleanup */
        /* Still need to add proper error return propagation! 010122:JRR */
        unlink(pjob->filename);
-       tdb_delete(tdb, print_key(jobid));
+       pjob_delete(jobid);
        return False;
 }
 
@@ -1389,7 +1449,6 @@ int print_queue_snum(char *qname)
 
 BOOL print_queue_pause(struct current_user *user, int snum, WERROR *errcode)
 {
-       char *printer_name;
        int ret;
        
        if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
@@ -1409,9 +1468,7 @@ BOOL print_queue_pause(struct current_user *user, int snum, WERROR *errcode)
 
        /* Send a printer notify message */
 
-       printer_name = PRINTERNAME(snum);
-
-       send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB);
+       notify_printer_status(snum, PRINTER_STATUS_PAUSED);
 
        return True;
 }
@@ -1422,7 +1479,6 @@ BOOL print_queue_pause(struct current_user *user, int snum, WERROR *errcode)
 
 BOOL print_queue_resume(struct current_user *user, int snum, WERROR *errcode)
 {
-       char *printer_name;
        int ret;
 
        if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
@@ -1442,9 +1498,7 @@ BOOL print_queue_resume(struct current_user *user, int snum, WERROR *errcode)
 
        /* Send a printer notify message */
 
-       printer_name = PRINTERNAME(snum);
-
-       send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB);
+       notify_printer_status(snum, PRINTER_STATUS_OK);
 
        return True;
 }
@@ -1457,7 +1511,6 @@ BOOL print_queue_purge(struct current_user *user, int snum, WERROR *errcode)
 {
        print_queue_struct *queue;
        print_status_struct status;
-       char *printer_name;
        int njobs, i;
        BOOL can_job_admin;
 
@@ -1475,13 +1528,7 @@ BOOL print_queue_purge(struct current_user *user, int snum, WERROR *errcode)
                }
        }
 
-       safe_free(queue);
-
-       /* Send a printer notify message */
-
-       printer_name = PRINTERNAME(snum);
-
-       send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB);
+       SAFE_FREE(queue);
 
        return True;
 }
diff --git a/source3/rpc_client/cli_spoolss_notify.c b/source3/rpc_client/cli_spoolss_notify.c
deleted file mode 100644 (file)
index eddf3d8..0000000
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- *  Unix SMB/CIFS implementation.
- *  RPC Pipe client / server routines
- *  Copyright (C) Andrew Tridgell              1992-2000,
- *  Copyright (C) Jean Francois Micouleau      1998-2000,
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "includes.h"
-#if 0
-#include "rpc_parse.h"
-#include "nterr.h"
-#endif
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_CLI
-
-extern pstring global_myname;
-
-struct msg_info_table {
-       uint32 msg;
-       uint32 field;
-       char*  name;
-       void (*construct_fn) (int snum, SPOOL_NOTIFY_INFO_DATA *data,
-               print_queue_struct *queue,
-               NT_PRINTER_INFO_LEVEL *printer, TALLOC_CTX *mem_ctx);
-};
-
-struct msg_info_table msg_table[] = {
-{ PRINTER_MESSAGE_DRIVER,      PRINTER_NOTIFY_DRIVER_NAME,    "PRINTER_MESSAGE_DRIVER",      spoolss_notify_driver_name  },
-{ PRINTER_MESSAGE_ATTRIBUTES,  PRINTER_NOTIFY_ATTRIBUTES,     "PRINTER_MESSAGE_ATTRIBUTES",  spoolss_notify_attributes   },
-{ PRINTER_MESSAGE_COMMENT,     PRINTER_NOTIFY_COMMENT,        "PRINTER_MESSAGE_COMMENT",     spoolss_notify_comment      },
-{ PRINTER_MESSAGE_LOCATION,    PRINTER_NOTIFY_LOCATION,       "PRINTER_MESSAGE_LOCATION",    spoolss_notify_location     },
-{ PRINTER_MESSAGE_PRINTERNAME, PRINTER_NOTIFY_PRINTER_NAME,   "PRINTER_MESSAGE_PRINTERNAME", spoolss_notify_printer_name },
-{ PRINTER_MESSAGE_SHARENAME,   PRINTER_NOTIFY_SHARE_NAME,     "PRINTER_MESSAGE_SHARENAME",   spoolss_notify_share_name   },
-{ PRINTER_MESSAGE_PORT,        PRINTER_NOTIFY_PORT_NAME,      "PRINTER_MESSAGE_PORT",        spoolss_notify_port_name    },
-{ PRINTER_MESSAGE_CJOBS,       PRINTER_NOTIFY_CJOBS,          "PRINTER_MESSAGE_CJOBS",       spoolss_notify_cjobs        },
-{ PRINTER_MESSAGE_SEPFILE,     PRINTER_NOTIFY_SEPFILE,        "PRINTER_MESSAGE_SEPFILE",     spoolss_notify_sepfile      },
-{ PRINTER_MESSAGE_PARAMS,      PRINTER_NOTIFY_PARAMETERS,     "PRINTER_MESSAGE_PARAMETERS",  spoolss_notify_parameters   },
-{ PRINTER_MESSAGE_DATATYPE,    PRINTER_NOTIFY_DATATYPE,       "PRINTER_MESSAGE_DATATYPE",    spoolss_notify_datatype     },
-{ PRINTER_MESSAGE_NULL,        0x0,                           "",                            NULL                        },
-};
-
-/*********************************************************
- Disconnect from the client machine.
-**********************************************************/
-BOOL spoolss_disconnect_from_client( struct cli_state *cli)
-{
-       cli_nt_session_close(cli);
-       cli_ulogoff(cli);
-       cli_shutdown(cli);
-
-       return True;
-}
-
-
-/*********************************************************
- Connect to the client machine.
-**********************************************************/
-
-BOOL spoolss_connect_to_client( struct cli_state *cli, char *remote_machine)
-{
-       ZERO_STRUCTP(cli);
-       if(cli_initialise(cli) == NULL) {
-               DEBUG(0,("connect_to_client: unable to initialize client connection.\n"));
-               return False;
-       }
-
-       if(!resolve_name( remote_machine, &cli->dest_ip, 0x20)) {
-               DEBUG(0,("connect_to_client: Can't resolve address for %s\n", remote_machine));
-               cli_shutdown(cli);
-       return False;
-       }
-
-       if (ismyip(cli->dest_ip)) {
-               DEBUG(0,("connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
-               cli_shutdown(cli);
-               return False;
-       }
-
-       if (!cli_connect(cli, remote_machine, &cli->dest_ip)) {
-               DEBUG(0,("connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
-               cli_shutdown(cli);
-               return False;
-       }
-  
-       if (!attempt_netbios_session_request(cli, global_myname, remote_machine, &cli->dest_ip)) {
-               DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request.\n", 
-                       remote_machine));
-               return False;
-       }
-
-       cli->protocol = PROTOCOL_NT1;
-    
-       if (!cli_negprot(cli)) {
-               DEBUG(0,("connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
-               cli_shutdown(cli);
-               return False;
-       }
-
-       if (cli->protocol != PROTOCOL_NT1) {
-               DEBUG(0,("connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
-               cli_shutdown(cli);
-               return False;
-       }
-    
-       /*
-        * Do an anonymous session setup.
-        */
-    
-       if (!cli_session_setup(cli, "", "", 0, "", 0, "")) {
-               DEBUG(0,("connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
-               cli_shutdown(cli);
-               return False;
-       }
-    
-       if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
-               DEBUG(0,("connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
-               cli_shutdown(cli);
-               return False;
-       }
-    
-       if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
-               DEBUG(0,("connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(cli) ));
-               cli_shutdown(cli);
-               return False;
-       }
-
-       /*
-        * Ok - we have an anonymous connection to the IPC$ share.
-        * Now start the NT Domain stuff :-).
-        */
-
-       if(cli_nt_session_open(cli, PIPE_SPOOLSS) == False) {
-               DEBUG(0,("connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(cli)));
-               cli_nt_session_close(cli);
-               cli_ulogoff(cli);
-               cli_shutdown(cli);
-               return False;
-       } 
-
-       return True;
-}
-
-/*
- * SPOOLSS Client RPC's used by servers as the notification
- * back channel
- */
-
-/***************************************************************************
- do a reply open printer
-****************************************************************************/
-
-WERROR cli_spoolss_reply_open_printer(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                               char *printer, uint32 localprinter, uint32 type, 
-                               POLICY_HND *handle)
-{
-       WERROR result = W_ERROR(ERRgeneral);
-       
-       prs_struct rbuf;
-       prs_struct buf; 
-
-       SPOOL_Q_REPLYOPENPRINTER q_s;
-       SPOOL_R_REPLYOPENPRINTER r_s;
-
-       prs_init(&buf, 1024, mem_ctx, MARSHALL);
-       prs_init(&rbuf, 0, mem_ctx, UNMARSHALL );
-
-       /* create and send a MSRPC command with api SPOOLSS_REPLYOPENPRINTER */
-       
-       /* store the parameters */
-       make_spoolss_q_replyopenprinter(&q_s, printer, localprinter, type);
-
-       /* turn parameters into data stream */
-       if(!spoolss_io_q_replyopenprinter("", &q_s,  &buf, 0)) {
-               DEBUG(0,("cli_spoolss_reply_open_printer: Error : failed to marshall SPOOL_Q_REPLYOPENPRINTER struct.\n"));
-               goto done;
-       }
-
-       /* send the data on \PIPE\ */
-       if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYOPENPRINTER, &buf, &rbuf)) 
-               goto done;
-
-       /* turn data stream into parameters*/
-       if(!spoolss_io_r_replyopenprinter("", &r_s, &rbuf, 0)) {
-               DEBUG(0,("cli_spoolss_reply_open_printer: Error : failed to unmarshall SPOOL_R_REPLYOPENPRINTER struct.\n"));
-               goto done;
-       }
-       
-       memcpy(handle, &r_s.handle, sizeof(r_s.handle));
-       result = r_s.status;
-
-done:
-       prs_mem_free(&buf);
-       prs_mem_free(&rbuf);
-
-       return result;
-}
-
-/***************************************************************************
- do a reply open printer
-****************************************************************************/
-
-WERROR cli_spoolss_reply_close_printer(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                       POLICY_HND *handle)
-{
-       WERROR result = W_ERROR(ERRgeneral);
-       prs_struct rbuf;
-       prs_struct buf; 
-
-       SPOOL_Q_REPLYCLOSEPRINTER q_s;
-       SPOOL_R_REPLYCLOSEPRINTER r_s;
-
-       prs_init(&buf, 1024, cli->mem_ctx, MARSHALL);
-       prs_init(&rbuf, 0, cli->mem_ctx, UNMARSHALL );
-
-       /* create and send a MSRPC command with api  */
-       
-       /* store the parameters */
-       make_spoolss_q_reply_closeprinter(&q_s, handle);
-
-       /* turn parameters into data stream */
-       if(!spoolss_io_q_replycloseprinter("", &q_s,  &buf, 0)) {
-               DEBUG(0,("cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_Q_REPLY_CLOSEPRINTER struct.\n"));
-               goto done;
-       }
-
-       /* send the data on \PIPE\ */
-       if (!rpc_api_pipe_req(cli, SPOOLSS_REPLYCLOSEPRINTER, &buf, &rbuf))
-               goto done;
-
-       /* turn data stream into parameters*/
-       if(!spoolss_io_r_replycloseprinter("", &r_s, &rbuf, 0)) {
-               DEBUG(0,("cli_spoolss_reply_close_printer: Error : failed to marshall SPOOL_R_REPLY_CLOSEPRINTER struct.\n"));
-               goto done;
-       }
-       
-
-       result = r_s.status;
-       
-done:
-               prs_mem_free(&buf);
-               prs_mem_free(&rbuf);
-
-       return result;
-}
-
-/*********************************************************************
- This SPOOLSS_ROUTERREPLYPRINTER function is used to send a change 
- notification event when the registration **did not** use 
- SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor.
- Also see cli_spolss_reply_rrpcn()
- *********************************************************************/
-WERROR cli_spoolss_routerreplyprinter (struct cli_state *cli, TALLOC_CTX *mem_ctx,
-                                       POLICY_HND *pol, uint32 condition, uint32 changd_id)
-{
-       prs_struct qbuf, rbuf;
-       SPOOL_Q_ROUTERREPLYPRINTER q;
-        SPOOL_R_ROUTERREPLYPRINTER r;
-       WERROR result = W_ERROR(ERRgeneral);
-
-       ZERO_STRUCT(q);
-       ZERO_STRUCT(r);
-
-
-       /* Initialise input parameters */
-
-       prs_init(&qbuf, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL);
-       prs_init(&rbuf, 0, mem_ctx, UNMARSHALL);
-
-
-       /* write the request */
-       make_spoolss_q_routerreplyprinter(&q, pol, condition, changd_id);
-
-       /* Marshall data and send request */
-       if (!spoolss_io_q_routerreplyprinter ("", &q, &qbuf, 0)) {
-               DEBUG(0,("cli_spoolss_routerreplyprinter: Unable to marshall SPOOL_Q_ROUTERREPLYPRINTER!\n"));
-               goto done;
-       }
-               
-               
-       if (!rpc_api_pipe_req (cli, SPOOLSS_ROUTERREPLYPRINTER, &qbuf, &rbuf)) 
-               goto done;
-
-       /* Unmarshall response */
-       if (!spoolss_io_r_routerreplyprinter ("", &r, &rbuf, 0)) {
-               DEBUG(0,("cli_spoolss_routerreplyprinter: Unable to unmarshall SPOOL_R_ROUTERREPLYPRINTER!\n"));
-               goto done;
-       }
-
-       /* Return output parameters */
-       result = r.status;
-       
-done:
-       prs_mem_free(&qbuf);
-               prs_mem_free(&rbuf);
-
-       return result;  
-}
-
-
-/**********************************************************************************
- Build the SPOOL_NOTIFY_INFO_DATA entries based upon the flags which have been set
- *********************************************************************************/
-
-static int build_notify_data (TALLOC_CTX *ctx, NT_PRINTER_INFO_LEVEL *printer, uint32 flags, 
-                       SPOOL_NOTIFY_INFO_DATA **notify_data)
-{
-       SPOOL_NOTIFY_INFO_DATA *data;
-       uint32 idx = 0;
-       int i = 0;
-       
-       while ((msg_table[i].msg != PRINTER_MESSAGE_NULL) && flags)
-       {
-               if (flags & msg_table[i].msg) 
-               {
-                       DEBUG(10,("build_notify_data: %s set on [%s][%d]\n", msg_table[i].name,
-                               printer->info_2->printername, idx));
-                       if ((data=Realloc(*notify_data, (idx+1)*sizeof(SPOOL_NOTIFY_INFO_DATA))) == NULL) {
-                               DEBUG(0,("build_notify_data: Realloc() failed with size [%d]!\n",
-                                       (idx+1)*sizeof(SPOOL_NOTIFY_INFO_DATA)));
-                               return -1;
-       }
-                       *notify_data = data;
-
-                       /* clear memory */
-                       memset(*notify_data+idx, 0x0, sizeof(SPOOL_NOTIFY_INFO_DATA));
-       
-                       /*
-                        * 'id' (last param here) is undefined when type == PRINTER_NOTIFY_TYPE
-                        * See PRINTER_NOTIFY_INFO_DATA entries in MSDN
-                        * --jerry
-                        */
-                       construct_info_data(*notify_data+idx, PRINTER_NOTIFY_TYPE, msg_table[i].field, 0x00);
-
-                       msg_table[i].construct_fn(-1, *notify_data+idx, NULL, printer, ctx);
-                       idx++;
-               }
-
-               i++;
-       }
-       
-       return idx;
-}
-
-/*********************************************************************
- This SPOOLSS_ROUTERREPLYPRINTER function is used to send a change 
- notification event when the registration **did** use 
- SPOOL_NOTIFY_OPTION_TYPE structure to specify the events to monitor
- Also see cli_spoolss_routereplyprinter()
- *********************************************************************/
-
-WERROR cli_spoolss_reply_rrpcn(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
-                                       POLICY_HND *handle, PRINTER_MESSAGE_INFO *info,
-                                       NT_PRINTER_INFO_LEVEL *printer)
-{
-       prs_struct rbuf;
-       prs_struct buf; 
-
-       SPOOL_NOTIFY_INFO       notify_info;
-       SPOOL_NOTIFY_INFO_DATA  *notify_data = NULL;
-       uint32                  data_len;
-
-       WERROR result = W_ERROR(ERRgeneral);
-
-       SPOOL_Q_REPLY_RRPCN q_s;
-       SPOOL_R_REPLY_RRPCN r_s;
-
-       if (!info) {
-               DEBUG(5,("cli_spoolss_reply_rrpcn: NULL printer message info pointer!\n"));
-               goto done;
-       }
-               
-       prs_init(&buf, 1024, mem_ctx, MARSHALL);
-       prs_init(&rbuf, 0,   mem_ctx, UNMARSHALL );
-
-       ZERO_STRUCT(notify_info);
-
-/*
-        * See comments in _spoolss_setprinter() about PRINTER_CHANGE_XXX
-        * events.  --jerry
-*/
-       DEBUG(10,("cli_spoolss_reply_rrpcn: PRINTER_MESSAGE flags = 0x%8x\n", info->flags));
-
-       data_len = build_notify_data(mem_ctx, printer, info->flags, &notify_data);
-       if (info->flags && (data_len == -1)) {
-               DEBUG(0,("cli_spoolss_reply_rrpcn: Failed to build SPOOL_NOTIFY_INFO_DATA [flags == 0x%x] for printer [%s]\n",
-                       info->flags, info->printer_name));
-               result = WERR_NOMEM;
-               goto done;
-       }
-       notify_info.version = 0x2;
-       notify_info.flags   = 0x00020000;       /* ?? */
-       notify_info.count   = data_len;
-       notify_info.data    = notify_data;
-
-       /* create and send a MSRPC command with api  */
-       /* store the parameters */
-
-       make_spoolss_q_reply_rrpcn(&q_s, handle, info->low, info->high, &notify_info);
-
-       /* turn parameters into data stream */
-       if(!spoolss_io_q_reply_rrpcn("", &q_s,  &buf, 0)) {
-               DEBUG(0,("cli_spoolss_reply_rrpcn: Error : failed to marshall SPOOL_Q_REPLY_RRPCN struct.\n"));
-               goto done;
-       }
-
-       /* send the data on \PIPE\ */
-       if (!rpc_api_pipe_req(cli, SPOOLSS_RRPCN, &buf, &rbuf)) 
-               goto done;
-
-       
-       /* turn data stream into parameters*/
-       if(!spoolss_io_r_reply_rrpcn("", &r_s, &rbuf, 0)) {
-               DEBUG(0,("cli_spoolss_reply_rrpcn: Error : failed to unmarshall SPOOL_R_REPLY_RRPCN struct.\n"));
-               goto done;
-       }
-
-       if (r_s.unknown0 == 0x00080000) {
-               DEBUG(8,("cli_spoolss_reply_rrpcn: I think the spooler resonded that the notification was ignored.\n"));
-       }
-       
-       result = r_s.status;
-
-done:
-       prs_mem_free(&buf);
-       prs_mem_free(&rbuf);
-       /*
-        * The memory allocated in this array is talloc'd so we only need
-        * free the array here. JRA.
-        */
-       SAFE_FREE(notify_data);
-
-       return result;
-}
-
index 841d303840cfb685eafb1c59056d9cf68564ebfe..017540638472b927c92063d30cd27dcf2b167f19 100644 (file)
@@ -48,7 +48,7 @@ static uint32 str_len_uni(UNISTR *source)
 This should be moved in a more generic lib.
 ********************************************************************/  
 
-static BOOL spoolss_io_system_time(char *desc, prs_struct *ps, int depth, SYSTEMTIME *systime)
+BOOL spoolss_io_system_time(char *desc, prs_struct *ps, int depth, SYSTEMTIME *systime)
 {
        if(!prs_uint16("year", ps, depth, &systime->year))
                return False;
@@ -124,7 +124,7 @@ reads or writes an DOC_INFO structure.
 
 static BOOL smb_io_doc_info(char *desc, DOC_INFO *info, prs_struct *ps, int depth)
 {
-       uint32 useless_ptr=1;
+       uint32 useless_ptr=0;
        
        if (info == NULL) return False;
 
@@ -324,53 +324,64 @@ static BOOL smb_io_notify_info_data(char *desc,SPOOL_NOTIFY_INFO_DATA *data, prs
 {
        uint32 useless_ptr=0xADDE0FF0;
 
-       uint32 how_many_words;
-       BOOL isvalue;
-       uint32 x;
-       
        prs_debug(ps, depth, desc, "smb_io_notify_info_data");
        depth++;
 
-       how_many_words=data->size;
-       if (how_many_words==POINTER) {
-               how_many_words=TWO_VALUE;
-       }
-       
-       isvalue=data->enc_type;
-
        if(!prs_align(ps))
                return False;
        if(!prs_uint16("type",           ps, depth, &data->type))
                return False;
        if(!prs_uint16("field",          ps, depth, &data->field))
                return False;
-       /*prs_align(ps);*/
 
-       if(!prs_uint32("how many words", ps, depth, &how_many_words))
+       if(!prs_uint32("how many words", ps, depth, &data->size))
                return False;
        if(!prs_uint32("id",             ps, depth, &data->id))
                return False;
-       if(!prs_uint32("how many words", ps, depth, &how_many_words))
+       if(!prs_uint32("how many words", ps, depth, &data->size))
                return False;
 
+       switch (data->enc_type) {
 
-       /*prs_align(ps);*/
+               /* One and two value data has two uint32 values */
+
+       case ONE_VALUE:
+       case TWO_VALUE:
 
-       if (isvalue==True) {
                if(!prs_uint32("value[0]", ps, depth, &data->notify_data.value[0]))
                        return False;
                if(!prs_uint32("value[1]", ps, depth, &data->notify_data.value[1]))
                        return False;
-               /*prs_align(ps);*/
-       } else {
-               /* it's a string */
-               /* length in ascii including \0 */
-               x=2*(data->notify_data.data.length+1);
-               if(!prs_uint32("string length", ps, depth, &x ))
+               break;
+
+               /* Pointers and strings have a string length and a
+                  pointer.  For a string the length is expressed as
+                  the number of uint16 characters plus a trailing
+                  \0\0. */
+
+       case POINTER:
+
+               if(!prs_uint32("string length", ps, depth, &data->notify_data.data.length ))
+                       return False;
+               if(!prs_uint32("pointer", ps, depth, &useless_ptr))
+                       return False;
+
+               break;
+
+       case STRING:
+
+               if(!prs_uint32("string length", ps, depth, &data->notify_data.data.length))
                        return False;
+
                if(!prs_uint32("pointer", ps, depth, &useless_ptr))
                        return False;
-               /*prs_align(ps);*/
+
+               break;
+
+       default:
+               DEBUG(3, ("invalid enc_type %d for smb_io_notify_info_data\n",
+                         data->enc_type));
+               break;
        }
 
        return True;
@@ -383,22 +394,79 @@ reads or writes an NOTIFY INFO DATA structure.
 BOOL smb_io_notify_info_data_strings(char *desc,SPOOL_NOTIFY_INFO_DATA *data,
                                      prs_struct *ps, int depth)
 {
-       uint32 x;
-       BOOL isvalue;
-       
        prs_debug(ps, depth, desc, "smb_io_notify_info_data_strings");
        depth++;
        
        if(!prs_align(ps))
                return False;
 
-       isvalue=data->enc_type;
+       switch(data->enc_type) {
+
+               /* No data for values */
+
+       case ONE_VALUE:
+       case TWO_VALUE:
+
+               break;
+
+               /* Strings start with a length in uint16s */
+
+       case STRING:
+
+               if (UNMARSHALLING(ps)) {
+                       data->notify_data.data.string = 
+                               (uint16 *)prs_alloc_mem(ps, data->notify_data.data.length);
+
+                       if (!data->notify_data.data.string) 
+                               return False;
+               }
+
+               if (MARSHALLING(ps))
+                       data->notify_data.data.length /= 2;
+
+               if(!prs_uint32("string length", ps, depth, &data->notify_data.data.length))
+                       return False;
+
+               if (!prs_uint16uni(True, "string", ps, depth, data->notify_data.data.string,
+                                  data->notify_data.data.length))
+                       return False;
+
+               if (MARSHALLING(ps))
+                       data->notify_data.data.length *= 2;
+
+               break;
+
+       case POINTER:
+
+               if (UNMARSHALLING(ps)) {
+                       data->notify_data.data.string = 
+                               (uint16 *)prs_alloc_mem(ps, data->notify_data.data.length);
+
+                       if (!data->notify_data.data.string) 
+                               return False;
+               }
+
+               if(!prs_uint8s(True,"buffer",ps,depth,(uint8*)data->notify_data.data.string,data->notify_data.data.length))
+                       return False;
+
+               break;
+
+       default:
+               DEBUG(3, ("invalid enc_type %d for smb_io_notify_info_data_strings\n",
+                         data->enc_type));
+               break;
+       }
 
+#if 0
        if (isvalue==False) {
+
                /* length of string in unicode include \0 */
                x=data->notify_data.data.length+1;
+
+               if (data->field != 16)
                if(!prs_uint32("string length", ps, depth, &x ))
                        return False;
+
                if (MARSHALLING(ps)) {
                        /* These are already in little endian format. Don't byte swap. */
                        if (x == 1) {
@@ -412,6 +480,10 @@ BOOL smb_io_notify_info_data_strings(char *desc,SPOOL_NOTIFY_INFO_DATA *data,
                                if(!prs_uint8s(True,"string",ps,depth, (uint8 *)&data->notify_data.data.length,x*2)) 
                                        return False;
                        } else {
+
+                               if (data->field == 16)
+                                       x /= 2;
+
                                if(!prs_uint16uni(True,"string",ps,depth,data->notify_data.data.string,x))
                                        return False;
                        }
@@ -427,10 +499,11 @@ BOOL smb_io_notify_info_data_strings(char *desc,SPOOL_NOTIFY_INFO_DATA *data,
                                return False;
                }
        }
-#if 0  /* JERRY */
 
-       /* Win2k does not seem to put this parse align here */
+#endif
 
+#if 0  /* JERRY */
+       /* Win2k does not seem to put this parse align here */
        if(!prs_align(ps))
                return False;
 #endif
@@ -959,6 +1032,7 @@ BOOL make_spoolss_printer_info_2(TALLOC_CTX *mem_ctx, SPOOL_PRINTER_INFO_LEVEL_2
        return True;
 }
 
+
 /*******************************************************************
  * read a structure.
  * called from spoolss_q_open_printer_ex (srv_spoolss.c)
@@ -1209,8 +1283,11 @@ BOOL spoolss_io_r_getprinterdata(char *desc, SPOOL_R_GETPRINTERDATA *r_u, prs_st
        if (!prs_uint32("size", ps, depth, &r_u->size))
                return False;
        
-       if (UNMARSHALLING(ps))
+       if (UNMARSHALLING(ps) && r_u->size) {
                r_u->data = prs_alloc_mem(ps, r_u->size);
+               if(r_u->data)
+                       return False;
+       }
 
        if (!prs_uint8s(False,"data", ps, depth, r_u->data, r_u->size))
                return False;
@@ -5748,9 +5825,7 @@ BOOL spoolss_io_r_enumprinterdata(char *desc, SPOOL_R_ENUMPRINTERDATA *r_u, prs_
                return False;
 
        if (UNMARSHALLING(ps) && r_u->valuesize) {
-
                r_u->value = (uint16 *)prs_alloc_mem(ps, r_u->valuesize * 2);
-
                if (!r_u->value) {
                        DEBUG(0, ("spoolss_io_r_enumprinterdata: out of memory for printerdata value\n"));
                        return False;
@@ -5773,10 +5848,8 @@ BOOL spoolss_io_r_enumprinterdata(char *desc, SPOOL_R_ENUMPRINTERDATA *r_u, prs_
                return False;
 
        if (UNMARSHALLING(ps) && r_u->datasize) {
-
                r_u->data = (uint8 *)prs_alloc_mem(ps, r_u->datasize);
-
-               if (!r_u->value) {
+               if (!r_u->data) {
                        DEBUG(0, ("spoolss_io_r_enumprinterdata: out of memory for printerdata data\n"));
                        return False;
                }
index af8f1c48a65a133f70a0357b83cfd791f6892cfe..0b172aa0e505e08cd206ba60e1a410aedd472981 100644 (file)
@@ -30,6 +30,7 @@
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_RPC_SRV
+/* #define EMULATE_WIN2K_HACK  1 */
 
 #ifndef MAX_OPEN_PRINTER_EXS
 #define MAX_OPEN_PRINTER_EXS 50
@@ -80,6 +81,7 @@ typedef struct _Printer{
                SPOOL_NOTIFY_OPTION *option;
                POLICY_HND client_hnd;
                uint32 client_connected;
+               uint32 change;
        } notify;
        struct {
                fstring machine;
@@ -190,10 +192,10 @@ static void srv_spoolss_replycloseprinter(POLICY_HND *handle)
 
        /* if it's the last connection, deconnect the IPC$ share */
        if (smb_connections==1) {
-               if(!spoolss_disconnect_from_client(&cli))
-                       return;
-
-               message_deregister(MSG_PRINTER_NOTIFY);
+               cli_nt_session_close(&cli);
+               cli_ulogoff(&cli);
+               cli_shutdown(&cli);
+               message_deregister(MSG_PRINTER_NOTIFY2);
        }
 
        smb_connections--;
@@ -438,7 +440,7 @@ static BOOL set_printer_hnd_name(Printer_entry *Printer, char *handlename)
         * anymore, so I've simplified this loop greatly.  Here
         * we are just verifying that the printer name is a valid
         * printer service defined in smb.conf
-        *                          --jerry [Fri Feb 15 11:17:46 CST 2002] 
+        *                          --jerry [Fri Feb 15 11:17:46 CST 2002]
         */
 
        for (snum=0; snum<n_services; snum++) {
@@ -547,279 +549,398 @@ static BOOL alloc_buffer_size(NEW_BUFFER *buffer, uint32 buffer_size)
 
        return True;
 }
+
 /***************************************************************************
- Always give preference Printer_entry.notify.option over 
- Printer_entry.notify.flags.  Return True if we should send notification 
- events using SPOOLSS_RRPCN.  False means that we should use 
- SPOOLSS_ROUTERREPLYPRINTER.
+ check to see if the client motify handle is monitoring the notification
+ given by (notify_type, notify_field).
  **************************************************************************/
-static BOOL valid_notify_options(Printer_entry *printer)
+
+static BOOL is_monitoring_event_flags(uint32 flags, uint16 notify_type,
+                                     uint16 notify_field)
 {
-       if (printer->notify.option == NULL)
-               return False;
-               
        return True;
 }
 
-/***************************************************************************
- Simple check to see if the client motify handle is set to watch for events
- represented by 'flags'
- FIXME!!!! only a stub right now     --jerry
- **************************************************************************/
-static BOOL is_client_monitoring_event(Printer_entry *p, uint32 flags)
+static BOOL is_monitoring_event(Printer_entry *p, uint16 notify_type,
+                               uint16 notify_field)
 {
+       SPOOL_NOTIFY_OPTION *option = p->notify.option;
+       uint32 i, j;
+       
+       if (p->notify.flags)
+               return is_monitoring_event_flags(
+                       p->notify.flags, notify_type, notify_field);
 
-       return True;
-}
+       for (i = 0; i < option->count; i++) {
+               
+               /* Check match for notify_type */
+               
+               if (option->ctr.type[i].type != notify_type)
+                       continue;
 
-/***************************************************************************
- Server wrapper for cli_spoolss_routerreplyprinter() since the client 
- function can only send a single change notification at a time.
- FIXME!!!  only handles one change currently (PRINTER_CHANGE_SET_PRINTER_DRIVER)
- --jerry
- **************************************************************************/
-static WERROR srv_spoolss_routerreplyprinter (struct cli_state *reply_cli, TALLOC_CTX *mem_ctx,
-                                       POLICY_HND *pol, PRINTER_MESSAGE_INFO *info,
-                                       NT_PRINTER_INFO_LEVEL *printer)                         
-{
-       WERROR result;
-       uint32 condition = 0x0;
+               /* Check match for field */
+               
+               for (j = 0; j < option->ctr.type[i].count; j++) {
+                       if (option->ctr.type[i].fields[j] == notify_field) {
+                               return True;
+                       }
+               }
+       }
        
-       if (info->flags & PRINTER_MESSAGE_DRIVER)
-               condition = PRINTER_CHANGE_SET_PRINTER_DRIVER;
+       DEBUG(10, ("%s is not monitoring 0x%02x/0x%02x\n",
+                  (p->printer_type == PRINTER_HANDLE_IS_PRINTER) ?
+                  p->dev.handlename : p->dev.printerservername,
+                  notify_type, notify_field));
        
-       result = cli_spoolss_routerreplyprinter(reply_cli, mem_ctx, pol, condition, 
-                       printer->info_2->changeid);
+       return False;
+}
 
-       return result;
+/* Convert a notification message to a SPOOL_NOTIFY_INFO_DATA struct */
+
+static void notify_one_value(struct spoolss_notify_msg *msg,
+                            SPOOL_NOTIFY_INFO_DATA *data,
+                            TALLOC_CTX *mem_ctx)
+{
+       data->notify_data.value[0] = msg->notify.value[0];
+       data->notify_data.value[1] = 0;
 }
 
-/***********************************************************************
- Wrapper around the decision of which RPC use to in the change 
- notification
- **********************************************************************/
-static WERROR srv_spoolss_send_event_to_client(Printer_entry* Printer, 
-       struct cli_state *send_cli,     PRINTER_MESSAGE_INFO *msg, 
-       NT_PRINTER_INFO_LEVEL *info)
+static void notify_string(struct spoolss_notify_msg *msg,
+                         SPOOL_NOTIFY_INFO_DATA *data,
+                         TALLOC_CTX *mem_ctx)
 {
-       WERROR result;
+       UNISTR2 unistr;
        
-       if (valid_notify_options(Printer)) {
-               /* This is a single call that can send information about multiple changes */
-               if (Printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
-                       msg->flags |= PRINTER_MESSAGE_ATTRIBUTES;
+       /* The length of the message includes the trailing \0 */
 
-               result = cli_spoolss_reply_rrpcn(send_cli, send_cli->mem_ctx, &Printer->notify.client_hnd, 
-                               msg, info);
-       }
-       else {
-               /* This requires that the server send an individual event notification for each change */
-               result = srv_spoolss_routerreplyprinter(send_cli, send_cli->mem_ctx, &Printer->notify.client_hnd, 
-                               msg, info);
+       init_unistr2(&unistr, msg->notify.data, msg->len);
+
+       data->notify_data.data.length = msg->len * 2;
+       data->notify_data.data.string = (uint16 *)talloc(mem_ctx, msg->len * 2);
+
+       if (!data->notify_data.data.string) {
+               data->notify_data.data.length = 0;
+               return;
        }
        
-       return result;
+       memcpy(data->notify_data.data.string, unistr.buffer, msg->len * 2);
+}
+
+static void notify_system_time(struct spoolss_notify_msg *msg,
+                              SPOOL_NOTIFY_INFO_DATA *data,
+                              TALLOC_CTX *mem_ctx)
+{
+       SYSTEMTIME systime;
+       prs_struct ps;
+
+       if (msg->len != sizeof(time_t)) {
+               DEBUG(5, ("notify_system_time: received wrong sized message (%d)\n",
+                         msg->len));
+               return;
+       }
+
+       if (!prs_init(&ps, MAX_PDU_FRAG_LEN, mem_ctx, MARSHALL)) {
+               DEBUG(5, ("notify_system_time: prs_init() failed\n"));
+               return;
+       }
+
+       if (!make_systemtime(&systime, localtime((time_t *)msg->notify.data))) {
+               DEBUG(5, ("notify_system_time: unable to make systemtime\n"));
+               return;
+       }
+
+       if (!spoolss_io_system_time("", &ps, 0, &systime))
+               return;
+
+       data->notify_data.data.length = prs_offset(&ps);
+       data->notify_data.data.string =
+               talloc(mem_ctx, prs_offset(&ps));
+
+       memcpy(data->notify_data.data.string, prs_data_p(&ps), prs_offset(&ps));
+
+       prs_mem_free(&ps);
 }
 
+struct notify2_message_table {
+       char *name;
+       void (*fn)(struct spoolss_notify_msg *msg,
+                  SPOOL_NOTIFY_INFO_DATA *data, TALLOC_CTX *mem_ctx);
+};
+
+static struct notify2_message_table printer_notify_table[] = {
+       /* 0x00 */ { "PRINTER_NOTIFY_SERVER_NAME", NULL },
+       /* 0x01 */ { "PRINTER_NOTIFY_PRINTER_NAME", NULL },
+       /* 0x02 */ { "PRINTER_NOTIFY_SHARE_NAME", NULL },
+       /* 0x03 */ { "PRINTER_NOTIFY_PORT_NAME", NULL },
+       /* 0x04 */ { "PRINTER_NOTIFY_DRIVER_NAME", NULL },
+       /* 0x05 */ { "PRINTER_NOTIFY_COMMENT", NULL },
+       /* 0x06 */ { "PRINTER_NOTIFY_LOCATION", NULL },
+       /* 0x07 */ { "PRINTER_NOTIFY_DEVMODE", NULL },
+       /* 0x08 */ { "PRINTER_NOTIFY_SEPFILE", NULL },
+       /* 0x09 */ { "PRINTER_NOTIFY_PRINT_PROCESSOR", NULL },
+       /* 0x0a */ { "PRINTER_NOTIFY_PARAMETERS", NULL },
+       /* 0x0b */ { "PRINTER_NOTIFY_DATATYPE", NULL },
+       /* 0x0c */ { "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", NULL },
+       /* 0x0d */ { "PRINTER_NOTIFY_ATTRIBUTES", NULL },
+       /* 0x0e */ { "PRINTER_NOTIFY_PRIORITY", NULL },
+       /* 0x0f */ { "PRINTER_NOTIFY_DEFAULT_PRIORITY", NULL },
+       /* 0x10 */ { "PRINTER_NOTIFY_START_TIME", NULL },
+       /* 0x11 */ { "PRINTER_NOTIFY_UNTIL_TIME", NULL },
+       /* 0x12 */ { "PRINTER_NOTIFY_STATUS", notify_one_value },
+};
+
+static struct notify2_message_table job_notify_table[] = {
+       /* 0x00 */ { "JOB_NOTIFY_PRINTER_NAME", NULL },
+       /* 0x01 */ { "JOB_NOTIFY_MACHINE_NAME", NULL },
+       /* 0x02 */ { "JOB_NOTIFY_PORT_NAME", NULL },
+       /* 0x03 */ { "JOB_NOTIFY_USER_NAME", notify_string },
+       /* 0x04 */ { "JOB_NOTIFY_NOTIFY_NAME", NULL },
+       /* 0x05 */ { "JOB_NOTIFY_DATATYPE", NULL },
+       /* 0x06 */ { "JOB_NOTIFY_PRINT_PROCESSOR", NULL },
+       /* 0x07 */ { "JOB_NOTIFY_PARAMETERS", NULL },
+       /* 0x08 */ { "JOB_NOTIFY_DRIVER_NAME", NULL },
+       /* 0x09 */ { "JOB_NOTIFY_DEVMODE", NULL },
+       /* 0x0a */ { "JOB_NOTIFY_STATUS", notify_one_value },
+       /* 0x0b */ { "JOB_NOTIFY_STATUS_STRING", NULL },
+       /* 0x0c */ { "JOB_NOTIFY_SECURITY_DESCRIPTOR", NULL },
+       /* 0x0d */ { "JOB_NOTIFY_DOCUMENT", notify_string },
+       /* 0x0e */ { "JOB_NOTIFY_PRIORITY", NULL },
+       /* 0x0f */ { "JOB_NOTIFY_POSITION", NULL },
+       /* 0x10 */ { "JOB_NOTIFY_SUBMITTED", notify_system_time },
+       /* 0x11 */ { "JOB_NOTIFY_START_TIME", NULL },
+       /* 0x12 */ { "JOB_NOTIFY_UNTIL_TIME", NULL },
+       /* 0x13 */ { "JOB_NOTIFY_TIME", NULL },
+       /* 0x14 */ { "JOB_NOTIFY_TOTAL_PAGES", notify_one_value },
+       /* 0x15 */ { "JOB_NOTIFY_PAGES_PRINTED", NULL },
+       /* 0x16 */ { "JOB_NOTIFY_TOTAL_BYTES", notify_one_value },
+       /* 0x17 */ { "JOB_NOTIFY_BYTES_PRINTED", NULL },
+};
 
 /***********************************************************************
  Send a change notication message on all handles which have a call 
  back registered
  **********************************************************************/
 
-static void send_spoolss_event_notification(PRINTER_MESSAGE_INFO *msg)
+static void process_notify2_message(struct spoolss_notify_msg *msg, 
+                                   TALLOC_CTX *mem_ctx)
 {
-       Printer_entry *find_printer;
-       WERROR result;
-       NT_PRINTER_INFO_LEVEL *printer = NULL;
+       Printer_entry *p;
 
-       if (!msg) {
-               DEBUG(0,("send_spoolss_event_notification: NULL msg pointer!\n"));
-               return;
-       }
+       for (p = printers_list; p; p = p->next) {
+               SPOOL_NOTIFY_INFO_DATA *data;
+               uint32 data_len = 1;
+               uint32 id;
 
-       for(find_printer = printers_list; find_printer; find_printer = find_printer->next) {
+               /* Is there notification on this handle? */
 
-               /*
-                * If the entry has a connected client we send the message. There should 
-                * only be one of these normally when dealing with the NT/2k spooler.
-                * However, iterate over all to make sure we deal with user applications
-                * in addition to spooler service.
-                *
-                * While we are only maintaining a single connection to the client, 
-                * the FindFirstPrinterChangeNotification() call is made on a printer 
-                * handle, so "client_connected" represents the whether or not the 
-                * client asked for change notication on this handle.
-                * 
-                * --jerry
-                */
+               if (!p->notify.client_connected)
+                       continue;
 
-               if (find_printer->notify.client_connected==True) {
-               
-                       /* does the client care about what changed? */
+               /* For this printer?  Print servers always receive 
+                   notifications. */
 
-                       if (msg->flags && !is_client_monitoring_event(find_printer, msg->flags)) {
-                               DEBUG(10,("send_spoolss_event_notification: Client [%s] not monitoring these events\n",
-                                       find_printer->client.machine)); 
-                               continue;
-                       }
+               if (p->printer_type == PRINTER_HANDLE_IS_PRINTER &&
+                   !strequal(msg->printer, p->dev.handlename))
+                       continue;
 
-                       if (find_printer->printer_type == PRINTER_HANDLE_IS_PRINTSERVER)
-                               DEBUG(10,("send_spoolss_event_notification: printserver [%s]\n", find_printer->dev.printerservername ));
-                       else
-                               DEBUG(10,("send_spoolss_event_notification: printer [%s]\n", find_printer->dev.handlename));
+               /* Are we monitoring this event? */
 
-                       /*
-                        * if handle is a printer, only send if the printer_name matches.
-                        * ...else if handle is a printerserver, send to all
-                        */
+               if (!is_monitoring_event(p, msg->type, msg->field))
+                       continue;
 
-                       if (*msg->printer_name && (find_printer->printer_type==PRINTER_HANDLE_IS_PRINTER) 
-                               && !strequal(msg->printer_name, find_printer->dev.handlename)) 
-                       {
-                               DEBUG(10,("send_spoolss_event_notification: ignoring message sent to %s [%s]\n",
-                                       msg->printer_name, find_printer->dev.handlename ));
-                               continue;
+               /* OK - send the event to the client */
+
+               data = talloc(mem_ctx, sizeof(SPOOL_NOTIFY_INFO_DATA));
+
+               ZERO_STRUCTP(data);
+
+               /* Convert unix jobid to smb jobid */
+
+               id = msg->id;
+
+               if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) {
+
+                       id = sysjob_to_jobid(msg->id);
+
+                       if (id == -1) {
+                               DEBUG(3, ("no such unix jobid %d\n", msg->id));
+                               goto done;
                        }
+               }
 
+               construct_info_data(data, msg->type, msg->field, id);
 
-                       /* lookup the printer if we have a name if we don't already have a 
-                          valid NT_PRINTER_INFO_LEVEL structure. And yes I'm assuming we 
-                          will always have a non-empty msg.printer_name */
-                                  
-                       if (!printer || !printer->info_2 || strcmp(msg->printer_name, printer->info_2->printername)) 
-                       {
-                       
-                               if (printer) {
-                                       free_a_printer(&printer, 2);
-                                       printer = NULL;
-                               }
-                                       
-                               result = get_a_printer(&printer, 2, msg->printer_name);
-                               if (!W_ERROR_IS_OK(result))
-                                       continue;
+               switch(msg->type) {
+               case PRINTER_NOTIFY_TYPE:
+                       if (printer_notify_table[msg->field].fn)
+                               printer_notify_table[msg->field].fn(
+                                       msg, data, mem_ctx);
+                       else
+                               goto done;
+                       break;
+               case JOB_NOTIFY_TYPE:
+                       if (job_notify_table[msg->field].fn)
+                               job_notify_table[msg->field].fn(
+                                       msg, data, mem_ctx);
+                       else
+                               goto done;
+                       break;
+               default:
+                       DEBUG(5, ("Unknown notification type %d\n", 
+                                 msg->type));
+                       goto done;
+               }
+
+               if (!p->notify.flags)
+                       cli_spoolss_rrpcn(
+                               &cli, mem_ctx, &p->notify.client_hnd, 
+                               data_len, data, p->notify.change, 0);
+               else {
+                       NT_PRINTER_INFO_LEVEL *printer = NULL;
+
+                       get_a_printer(&printer, 2, msg->printer);
+
+                       if (!printer) {
+                               DEBUG(5, ("unable to load info2 for %s\n",
+                                         msg->printer));
+                               goto done;
                        }
 
-                       /* issue the client call */
+                       /* XXX: This needs to be updated for 
+                           PRINTER_CHANGE_SET_PRINTER_DRIVER. */ 
 
-                       result = srv_spoolss_send_event_to_client(find_printer, &cli, msg, printer);
-                       
-                       if (!W_ERROR_IS_OK(result)) {
-                               DEBUG(5,("send_spoolss_event_notification: Event notification failed [%s]\n",
-                                       dos_errstr(result)));
+                       cli_spoolss_routerreplyprinter(
+                               &cli, mem_ctx, &p->notify.client_hnd,
+                               0, printer->info_2->changeid);
+
+                       free_a_printer(&printer, 2);
                }
        }
-}
-
+done:
        return;
 }
-/***************************************************************************
- Receive the notify message and decode the message.  Do not send 
- notification if we sent this originally as that would result in 
- duplicates.
-****************************************************************************/
 
-static void srv_spoolss_receive_message(int msg_type, pid_t src, void *buf, size_t len)
+/* Receive a notify2 message */
+
+static void receive_notify2_message(int msg_type, pid_t src, void *buf, 
+                                   size_t len)
 {
-       PRINTER_MESSAGE_INFO msg;
-       
-       if (len < sizeof(msg)) {
-               DEBUG(2,("srv_spoolss_receive_message: got incorrect message size (%u)!\n", (unsigned int)len));
-               return;
-       }
+       struct spoolss_notify_msg msg;
+       int offset = 0;
+       TALLOC_CTX *mem_ctx = talloc_init();
 
-       memcpy(&msg, buf, sizeof(PRINTER_MESSAGE_INFO));
-       
-       DEBUG(10,("srv_spoolss_receive_message: Got message printer change [queue = %s] low=0x%x  high=0x%x flags=0x%x\n",
-               msg.printer_name, (unsigned int)msg.low, (unsigned int)msg.high, msg.flags ));
+       /* Unpack message */
 
-       /* Iterate the printer list */
-       
-       send_spoolss_event_notification(&msg);
+       ZERO_STRUCT(msg);
+
+       offset += tdb_unpack((char *)buf + offset, len - offset, "f",
+                            msg.printer);
        
+       offset += tdb_unpack((char *)buf + offset, len - offset, "ddddd",
+                            &msg.type, &msg.field, &msg.id, &msg.len, &msg.flags);
+
+       if (msg.len == 0)
+               tdb_unpack((char *)buf + offset, len - offset, "dd",
+                          &msg.notify.value[0], &msg.notify.value[1]);
+       else
+               tdb_unpack((char *)buf + offset, len - offset, "B", 
+                          &msg.len, &msg.notify.data);
+
+       DEBUG(3, ("got NOTIFY2 message, type %d, field 0x%02x, flags 0x%04x\n",
+                 msg.type, msg.field, msg.flags));
+
+       if (msg.len == 0)
+               DEBUG(3, ("value1 = %d, value2 = %d\n", msg.notify.value[0],
+                         msg.notify.value[1]));
+       else
+               dump_data(3, msg.notify.data, msg.len);
+
+       /* Process message */
+
+       process_notify2_message(&msg, mem_ctx);
+
+       /* Free message */
+
+       if (msg.len > 0)
+               free(msg.notify.data);
+
+       talloc_destroy(mem_ctx);
 }
 
 /***************************************************************************
- Send a notify event.
-****************************************************************************/
-
-static BOOL srv_spoolss_sendnotify(char* printer_name, uint32 high, uint32 low, uint32 flags)
+ Server wrapper for cli_spoolss_routerreplyprinter() since the client 
+ function can only send a single change notification at a time.
+ FIXME!!!  only handles one change currently (PRINTER_CHANGE_SET_PRINTER_DRIVER)
+ --jerry
+ **************************************************************************/
+static WERROR srv_spoolss_routerreplyprinter (struct cli_state *reply_cli, TALLOC_CTX *mem_ctx,
+                                       POLICY_HND *pol, PRINTER_MESSAGE_INFO *info,
+                                       NT_PRINTER_INFO_LEVEL *printer)                         
 {
-       char msg[sizeof(PRINTER_MESSAGE_INFO)];
-       PRINTER_MESSAGE_INFO info;
+       WERROR result;
+       uint32 condition = 0x0;
        
-       ZERO_STRUCT(info);
-
-       info.low        = low;
-       info.high       = high;
-       info.flags      = flags;
-       fstrcpy(info.printer_name, printer_name);
+       if (info->flags & PRINTER_MESSAGE_DRIVER)
+               condition = PRINTER_CHANGE_SET_PRINTER_DRIVER;
        
-       memcpy(msg, &info, sizeof(PRINTER_MESSAGE_INFO));       
-
-       DEBUG(10,("srv_spoolss_sendnotify: printer change low=0x%x  high=0x%x [%s], flags=0x%x\n", 
-               low, high, printer_name, flags));
-               
-       message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, msg, sizeof(PRINTER_MESSAGE_INFO), 
-               False, NULL);
+       result = cli_spoolss_routerreplyprinter(reply_cli, mem_ctx, pol, condition, 
+                       printer->info_2->changeid);
 
-       return True;
-}      
+       return result;
+}
 
 /********************************************************************
  Send a message to ourself about new driver being installed
  so we can upgrade the information for each printer bound to this
  driver
-********************************************************************/
-
+ ********************************************************************/
 static BOOL srv_spoolss_drv_upgrade_printer(char* drivername)
 {
        int len = strlen(drivername);
-
+       
        if (!len)
                return False;
 
        DEBUG(10,("srv_spoolss_drv_upgrade_printer: Sending message about driver upgrade [%s]\n",
                drivername));
-
+               
        message_send_pid(sys_getpid(), MSG_PRINTER_DRVUPGRADE, drivername, len+1, False);
+
        return True;
 }
 
 /**********************************************************************
  callback to receive a MSG_PRINTER_DRVUPGRADE message and interate
- over all printers, upgrading ones as neessary
-**********************************************************************/
-
+ over all printers, upgrading ones as neessary 
+ **********************************************************************/
 void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
 {
        fstring drivername;
        int snum;
        int n_services = lp_numservices();
-
+       
        len = MIN(len,sizeof(drivername)-1);
        strncpy(drivername, buf, len);
-
+       
        DEBUG(10,("do_drv_upgrade_printer: Got message for new driver [%s]\n", drivername ));
 
        /* Iterate the printer list */
-
+       
        for (snum=0; snum<n_services; snum++)
        {
                if (lp_snum_ok(snum) && lp_print_ok(snum) ) 
                {
                        WERROR result;
                        NT_PRINTER_INFO_LEVEL *printer = NULL;
-
+                       
                        result = get_a_printer(&printer, 2, lp_servicename(snum));
                        if (!W_ERROR_IS_OK(result))
                                continue;
-
+                               
                        if (printer && printer->info_2 && !strcmp(drivername, printer->info_2->drivername)) 
                        {
                                DEBUG(6,("Updating printer [%s]\n", printer->info_2->printername));
@@ -828,16 +949,16 @@ void do_drv_upgrade_printer(int msg_type, pid_t src, void *buf, size_t len)
                                
                                result = mod_a_printer(*printer, 2);
                                if (!W_ERROR_IS_OK(result)) {
-                                       DEBUG(3,("do_drv_upgrade_printer: mod_a_printer() failed with status [%s]\n",
-                                       dos_errstr(result)));
+                                       DEBUG(3,("do_drv_upgrade_printer: mod_a_printer() failed with status [%s]\n", 
+                                               dos_errstr(result)));
                                }
                        }
                        
-                       free_a_printer(&printer, 2);
+                       free_a_printer(&printer, 2);                    
                }
        }
-
-       /* all done */
+       
+       /* all done */  
 }
 
 /********************************************************************
@@ -1005,7 +1126,7 @@ Can't find printer handle we created for printer %s\n", name ));
                return WERR_INVALID_PRINTER_NAME;
        }
 
-/*
+       /*
           First case: the user is opening the print server:
 
           Disallow MS AddPrinterWizard if parameter disables it. A Win2k
@@ -1381,10 +1502,6 @@ WERROR _spoolss_deleteprinter(pipes_struct *p, SPOOL_Q_DELETEPRINTER *q_u, SPOOL
 
        update_c_setprinter(False);
 
-       if (W_ERROR_IS_OK(result)) {
-               srv_spoolss_sendnotify(Printer->dev.handlename, 0, PRINTER_CHANGE_DELETE_PRINTER, 0x0);
-       }
-               
        return result;
 }
 
@@ -1683,6 +1800,96 @@ WERROR _spoolss_getprinterdata(pipes_struct *p, SPOOL_Q_GETPRINTERDATA *q_u, SPO
                return WERR_OK;
 }
 
+/*********************************************************
+ Connect to the client machine.
+**********************************************************/
+
+static BOOL spoolss_connect_to_client(struct cli_state *the_cli, char *remote_machine)
+{
+       extern pstring global_myname;
+
+       ZERO_STRUCTP(the_cli);
+       if(cli_initialise(the_cli) == NULL) {
+               DEBUG(0,("connect_to_client: unable to initialize client connection.\n"));
+               return False;
+       }
+
+       if(!resolve_name( remote_machine, &the_cli->dest_ip, 0x20)) {
+               DEBUG(0,("connect_to_client: Can't resolve address for %s\n", remote_machine));
+               cli_shutdown(the_cli);
+       return False;
+       }
+
+       if (ismyip(the_cli->dest_ip)) {
+               DEBUG(0,("connect_to_client: Machine %s is one of our addresses. Cannot add to ourselves.\n", remote_machine));
+               cli_shutdown(the_cli);
+               return False;
+       }
+
+       if (!cli_connect(the_cli, remote_machine, &the_cli->dest_ip)) {
+               DEBUG(0,("connect_to_client: unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+               cli_shutdown(the_cli);
+               return False;
+       }
+  
+       if (!attempt_netbios_session_request(the_cli, global_myname, remote_machine, &the_cli->dest_ip)) {
+               DEBUG(0,("connect_to_client: machine %s rejected the NetBIOS session request.\n", 
+                       remote_machine));
+               return False;
+       }
+
+       the_cli->protocol = PROTOCOL_NT1;
+    
+       if (!cli_negprot(the_cli)) {
+               DEBUG(0,("connect_to_client: machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+               cli_shutdown(the_cli);
+               return False;
+       }
+
+       if (the_cli->protocol != PROTOCOL_NT1) {
+               DEBUG(0,("connect_to_client: machine %s didn't negotiate NT protocol.\n", remote_machine));
+               cli_shutdown(the_cli);
+               return False;
+       }
+    
+       /*
+        * Do an anonymous session setup.
+        */
+    
+       if (!cli_session_setup(the_cli, "", "", 0, "", 0, "")) {
+               DEBUG(0,("connect_to_client: machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+               cli_shutdown(the_cli);
+               return False;
+       }
+    
+       if (!(the_cli->sec_mode & 1)) {
+               DEBUG(0,("connect_to_client: machine %s isn't in user level security mode\n", remote_machine));
+               cli_shutdown(the_cli);
+               return False;
+       }
+    
+       if (!cli_send_tconX(the_cli, "IPC$", "IPC", "", 1)) {
+               DEBUG(0,("connect_to_client: machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(the_cli) ));
+               cli_shutdown(the_cli);
+               return False;
+       }
+
+       /*
+        * Ok - we have an anonymous connection to the IPC$ share.
+        * Now start the NT Domain stuff :-).
+        */
+
+       if(cli_nt_session_open(the_cli, PIPE_SPOOLSS) == False) {
+               DEBUG(0,("connect_to_client: unable to open the domain client session to machine %s. Error was : %s.\n", remote_machine, cli_errstr(the_cli)));
+               cli_nt_session_close(the_cli);
+               cli_ulogoff(the_cli);
+               cli_shutdown(the_cli);
+               return False;
+       } 
+
+       return True;
+}
+
 /***************************************************************************
  Connect to the client.
 ****************************************************************************/
@@ -1703,15 +1910,14 @@ static BOOL srv_spoolss_replyopenprinter(char *printer, uint32 localprinter, uin
                if(!spoolss_connect_to_client(&cli, unix_printer))
                        return False;
                        
-               message_register(MSG_PRINTER_NOTIFY, srv_spoolss_receive_message);
-
+               message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message);
        }
 
        smb_connections++;
 
        result = cli_spoolss_reply_open_printer(&cli, cli.mem_ctx, printer, localprinter, 
                        type, handle);
-
+                       
        if (!W_ERROR_IS_OK(result))
                DEBUG(5,("srv_spoolss_reply_open_printer: Client RPC returned [%s]\n",
                        dos_errstr(result)));
@@ -1757,15 +1963,17 @@ WERROR _spoolss_rffpcnex(pipes_struct *p, SPOOL_Q_RFFPCNEX *q_u, SPOOL_R_RFFPCNE
 
        Printer->notify.option=dup_spool_notify_option(option);
 
-       unistr2_to_ascii(Printer->notify.localmachine, localmachine, sizeof(Printer->notify.localmachine)-1);
+       unistr2_to_ascii(Printer->notify.localmachine, localmachine, 
+                      sizeof(Printer->notify.localmachine)-1);
+
+       /* Connect to the client machine and send a ReplyOpenPrinter */
 
-       /* connect to the client machine and send a ReplyOpenPrinter */
-       if(srv_spoolss_replyopenprinter(Printer->notify.localmachine,
+       if(!srv_spoolss_replyopenprinter(Printer->notify.localmachine,
                                        Printer->notify.printerlocal, 1,
                                        &Printer->notify.client_hnd))
-       {
-               Printer->notify.client_connected=True;
-       }
+               return WERR_SERVER_UNAVAILABLE;
+
+       Printer->notify.client_connected=True;
 
        return WERR_OK;
 }
@@ -1787,7 +1995,7 @@ 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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
 
        if (!data->notify_data.data.string) {
@@ -1822,7 +2030,7 @@ void spoolss_notify_printer_name(int snum,
 
        len = rpcstr_push(temp, p, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1848,7 +2056,7 @@ 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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1876,7 +2084,7 @@ 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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1902,7 +2110,8 @@ 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 - 1;
+
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1931,7 +2140,7 @@ void spoolss_notify_comment(int snum,
        else
                len = rpcstr_push(temp, printer->info_2->comment, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1958,7 +2167,7 @@ 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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -1997,7 +2206,7 @@ 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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -2024,7 +2233,7 @@ 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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -2051,7 +2260,7 @@ 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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -2078,7 +2287,7 @@ 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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -2238,7 +2447,7 @@ static void spoolss_notify_username(int snum,
 
        len = rpcstr_push(temp, queue->fs_user, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -2278,7 +2487,7 @@ static void spoolss_notify_job_name(int snum,
 
        len = rpcstr_push(temp, queue->fs_file, sizeof(temp)-2, STR_TERMINATE);
 
-       data->notify_data.data.length = len / 2 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -2328,7 +2537,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 - 1;
+       data->notify_data.data.length = len;
        data->notify_data.data.string = (uint16 *)talloc(mem_ctx, len);
        
        if (!data->notify_data.data.string) {
@@ -2452,8 +2661,6 @@ static void spoolss_notify_submitted_time(int snum,
        SSVAL(p, 14, st.milliseconds);
 }
 
-#define END 65535
-
 struct s_notify_info_data_table
 {
        uint16 type;
@@ -2471,18 +2678,18 @@ struct s_notify_info_data_table
 
 struct s_notify_info_data_table notify_info_data_table[] =
 {
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME,         "PRINTER_NOTIFY_SERVER_NAME",         POINTER,   spoolss_notify_server_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME,        "PRINTER_NOTIFY_PRINTER_NAME",        POINTER,   spoolss_notify_printer_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME,          "PRINTER_NOTIFY_SHARE_NAME",          POINTER,   spoolss_notify_share_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME,           "PRINTER_NOTIFY_PORT_NAME",           POINTER,   spoolss_notify_port_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME,         "PRINTER_NOTIFY_DRIVER_NAME",         POINTER,   spoolss_notify_driver_name },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT,             "PRINTER_NOTIFY_COMMENT",             POINTER,   spoolss_notify_comment },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION,            "PRINTER_NOTIFY_LOCATION",            POINTER,   spoolss_notify_location },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SERVER_NAME,         "PRINTER_NOTIFY_SERVER_NAME",         STRING,   spoolss_notify_server_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME,        "PRINTER_NOTIFY_PRINTER_NAME",        STRING,   spoolss_notify_printer_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME,          "PRINTER_NOTIFY_SHARE_NAME",          STRING,   spoolss_notify_share_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME,           "PRINTER_NOTIFY_PORT_NAME",           STRING,   spoolss_notify_port_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME,         "PRINTER_NOTIFY_DRIVER_NAME",         STRING,   spoolss_notify_driver_name },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT,             "PRINTER_NOTIFY_COMMENT",             STRING,   spoolss_notify_comment },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION,            "PRINTER_NOTIFY_LOCATION",            STRING,   spoolss_notify_location },
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DEVMODE,             "PRINTER_NOTIFY_DEVMODE",             POINTER,   spoolss_notify_devmode },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SEPFILE,             "PRINTER_NOTIFY_SEPFILE",             POINTER,   spoolss_notify_sepfile },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINT_PROCESSOR,     "PRINTER_NOTIFY_PRINT_PROCESSOR",     POINTER,   spoolss_notify_print_processor },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PARAMETERS,          "PRINTER_NOTIFY_PARAMETERS",          POINTER,   spoolss_notify_parameters },
-{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DATATYPE,            "PRINTER_NOTIFY_DATATYPE",            POINTER,   spoolss_notify_datatype },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SEPFILE,             "PRINTER_NOTIFY_SEPFILE",             STRING,   spoolss_notify_sepfile },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINT_PROCESSOR,     "PRINTER_NOTIFY_PRINT_PROCESSOR",     STRING,   spoolss_notify_print_processor },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PARAMETERS,          "PRINTER_NOTIFY_PARAMETERS",          STRING,   spoolss_notify_parameters },
+{ PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DATATYPE,            "PRINTER_NOTIFY_DATATYPE",            STRING,   spoolss_notify_datatype },
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SECURITY_DESCRIPTOR, "PRINTER_NOTIFY_SECURITY_DESCRIPTOR", POINTER,   spoolss_notify_security_desc },
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_ATTRIBUTES,          "PRINTER_NOTIFY_ATTRIBUTES",          ONE_VALUE, spoolss_notify_attributes },
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRIORITY,            "PRINTER_NOTIFY_PRIORITY",            ONE_VALUE, spoolss_notify_priority },
@@ -2497,20 +2704,20 @@ struct s_notify_info_data_table notify_info_data_table[] =
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PAGES_PRINTED,       "PRINTER_NOTIFY_PAGES_PRINTED",       POINTER,   NULL },
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_TOTAL_BYTES,         "PRINTER_NOTIFY_TOTAL_BYTES",         POINTER,   NULL },
 { PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_BYTES_PRINTED,       "PRINTER_NOTIFY_BYTES_PRINTED",       POINTER,   NULL },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINTER_NAME,            "JOB_NOTIFY_PRINTER_NAME",            POINTER,   spoolss_notify_printer_name },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_MACHINE_NAME,            "JOB_NOTIFY_MACHINE_NAME",            POINTER,   spoolss_notify_server_name },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PORT_NAME,               "JOB_NOTIFY_PORT_NAME",               POINTER,   spoolss_notify_port_name },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_USER_NAME,               "JOB_NOTIFY_USER_NAME",               POINTER,   spoolss_notify_username },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_NOTIFY_NAME,             "JOB_NOTIFY_NOTIFY_NAME",             POINTER,   spoolss_notify_username },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DATATYPE,                "JOB_NOTIFY_DATATYPE",                POINTER,   spoolss_notify_datatype },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINT_PROCESSOR,         "JOB_NOTIFY_PRINT_PROCESSOR",         POINTER,   spoolss_notify_print_processor },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PARAMETERS,              "JOB_NOTIFY_PARAMETERS",              POINTER,   spoolss_notify_parameters },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DRIVER_NAME,             "JOB_NOTIFY_DRIVER_NAME",             POINTER,   spoolss_notify_driver_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINTER_NAME,            "JOB_NOTIFY_PRINTER_NAME",            STRING,   spoolss_notify_printer_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_MACHINE_NAME,            "JOB_NOTIFY_MACHINE_NAME",            STRING,   spoolss_notify_server_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PORT_NAME,               "JOB_NOTIFY_PORT_NAME",               STRING,   spoolss_notify_port_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_USER_NAME,               "JOB_NOTIFY_USER_NAME",               STRING,   spoolss_notify_username },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_NOTIFY_NAME,             "JOB_NOTIFY_NOTIFY_NAME",             STRING,   spoolss_notify_username },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DATATYPE,                "JOB_NOTIFY_DATATYPE",                STRING,   spoolss_notify_datatype },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRINT_PROCESSOR,         "JOB_NOTIFY_PRINT_PROCESSOR",         STRING,   spoolss_notify_print_processor },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_PARAMETERS,              "JOB_NOTIFY_PARAMETERS",              STRING,   spoolss_notify_parameters },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DRIVER_NAME,             "JOB_NOTIFY_DRIVER_NAME",             STRING,   spoolss_notify_driver_name },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_DEVMODE,                 "JOB_NOTIFY_DEVMODE",                 POINTER,   spoolss_notify_devmode },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS,                  "JOB_NOTIFY_STATUS",                  ONE_VALUE, spoolss_notify_job_status },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS_STRING,           "JOB_NOTIFY_STATUS_STRING",           POINTER,   spoolss_notify_job_status_string },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_STATUS_STRING,           "JOB_NOTIFY_STATUS_STRING",           STRING,   spoolss_notify_job_status_string },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_SECURITY_DESCRIPTOR,     "JOB_NOTIFY_SECURITY_DESCRIPTOR",     POINTER,   NULL },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DOCUMENT,                "JOB_NOTIFY_DOCUMENT",                POINTER,   spoolss_notify_job_name },
+{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_DOCUMENT,                "JOB_NOTIFY_DOCUMENT",                STRING,   spoolss_notify_job_name },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PRIORITY,                "JOB_NOTIFY_PRIORITY",                ONE_VALUE, spoolss_notify_priority },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_POSITION,                "JOB_NOTIFY_POSITION",                ONE_VALUE, spoolss_notify_job_position },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_SUBMITTED,               "JOB_NOTIFY_SUBMITTED",               POINTER,   spoolss_notify_submitted_time },
@@ -2520,8 +2727,6 @@ struct s_notify_info_data_table notify_info_data_table[] =
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_PAGES,             "JOB_NOTIFY_TOTAL_PAGES",             ONE_VALUE, spoolss_notify_total_pages },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_PAGES_PRINTED,           "JOB_NOTIFY_PAGES_PRINTED",           ONE_VALUE, spoolss_notify_pages_printed },
 { JOB_NOTIFY_TYPE,     JOB_NOTIFY_TOTAL_BYTES,             "JOB_NOTIFY_TOTAL_BYTES",             ONE_VALUE, spoolss_notify_job_size },
-{ JOB_NOTIFY_TYPE,     JOB_NOTIFY_BYTES_PRINTED,           "JOB_NOTIFY_BYTES_PRINTED",           ONE_VALUE, NULL },
-{ END,                 END,                                "",                                   END,       NULL }
 };
 
 /*******************************************************************
@@ -2532,43 +2737,46 @@ static uint32 size_of_notify_info_data(uint16 type, uint16 field)
 {
        int i=0;
 
-       while (notify_info_data_table[i].type != END)
-       {
-               if ( (notify_info_data_table[i].type == type ) &&
-                    (notify_info_data_table[i].field == field ) )
-               {
-                       return (notify_info_data_table[i].size);
+       for (i = 0; i < sizeof(notify_info_data_table); i++) {
+               if (notify_info_data_table[i].type == type &&
+                   notify_info_data_table[i].field == field) {
+                       switch(notify_info_data_table[i].size) {
+                       case ONE_VALUE:
+                       case TWO_VALUE:
+                               return 1;
+                       case STRING:
+                               return 2;
+
+                       /* The only pointer notify data I have seen on
+                          the wire is the submitted time and this has
+                          the notify size set to 4. -tpot */
+
+                       case POINTER:
+                               return 4;
+                       }
                }
-               i++;
        }
-       return (65535);
+
+       DEBUG(5, ("invalid notify data type %d/%d\n", type, field));
+
+       return 0;
 }
 
 /*******************************************************************
  Return the type of notify_info_data.
 ********************************************************************/
 
-static BOOL type_of_notify_info_data(uint16 type, uint16 field)
+static int type_of_notify_info_data(uint16 type, uint16 field)
 {
        int i=0;
 
-       while (notify_info_data_table[i].type != END)
-       {
-               if ( (notify_info_data_table[i].type == type ) &&
-                    (notify_info_data_table[i].field == field ) )
-               {
-                       if (notify_info_data_table[i].size == POINTER)
-                       {
-                               return (False);
-                       }
-                       else
-                       {
-                               return (True);
-                       }
-               }
-               i++;
+       for (i = 0; i < sizeof(notify_info_data_table); i++) {
+               if (notify_info_data_table[i].type == type &&
+                   notify_info_data_table[i].field == field)
+                       return notify_info_data_table[i].size;
        }
-       return (False);
+
+       return False;
 }
 
 /****************************************************************************
@@ -2576,21 +2784,18 @@ static BOOL type_of_notify_info_data(uint16 type, uint16 field)
 
 static int search_notify(uint16 type, uint16 field, int *value)
 {      
-       int j;
-       BOOL found;
+       int i;
 
-       for (j=0, found=False; found==False && notify_info_data_table[j].type != END ; j++)
-       {
-               if ( (notify_info_data_table[j].type  == type  ) &&
-                    (notify_info_data_table[j].field == field ) )
-                       found=True;
+       for (i = 0; i < sizeof(notify_info_data_table); i++) {
+               if (notify_info_data_table[i].type == type &&
+                   notify_info_data_table[i].field == field &&
+                   notify_info_data_table[i].fn != NULL) {
+                       *value = i;
+                       return True;
+               }
        }
-       *value=--j;
-
-       if ( found && (notify_info_data_table[j].fn != NULL) )
-               return True;
-       else
-               return False;   
+       
+       return False;   
 }
 
 /****************************************************************************
@@ -2601,7 +2806,12 @@ void construct_info_data(SPOOL_NOTIFY_INFO_DATA *info_data, uint16 type, uint16
        info_data->type     = type;
        info_data->field    = field;
        info_data->reserved = 0;
-       info_data->id       = id;
+
+       if (type == JOB_NOTIFY_TYPE)
+               info_data->id = id;
+       else 
+               info_data->id = 0;
+
        info_data->size     = size_of_notify_info_data(type, field);
        info_data->enc_type = type_of_notify_info_data(type, field);
 }
@@ -2650,7 +2860,7 @@ static BOOL construct_notify_printer_info(SPOOL_NOTIFY_INFO *info, int
 
                current_data=&info->data[info->count];
 
-               construct_info_data(current_data, type, field, id);             
+               construct_info_data(current_data, type, field, id);
 
                DEBUG(10,("construct_notify_printer_info: calling [%s]  snum=%d  printername=[%s])\n",
                                notify_info_data_table[j].name, snum, printer->info_2->printername ));
@@ -2892,7 +3102,6 @@ static WERROR printer_notify_info(pipes_struct *p, POLICY_HND *hnd, SPOOL_NOTIFY
 WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCNEX *r_u)
 {
        POLICY_HND *handle = &q_u->handle;
-/*     uint32 change = q_u->change; - notused. */
 /*     SPOOL_NOTIFY_OPTION *option = q_u->option; - notused. */
        SPOOL_NOTIFY_INFO *info = &r_u->info;
 
@@ -2910,17 +3119,19 @@ WERROR _spoolss_rfnpcnex( pipes_struct *p, SPOOL_Q_RFNPCNEX *q_u, SPOOL_R_RFNPCN
 
        DEBUG(4,("Printer type %x\n",Printer->printer_type));
 
-       /* jfm: the change value isn't used right now.
-        *      we will honour it when
-        *      a) we'll be able to send notification to the client
-        *      b) we'll have a way to communicate between the spoolss process.
-        *
-        *      same thing for option->flags
+       /*
+        *      We are now using the change value, and 
         *      I should check for PRINTER_NOTIFY_OPTIONS_REFRESH but as
         *      I don't have a global notification system, I'm sending back all the
         *      informations even when _NOTHING_ has changed.
         */
 
+       /* We need to keep track of the change value to send back in 
+           RRPCN replies otherwise our updates are ignored. */
+
+       if (Printer->notify.client_connected)
+               Printer->notify.change = q_u->change;
+
        /* just ignore the SPOOL_NOTIFY_OPTION */
        
        switch (Printer->printer_type) {
@@ -3051,7 +3262,6 @@ static BOOL construct_printer_info_0(PRINTER_INFO_0 *printer, int snum)
  * construct_printer_info_1
  * fill a printer_info_1 struct
  ********************************************************************/
-
 static BOOL construct_printer_info_1(uint32 flags, PRINTER_INFO_1 *printer, int snum)
 {
        pstring chaine;
@@ -3126,8 +3336,10 @@ static DEVICEMODE *construct_dev_mode(int snum)
        if (printer->info_2->devmode)
                ntdevmode = dup_nt_devicemode(printer->info_2->devmode);
 
-       if (ntdevmode == NULL)
+       if (ntdevmode == NULL) {
+               DEBUG(5, ("BONG! There was no device mode!\n"));
                goto fail;
+       }
 
        DEBUGADD(8,("loading DEVICEMODE\n"));
 
@@ -3545,9 +3757,9 @@ static WERROR enum_all_printers_info_2(NEW_BUFFER *buffer, uint32 offered, uint3
        }
        
        /* check the required size. */  
-       for (i=0; i<*returned; i++)
+       for (i=0; i<*returned; i++) 
                (*needed) += spoolss_size_printer_info_2(&printers[i]);
-
+       
        if (!alloc_buffer_size(buffer, *needed)) {
                for (i=0; i<*returned; i++) {
                        free_devmode(printers[i].devmode);
@@ -3777,7 +3989,7 @@ static WERROR getprinter_level_2(int snum, NEW_BUFFER *buffer, uint32 offered, u
        
        /* check the required size. */  
        *needed += spoolss_size_printer_info_2(printer);
-
+       
        if (!alloc_buffer_size(buffer, *needed)) {
                free_printer_info_2(printer);
                return WERR_INSUFFICIENT_BUFFER;
@@ -4824,6 +5036,7 @@ static BOOL check_printer_ok(NT_PRINTER_INFO_LEVEL_2 *info, int snum)
 
 static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
 {
+       extern userdom_struct current_user_info;
        char *cmd = lp_addprinter_cmd();
        char **qlines;
        pstring command;
@@ -4838,14 +5051,13 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
                        get_called_name());
        /* change \ to \\ for the shell */
        all_string_sub(driverlocation,"\\","\\\\",sizeof(pstring));
-       standard_sub_basic("", remote_machine);
-
+       standard_sub_basic(current_user_info.smb_name, remote_machine);
+       
        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, remote_machine);
 
-       /* Convert script args to unix-codepage */
        DEBUG(10,("Running [%s]\n", command));
        ret = smbrun(command, &fd);
        DEBUGADD(10,("returned [%d]\n", ret));
@@ -4873,9 +5085,6 @@ static BOOL add_printer_hook(NT_PRINTER_INFO_LEVEL *printer)
        }
 
        file_lines_free(qlines);
-
-       update_server_announce_as_printserver();
-
        return True;
 }
 
@@ -5139,13 +5348,10 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
        int snum;
        NT_PRINTER_INFO_LEVEL *printer = NULL, *old_printer = NULL;
        Printer_entry *Printer = find_printer_index_by_hnd(p, handle);
-       PRINTER_MESSAGE_INFO msg;
        WERROR result;
 
        DEBUG(8,("update_printer\n"));
-       
-       ZERO_STRUCT(msg);
-       
+
        result = WERR_OK;
 
        if (level!=2) {
@@ -5263,7 +5469,7 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
                                DEBUG(5,("update_printer: Error restoring driver initialization data for driver [%s]!\n",
                                        printer->info_2->drivername));
                        }
-                       msg.flags |= PRINTER_MESSAGE_DRIVER;
+                       notify_printer_driver(snum, printer->info_2->drivername);
                }
        }
 
@@ -5274,26 +5480,18 @@ static WERROR update_printer(pipes_struct *p, POLICY_HND *handle, uint32 level,
           all the possible changes                                         */
 
        if (!strequal(printer->info_2->comment, old_printer->info_2->comment))
-               msg.flags |= PRINTER_MESSAGE_COMMENT;
+               notify_printer_comment(snum, printer->info_2->comment);
 
        if (!strequal(printer->info_2->sharename, old_printer->info_2->sharename))
-               msg.flags |= PRINTER_MESSAGE_SHARENAME;
+               notify_printer_sharename(snum, printer->info_2->sharename);
 
        if (!strequal(printer->info_2->portname, old_printer->info_2->portname))
-               msg.flags |= PRINTER_MESSAGE_PORT;
+               notify_printer_port(snum, printer->info_2->portname);
 
        if (!strequal(printer->info_2->location, old_printer->info_2->location))
-               msg.flags |= PRINTER_MESSAGE_LOCATION;
-
-       msg.low = PRINTER_CHANGE_ADD_PRINTER;
-       fstrcpy(msg.printer_name, printer->info_2->printername);
+               notify_printer_location(snum, printer->info_2->location);
 
-       /* only send a notify if something changed */
-       if (msg.flags) {
-               srv_spoolss_sendnotify(msg.printer_name, 0, PRINTER_CHANGE_ADD_PRINTER, msg.flags);
-       }
-
- done:
+done:
        free_a_printer(&printer, 2);
        free_a_printer(&old_printer, 2);
 
@@ -5411,7 +5609,7 @@ static void fill_job_info_1(JOB_INFO_1 *job_info, print_queue_struct *queue,
 
 static BOOL fill_job_info_2(JOB_INFO_2 *job_info, print_queue_struct *queue,
                             int position, int snum, 
-                           NT_PRINTER_INFO_LEVEL *ntprinter, 
+                           NT_PRINTER_INFO_LEVEL *ntprinter,
                            DEVICEMODE *devmode)
 {
        pstring temp_name;
@@ -5528,7 +5726,7 @@ static WERROR enumjobs_level2(print_queue_struct *queue, int snum,
                *returned = 0;
                goto done;
        }
-
+               
        if (!(devmode = construct_dev_mode(snum))) {
                *returned = 0;
                result = WERR_NOMEM;
@@ -5571,6 +5769,7 @@ static WERROR enumjobs_level2(print_queue_struct *queue, int snum,
        SAFE_FREE(info);
 
        return result;
+
 }
 
 /****************************************************************************
@@ -6516,9 +6715,6 @@ static WERROR spoolss_addprinterex_level_2( pipes_struct *p, const UNISTR2 *uni_
        }
 
        update_c_setprinter(False);
-
-       srv_spoolss_sendnotify(printer->info_2->printername, 0, PRINTER_CHANGE_ADD_PRINTER, 0x0);
-
        free_a_printer(&printer,2);
 
        return WERR_OK;
@@ -6593,27 +6789,27 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u,
        }
 
        /* BEGIN_ADMIN_LOG */
-       switch(level) {
-               case 3:
-                       sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.",
-                               driver.info_3->name,drv_ver_to_os[driver.info_3->cversion],uidtoname(user.uid));
-                       fstrcpy(driver_name, driver.info_3->name);
-                       break;
-               case 6:
-                       sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.",
-                               driver.info_6->name,drv_ver_to_os[driver.info_6->version],uidtoname(user.uid));
-                       fstrcpy(driver_name, driver.info_6->name);
-                       break;
-       }
+        switch(level) {
+           case 3:
+               sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.",
+                       driver.info_3->name,drv_ver_to_os[driver.info_3->cversion],uidtoname(user.uid));
+               fstrcpy(driver_name, driver.info_3->name);
+               break;
+           case 6:   
+               sys_adminlog(LOG_INFO,"Added printer driver. Print driver name: %s. Print driver OS: %s. Administrator name: %s.",
+                       driver.info_6->name,drv_ver_to_os[driver.info_6->version],uidtoname(user.uid));
+               fstrcpy(driver_name, driver.info_6->name);
+               break;
+        }
        /* END_ADMIN_LOG */
 
-       /*
+       /* 
         * I think this is where he DrvUpgradePrinter() hook would be
         * be called in a driver's interface DLL on a Windows NT 4.0/2k
         * server.  Right now, we just need to send ourselves a message
-        * to update each printer bound to this driver.   --jerry
+        * to update each printer bound to this driver.   --jerry       
         */
-
+        
        if (!srv_spoolss_drv_upgrade_printer(driver_name)) {
                DEBUG(0,("_spoolss_addprinterdriver: Failed to send message about upgrading driver [%s]!\n",
                        driver_name));
@@ -6656,9 +6852,9 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u,
                                /*
                                 * No 2k/Xp driver found, delete init data (if any) for the new Nt driver.
                                */
-               if (!del_driver_init(driver_name))
+                               if (!del_driver_init(driver_name))
                                        DEBUG(6,("_spoolss_addprinterdriver: del_driver_init(%s) Nt failed!\n", driver_name));
-       } else {
+                       } else {
                                /*
                                 * a 2k/Xp driver was found, don't delete init data because Nt driver will use it.
                                */
@@ -6680,10 +6876,10 @@ WERROR _spoolss_addprinterdriver(pipes_struct *p, SPOOL_Q_ADDPRINTERDRIVER *q_u,
                default:
                        DEBUG(0,("_spoolss_addprinterdriver: invalid level=%d\n", level));
                        break;
-       }
+       }
 
        
- done:
+done:
        free_a_printer_driver(driver, level);
        return err;
 }
@@ -6869,7 +7065,7 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
                if((*out_value=(uint16 *)talloc_zero(p->mem_ctx, in_value_len*sizeof(uint8))) == NULL)
                        return WERR_NOMEM;
 
-               *out_value_len = rpcstr_push((char *)*out_value, "", in_value_len, 0);
+               *out_value_len = (uint32)rpcstr_push((char *)*out_value, "", in_value_len, 0);
 
                /* the data is counted in bytes */
                *out_max_data_len = in_data_len;
@@ -6897,7 +7093,7 @@ WERROR _spoolss_enumprinterdata(pipes_struct *p, SPOOL_Q_ENUMPRINTERDATA *q_u, S
                return WERR_NOMEM;
        }
        
-       *out_value_len = rpcstr_push((char *)*out_value,value, in_value_len, 0);
+       *out_value_len = (uint32)rpcstr_push((char *)*out_value,value, in_value_len, 0);
 
        *out_type=type;
 
@@ -7604,7 +7800,7 @@ static WERROR getjob_level_2(print_queue_struct *queue, int count, int snum, uin
        free_job_info_2(info_2);        /* Also frees devmode */
        SAFE_FREE(info_2);
        free_a_printer(&ntprinter, 2);
-       
+
        return ret;
 }
 
index 2f75db9ef6caf2b782d86e4f842ce3abf6586c57..47e3f123ba76e86774d3404f350af99a8437a79f 100644 (file)
@@ -1778,10 +1778,10 @@ static NTSTATUS cmd_spoolss_enum_jobs(struct cli_state *cli,
        for (i = 0; i < num_jobs; i++) {
                switch(level) {
                case 1:
-                       display_job_info_1(&ctr.job.job_info_1[i]);
+                       display_job_info_1(ctr.job.job_info_1[i]);
                        break;
                case 2:
-                       display_job_info_2(&ctr.job.job_info_2[i]);
+                       display_job_info_2(ctr.job.job_info_2[i]);
                        break;
                default:
                        d_printf("unknown info level %d\n", level);
index 1a8b1a6adafd26786f684c840a1333dd68248a74..65519e8888f8963f42d3331abc0db2476c185b7d 100644 (file)
@@ -34,7 +34,7 @@ static struct {
        {"profile", MSG_PROFILE},
        {"profilelevel", MSG_REQ_PROFILELEVEL},
        {"debuglevel", MSG_REQ_DEBUGLEVEL},
-       {"printer-notify", MSG_PRINTER_NOTIFY},
+       {"printnotify", MSG_PRINTER_NOTIFY2 },
        {"close-share", MSG_SMB_FORCE_TDIS},
         {"samsync", MSG_SMB_SAM_SYNC},
         {"samrepl", MSG_SMB_SAM_REPL},
@@ -341,24 +341,106 @@ static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
                }
                break;
 
-       case MSG_PRINTER_NOTIFY:
-               if (!strequal(dest, "smbd")) {
-                       fprintf(stderr,"printer-notify can only be sent to smbd\n");
-                       return(False);
-               }
+               /* Send a notification message to a printer */
+
+       case MSG_PRINTER_NOTIFY2: {
+               char *cmd;
+
+               /* Read subcommand */
+
                if (!params || !params[0]) {
-                       fprintf(stderr, "printer-notify needs a printer name\n");
-                       return (False);
+                       fprintf(stderr, "Must specify subcommand:\n");
+                       fprintf(stderr, "\tqueuepause <printername>\n");
+                       fprintf(stderr, "\tqueueresume <printername>\n");
+                       return False;
                }
-               {
-                       char msg[8 + sizeof(fstring)];
-                       SIVAL(msg,0,PRINTER_CHANGE_ALL);
-                       SIVAL(msg,4,0);
-                       fstrcpy(&msg[8], params[0]);
 
-                       retval = send_message(dest, MSG_PRINTER_NOTIFY, msg, 8 + strlen(params[0]) + 1, False);
+               cmd = params[0];
+
+               /* Pause a print queue */
+
+               if (strequal(cmd, "queuepause")) {
+
+                       if (!params[1]) {
+                               fprintf(stderr, "queuepause command requires a printer name\n");
+                               return False;
+                       }
+
+                       notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED);
+                       break;
+               }
+
+               /* Resume a print queue */
+
+               if (strequal(cmd, "queueresume")) {
+
+                       if (!params[1]) {
+                               fprintf(stderr, "queueresume command requires a printer name\n");
+                               return False;
+                       }
+
+                       notify_printer_status_byname(params[1], PRINTER_STATUS_OK);
+                       break;
                }
+
+               /* Pause a print job */
+
+               if (strequal(cmd, "jobpause")) {
+                       int jobid;
+
+                       if (!params[1] || !params[2]) {
+                               fprintf(stderr, "jobpause command requires a printer name and a jobid\n");
+                               return False;
+                       }
+
+                       jobid = atoi(params[2]);
+
+                       notify_job_status_byname(
+                               params[1], jobid, JOB_STATUS_PAUSED, 
+                               SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+               }
+
+               /* Resume a print job */
+
+               if (strequal(cmd, "jobresume")) {
+                       int jobid;
+
+                       if (!params[1] || !params[2]) {
+                               fprintf(stderr, "jobresume command requires a printer name and a jobid\n");
+                               return False;
+                       }
+
+                       jobid = atoi(params[2]);
+
+                       notify_job_status_byname(
+                               params[1], jobid, JOB_STATUS_QUEUED,
+                               SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+               }
+
+               /* Delete a print job */
+
+               if (strequal(cmd, "jobdelete")) {
+                       int jobid;
+
+                       if (!params[1] || !params[2]) {
+                               fprintf(stderr, "jobdelete command requires a printer name and a jobid\n");
+                               return False;
+                       }
+
+                       jobid = atoi(params[2]);
+
+                       notify_job_status_byname(
+                               params[1], jobid, JOB_STATUS_DELETING,
+                               SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+
+                       notify_job_status_byname(
+                               params[1], jobid, JOB_STATUS_DELETING|
+                               JOB_STATUS_DELETED,
+                               SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
+               }
+
                break;
+         }
 
        case MSG_SMB_FORCE_TDIS:
                if (!strequal(dest, "smbd")) {