2 Unix SMB/Netbios implementation.
4 printing backend routines
5 Copyright (C) Tim Potter, 2002
6 Copyright (C) Gerald Carter, 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../librpc/gen_ndr/spoolss.h"
25 #include "nt_printing.h"
26 #include "printing/notify.h"
29 #include "lib/util/string_wrappers.h"
31 static TALLOC_CTX
*send_ctx
;
33 static unsigned int num_messages
;
35 static struct notify_queue
{
36 struct notify_queue
*next
, *prev
;
37 struct spoolss_notify_msg
*msg
;
41 } *notify_queue_head
= NULL
;
43 static struct tevent_timer
*notify_event
;
45 static bool print_notify_pid_list(const char *printername
, TALLOC_CTX
*mem_ctx
,
46 size_t *p_num_pids
, pid_t
**pp_pid_list
);
48 static bool create_send_ctx(void)
51 send_ctx
= talloc_init("print notify queue");
59 /****************************************************************************
60 Turn a queue name into a snum.
61 ****************************************************************************/
63 int print_queue_snum(const char *qname
)
65 int snum
= lp_servicenumber(qname
);
66 if (snum
== -1 || !lp_printable(snum
))
71 /*******************************************************************
72 Used to decide if we need a short select timeout.
73 *******************************************************************/
75 static bool print_notify_messages_pending(void)
77 return (notify_queue_head
!= NULL
);
80 /*******************************************************************
81 Flatten data into a message.
82 *******************************************************************/
84 static bool flatten_message(struct notify_queue
*q
)
86 struct spoolss_notify_msg
*msg
= q
->msg
;
88 size_t buflen
= 0, len
;
95 len
+= tdb_pack(buf
? buf
+ len
: NULL
,
96 buf
? buflen
- len
: 0, "f", msg
->printer
);
98 len
+= tdb_pack(buf
? buf
+ len
: NULL
,
99 buf
? buflen
- len
: 0, "ddddddd",
100 (uint32_t)q
->tv
.tv_sec
, (uint32_t)q
->tv
.tv_usec
,
101 msg
->type
, msg
->field
, msg
->id
, msg
->len
, msg
->flags
);
106 len
+= tdb_pack(buf
? buf
+ len
: NULL
,
107 buf
? buflen
- len
: 0, "dd",
108 msg
->notify
.value
[0], msg
->notify
.value
[1]);
110 len
+= tdb_pack(buf
? buf
+ len
: NULL
,
111 buf
? buflen
- len
: 0, "B",
112 msg
->len
, msg
->notify
.data
);
115 buf
= (uint8_t *)TALLOC_REALLOC(send_ctx
, buf
, len
);
128 /*******************************************************************
129 Send the batched messages - on a per-printer basis.
130 *******************************************************************/
132 static void print_notify_send_messages_to_printer(struct messaging_context
*msg_ctx
,
134 unsigned int timeout
)
137 struct notify_queue
*pq
, *pq_next
;
138 size_t msg_count
= 0, offset
= 0;
141 pid_t
*pid_list
= NULL
;
142 struct timeval end_time
= timeval_zero();
144 /* Count the space needed to send the messages. */
145 for (pq
= notify_queue_head
; pq
; pq
= pq
->next
) {
146 if (strequal(printer
, pq
->msg
->printer
)) {
147 if (!flatten_message(pq
)) {
148 DEBUG(0,("print_notify_send_messages: Out of memory\n"));
149 talloc_free_children(send_ctx
);
153 offset
+= (pq
->buflen
+ 4);
157 offset
+= 4; /* For count. */
159 buf
= (char *)TALLOC(send_ctx
, offset
);
161 DEBUG(0,("print_notify_send_messages: Out of memory\n"));
162 talloc_free_children(send_ctx
);
168 SIVAL(buf
,offset
,msg_count
);
170 for (pq
= notify_queue_head
; pq
; pq
= pq_next
) {
173 if (strequal(printer
, pq
->msg
->printer
)) {
174 SIVAL(buf
,offset
,pq
->buflen
);
176 memcpy(buf
+ offset
, pq
->buf
, pq
->buflen
);
177 offset
+= pq
->buflen
;
179 /* Remove from list. */
180 DLIST_REMOVE(notify_queue_head
, pq
);
184 DEBUG(5, ("print_notify_send_messages_to_printer: sending %lu print notify message%s to printer %s\n",
185 (unsigned long)msg_count
, msg_count
!= 1 ? "s" : "", printer
));
188 * Get the list of PID's to send to.
191 if (!print_notify_pid_list(printer
, send_ctx
, &num_pids
, &pid_list
))
195 end_time
= timeval_current_ofs(timeout
, 0);
198 for (i
= 0; i
< num_pids
; i
++) {
199 messaging_send_buf(msg_ctx
,
200 pid_to_procid(pid_list
[i
]),
201 MSG_PRINTER_NOTIFY2
| MSG_FLAG_LOWPRIORITY
,
202 (uint8_t *)buf
, offset
);
204 if ((timeout
!= 0) && timeval_expired(&end_time
)) {
210 /*******************************************************************
211 Actually send the batched messages.
212 *******************************************************************/
214 void print_notify_send_messages(struct messaging_context
*msg_ctx
,
215 unsigned int timeout
)
217 if (!print_notify_messages_pending())
220 if (!create_send_ctx())
223 while (print_notify_messages_pending())
224 print_notify_send_messages_to_printer(
225 msg_ctx
, notify_queue_head
->msg
->printer
, timeout
);
227 talloc_free_children(send_ctx
);
231 /*******************************************************************
232 Event handler to send the messages.
233 *******************************************************************/
235 static void print_notify_event_send_messages(struct tevent_context
*event_ctx
,
236 struct tevent_timer
*te
,
240 struct messaging_context
*msg_ctx
= talloc_get_type_abort(
241 private_data
, struct messaging_context
);
242 /* Remove this timed event handler. */
243 TALLOC_FREE(notify_event
);
245 change_to_root_user();
246 print_notify_send_messages(msg_ctx
, 0);
249 /**********************************************************************
250 deep copy a SPOOLSS_NOTIFY_MSG structure using a TALLOC_CTX
251 *********************************************************************/
253 static bool copy_notify2_msg( SPOOLSS_NOTIFY_MSG
*to
, SPOOLSS_NOTIFY_MSG
*from
)
259 memcpy( to
, from
, sizeof(SPOOLSS_NOTIFY_MSG
) );
262 to
->notify
.data
= (char *)talloc_memdup(send_ctx
, from
->notify
.data
, from
->len
);
263 if ( !to
->notify
.data
) {
264 DEBUG(0,("copy_notify2_msg: talloc_memdup() of size [%d] failed!\n", from
->len
));
273 /*******************************************************************
274 Batch up print notify messages.
275 *******************************************************************/
277 static void send_spoolss_notify2_msg(struct tevent_context
*ev
,
278 struct messaging_context
*msg_ctx
,
279 SPOOLSS_NOTIFY_MSG
*msg
)
281 struct notify_queue
*pnqueue
, *tmp_ptr
;
284 * Ensure we only have one job total_bytes and job total_pages for
285 * each job. There is no point in sending multiple messages that match
286 * as they will just cause flickering updates in the client.
289 if ((num_messages
< 100) && (msg
->type
== JOB_NOTIFY_TYPE
)
290 && (msg
->field
== JOB_NOTIFY_FIELD_TOTAL_BYTES
291 || msg
->field
== JOB_NOTIFY_FIELD_TOTAL_PAGES
))
294 for (tmp_ptr
= notify_queue_head
; tmp_ptr
; tmp_ptr
= tmp_ptr
->next
)
296 if (tmp_ptr
->msg
->type
== msg
->type
&&
297 tmp_ptr
->msg
->field
== msg
->field
&&
298 tmp_ptr
->msg
->id
== msg
->id
&&
299 tmp_ptr
->msg
->flags
== msg
->flags
&&
300 strequal(tmp_ptr
->msg
->printer
, msg
->printer
)) {
302 DEBUG(5,("send_spoolss_notify2_msg: replacing message 0x%02x/0x%02x for "
303 "printer %s in notify_queue\n", msg
->type
, msg
->field
, msg
->printer
));
311 /* Store the message on the pending queue. */
313 pnqueue
= talloc(send_ctx
, struct notify_queue
);
315 DEBUG(0,("send_spoolss_notify2_msg: Out of memory.\n"));
319 /* allocate a new msg structure and copy the fields */
321 if ( !(pnqueue
->msg
= talloc(send_ctx
, SPOOLSS_NOTIFY_MSG
)) ) {
322 DEBUG(0,("send_spoolss_notify2_msg: talloc() of size [%lu] failed!\n",
323 (unsigned long)sizeof(SPOOLSS_NOTIFY_MSG
)));
326 copy_notify2_msg(pnqueue
->msg
, msg
);
327 GetTimeOfDay(&pnqueue
->tv
);
331 DEBUG(5, ("send_spoolss_notify2_msg: appending message 0x%02x/0x%02x for printer %s \
332 to notify_queue_head\n", msg
->type
, msg
->field
, msg
->printer
));
335 * Note we add to the end of the list to ensure
336 * the messages are sent in the order they were received. JRA.
339 DLIST_ADD_END(notify_queue_head
, pnqueue
);
342 if ((notify_event
== NULL
) && (ev
!= NULL
)) {
343 /* Add an event for 1 second's time to send this queue. */
344 notify_event
= tevent_add_timer(
345 ev
, NULL
, timeval_current_ofs(1,0),
346 print_notify_event_send_messages
, msg_ctx
);
351 static void send_notify_field_values(struct tevent_context
*ev
,
352 struct messaging_context
*msg_ctx
,
353 const char *sharename
, uint32_t type
,
354 uint32_t field
, uint32_t id
, uint32_t value1
,
355 uint32_t value2
, uint32_t flags
)
357 struct spoolss_notify_msg
*msg
;
359 if (lp_disable_spoolss())
362 if (!create_send_ctx())
365 msg
= talloc_zero(send_ctx
, struct spoolss_notify_msg
);
369 fstrcpy(msg
->printer
, sharename
);
373 msg
->notify
.value
[0] = value1
;
374 msg
->notify
.value
[1] = value2
;
377 send_spoolss_notify2_msg(ev
, msg_ctx
, msg
);
380 static void send_notify_field_buffer(struct tevent_context
*ev
,
381 struct messaging_context
*msg_ctx
,
382 const char *sharename
, uint32_t type
,
383 uint32_t field
, uint32_t id
, uint32_t len
,
386 struct spoolss_notify_msg
*msg
;
388 if (lp_disable_spoolss())
391 if (!create_send_ctx())
394 msg
= talloc_zero(send_ctx
, struct spoolss_notify_msg
);
398 fstrcpy(msg
->printer
, sharename
);
403 msg
->notify
.data
= discard_const_p(char, buffer
);
405 send_spoolss_notify2_msg(ev
, msg_ctx
, msg
);
408 /* Send a message that the printer status has changed */
410 void notify_printer_status_byname(struct tevent_context
*ev
,
411 struct messaging_context
*msg_ctx
,
412 const char *sharename
, uint32_t status
)
414 /* Printer status stored in value1 */
416 int snum
= print_queue_snum(sharename
);
418 send_notify_field_values(ev
, msg_ctx
, sharename
, PRINTER_NOTIFY_TYPE
,
419 PRINTER_NOTIFY_FIELD_STATUS
, snum
,
423 void notify_printer_status(struct tevent_context
*ev
,
424 struct messaging_context
*msg_ctx
,
425 int snum
, uint32_t status
)
427 const struct loadparm_substitution
*lp_sub
=
428 loadparm_s3_global_substitution();
429 const char *sharename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
432 notify_printer_status_byname(ev
, msg_ctx
, sharename
, status
);
435 void notify_job_status_byname(struct tevent_context
*ev
,
436 struct messaging_context
*msg_ctx
,
437 const char *sharename
, uint32_t jobid
,
441 /* Job id stored in id field, status in value1 */
443 send_notify_field_values(ev
, msg_ctx
,
444 sharename
, JOB_NOTIFY_TYPE
,
445 JOB_NOTIFY_FIELD_STATUS
, jobid
,
449 void notify_job_status(struct tevent_context
*ev
,
450 struct messaging_context
*msg_ctx
,
451 const char *sharename
, uint32_t jobid
, uint32_t status
)
453 notify_job_status_byname(ev
, msg_ctx
, sharename
, jobid
, status
, 0);
456 void notify_job_total_bytes(struct tevent_context
*ev
,
457 struct messaging_context
*msg_ctx
,
458 const char *sharename
, uint32_t jobid
,
461 /* Job id stored in id field, status in value1 */
463 send_notify_field_values(ev
, msg_ctx
,
464 sharename
, JOB_NOTIFY_TYPE
,
465 JOB_NOTIFY_FIELD_TOTAL_BYTES
, jobid
,
469 void notify_job_total_pages(struct tevent_context
*ev
,
470 struct messaging_context
*msg_ctx
,
471 const char *sharename
, uint32_t jobid
,
474 /* Job id stored in id field, status in value1 */
476 send_notify_field_values(ev
, msg_ctx
,
477 sharename
, JOB_NOTIFY_TYPE
,
478 JOB_NOTIFY_FIELD_TOTAL_PAGES
, jobid
,
482 void notify_job_username(struct tevent_context
*ev
,
483 struct messaging_context
*msg_ctx
,
484 const char *sharename
, uint32_t jobid
, char *name
)
486 send_notify_field_buffer(
488 sharename
, JOB_NOTIFY_TYPE
, JOB_NOTIFY_FIELD_USER_NAME
,
489 jobid
, strlen(name
) + 1, name
);
492 void notify_job_name(struct tevent_context
*ev
,
493 struct messaging_context
*msg_ctx
,
494 const char *sharename
, uint32_t jobid
, char *name
)
496 send_notify_field_buffer(
498 sharename
, JOB_NOTIFY_TYPE
, JOB_NOTIFY_FIELD_DOCUMENT
,
499 jobid
, strlen(name
) + 1, name
);
502 void notify_job_submitted(struct tevent_context
*ev
,
503 struct messaging_context
*msg_ctx
,
504 const char *sharename
, uint32_t jobid
,
507 send_notify_field_buffer(
509 sharename
, JOB_NOTIFY_TYPE
, JOB_NOTIFY_FIELD_SUBMITTED
,
510 jobid
, sizeof(submitted
), (char *)&submitted
);
513 void notify_printer_driver(struct tevent_context
*ev
,
514 struct messaging_context
*msg_ctx
,
515 int snum
, const char *driver_name
)
517 const struct loadparm_substitution
*lp_sub
=
518 loadparm_s3_global_substitution();
519 const char *sharename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
521 send_notify_field_buffer(
523 sharename
, PRINTER_NOTIFY_TYPE
, PRINTER_NOTIFY_FIELD_DRIVER_NAME
,
524 snum
, strlen(driver_name
) + 1, driver_name
);
527 void notify_printer_comment(struct tevent_context
*ev
,
528 struct messaging_context
*msg_ctx
,
529 int snum
, const char *comment
)
531 const struct loadparm_substitution
*lp_sub
=
532 loadparm_s3_global_substitution();
533 const char *sharename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
535 send_notify_field_buffer(
537 sharename
, PRINTER_NOTIFY_TYPE
, PRINTER_NOTIFY_FIELD_COMMENT
,
538 snum
, strlen(comment
) + 1, comment
);
541 void notify_printer_sharename(struct tevent_context
*ev
,
542 struct messaging_context
*msg_ctx
,
543 int snum
, const char *share_name
)
545 const struct loadparm_substitution
*lp_sub
=
546 loadparm_s3_global_substitution();
547 const char *sharename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
549 send_notify_field_buffer(
551 sharename
, PRINTER_NOTIFY_TYPE
, PRINTER_NOTIFY_FIELD_SHARE_NAME
,
552 snum
, strlen(share_name
) + 1, share_name
);
555 void notify_printer_printername(struct tevent_context
*ev
,
556 struct messaging_context
*msg_ctx
,
557 int snum
, const char *printername
)
559 const struct loadparm_substitution
*lp_sub
=
560 loadparm_s3_global_substitution();
561 const char *sharename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
563 send_notify_field_buffer(
565 sharename
, PRINTER_NOTIFY_TYPE
, PRINTER_NOTIFY_FIELD_PRINTER_NAME
,
566 snum
, strlen(printername
) + 1, printername
);
569 void notify_printer_port(struct tevent_context
*ev
,
570 struct messaging_context
*msg_ctx
,
571 int snum
, const char *port_name
)
573 const struct loadparm_substitution
*lp_sub
=
574 loadparm_s3_global_substitution();
575 const char *sharename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
577 send_notify_field_buffer(
579 sharename
, PRINTER_NOTIFY_TYPE
, PRINTER_NOTIFY_FIELD_PORT_NAME
,
580 snum
, strlen(port_name
) + 1, port_name
);
583 void notify_printer_location(struct tevent_context
*ev
,
584 struct messaging_context
*msg_ctx
,
585 int snum
, const char *location
)
587 const struct loadparm_substitution
*lp_sub
=
588 loadparm_s3_global_substitution();
589 const char *sharename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
591 send_notify_field_buffer(
593 sharename
, PRINTER_NOTIFY_TYPE
, PRINTER_NOTIFY_FIELD_LOCATION
,
594 snum
, strlen(location
) + 1, location
);
597 void notify_printer_sepfile(struct tevent_context
*ev
,
598 struct messaging_context
*msg_ctx
,
599 int snum
, const char *sepfile
)
601 const struct loadparm_substitution
*lp_sub
=
602 loadparm_s3_global_substitution();
603 const char *sharename
= lp_servicename(talloc_tos(), lp_sub
, snum
);
605 send_notify_field_buffer(
607 sharename
, PRINTER_NOTIFY_TYPE
, PRINTER_NOTIFY_FIELD_SEPFILE
,
608 snum
, strlen(sepfile
) + 1, sepfile
);
612 void notify_printer_byname(struct tevent_context
*ev
,
613 struct messaging_context
*msg_ctx
,
614 const char *printername
, uint32_t change
,
617 int snum
= print_queue_snum(printername
);
618 int type
= PRINTER_NOTIFY_TYPE
;
623 send_notify_field_buffer(
625 printername
, type
, change
, snum
, strlen(value
)+1, value
);
629 /****************************************************************************
630 Return a malloced list of pid_t's that are interested in getting update
631 messages on this print queue. Used in printing/notify to send the messages.
632 ****************************************************************************/
634 static bool print_notify_pid_list(const char *printername
, TALLOC_CTX
*mem_ctx
,
635 size_t *p_num_pids
, pid_t
**pp_pid_list
)
637 struct tdb_print_db
*pdb
= NULL
;
638 TDB_CONTEXT
*tdb
= NULL
;
641 size_t i
, num_pids
, offset
;
647 pdb
= get_print_db_byname(printername
);
652 if (tdb_read_lock_bystring_with_timeout(tdb
, NOTIFY_PID_LIST_KEY
, 10) != 0) {
653 DEBUG(0,("print_notify_pid_list: Failed to lock printer %s database\n",
656 release_print_db(pdb
);
660 data
= get_printer_notify_pid_list( tdb
, printername
, True
);
667 num_pids
= data
.dsize
/ 8;
670 if ((pid_list
= talloc_array(mem_ctx
, pid_t
, num_pids
)) == NULL
) {
678 for( i
= 0, offset
= 0; i
< num_pids
; offset
+= 8, i
++)
679 pid_list
[i
] = (pid_t
)IVAL(data
.dptr
, offset
);
681 *pp_pid_list
= pid_list
;
682 *p_num_pids
= num_pids
;
688 tdb_read_unlock_bystring(tdb
, NOTIFY_PID_LIST_KEY
);
690 release_print_db(pdb
);
691 SAFE_FREE(data
.dptr
);