root/source3/printing/notify.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. create_send_ctx
  2. print_queue_snum
  3. print_notify_messages_pending
  4. flatten_message
  5. print_notify_send_messages_to_printer
  6. print_notify_send_messages
  7. print_notify_event_send_messages
  8. copy_notify2_msg
  9. send_spoolss_notify2_msg
  10. send_notify_field_values
  11. send_notify_field_buffer
  12. notify_printer_status_byname
  13. notify_printer_status
  14. notify_job_status_byname
  15. notify_job_status
  16. notify_job_total_bytes
  17. notify_job_total_pages
  18. notify_job_username
  19. notify_job_name
  20. notify_job_submitted
  21. notify_printer_driver
  22. notify_printer_comment
  23. notify_printer_sharename
  24. notify_printer_printername
  25. notify_printer_port
  26. notify_printer_location
  27. notify_printer_byname
  28. print_notify_pid_list

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

/* [<][>][^][v][top][bottom][index][help] */