change notify merge from APP_HEAD
authorGerald Carter <jerry@samba.org>
Tue, 10 Sep 2002 02:38:15 +0000 (02:38 +0000)
committerGerald Carter <jerry@samba.org>
Tue, 10 Sep 2002 02:38:15 +0000 (02:38 +0000)
(This used to be commit b5227f0a645fdf2358fcb880f22e4662efdfe8e3)

source3/include/nt_printing.h
source3/rpc_client/cli_spoolss_notify.c
source3/rpc_server/srv_spoolss_nt.c

index 26d6e7e5f29ea1d2ea6852966fb5dd2268073e11..57767fc3c6b883de72cb5bf71ad617b8c84ffaa9 100644 (file)
@@ -351,7 +351,7 @@ typedef struct _form
 
 #define SPOOLSS_NOTIFY_MSG_UNIX_JOBID 0x0001    /* Job id is unix  */
 
-struct spoolss_notify_msg {
+typedef struct spoolss_notify_msg {
        fstring printer;        /* Name of printer notified */
        uint32 type;            /* Printer or job notify */
        uint32 field;           /* Notify field changed */
@@ -362,6 +362,18 @@ struct spoolss_notify_msg {
                uint32 value[2];
                char *data;
        } notify;
-};
+} SPOOLSS_NOTIFY_MSG;
+
+typedef struct {
+       fstring                 printername;
+       uint32                  num_msgs;
+       SPOOLSS_NOTIFY_MSG      *msgs;
+} SPOOLSS_NOTIFY_MSG_GROUP;
+
+typedef struct {
+       TALLOC_CTX                      *ctx;
+       uint32                          num_groups;
+       SPOOLSS_NOTIFY_MSG_GROUP        *msg_groups;
+} SPOOLSS_NOTIFY_MSG_CTR;
 
 #endif /* NT_PRINTING_H_ */
index f03046558ee5a15ef5190928ac7c76f9736fd2bd..d07ace8e0cd4b7042882cd4b6d646d270738cfb0 100644 (file)
@@ -222,6 +222,9 @@ done:
        return result;
 }
 
