printing/notify.c

説明を見る。
00001 /* 
00002    Unix SMB/Netbios implementation.
00003    Version 3.0
00004    printing backend routines
00005    Copyright (C) Tim Potter, 2002
00006    Copyright (C) Gerald Carter,         2002
00007    
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017    
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 
00023 #include "includes.h"
00024 #include "printing.h"
00025 
00026 static TALLOC_CTX *send_ctx;
00027 
00028 static unsigned int num_messages;
00029 
00030 static struct notify_queue {
00031         struct notify_queue *next, *prev;
00032         struct spoolss_notify_msg *msg;
00033         struct timeval tv;
00034         char *buf;
00035         size_t buflen;
00036 } *notify_queue_head = NULL;
00037 
00038 
00039 static BOOL create_send_ctx(void)
00040 {
00041         if (!send_ctx)
00042                 send_ctx = talloc_init("print notify queue");
00043 
00044         if (!send_ctx)
00045                 return False;
00046 
00047         return True;
00048 }
00049 
00050 /****************************************************************************
00051  Turn a queue name into a snum.
00052 ****************************************************************************/
00053 
00054 int print_queue_snum(const char *qname)
00055 {
00056         int snum = lp_servicenumber(qname);
00057         if (snum == -1 || !lp_print_ok(snum))
00058                 return -1;
00059         return snum;
00060 }
00061 
00062 /*******************************************************************
00063  Used to decide if we need a short select timeout.
00064 *******************************************************************/
00065 
00066 BOOL print_notify_messages_pending(void)
00067 {
00068         return (notify_queue_head != NULL);
00069 }
00070 
00071 /*******************************************************************
00072  Flatten data into a message.
00073 *******************************************************************/
00074 
00075 static BOOL flatten_message(struct notify_queue *q)
00076 {
00077         struct spoolss_notify_msg *msg = q->msg;
00078         char *buf = NULL;
00079         size_t buflen = 0, len;
00080 
00081 again:
00082         len = 0;
00083 
00084         /* Pack header */
00085 
00086         len += tdb_pack(buf + len, buflen - len, "f", msg->printer);
00087 
00088         len += tdb_pack(buf + len, buflen - len, "ddddddd",
00089                         (uint32)q->tv.tv_sec, (uint32)q->tv.tv_usec,
00090                         msg->type, msg->field, msg->id, msg->len, msg->flags);
00091 
00092         /* Pack data */
00093 
00094         if (msg->len == 0)
00095                 len += tdb_pack(buf + len, buflen - len, "dd",
00096                                 msg->notify.value[0], msg->notify.value[1]);
00097         else
00098                 len += tdb_pack(buf + len, buflen - len, "B",
00099                                 msg->len, msg->notify.data);
00100 
00101         if (buflen != len) {
00102                 buf = (char *)TALLOC_REALLOC(send_ctx, buf, len);
00103                 if (!buf)
00104                         return False;
00105                 buflen = len;
00106                 goto again;
00107         }
00108 
00109         q->buf = buf;
00110         q->buflen = buflen;
00111 
00112         return True;
00113 }
00114 
00115 /*******************************************************************
00116  Send the batched messages - on a per-printer basis.
00117 *******************************************************************/
00118 
00119 static void print_notify_send_messages_to_printer(const char *printer, unsigned int timeout)
00120 {
00121         char *buf;
00122         struct notify_queue *pq, *pq_next;
00123         size_t msg_count = 0, offset = 0;
00124         size_t num_pids = 0;
00125         size_t i;
00126         pid_t *pid_list = NULL;
00127 
00128         /* Count the space needed to send the messages. */
00129         for (pq = notify_queue_head; pq; pq = pq->next) {
00130                 if (strequal(printer, pq->msg->printer)) {
00131                         if (!flatten_message(pq)) {
00132                                 DEBUG(0,("print_notify_send_messages: Out of memory\n"));
00133                                 talloc_free_children(send_ctx);
00134                                 num_messages = 0;
00135                                 return;
00136                         }
00137                         offset += (pq->buflen + 4);
00138                         msg_count++;
00139                 }       
00140         }
00141         offset += 4; /* For count. */
00142 
00143         buf = (char *)TALLOC(send_ctx, offset);
00144         if (!buf) {
00145                 DEBUG(0,("print_notify_send_messages: Out of memory\n"));
00146                 talloc_free_children(send_ctx);
00147                 num_messages = 0;
00148                 return;
00149         }
00150 
00151         offset = 0;
00152         SIVAL(buf,offset,msg_count);
00153         offset += 4;
00154         for (pq = notify_queue_head; pq; pq = pq_next) {
00155                 pq_next = pq->next;
00156 
00157                 if (strequal(printer, pq->msg->printer)) {
00158                         SIVAL(buf,offset,pq->buflen);
00159                         offset += 4;
00160                         memcpy(buf + offset, pq->buf, pq->buflen);
00161                         offset += pq->buflen;
00162 
00163                         /* Remove from list. */
00164                         DLIST_REMOVE(notify_queue_head, pq);
00165                 }
00166         }
00167 
00168         DEBUG(5, ("print_notify_send_messages_to_printer: sending %lu print notify message%s to printer %s\n", 
00169                   (unsigned long)msg_count, msg_count != 1 ? "s" : "", printer));
00170 
00171         /*
00172          * Get the list of PID's to send to.
00173          */
00174 
00175         if (!print_notify_pid_list(printer, send_ctx, &num_pids, &pid_list))
00176                 return;
00177 
00178         for (i = 0; i < num_pids; i++) {
00179                 unsigned int q_len = messages_pending_for_pid(pid_to_procid(pid_list[i]));
00180                 if (q_len > 1000) {
00181                         DEBUG(5, ("print_notify_send_messages_to_printer: discarding notify to printer %s as queue length = %u\n",
00182                                 printer, q_len ));
00183                         continue;
00184                 }
00185                 message_send_pid_with_timeout(pid_to_procid(pid_list[i]),
00186                                               MSG_PRINTER_NOTIFY2,
00187                                               buf, offset, True, timeout);
00188         }
00189 }
00190 
00191 /*******************************************************************
00192  Actually send the batched messages.
00193 *******************************************************************/
00194 
00195 void print_notify_send_messages(unsigned int timeout)
00196 {
00197         if (!print_notify_messages_pending())
00198                 return;
00199 
00200         if (!create_send_ctx())
00201                 return;
00202 
00203         while (print_notify_messages_pending())
00204                 print_notify_send_messages_to_printer(notify_queue_head->msg->printer, timeout);
00205 
00206         talloc_free_children(send_ctx);
00207         num_messages = 0;
00208 }
00209 
00210 /**********************************************************************
00211  deep copy a SPOOLSS_NOTIFY_MSG structure using a TALLOC_CTX
00212  *********************************************************************/
00213  
00214 static BOOL copy_notify2_msg( SPOOLSS_NOTIFY_MSG *to, SPOOLSS_NOTIFY_MSG *from )
00215 {
00216 
00217         if ( !to || !from )
00218                 return False;
00219         
00220         memcpy( to, from, sizeof(SPOOLSS_NOTIFY_MSG) );
00221         
00222         if ( from->len ) {
00223                 to->notify.data = (char *)TALLOC_MEMDUP(send_ctx, from->notify.data, from->len );
00224                 if ( !to->notify.data ) {
00225                         DEBUG(0,("copy_notify2_msg: TALLOC_MEMDUP() of size [%d] failed!\n", from->len ));
00226                         return False;
00227                 }
00228         }
00229         
00230 
00231         return True;
00232 }
00233 
00234 /*******************************************************************
00235  Batch up print notify messages.
00236 *******************************************************************/
00237 
00238 static void send_spoolss_notify2_msg(SPOOLSS_NOTIFY_MSG *msg)
00239 {
00240         struct notify_queue *pnqueue, *tmp_ptr;
00241 
00242         /*
00243          * Ensure we only have one job total_bytes and job total_pages for
00244          * each job. There is no point in sending multiple messages that match
00245          * as they will just cause flickering updates in the client.
00246          */
00247 
00248         if ((num_messages < 100) && (msg->type == JOB_NOTIFY_TYPE) 
00249                 && (msg->field == JOB_NOTIFY_TOTAL_BYTES 
00250                     || msg->field == JOB_NOTIFY_TOTAL_PAGES )) 
00251         {
00252 
00253                 for (tmp_ptr = notify_queue_head; tmp_ptr; tmp_ptr = tmp_ptr->next) 
00254                 {
00255                         if (tmp_ptr->msg->type == msg->type &&
00256                                         tmp_ptr->msg->field == msg->field &&
00257                                         tmp_ptr->msg->id == msg->id &&
00258                                         tmp_ptr->msg->flags == msg->flags &&
00259                                         strequal(tmp_ptr->msg->printer, msg->printer)) {
00260 
00261                                 DEBUG(5,("send_spoolss_notify2_msg: replacing message 0x%02x/0x%02x for "
00262                                          "printer %s in notify_queue\n", msg->type, msg->field, msg->printer));
00263 
00264                                 tmp_ptr->msg = msg;
00265                                 return;
00266                         }
00267                 }
00268         }
00269 
00270         /* Store the message on the pending queue. */
00271 
00272         pnqueue = TALLOC_P(send_ctx, struct notify_queue);
00273         if (!pnqueue) {
00274                 DEBUG(0,("send_spoolss_notify2_msg: Out of memory.\n"));
00275                 return;
00276         }
00277 
00278         /* allocate a new msg structure and copy the fields */
00279         
00280         if ( !(pnqueue->msg = TALLOC_P(send_ctx, SPOOLSS_NOTIFY_MSG)) ) {
00281                 DEBUG(0,("send_spoolss_notify2_msg: talloc() of size [%lu] failed!\n", 
00282                         (unsigned long)sizeof(SPOOLSS_NOTIFY_MSG)));
00283                 return;
00284         }
00285         copy_notify2_msg(pnqueue->msg, msg);
00286         GetTimeOfDay(&pnqueue->tv);
00287         pnqueue->buf = NULL;
00288         pnqueue->buflen = 0;
00289 
00290         DEBUG(5, ("send_spoolss_notify2_msg: appending message 0x%02x/0x%02x for printer %s \
00291 to notify_queue_head\n", msg->type, msg->field, msg->printer));
00292 
00293         /*
00294          * Note we add to the end of the list to ensure
00295          * the messages are sent in the order they were received. JRA.
00296          */
00297 
00298         DLIST_ADD_END(notify_queue_head, pnqueue, struct notify_queue *);
00299         num_messages++;
00300 }
00301 
00302 static void send_notify_field_values(const char *sharename, uint32 type,
00303                                      uint32 field, uint32 id, uint32 value1, 
00304                                      uint32 value2, uint32 flags)
00305 {
00306         struct spoolss_notify_msg *msg;
00307 
00308         if (lp_disable_spoolss())
00309                 return;
00310 
00311         if (!create_send_ctx())
00312                 return;
00313 
00314         msg = TALLOC_P(send_ctx, struct spoolss_notify_msg);
00315         if (!msg)
00316                 return;
00317 
00318         ZERO_STRUCTP(msg);
00319 
00320         fstrcpy(msg->printer, sharename);
00321         msg->type = type;
00322         msg->field = field;
00323         msg->id = id;
00324         msg->notify.value[0] = value1;
00325         msg->notify.value[1] = value2;
00326         msg->flags = flags;
00327 
00328         send_spoolss_notify2_msg(msg);
00329 }
00330 
00331 static void send_notify_field_buffer(const char *sharename, uint32 type,
00332                                      uint32 field, uint32 id, uint32 len,
00333                                      const char *buffer)
00334 {
00335         struct spoolss_notify_msg *msg;
00336 
00337         if (lp_disable_spoolss())
00338                 return;
00339 
00340         if (!create_send_ctx())
00341                 return;
00342 
00343         msg = TALLOC_P(send_ctx, struct spoolss_notify_msg);
00344         if (!msg)
00345                 return;
00346 
00347         ZERO_STRUCTP(msg);
00348 
00349         fstrcpy(msg->printer, sharename);
00350         msg->type = type;
00351         msg->field = field;
00352         msg->id = id;
00353         msg->len = len;
00354         msg->notify.data = CONST_DISCARD(char *,buffer);
00355 
00356         send_spoolss_notify2_msg(msg);
00357 }
00358 
00359 /* Send a message that the printer status has changed */
00360 
00361 void notify_printer_status_byname(const char *sharename, uint32 status)
00362 {
00363         /* Printer status stored in value1 */
00364 
00365         send_notify_field_values(sharename, PRINTER_NOTIFY_TYPE, 
00366                                  PRINTER_NOTIFY_STATUS, 0, 
00367                                  status, 0, 0);
00368 }
00369 
00370 void notify_printer_status(int snum, uint32 status)
00371 {
00372         const char *sharename = SERVICE(snum); 
00373 
00374         if (sharename)
00375                 notify_printer_status_byname(sharename, status);
00376 }
00377 
00378 void notify_job_status_byname(const char *sharename, uint32 jobid, uint32 status,
00379                               uint32 flags)
00380 {
00381         /* Job id stored in id field, status in value1 */
00382 
00383         send_notify_field_values(sharename, JOB_NOTIFY_TYPE,
00384                                  JOB_NOTIFY_STATUS, jobid,
00385                                  status, 0, flags);
00386 }
00387 
00388 void notify_job_status(const char *sharename, uint32 jobid, uint32 status)
00389 {
00390         notify_job_status_byname(sharename, jobid, status, 0);
00391 }
00392 
00393 void notify_job_total_bytes(const char *sharename, uint32 jobid,
00394                             uint32 size)
00395 {
00396         /* Job id stored in id field, status in value1 */
00397 
00398         send_notify_field_values(sharename, JOB_NOTIFY_TYPE,
00399                                  JOB_NOTIFY_TOTAL_BYTES, jobid,
00400                                  size, 0, 0);
00401 }
00402 
00403 void notify_job_total_pages(const char *sharename, uint32 jobid,
00404                             uint32 pages)
00405 {
00406         /* Job id stored in id field, status in value1 */
00407 
00408         send_notify_field_values(sharename, JOB_NOTIFY_TYPE,
00409                                  JOB_NOTIFY_TOTAL_PAGES, jobid,
00410                                  pages, 0, 0);
00411 }
00412 
00413 void notify_job_username(const char *sharename, uint32 jobid, char *name)
00414 {
00415         send_notify_field_buffer(
00416                 sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_USER_NAME,
00417                 jobid, strlen(name) + 1, name);
00418 }
00419 
00420 void notify_job_name(const char *sharename, uint32 jobid, char *name)
00421 {
00422         send_notify_field_buffer(
00423                 sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_DOCUMENT,
00424                 jobid, strlen(name) + 1, name);
00425 }
00426 
00427 void notify_job_submitted(const char *sharename, uint32 jobid,
00428                           time_t submitted)
00429 {
00430         send_notify_field_buffer(
00431                 sharename, JOB_NOTIFY_TYPE, JOB_NOTIFY_SUBMITTED,
00432                 jobid, sizeof(submitted), (char *)&submitted);
00433 }
00434 
00435 void notify_printer_driver(int snum, char *driver_name)
00436 {
00437         const char *sharename = SERVICE(snum);
00438 
00439         send_notify_field_buffer(
00440                 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_DRIVER_NAME,
00441                 snum, strlen(driver_name) + 1, driver_name);
00442 }
00443 
00444 void notify_printer_comment(int snum, char *comment)
00445 {
00446         const char *sharename = SERVICE(snum);
00447 
00448         send_notify_field_buffer(
00449                 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_COMMENT,
00450                 snum, strlen(comment) + 1, comment);
00451 }
00452 
00453 void notify_printer_sharename(int snum, char *share_name)
00454 {
00455         const char *sharename = SERVICE(snum);
00456 
00457         send_notify_field_buffer(
00458                 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_SHARE_NAME,
00459                 snum, strlen(share_name) + 1, share_name);
00460 }
00461 
00462 void notify_printer_printername(int snum, char *printername)
00463 {
00464         const char *sharename = SERVICE(snum);
00465 
00466         send_notify_field_buffer(
00467                 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PRINTER_NAME,
00468                 snum, strlen(printername) + 1, printername);
00469 }
00470 
00471 void notify_printer_port(int snum, char *port_name)
00472 {
00473         const char *sharename = SERVICE(snum);
00474 
00475         send_notify_field_buffer(
00476                 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_PORT_NAME,
00477                 snum, strlen(port_name) + 1, port_name);
00478 }
00479 
00480 void notify_printer_location(int snum, char *location)
00481 {
00482         const char *sharename = SERVICE(snum);
00483 
00484         send_notify_field_buffer(
00485                 sharename, PRINTER_NOTIFY_TYPE, PRINTER_NOTIFY_LOCATION,
00486                 snum, strlen(location) + 1, location);
00487 }
00488 
00489 void notify_printer_byname( const char *printername, uint32 change, const char *value )
00490 {
00491         int snum = print_queue_snum(printername);
00492         int type = PRINTER_NOTIFY_TYPE;
00493         
00494         if ( snum == -1 )
00495                 return;
00496                 
00497         send_notify_field_buffer( printername, type, change, snum, strlen(value)+1, value );
00498 } 
00499 
00500 
00501 /****************************************************************************
00502  Return a malloced list of pid_t's that are interested in getting update
00503  messages on this print queue. Used in printing/notify to send the messages.
00504 ****************************************************************************/
00505 
00506 BOOL print_notify_pid_list(const char *printername, TALLOC_CTX *mem_ctx, size_t *p_num_pids, pid_t **pp_pid_list)
00507 {
00508         struct tdb_print_db *pdb = NULL;
00509         TDB_CONTEXT *tdb = NULL;
00510         TDB_DATA data;
00511         BOOL ret = True;
00512         size_t i, num_pids, offset;
00513         pid_t *pid_list;
00514 
00515         *p_num_pids = 0;
00516         *pp_pid_list = NULL;
00517 
00518         pdb = get_print_db_byname(printername);
00519         if (!pdb)
00520                 return False;
00521         tdb = pdb->tdb;
00522 
00523         if (tdb_read_lock_bystring_with_timeout(tdb, NOTIFY_PID_LIST_KEY, 10) == -1) {
00524                 DEBUG(0,("print_notify_pid_list: Failed to lock printer %s database\n",
00525                                         printername));
00526                 if (pdb)
00527                         release_print_db(pdb);
00528                 return False;
00529         }
00530 
00531         data = get_printer_notify_pid_list( tdb, printername, True );
00532 
00533         if (!data.dptr) {
00534                 ret = True;
00535                 goto done;
00536         }
00537 
00538         num_pids = data.dsize / 8;
00539 
00540         if (num_pids) {
00541                 if ((pid_list = TALLOC_ARRAY(mem_ctx, pid_t, num_pids)) == NULL) {
00542                         ret = False;
00543                         goto done;
00544                 }
00545         } else {
00546                 pid_list = NULL;
00547         }
00548 
00549         for( i = 0, offset = 0; offset < data.dsize; offset += 8, i++)
00550                 pid_list[i] = (pid_t)IVAL(data.dptr, offset);
00551 
00552         *pp_pid_list = pid_list;
00553         *p_num_pids = num_pids;
00554 
00555         ret = True;
00556 
00557   done:
00558 
00559         tdb_read_unlock_bystring(tdb, NOTIFY_PID_LIST_KEY);
00560         if (pdb)
00561                 release_print_db(pdb);
00562         SAFE_FREE(data.dptr);
00563         return ret;
00564 }

Sambaに対してSat Aug 29 21:23:13 2009に生成されました。  doxygen 1.4.7