summaryrefslogtreecommitdiff
path: root/source3/printing
diff options
context:
space:
mode:
Diffstat (limited to 'source3/printing')
-rw-r--r--source3/printing/printing.c204
1 files changed, 174 insertions, 30 deletions
diff --git a/source3/printing/printing.c b/source3/printing/printing.c
index 9e0e4a570b..ca6139cad5 100644
--- a/source3/printing/printing.c
+++ b/source3/printing/printing.c
@@ -558,19 +558,97 @@ static uint32 map_to_spoolss_status(uint32 lpq_status)
return 0;
}
+/***************************************************************************
+ Append a jobid to the 'jobs changed' list.
+***************************************************************************/
+
+static bool add_to_jobs_changed(struct tdb_print_db *pdb, uint32_t jobid)
+{
+ TDB_DATA data;
+ uint32_t store_jobid;
+
+ SIVAL(&store_jobid, 0, jobid);
+ data.dptr = (uint8 *) &store_jobid;
+ data.dsize = 4;
+
+ DEBUG(10,("add_to_jobs_added: Added jobid %u\n", (unsigned int)jobid ));
+
+ return (tdb_append(pdb->tdb, string_tdb_data("INFO/jobs_changed"),
+ data) == 0);
+}
+
+/***************************************************************************
+ Remove a jobid from the 'jobs changed' list.
+***************************************************************************/
+
+static bool remove_from_jobs_changed(const char* sharename, uint32_t jobid)
+{
+ struct tdb_print_db *pdb = get_print_db_byname(sharename);
+ TDB_DATA data, key;
+ size_t job_count, i;
+ bool ret = False;
+ bool gotlock = False;
+
+ if (!pdb) {
+ return False;
+ }
+
+ ZERO_STRUCT(data);
+
+ key = string_tdb_data("INFO/jobs_changed");
+
+ if (tdb_chainlock_with_timeout(pdb->tdb, key, 5) == -1)
+ goto out;
+
+ gotlock = True;
+
+ data = tdb_fetch(pdb->tdb, key);
+
+ if (data.dptr == NULL || data.dsize == 0 || (data.dsize % 4 != 0))
+ goto out;
+
+ job_count = data.dsize / 4;
+ for (i = 0; i < job_count; i++) {
+ uint32 ch_jobid;
+
+ ch_jobid = IVAL(data.dptr, i*4);
+ if (ch_jobid == jobid) {
+ if (i < job_count -1 )
+ memmove(data.dptr + (i*4), data.dptr + (i*4) + 4, (job_count - i - 1)*4 );
+ data.dsize -= 4;
+ if (tdb_store(pdb->tdb, key, data, TDB_REPLACE) == -1)
+ goto out;
+ break;
+ }
+ }
+
+ ret = True;
+ out:
+
+ if (gotlock)
+ tdb_chainunlock(pdb->tdb, key);
+ SAFE_FREE(data.dptr);
+ release_print_db(pdb);
+ if (ret)
+ DEBUG(10,("remove_from_jobs_changed: removed jobid %u\n", (unsigned int)jobid ));
+ else
+ DEBUG(10,("remove_from_jobs_changed: Failed to remove jobid %u\n", (unsigned int)jobid ));
+ return ret;
+}
+
static void pjob_store_notify(struct tevent_context *ev,
struct messaging_context *msg_ctx,
const char* sharename, uint32 jobid,
struct printjob *old_data,
- struct printjob *new_data)
+ struct printjob *new_data,
+ bool *pchanged)
{
- bool new_job = False;
-
- if (!old_data)
- new_job = True;
+ bool new_job = false;
+ bool changed = false;
- /* Job attributes that can't be changed. We only send
- notification for these on a new job. */
+ if (old_data == NULL) {
+ new_job = true;
+ }
/* ACHTUNG! Due to a bug in Samba's spoolss parsing of the
NOTIFY_INFO_DATA buffer, we *have* to send the job submission
@@ -584,31 +662,40 @@ static void pjob_store_notify(struct tevent_context *ev,
sharename, jobid, new_data->starttime);
notify_job_username(ev, msg_ctx,
sharename, jobid, new_data->user);
- }
-
- if (new_job || !strequal(old_data->jobname, new_data->jobname))
- notify_job_name(ev, msg_ctx,
- sharename, jobid, new_data->jobname);
-
- /* Job attributes of a new job or attributes that can be
- modified. */
-
- if (new_job || !strequal(old_data->jobname, new_data->jobname))
notify_job_name(ev, msg_ctx,
sharename, jobid, new_data->jobname);
-
- if (new_job || old_data->status != new_data->status)
notify_job_status(ev, msg_ctx,
- sharename, jobid,
- map_to_spoolss_status(new_data->status));
-
- if (new_job || old_data->size != new_data->size)
+ sharename, jobid, map_to_spoolss_status(new_data->status));
notify_job_total_bytes(ev, msg_ctx,
sharename, jobid, new_data->size);
-
- if (new_job || old_data->page_count != new_data->page_count)
notify_job_total_pages(ev, msg_ctx,
sharename, jobid, new_data->page_count);
+ } else {
+ if (!strequal(old_data->jobname, new_data->jobname)) {
+ notify_job_name(ev, msg_ctx, sharename,
+ jobid, new_data->jobname);
+ changed = true;
+ }
+
+ if (old_data->status != new_data->status) {
+ notify_job_status(ev, msg_ctx,
+ sharename, jobid,
+ map_to_spoolss_status(new_data->status));
+ }
+
+ if (old_data->size != new_data->size) {
+ notify_job_total_bytes(ev, msg_ctx,
+ sharename, jobid, new_data->size);
+ }
+
+ if (old_data->page_count != new_data->page_count) {
+ notify_job_total_pages(ev, msg_ctx,
+ sharename, jobid,
+ new_data->page_count);
+ }
+ }
+
+ *pchanged = changed;
}
/****************************************************************************
@@ -678,11 +765,10 @@ static bool pjob_store(struct tevent_context *ev,
ret = (tdb_store(pdb->tdb, print_key(jobid, &tmp), new_data,
TDB_REPLACE) == 0);
- release_print_db(pdb);
-
/* Send notify updates for what has changed */
if ( ret ) {
+ bool changed = false;
struct printjob old_pjob;
if ( old_data.dsize )
@@ -692,17 +778,25 @@ static bool pjob_store(struct tevent_context *ev,
pjob_store_notify(server_event_context(),
msg_ctx,
sharename, jobid, &old_pjob,
- pjob);
+ pjob,
+ &changed);
talloc_free(old_pjob.devmode);
+
+ if (changed) {
+ add_to_jobs_changed(pdb, jobid);
+ }
}
+
}
else {
/* new job */
pjob_store_notify(server_event_context(), msg_ctx,
- sharename, jobid, NULL, pjob);
+ sharename, jobid, NULL, pjob,
+ &changed);
}
}
+ release_print_db(pdb);
done:
SAFE_FREE( old_data.dptr );
SAFE_FREE( buf );
@@ -2913,10 +3007,11 @@ static bool get_stored_queue_info(struct messaging_context *msg_ctx,
struct tdb_print_db *pdb, int snum,
int *pcount, print_queue_struct **ppqueue)
{
- TDB_DATA data, cgdata;
+ TDB_DATA data, cgdata, jcdata;
print_queue_struct *queue = NULL;
uint32 qcount = 0;
uint32 extra_count = 0;
+ uint32_t changed_count = 0;
int total_count = 0;
size_t len = 0;
uint32 i;
@@ -2945,6 +3040,11 @@ static bool get_stored_queue_info(struct messaging_context *msg_ctx,
if (cgdata.dptr != NULL && (cgdata.dsize % 4 == 0))
extra_count = cgdata.dsize/4;
+ /* Get the changed jobs list. */
+ jcdata = tdb_fetch(pdb->tdb, string_tdb_data("INFO/jobs_changed"));
+ if (jcdata.dptr != NULL && (jcdata.dsize % 4 == 0))
+ changed_count = jcdata.dsize / 4;
+
DEBUG(5,("get_stored_queue_info: qcount = %u, extra_count = %u\n", (unsigned int)qcount, (unsigned int)extra_count));
/* Allocate the queue size. */
@@ -3002,6 +3102,50 @@ static bool get_stored_queue_info(struct messaging_context *msg_ctx,
total_count++;
}
+ /* Update the changed jobids. */
+ for (i = 0; i < changed_count; i++) {
+ uint32_t jobid = IVAL(jcdata.dptr, i * 4);
+ uint32_t j;
+ bool found = false;
+
+ for (j = 0; j < total_count; j++) {
+ if (queue[j].job == jobid) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ struct printjob *pjob;
+
+ DEBUG(5,("get_stored_queue_info: changed job: %u\n",
+ (unsigned int) jobid));
+
+ pjob = print_job_find(sharename, jobid);
+ if (pjob == NULL) {
+ DEBUG(5,("get_stored_queue_info: failed to find "
+ "changed job = %u\n",
+ (unsigned int) jobid));
+ remove_from_jobs_changed(sharename, jobid);
+ continue;
+ }
+
+ queue[j].job = jobid;
+ queue[j].size = pjob->size;
+ queue[j].page_count = pjob->page_count;
+ queue[j].status = pjob->status;
+ queue[j].priority = 1;
+ queue[j].time = pjob->starttime;
+ fstrcpy(queue[j].fs_user, pjob->user);
+ fstrcpy(queue[j].fs_file, pjob->jobname);
+
+ DEBUG(5,("get_stored_queue_info: updated queue[%u], jobid: %u, jobname: %s\n",
+ (unsigned int) j, (unsigned int) jobid, pjob->jobname));
+ }
+
+ remove_from_jobs_changed(sharename, jobid);
+ }
+
/* Sort the queue by submission time otherwise they are displayed
in hash order. */