1/* 2 Unix SMB/Netbios implementation. 3 Version 3.0 4 printing backend routines 5 Copyright (C) Tim Potter, 2002 6 Copyright (C) Gerald Carter, 2002 7 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 2 of the License, or 11 (at your option) any later version. 12 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. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21*/ 22 23#include "includes.h" 24#include "printing.h" 25 26static TALLOC_CTX *send_ctx; 27 28static unsigned int num_messages; 29 30static struct notify_queue { 31 struct notify_queue *next, *prev; 32 struct spoolss_notify_msg *msg; 33 struct timeval tv; 34 char *buf; 35 size_t buflen; 36} *notify_queue_head = NULL; 37 38 39static BOOL create_send_ctx(void) 40{ 41 if (!send_ctx) 42 send_ctx = talloc_init("print notify queue"); 43 44 if (!send_ctx) 45 return False; 46 47 return True; 48} 49 50/**************************************************************************** 51 Turn a queue name into a snum. 52****************************************************************************/ 53 54int print_queue_snum(const char *qname) 55{ 56 int snum = lp_servicenumber(qname); 57 if (snum == -1 || !lp_print_ok(snum)) 58 return -1; 59 return snum; 60} 61 62/******************************************************************* 63 Used to decide if we need a short select timeout. 64*******************************************************************/ 65 66BOOL print_notify_messages_pending(void) 67{ 68 return (notify_queue_head != NULL); 69} 70 71/******************************************************************* 72 Flatten data into a message. 73*******************************************************************/ 74 75static BOOL flatten_message(struct notify_queue *q) 76{ 77 struct spoolss_notify_msg *msg = q->msg; 78 char *buf = NULL; 79 size_t buflen = 0, len; 80 81again: 82 len = 0; 83 84 /* Pack header */ 85 86 len += tdb_pack(buf + len, buflen - len, "f", msg->printer); 87 88 len += tdb_pack(buf + len, buflen - len, "ddddddd", 89 (uint32)q->tv.tv_sec, (uint32)q->tv.tv_usec, 90 msg->type, msg->field, msg->id, msg->len, msg->flags); 91 92 /* Pack data */ 93 94 if (msg->len == 0) 95 len += tdb_pack(buf + len, buflen - len, "dd", 96 msg->notify.value[0], msg->notify.value[1]); 97 else 98 len += tdb_pack(buf + len, buflen - len, "B", 99 msg->len, msg->notify.data); 100 101 if (buflen != len) { 102 buf = TALLOC_REALLOC(send_ctx, buf, len); 103 if (!buf) 104 return False; 105 buflen = len; 106 goto again; 107 } 108 109 q->buf = buf; 110 q->buflen = buflen; 111 112 return True; 113} 114 115/******************************************************************* 116 Send the batched messages - on a per-printer basis. 117*******************************************************************/ 118 119static void print_notify_send_messages_to_printer(const char *printer, unsigned int timeout) 120{ 121 char *buf; 122 struct notify_queue *pq, *pq_next; 123 size_t msg_count = 0, offset = 0; 124 size_t num_pids = 0; 125 size_t i; 126 pid_t *pid_list = NULL; 127 128 /* Count the space needed to send the messages. */ 129 for (pq = notify_queue_head; pq; pq = pq->next) { 130 if (strequal(printer, pq->msg->printer)) { 131 if (!flatten_message(pq)) { 132 DEBUG(0,("print_notify_send_messages: Out of memory\n")); 133 talloc_destroy_pool(send_ctx); 134 num_messages = 0; 135 return; 136 } 137 offset += (pq->buflen + 4); 138 msg_count++; 139 } 140 } 141 offset += 4; /* For count. */ 142 143 buf = TALLOC(send_ctx, offset); 144 if (!buf) { 145 DEBUG(0,("print_notify_send_messages: Out of memory\n")); 146 talloc_destroy_pool(send_ctx); 147 num_messages = 0; 148 return; 149 } 150 151 offset = 0; 152 SIVAL(buf,offset,msg_count); 153 offset += 4; 154 for (pq = notify_queue_head; pq; pq = pq_next) { 155 pq_next = pq->next; 156 157 if (strequal(printer, pq->msg->printer)) { 158 SIVAL(buf,offset,pq->buflen); 159 offset += 4; 160 memcpy(buf + offset, pq->buf, pq->buflen); 161 offset += pq->buflen; 162 163 /* Remove from list. */ 164 DLIST_REMOVE(notify_queue_head, pq); 165 } 166 } 167 168 DEBUG(5, ("print_notify_send_messages_to_printer: sending %lu print notify message%s to printer %s\n", 169 (unsigned long)msg_count, msg_count != 1 ? "s" : "", printer)); 170 171 /* 172 * Get the list of PID's to send to. 173 */ 174 175 if (!print_notify_pid_list(printer, send_ctx, &num_pids, &pid_list)) 176 return; 177 178 for (i = 0; i < num_pids; i++) { 179 unsigned int q_len = messages_pending_for_pid(pid_list[i]); 180 if (q_len > 1000) { 181 DEBUG(5, ("print_notify_send_messages_to_printer: discarding notify to printer %s as queue length = %u\n", 182 printer, q_len )); 183 continue; 184 } 185 message_send_pid_with_timeout(pid_list[i], MSG_PRINTER_NOTIFY2, buf, offset, True, timeout); 186 } 187} 188 189/******************************************************************* 190 Actually send the batched messages. 191*******************************************************************/ 192 193void print_notify_send_messages(unsigned int timeout) 194{ 195 if (!print_notify_messages_pending()) 196 return; 197 198 if (!create_send_ctx()) 199 return; 200 201 while (print_notify_messages_pending()) 202 print_notify_send_messages_to_printer(notify_queue_head->msg->printer, timeout); 203 204 talloc_destroy_pool(send_ctx); 205 num_messages = 0; 206} 207 208/********************************************************************** 209 deep copy a SPOOLSS_NOTIFY_MSG structure using a TALLOC_CTX 210 *********************************************************************/ 211 212static BOOL copy_notify2_msg( SPOOLSS_NOTIFY_MSG *to, SPOOLSS_NOTIFY_MSG *from ) 213{ 214 215 if ( !to || !from ) 216 return False; 217 218 memcpy( to, from, sizeof(SPOOLSS_NOTIFY_MSG) ); 219 220 if ( from->len ) { 221 to->notify.data = TALLOC_MEMDUP(send_ctx, from->notify.data, from->len ); 222 if ( !to->notify.data ) { 223 DEBUG(0,("copy_notify2_msg: talloc_memdup() of size [%d] failed!\n", from->len )); 224 return False; 225 } 226 } 227 228 229 return True; 230} 231 232/******************************************************************* 233 Batch up print notify messages. 234*******************************************************************/ 235 236static void send_spoolss_notify2_msg(SPOOLSS_NOTIFY_MSG *msg) 237{ 238 struct notify_queue *pnqueue, *tmp_ptr; 239 240 /* 241 * Ensure we only have one job total_bytes and job total_pages for 242 * each job. There is no point in sending multiple messages that match 243 * as they will just cause flickering updates in the client. 244 */ 245 246 if ((num_messages < 100) && (msg->type == JOB_NOTIFY_TYPE) 247 && (msg->field == JOB_NOTIFY_TOTAL_BYTES 248 || msg->field == JOB_NOTIFY_TOTAL_PAGES )) 249 { 250 251 for (tmp_ptr = notify_queue_head; tmp_ptr; tmp_ptr = tmp_ptr->next) 252 { 253 if (tmp_ptr->msg->type == msg->type && 254 tmp_ptr->msg->field == msg->field && 255 tmp_ptr->msg->id == msg->id && 256 tmp_ptr->msg->flags == msg->flags && 257 strequal(tmp_ptr->msg->printer, msg->printer)) { 258 259 DEBUG(5,("send_spoolss_notify2_msg: replacing message 0x%02x/0x%02x for " 260 "printer %s in notify_queue\n", msg->type, msg->field, msg->printer)); 261 262 tmp_ptr->msg = msg; 263 return; 264 } 265 } 266 } 267 268 /* Store the message on the pending queue. */ 269 270 pnqueue = TALLOC_P(send_ctx, struct notify_queue); 271 if (!pnqueue) { 272 DEBUG(0,("send_spoolss_notify2_msg: Out of memory.\n")); 273 return; 274 } 275 276 /* allocate a new msg structure and copy the fields */ 277 278 if ( !(pnqueue->msg = TALLOC_P(send_ctx, SPOOLSS_NOTIFY_MSG)) ) { 279 DEBUG(0,("send_spoolss_notify2_msg: talloc() of size [%lu] failed!\n", 280 (unsigned long)sizeof(SPOOLSS_NOTIFY_MSG))); 281 return; 282 } 283 copy_notify2_msg(pnqueue->msg, msg); 284 GetTimeOfDay(&pnqueue->tv); 285 pnqueue->buf = NULL; 286 pnqueue->buflen = 0; 287 288 DEBUG(5, ("send_spoolss_notify2_msg: appending message 0x%02x/0x%02x for printer %s \ 289to notify_queue_head\n", msg->type, msg->field, msg->printer)); 290 291 /* 292 * Note we add to the end of the list to ensure 293 * the messages are sent in the order they were received. JRA. 294 */ 295 296 DLIST_ADD_END(notify_queue_head, pnqueue, tmp_ptr); 297 num_messages++; 298} 299 300static void send_notify_field_values(const char *sharename, uint32 type, 301 uint32 field, uint32 id, uint32 value1, 302 uint32 value2, uint32 flags) 303{ 304 struct spoolss_notify_msg *msg; 305 306 if (lp_disable_spoolss()) 307 return; 308 309 if (!create_send_ctx()) 310 return; 311 312 msg = TALLOC_P(send_ctx, struct spoolss_notify_msg); 313 if (!msg) 314 return; 315 316 ZERO_STRUCTP(msg); 317 318 fstrcpy(msg->printer, sharename); 319 msg->type = type; 320 msg->field = field; 321 msg->id = id; 322 msg->notify.value[0] = value1; 323 msg->notify.value[1] = value2; 324 msg->flags = flags; 325 326 send_spoolss_notify2_msg(msg); 327} 328 329static void send_notify_field_buffer(const char *sharename, uint32 type, 330 uint32 field, uint32 id, uint32 len, 331 char *buffer) 332{ 333 struct spoolss_notify_msg *msg; 334 335 if (lp_disable_spoolss()) 336 return; 337 338 if (!create_send_ctx()) 339 return; 340 341 msg = TALLOC_P(send_ctx, struct spoolss_notify_msg); 342 if (!msg) 343 return; 344 345 ZERO_STRUCTP(msg); 346 347 fstrcpy(msg->printer, sharename); 348 msg->type = type; 349 msg->field = field; 350 msg->id = id; 351 msg->len = len; 352 msg->notify.data = buffer; 353 354 send_spoolss_notify2_msg(msg); 355} 356 357/* Send a message that the printer status has changed */ 358 359void notify_printer_status_byname(const char *sharename, uint32 status) 360{ 361 /* Printer status stored in value1 */ 362 363 send_notify_field_values(sharename, PRINTER_NOTIFY_TYPE, 364 PRINTER_NOTIFY_STATUS, 0, 365 status, 0, 0); 366} 367 368void notify_printer_status(int snum, uint32 status) 369{ 370 const char *sharename = SERVICE(snum); 371 372 if (sharename) 373 notify_printer_status_byname(sharename, status); 374} 375 376void notify_job_status_byname(const char *sharename, uint32 jobid, uint32 status, 377 uint32 flags) 378{ 379 /* Job id stored in id field, status in value1 */ 380 381 send_notify_field_values(sharename, JOB_NOTIFY_TYPE, 382 JOB_NOTIFY_STATUS, jobid, 383 status, 0, flags); 384} 385 386void notify_job_status(const char *sharename, uint32 jobid, uint32 status) 387{ 388 notify_job_status_byname(sharename, jobid, status, 0); 389} 390 391void notify_job_total_bytes(const char *sharename, uint32 jobid, 392 uint32 size) 393{ 394 /* Job id stored in id field, status in value1 */ 395 396 send_notify_field_values(sharename, JOB_NOTIFY_TYPE, 397 JOB_NOTIFY_TOTAL_BYTES, jobid, 398 size, 0, 0); 399} 400 401void notify_job_total_pages(const char *sharename, uint32 jobid, 402 uint32 pages) 403{ 404 /* Job id stored in id field, status in value1 */ 405 406 send_notify_field_values(sharename, JOB_NOTIFY_TYPE, 407 JOB_NOTIFY_TOTAL_PAGES, jobid, 408 pages, 0, 0); 409} 410 411void notify_job_username(const char *sharename, uint32 jobid, char *name) 412{ 413 send_notify_field_buffer( 414 sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_USER_NAME, 415 jobid, strlen(name) + 1, name); 416} 417 418void notify_job_name(const char *sharename, uint32 jobid, char *name) 419{ 420 send_notify_field_buffer( 421 sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_DOCUMENT, 422 jobid, strlen(name) + 1, name); 423} 424 425void notify_job_submitted(const char *sharename, uint32 jobid, 426 time_t submitted) 427{ 428 send_notify_field_buffer( 429 sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_SUBMITTED, 430 jobid, sizeof(submitted), (char *)&submitted); 431} 432 433void notify_printer_driver(int snum, char *driver_name) 434{ 435 const char *sharename = SERVICE(snum); 436 437 send_notify_field_buffer( 438 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME, 439 snum, strlen(driver_name) + 1, driver_name); 440} 441 442void notify_printer_comment(int snum, char *comment) 443{ 444 const char *sharename = SERVICE(snum); 445 446 send_notify_field_buffer( 447 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT, 448 snum, strlen(comment) + 1, comment); 449} 450 451void notify_printer_sharename(int snum, char *share_name) 452{ 453 const char *sharename = SERVICE(snum); 454 455 send_notify_field_buffer( 456 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME, 457 snum, strlen(share_name) + 1, share_name); 458} 459 460void notify_printer_printername(int snum, char *printername) 461{ 462 const char *sharename = SERVICE(snum); 463 464 send_notify_field_buffer( 465 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME, 466 snum, strlen(printername) + 1, printername); 467} 468 469void notify_printer_port(int snum, char *port_name) 470{ 471 const char *sharename = SERVICE(snum); 472 473 send_notify_field_buffer( 474 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME, 475 snum, strlen(port_name) + 1, port_name); 476} 477 478void notify_printer_location(int snum, char *location) 479{ 480 const char *sharename = SERVICE(snum); 481 482 send_notify_field_buffer( 483 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION, 484 snum, strlen(location) + 1, location); 485} 486 487void notify_printer_byname( const char *printername, uint32 change, char *value ) 488{ 489 int snum = print_queue_snum(printername); 490 int type = PRINTER_NOTIFY_TYPE; 491 492 if ( snum == -1 ) 493 return; 494 495 send_notify_field_buffer( printername, type, change, snum, strlen(value)+1, value ); 496} 497 498 499/**************************************************************************** 500 Return a malloced list of pid_t's that are interested in getting update 501 messages on this print queue. Used in printing/notify to send the messages. 502****************************************************************************/ 503 504BOOL print_notify_pid_list(const char *printername, TALLOC_CTX *mem_ctx, size_t *p_num_pids, pid_t **pp_pid_list) 505{ 506 struct tdb_print_db *pdb = NULL; 507 TDB_CONTEXT *tdb = NULL; 508 TDB_DATA data; 509 BOOL ret = True; 510 size_t i, num_pids, offset; 511 pid_t *pid_list; 512 513 *p_num_pids = 0; 514 *pp_pid_list = NULL; 515 516 pdb = get_print_db_byname(printername); 517 if (!pdb) 518 return False; 519 tdb = pdb->tdb; 520 521 if (tdb_read_lock_bystring(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) { 522 DEBUG(0,("print_notify_pid_list: Failed to lock printer %s database\n", 523 printername)); 524 if (pdb) 525 release_print_db(pdb); 526 return False; 527 } 528 529 data = get_printer_notify_pid_list( tdb, printername, True ); 530 531 if (!data.dptr) { 532 ret = True; 533 goto done; 534 } 535 536 num_pids = data.dsize / 8; 537 538 if ((pid_list = TALLOC_ARRAY(mem_ctx, pid_t, num_pids)) == NULL) { 539 ret = False; 540 goto done; 541 } 542 543 for( i = 0, offset = 0; offset < data.dsize; offset += 8, i++) 544 pid_list[i] = (pid_t)IVAL(data.dptr, offset); 545 546 *pp_pid_list = pid_list; 547 *p_num_pids = num_pids; 548 549 ret = True; 550 551 done: 552 553 tdb_read_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY); 554 if (pdb) 555 release_print_db(pdb); 556 SAFE_FREE(data.dptr); 557 return ret; 558} 559