+/*********************************************************************
+ *********************************************************************/
 WERROR cli_spoolss_rffpcnex(struct cli_state *cli, TALLOC_CTX *mem_ctx,
                            POLICY_HND *pol, uint32 flags, uint32 options,
                            char *localmachine, uint32 printerlocal,
index a464f073fddd7b5c2dceb291ce472cb5a059ebd0..ff9ac2ce506a3f3d7b7e0df5dfc9269c33214f1d 100644 (file)
@@ -728,25 +728,177 @@ static struct notify2_message_table job_notify_table[] = {
        /* 0x17 */ { "JOB_NOTIFY_BYTES_PRINTED", NULL },
 };
 
+
+/***********************************************************************
+ Allocate talloc context for container object
+ **********************************************************************/
+static void notify_msg_ctr_init( SPOOLSS_NOTIFY_MSG_CTR *ctr )
+{
+       if ( !ctr )
+               return;
+
+       ctr->ctx = talloc_init();
+               
+       return;
+}
+
+/***********************************************************************
+ release all allocated memory and zero out structure
+ **********************************************************************/
+static void notify_msg_ctr_destroy( SPOOLSS_NOTIFY_MSG_CTR *ctr )
+{
+       if ( !ctr )
+               return;
+
+       if ( ctr->ctx )
+               talloc_destroy(ctr->ctx);
+               
+       ZERO_STRUCTP(ctr);
+               
+       return;
+}
+
+/***********************************************************************
+ **********************************************************************/
+static TALLOC_CTX* notify_ctr_getctx( SPOOLSS_NOTIFY_MSG_CTR *ctr )
+{
+       if ( !ctr )
+               return NULL;
+               
+       return ctr->ctx;
+}
+
+/***********************************************************************
+ **********************************************************************/
+static SPOOLSS_NOTIFY_MSG_GROUP* notify_ctr_getgroup( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 index )
+{
+       if ( !ctr || !ctr->msg_groups )
+               return NULL;
+       
+       if ( index >= ctr->num_groups )
+               return NULL;
+               
+       return &ctr->msg_groups[index];
+
+}
+
+/***********************************************************************
+ How many groups of change messages do we have ?
+ **********************************************************************/
+static int notify_msg_ctr_numgroups( SPOOLSS_NOTIFY_MSG_CTR *ctr )
+{
+       if ( !ctr )
+               return 0;
+               
+       return ctr->num_groups;
+}
+
+/***********************************************************************
+ Add a SPOOLSS_NOTIFY_MSG_CTR to the correct group
+ **********************************************************************/
+static int notify_msg_ctr_addmsg( SPOOLSS_NOTIFY_MSG_CTR *ctr, SPOOLSS_NOTIFY_MSG *msg )
+{
+       SPOOLSS_NOTIFY_MSG_GROUP        *groups = NULL;
+       SPOOLSS_NOTIFY_MSG_GROUP        *msg_grp = NULL;
+       SPOOLSS_NOTIFY_MSG              *msg_list = NULL;
+       int                             i, new_slot;
+       
+       if ( !ctr || !msg )
+               return 0;
+       
+       /* loop over all groups looking for a matching printer name */
+       
+       for ( i=0; i<ctr->num_groups; i++ ) {
+               if ( strcmp(ctr->msg_groups[i].printername, msg->printer) == 0 )
+                       break;
+       }
+       
+       /* add a new group? */
+       
+       if ( i == ctr->num_groups )
+       {
+               ctr->num_groups++;
+
+               if ( !(groups = talloc_realloc( ctr->ctx, ctr->msg_groups, sizeof(SPOOLSS_NOTIFY_MSG_GROUP)*ctr->num_groups)) ) {
+                       DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed!\n"));
+                       return 0;
+               }
+               ctr->msg_groups = groups;
+
+               /* clear the new entry and set the printer name */
+               
+               ZERO_STRUCT( ctr->msg_groups[ctr->num_groups-1] );
+               fstrcpy( ctr->msg_groups[ctr->num_groups-1].printername, msg->printer );
+       }
+       
+       /* add the change messages; 'i' is the correct index now regardless */
+       
+       msg_grp = &ctr->msg_groups[i];
+       
+       msg_grp->num_msgs++;
+       
+       if ( !(msg_list =  talloc_realloc( ctr->ctx, msg_grp->msgs, sizeof(SPOOLSS_NOTIFY_MSG)*msg_grp->num_msgs )) ) {
+               DEBUG(0,("notify_msg_ctr_addmsg: talloc_realloc() failed for new message [%d]!\n", msg_grp->num_msgs));
+               return 0;
+       }
+       msg_grp->msgs = msg_list;
+       
+       new_slot = msg_grp->num_msgs-1;
+       memcpy( &msg_grp->msgs[new_slot], msg, sizeof(SPOOLSS_NOTIFY_MSG) );
+       
+       /* need to allocate own copy of data */
+       
+       if ( msg->len != 0 ) 
+               msg_grp->msgs[new_slot].notify.data = talloc_memdup( ctr->ctx, msg->notify.data, msg->len );
+       
+       return ctr->num_groups;
+}
+
 /***********************************************************************
  Send a change notication message on all handles which have a call 
  back registered
  **********************************************************************/
 
-static void process_notify2_message(struct spoolss_notify_msg *msg, TALLOC_CTX *mem_ctx)
+static void send_notify2_changes( SPOOLSS_NOTIFY_MSG_CTR *ctr, uint32 index )
 {
-       Printer_entry *p;
-
-       DEBUG(8,("process_notify2_message: Enter...[%s]\n", msg->printer));
+       Printer_entry            *p;
+       TALLOC_CTX               *mem_ctx = notify_ctr_getctx( ctr );
+       SPOOLSS_NOTIFY_MSG_GROUP *msg_group = notify_ctr_getgroup( ctr, index );
+       SPOOLSS_NOTIFY_MSG       *messages;
+       
+       
+       if ( !msg_group ) {
+               DEBUG(5,("send_notify2_changes() called with no msg group!\n"));
+               return;
+       }
+       
+       messages = msg_group->msgs;
        
-       for (p = printers_list; p; p = p->next) {
+       if ( !messages ) {
+               DEBUG(5,("send_notify2_changes() called with no messages!\n"));
+               return;
+       }
+       
+       DEBUG(8,("send_notify2_changes: Enter...[%s]\n", msg_group->printername));
+       
+       /* loop over all printers */
+       
+       for (p = printers_list; p; p = p->next) 
+       {
                SPOOL_NOTIFY_INFO_DATA *data;
-               uint32 data_len = 1;
-               uint32 id;
+               uint32  data_len = 0;
+               uint32  id;
+               int     i;
 
                /* Is there notification on this handle? */
 
-               if (!p->notify.client_connected)
+               if ( !p->notify.client_connected )
                        continue;
 
                DEBUG(10,("Client connected! [%s]\n", p->dev.handlename));
@@ -755,25 +907,31 @@ static void process_notify2_message(struct spoolss_notify_msg *msg, TALLOC_CTX *
                    notifications. */
 
                if ( ( p->printer_type == PRINTER_HANDLE_IS_PRINTER )  &&
-                   ( !strequal(msg->printer, p->dev.handlename) ) )
+                   ( !strequal(msg_group->printername, p->dev.handlename) ) )
                        continue;
 
                DEBUG(10,("Our printer\n"));
                
+               /* allocate the max entries possible */
+               
+               data = talloc( mem_ctx, msg_group->num_msgs*sizeof(SPOOL_NOTIFY_INFO_DATA) );
+               ZERO_STRUCTP(data);
+               
+               /* build the array of change notifications */
+               
+               for ( i=0; i<msg_group->num_msgs; i++ )
+               {
+                       SPOOLSS_NOTIFY_MSG      *msg = &messages[i];
+                       
                /* Are we monitoring this event? */
 
                if (!is_monitoring_event(p, msg->type, msg->field))
                        continue;
 
+                       
                DEBUG(10,("process_notify2_message: Sending message type [%x] field [%x] for printer [%s]\n",
                        msg->type, msg->field, p->dev.handlename));
 
-               /* OK - send the event to the client */
-
-               data = talloc(mem_ctx, sizeof(SPOOL_NOTIFY_INFO_DATA));
-
-               ZERO_STRUCTP(data);
-
                /* 
                 * if the is a printer notification handle and not a job notification 
                 * type, then set the id to 0.  Other wise just use what was specified
@@ -795,8 +953,8 @@ static void process_notify2_message(struct spoolss_notify_msg *msg, TALLOC_CTX *
 
                /* Convert unix jobid to smb jobid */
 
-               if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) {
-
+                       if (msg->flags & SPOOLSS_NOTIFY_MSG_UNIX_JOBID) 
+                       {
                        id = sysjob_to_jobid(msg->id);
 
                        if (id == -1) {
@@ -805,22 +963,20 @@ static void process_notify2_message(struct spoolss_notify_msg *msg, TALLOC_CTX *
                        }
                }
 
-               construct_info_data(data, msg->type, msg->field, id);
+                       construct_info_data( &data[data_len], msg->type, msg->field, id );
 
                switch(msg->type) {
                case PRINTER_NOTIFY_TYPE:
                                if ( !printer_notify_table[msg->field].fn )
                                goto done;
-                                       
-                               printer_notify_table[msg->field].fn(msg, data, mem_ctx);
+                                       printer_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
                                
                        break;
                        
                case JOB_NOTIFY_TYPE:
                                if ( !job_notify_table[msg->field].fn )
                                goto done;
-
-                               job_notify_table[msg->field].fn(msg, data, mem_ctx);
+                                       job_notify_table[msg->field].fn(msg, &data[data_len], mem_ctx);
 
                                break;
 
@@ -829,60 +985,51 @@ static void process_notify2_message(struct spoolss_notify_msg *msg, TALLOC_CTX *
                                goto done;
                        }
 
+                       data_len++;
+               }
+
                cli_spoolss_rrpcn( &notify_cli, mem_ctx, &p->notify.client_hnd, 
                                data_len, data, p->notify.change, 0 );
        }
+       
 done:
-       DEBUG(8,("process_notify2_message: Exit...\n"));
+       DEBUG(8,("send_notify2_changes: Exit...\n"));
        return;
 }
 
-/********************************************************************
- Receive a notify2 message
- ********************************************************************/
+/***********************************************************************
+ **********************************************************************/
 
-static void receive_notify2_message(void *buf, size_t len)
+static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, void *buf, size_t len )
 {
-       struct spoolss_notify_msg msg;
+
        int offset = 0;
-       TALLOC_CTX *mem_ctx = talloc_init();
 
        /* Unpack message */
 
-       ZERO_STRUCT(msg);
-
        offset += tdb_unpack((char *)buf + offset, len - offset, "f",
-                            msg.printer);
+                            msg->printer);
        
        offset += tdb_unpack((char *)buf + offset, len - offset, "ddddd",
-                            &msg.type, &msg.field, &msg.id, &msg.len, &msg.flags);
+                            &msg->type, &msg->field, &msg->id, &msg->len, &msg->flags);
 
-       if (msg.len == 0)
+       if (msg->len == 0)
                tdb_unpack((char *)buf + offset, len - offset, "dd",
-                          &msg.notify.value[0], &msg.notify.value[1]);
+                          &msg->notify.value[0], &msg->notify.value[1]);
        else
                tdb_unpack((char *)buf + offset, len - offset, "B", 
-                          &msg.len, &msg.notify.data);
+                          &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));
+       DEBUG(3, ("notify2_unpack_msg: 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]));
+       if (msg->len == 0)
+               DEBUG(3, ("notify2_unpack_msg: 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 */
+               dump_data(3, msg->notify.data, msg->len);
 
-       if (msg.len > 0)
-               free(msg.notify.data);
-
-       talloc_destroy(mem_ctx);
+       return True;
 }
 
 /********************************************************************
@@ -891,43 +1038,86 @@ static void receive_notify2_message(void *buf, size_t len)
 
 static void receive_notify2_message_list(int msg_type, pid_t src, void *msg, size_t len)
 {
-       size_t msg_count, i;
-       char *buf = (char *)msg;
-       char *msg_ptr;
-
-       if (len < 4)
-               goto bad_msg;
+       size_t                  msg_count, i;
+       char                    *buf = (char *)msg;
+       char                    *msg_ptr;
+       size_t                  msg_len;
+       SPOOLSS_NOTIFY_MSG      notify;
+       SPOOLSS_NOTIFY_MSG_CTR  messages;
+       int                     num_groups;
 
+       if (len < 4) {
+               DEBUG(0,("receive_notify2_message_list: bad message format (len < 4)!\n"));
+               return;
+       }
+       
        msg_count = IVAL(buf, 0);
        msg_ptr = buf + 4;
 
        DEBUG(5, ("receive_notify2_message_list: got %d messages in list\n", msg_count));
 
-       if (msg_count == 0)
-               goto bad_msg;
-
-       for (i = 0; i < msg_count; i++) {
-               size_t msg_len;
+       if (msg_count == 0) {
+               DEBUG(0,("receive_notify2_message_list: bad message format (msg_count == 0) !\n"));
+               return;
+       }
 
-               if (msg_ptr + 4 - buf > len)
-                       goto bad_msg;
+       /* initialize the container */
+       
+       ZERO_STRUCT( messages );
+       notify_msg_ctr_init( &messages );
+       
+       /* 
+        * build message groups for each printer identified
+        * in a change_notify msg.  Remember that a PCN message
+        * includes the handle returned for the srv_spoolss_replyopenprinter()
+        * call.  Therefore messages are grouped according to printer handle.
+        */
+        
+       for ( i=0; i<msg_count; i++ ) 
+       {
+               if (msg_ptr + 4 - buf > len) {
+                       DEBUG(0,("receive_notify2_message_list: bad message format (len > buf_size) !\n"));
+                       return;
+               }
 
                msg_len = IVAL(msg_ptr,0);
                msg_ptr += 4;
 
-               if (msg_ptr + msg_len - buf > len)
-                       goto bad_msg;
-               receive_notify2_message(msg_ptr, msg_len);
+               if (msg_ptr + msg_len - buf > len) {
+                       DEBUG(0,("receive_notify2_message_list: bad message format (bad len) !\n"));
+                       return;
+               }
+               
+               /* unpack messages */
+               
+               ZERO_STRUCT( notify );
+               notify2_unpack_msg( &notify, msg_ptr, msg_len );
                msg_ptr += msg_len;
+               
+               /* add to correct list in container */
+               
+               notify_msg_ctr_addmsg( &messages, &notify );
+               
+               /* free memory that might have been allocated by notify2_unpack_msg() */
+               
+               if ( notify.len != 0 )
+                       SAFE_FREE( notify.notify.data );
        }
-
-       DEBUG(10,("receive_notify2_message_list: processed %u messages\n",
-               (unsigned int)msg_count ));
+       
+       /* process each group of messages */
+       
+       num_groups = notify_msg_ctr_numgroups( &messages );
+       for ( i=0; i<num_groups; i++ )
+               send_notify2_changes( &messages, i );
+       
+       
+       /* cleanup */
+               
+       DEBUG(10,("receive_notify2_message_list: processed %u messages\n", (uint32)msg_count ));
+               
+       notify_msg_ctr_destroy( &messages );
+       
        return;
-
-  bad_msg:
-
-       DEBUG(0,("receive_notify2_message_list: bad message format !\n"));
 }
 
 /********************************************************************