00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
00064
00065
00066 BOOL print_notify_messages_pending(void)
00067 {
00068 return (notify_queue_head != NULL);
00069 }
00070
00071
00072
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
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
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
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
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;
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
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
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
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
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
00236
00237
00238 static void send_spoolss_notify2_msg(SPOOLSS_NOTIFY_MSG *msg)
00239 {
00240 struct notify_queue *pnqueue, *tmp_ptr;
00241
00242
00243
00244
00245
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
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
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
00295
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
00360
00361 void notify_printer_status_byname(const char *sharename, uint32 status)
00362 {
00363
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
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
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
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
00503
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 }