diff options
Diffstat (limited to 'source/printing/printing.c')
-rw-r--r-- | source/printing/printing.c | 1185 |
1 files changed, 328 insertions, 857 deletions
diff --git a/source/printing/printing.c b/source/printing/printing.c index 6474c92c692..4ac2cfcb148 100644 --- a/source/printing/printing.c +++ b/source/printing/printing.c @@ -3,7 +3,6 @@ Version 3.0 printing backend routines Copyright (C) Andrew Tridgell 1992-2000 - Copyright (C) Jeremy Allison 2002 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,7 +22,7 @@ #include "printing.h" /* Current printer interface */ -static struct printif *current_printif = &generic_printif; +struct printif *current_printif = &generic_printif; /* the printing backend revolves around a tdb database that stores the @@ -39,193 +38,12 @@ static struct printif *current_printif = &generic_printif; jobids are assigned when a job starts spooling. */ -/*************************************************************************** - Nightmare. LANMAN jobid's are 16 bit numbers..... We must map them to 32 - bit RPC jobids.... JRA. -***************************************************************************/ - -static TDB_CONTEXT *rap_tdb; -static uint16 next_rap_jobid; - -uint16 pjobid_to_rap(int snum, uint32 jobid) -{ - uint16 rap_jobid; - TDB_DATA data, key; - char jinfo[8]; - - if (!rap_tdb) { - /* Create the in-memory tdb. */ - rap_tdb = tdb_open_log(NULL, 0, TDB_INTERNAL, (O_RDWR|O_CREAT), 0644); - if (!rap_tdb) - return 0; - } - - SIVAL(&jinfo,0,(int32)snum); - SIVAL(&jinfo,4,jobid); - - key.dptr = (char *)&jinfo; - key.dsize = sizeof(jinfo); - data = tdb_fetch(rap_tdb, key); - if (data.dptr && data.dsize == sizeof(uint16)) { - memcpy(&rap_jobid, data.dptr, sizeof(uint16)); - SAFE_FREE(data.dptr); - return rap_jobid; - } - /* Not found - create and store mapping. */ - rap_jobid = ++next_rap_jobid; - if (rap_jobid == 0) - rap_jobid = ++next_rap_jobid; - data.dptr = (char *)&rap_jobid; - data.dsize = sizeof(rap_jobid); - tdb_store(rap_tdb, key, data, TDB_REPLACE); - tdb_store(rap_tdb, data, key, TDB_REPLACE); - return rap_jobid; -} - -BOOL rap_to_pjobid(uint16 rap_jobid, int *psnum, uint32 *pjobid) -{ - TDB_DATA data, key; - char jinfo[8]; - - if (!rap_tdb) - return False; - - key.dptr = (char *)&rap_jobid; - key.dsize = sizeof(rap_jobid); - data = tdb_fetch(rap_tdb, key); - if (data.dptr && data.dsize == sizeof(jinfo)) { - *psnum = IVAL(&jinfo,0); - *pjobid = IVAL(&jinfo,4); - SAFE_FREE(data.dptr); - return True; - } - return False; -} - -static void rap_jobid_delete(int snum, uint32 jobid) -{ - TDB_DATA key, data; - uint16 rap_jobid; - char jinfo[8]; - - if (!rap_tdb) - return; - - SIVAL(&jinfo,0,(int32)snum); - SIVAL(&jinfo,4,jobid); - - key.dptr = (char *)&jinfo; - key.dsize = sizeof(jinfo); - data = tdb_fetch(rap_tdb, key); - if (!data.dptr || (data.dsize != sizeof(uint16))) - return; - - memcpy(&rap_jobid, data.dptr, sizeof(uint16)); - SAFE_FREE(data.dptr); - data.dptr = (char *)&rap_jobid; - data.dsize = sizeof(rap_jobid); - tdb_delete(rap_tdb, key); - tdb_delete(rap_tdb, data); -} - +/* the open printing.tdb database */ +static TDB_CONTEXT *tdb; static pid_t local_pid; static int get_queue_status(int, print_status_struct *); -/* There can be this many printing tdb's open, plus any locked ones. */ -#define MAX_PRINT_DBS_OPEN 1 - -struct tdb_print_db { - struct tdb_print_db *next, *prev; - TDB_CONTEXT *tdb; - int ref_count; - fstring printer_name; -}; - -static struct tdb_print_db *print_db_head; - -/**************************************************************************** - Function to find or create the printer specific job tdb given a printername. - Limits the number of tdb's open to MAX_PRINT_DBS_OPEN. -****************************************************************************/ - -static struct tdb_print_db *get_print_db_byname(const char *printername) -{ - struct tdb_print_db *p = NULL, *last_entry = NULL; - int num_open = 0; - pstring printdb_path; - - for (p = print_db_head, last_entry = print_db_head; p; p = p->next) { - if (p->tdb && strequal(p->printer_name, printername)) { - DLIST_PROMOTE(print_db_head, p); - p->ref_count++; - return p; - } - num_open++; - last_entry = p; - } - - /* Not found. */ - if (num_open >= MAX_PRINT_DBS_OPEN) { - /* Try and recycle the last entry. */ - DLIST_PROMOTE(print_db_head, last_entry); - - for (p = print_db_head; p; p = p->next) { - if (p->ref_count) - continue; - if (p->tdb) { - if (tdb_close(print_db_head->tdb)) { - DEBUG(0,("get_print_db: Failed to close tdb for printer %s\n", - print_db_head->printer_name )); - return NULL; - } - } - ZERO_STRUCTP(p); - break; - } - if (p) { - DLIST_PROMOTE(print_db_head, p); - p = print_db_head; - } - } - - if (!p) { - /* Create one. */ - p = (struct tdb_print_db *)malloc(sizeof(struct tdb_print_db)); - if (!p) { - DEBUG(0,("get_print_db: malloc fail !\n")); - return NULL; - } - ZERO_STRUCTP(p); - DLIST_ADD(print_db_head, p); - } - - pstrcpy(printdb_path, lock_path("printing/")); - pstrcat(printdb_path, printername); - pstrcat(printdb_path, ".tdb"); - - become_root(); - p->tdb = tdb_open_log(printdb_path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); - unbecome_root(); - - if (!p->tdb) { - DEBUG(0,("get_print_db: Failed to open printer backend database %s.\n", - printdb_path )); - DLIST_REMOVE(print_db_head, p); - SAFE_FREE(p); - return NULL; - } - fstrcpy(p->printer_name, printername); - p->ref_count++; - return p; -} - -static void release_print_db( struct tdb_print_db *pdb) -{ - pdb->ref_count--; - SMB_ASSERT(pdb->ref_count >= 0); -} - /**************************************************************************** Initialise the printing backend. Called once at startup. Does not survive a fork @@ -234,39 +52,24 @@ static void release_print_db( struct tdb_print_db *pdb) BOOL print_backend_init(void) { char *sversion = "INFO/version"; - pstring printing_path; - int services = lp_numservices(); - int snum; - if (local_pid == sys_getpid()) + if (tdb && local_pid == sys_getpid()) return True; - - unlink(lock_path("printing.tdb")); - pstrcpy(printing_path,lock_path("printing")); - mkdir(printing_path,0755); - + tdb = tdb_open_log(lock_path("printing.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + if (!tdb) { + DEBUG(0,("print_backend_init: Failed to open printing backend database %s.\n", + lock_path("printing.tdb") )); + return False; + } local_pid = sys_getpid(); /* handle a Samba upgrade */ - - for (snum = 0; snum < services; snum++) { - struct tdb_print_db *pdb; - if (!lp_print_ok(snum)) - continue; - - pdb = get_print_db_byname(lp_const_servicename(snum)); - if (!pdb) - continue; - if (tdb_lock_bystring(pdb->tdb, sversion) == -1) { - DEBUG(0,("print_backend_init: Failed to open printer %s database\n", lp_const_servicename(snum) )); - return False; - } - if (tdb_fetch_int32(pdb->tdb, sversion) != PRINT_DATABASE_VERSION) { - tdb_traverse(pdb->tdb, tdb_traverse_delete_fn, NULL); - tdb_store_int32(pdb->tdb, sversion, PRINT_DATABASE_VERSION); - } - tdb_unlock_bystring(pdb->tdb, sversion); + tdb_lock_bystring(tdb, sversion); + if (tdb_fetch_int32(tdb, sversion) != PRINT_DATABASE_VERSION) { + tdb_traverse(tdb, tdb_traverse_delete_fn, NULL); + tdb_store_int32(tdb, sversion, PRINT_DATABASE_VERSION); } + tdb_unlock_bystring(tdb, sversion); /* select the appropriate printing interface... */ #ifdef HAVE_CUPS @@ -279,30 +82,12 @@ BOOL print_backend_init(void) } /**************************************************************************** - Shut down printing backend. Called once at shutdown to close the tdb. -****************************************************************************/ - -void printing_end(void) -{ - struct tdb_print_db *p; - - for (p = print_db_head; p; ) { - struct tdb_print_db *next_p = p->next; - if (p->tdb) - tdb_close(p->tdb); - DLIST_REMOVE(print_db_head, p); - SAFE_FREE(p); - p = next_p; - } -} - -/**************************************************************************** Useful function to generate a tdb key. ****************************************************************************/ -static TDB_DATA print_key(uint32 jobid) +static TDB_DATA print_key(int jobid) { - static uint32 j; + static int j; TDB_DATA ret; j = jobid; @@ -311,341 +96,59 @@ static TDB_DATA print_key(uint32 jobid) return ret; } -/*********************************************************************** - unpack a pjob from a tdb buffer -***********************************************************************/ - -int unpack_pjob( char* buf, int buflen, struct printjob *pjob ) -{ - int len = 0; - int used; - - if ( !buf || !pjob ) - return -1; - - len += tdb_unpack(buf+len, buflen-len, "dddddddddffff", - &pjob->pid, - &pjob->sysjob, - &pjob->fd, - &pjob->starttime, - &pjob->status, - &pjob->size, - &pjob->page_count, - &pjob->spooled, - &pjob->smbjob, - pjob->filename, - pjob->jobname, - pjob->user, - pjob->queuename); - - if ( len == -1 ) - return -1; - - if ( (used = unpack_devicemode(&pjob->nt_devmode, buf+len, buflen-len)) == -1 ) - return -1; - - len += used; - - return len; - -} - /**************************************************************************** Useful function to find a print job in the database. ****************************************************************************/ -static struct printjob *print_job_find(int snum, uint32 jobid) +static struct printjob *print_job_find(int jobid) { - static struct printjob pjob; - TDB_DATA ret; - struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum)); - + static struct printjob pjob; + TDB_DATA ret; - if (!pdb) + ret = tdb_fetch(tdb, print_key(jobid)); + if (!ret.dptr || ret.dsize != sizeof(pjob)) return NULL; - ret = tdb_fetch(pdb->tdb, print_key(jobid)); - release_print_db(pdb); - - if (!ret.dptr) - return NULL; - - if ( pjob.nt_devmode ) - free_nt_devicemode( &pjob.nt_devmode ); - - ZERO_STRUCT( pjob ); - - if ( unpack_pjob( ret.dptr, ret.dsize, &pjob ) == -1 ) - return NULL; - - SAFE_FREE(ret.dptr); + memcpy(&pjob, ret.dptr, sizeof(pjob)); + SAFE_FREE(ret.dptr); + unix_to_dos(pjob.queuename); return &pjob; } -/* Convert a unix jobid to a smb jobid */ - -static uint32 sysjob_to_jobid_value; - -static int unixjob_traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, - TDB_DATA data, void *state) -{ - struct printjob *pjob; - int *sysjob = (int *)state; - - if (!data.dptr || data.dsize == 0) - return 0; - - pjob = (struct printjob *)data.dptr; - if (key.dsize != sizeof(uint32)) - return 0; - - if (*sysjob == pjob->sysjob) { - uint32 *jobid = (uint32 *)key.dptr; - - sysjob_to_jobid_value = *jobid; - return 1; - } - - return 0; -} - -/**************************************************************************** - This is a *horribly expensive call as we have to iterate through all the - current printer tdb's. Don't do this often ! JRA. -****************************************************************************/ - -uint32 sysjob_to_jobid(int unix_jobid) -{ - int services = lp_numservices(); - int snum; - - sysjob_to_jobid_value = (uint32)-1; - - for (snum = 0; snum < services; snum++) { - struct tdb_print_db *pdb; - if (!lp_print_ok(snum)) - continue; - pdb = get_print_db_byname(lp_const_servicename(snum)); - if (pdb) - tdb_traverse(pdb->tdb, unixjob_traverse_fn, &unix_jobid); - release_print_db(pdb); - if (sysjob_to_jobid_value != (uint32)-1) - return sysjob_to_jobid_value; - } - return (uint32)-1; -} - -/**************************************************************************** - Send notifications based on what has changed after a pjob_store. -****************************************************************************/ - -static struct { - uint32 lpq_status; - uint32 spoolss_status; -} lpq_to_spoolss_status_map[] = { - { LPQ_QUEUED, JOB_STATUS_QUEUED }, - { LPQ_PAUSED, JOB_STATUS_PAUSED }, - { LPQ_SPOOLING, JOB_STATUS_SPOOLING }, - { LPQ_PRINTING, JOB_STATUS_PRINTING }, - { LPQ_DELETING, JOB_STATUS_DELETING }, - { LPQ_OFFLINE, JOB_STATUS_OFFLINE }, - { LPQ_PAPEROUT, JOB_STATUS_PAPEROUT }, - { LPQ_PRINTED, JOB_STATUS_PRINTED }, - { LPQ_DELETED, JOB_STATUS_DELETED }, - { LPQ_BLOCKED, JOB_STATUS_BLOCKED }, - { LPQ_USER_INTERVENTION, JOB_STATUS_USER_INTERVENTION }, - { -1, 0 } -}; - -/* Convert a lpq status value stored in printing.tdb into the - appropriate win32 API constant. */ - -static uint32 map_to_spoolss_status(uint32 lpq_status) -{ - int i = 0; - - while (lpq_to_spoolss_status_map[i].lpq_status != -1) { - if (lpq_to_spoolss_status_map[i].lpq_status == lpq_status) - return lpq_to_spoolss_status_map[i].spoolss_status; - i++; - } - - return 0; -} - -static void pjob_store_notify(int snum, uint32 jobid, struct printjob *old_data, - struct printjob *new_data) -{ - BOOL new_job = False; - - if (!old_data) - new_job = True; - - /* Notify the job name first */ - - if (new_job || !strequal(old_data->jobname, new_data->jobname)) - notify_job_name(snum, jobid, new_data->jobname); - - /* Job attributes that can't be changed. We only send - notification for these on a new job. */ - - if (new_job) { - notify_job_submitted(snum, jobid, new_data->starttime); - notify_job_username(snum, jobid, new_data->user); - } - - /* Job attributes of a new job or attributes that can be - modified. */ - - if (new_job || old_data->status != new_data->status) - notify_job_status(snum, jobid, map_to_spoolss_status(new_data->status)); - - if (new_job || old_data->size != new_data->size) - notify_job_total_bytes(snum, jobid, new_data->size); - - if (new_job || old_data->page_count != new_data->page_count) - notify_job_total_pages(snum, jobid, new_data->page_count); -} - /**************************************************************************** Store a job structure back to the database. ****************************************************************************/ -static BOOL pjob_store(int snum, uint32 jobid, struct printjob *pjob) +static BOOL print_job_store(int jobid, struct printjob *pjob) { - TDB_DATA old_data, new_data; - BOOL ret = False; - struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum)); - char *buf = NULL; - int len, newlen, buflen; - - - if (!pdb) - return False; - - /* Get old data */ - - old_data = tdb_fetch(pdb->tdb, print_key(jobid)); - - /* Doh! Now we have to pack/unpack data since the NT_DEVICEMODE was added */ - - newlen = 0; - - do { - len = 0; - buflen = newlen; - len += tdb_pack(buf+len, buflen-len, "dddddddddffff", - pjob->pid, - pjob->sysjob, - pjob->fd, - pjob->starttime, - pjob->status, - pjob->size, - pjob->page_count, - pjob->spooled, - pjob->smbjob, - pjob->filename, - pjob->jobname, - pjob->user, - pjob->queuename); - - len += pack_devicemode(pjob->nt_devmode, buf+len, buflen-len); - - if (buflen != len) - { - char *tb; - - tb = (char *)Realloc(buf, len); - if (!tb) { - DEBUG(0,("pjob_store: failed to enlarge buffer!\n")); - goto done; - } - else - buf = tb; - newlen = len; - } - } - while ( buflen != len ); - - - /* Store new data */ - - new_data.dptr = buf; - new_data.dsize = len; - ret = (tdb_store(pdb->tdb, print_key(jobid), new_data, TDB_REPLACE) == 0); - - release_print_db(pdb); - - /* Send notify updates for what has changed */ - - if ( ret && (old_data.dsize == 0 || old_data.dsize == sizeof(*pjob)) ) - pjob_store_notify( snum, jobid, (struct printjob *)old_data.dptr, pjob ); - -done: - SAFE_FREE( old_data.dptr ); - SAFE_FREE( buf ); + TDB_DATA d; + BOOL ret; + dos_to_unix(pjob->queuename); + d.dptr = (void *)pjob; + d.dsize = sizeof(*pjob); + ret = (tdb_store(tdb, print_key(jobid), d, TDB_REPLACE) == 0); + unix_to_dos(pjob->queuename); return ret; } /**************************************************************************** - Remove a job structure from the database. -****************************************************************************/ - -static void pjob_delete(int snum, uint32 jobid) -{ - struct printjob *pjob = print_job_find(snum, jobid); - uint32 job_status = 0; - struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum)); - - if (!pdb) - return; - - if (!pjob) { - DEBUG(5, ("pjob_delete(): we were asked to delete nonexistent job %u\n", - (unsigned int)jobid)); - release_print_db(pdb); - return; - } - - /* Send a notification that a job has been deleted */ - - job_status = map_to_spoolss_status(pjob->status); - - /* We must cycle through JOB_STATUS_DELETING and - JOB_STATUS_DELETED for the port monitor to delete the job - properly. */ - - job_status |= JOB_STATUS_DELETING; - notify_job_status(snum, jobid, job_status); - - job_status |= JOB_STATUS_DELETED; - notify_job_status(snum, jobid, job_status); - - /* Remove from printing.tdb */ - - tdb_delete(pdb->tdb, print_key(jobid)); - release_print_db(pdb); - rap_jobid_delete(snum, jobid); -} - -/**************************************************************************** Parse a file name from the system spooler to generate a jobid. ****************************************************************************/ -static uint32 print_parse_jobid(char *fname) +static int print_parse_jobid(char *fname) { int jobid; if (strncmp(fname,PRINT_SPOOL_PREFIX,strlen(PRINT_SPOOL_PREFIX)) != 0) - return (uint32)-1; + return -1; fname += strlen(PRINT_SPOOL_PREFIX); jobid = atoi(fname); if (jobid <= 0) - return (uint32)-1; + return -1; - return (uint32)jobid; + return jobid; } /**************************************************************************** @@ -654,12 +157,12 @@ static uint32 print_parse_jobid(char *fname) static void print_unix_job(int snum, print_queue_struct *q) { - uint32 jobid = q->job + UNIX_JOB_START; + int jobid = q->job + UNIX_JOB_START; struct printjob pj, *old_pj; /* Preserve the timestamp on an existing unix print job */ - old_pj = print_job_find(snum, jobid); + old_pj = print_job_find(jobid); ZERO_STRUCT(pj); @@ -674,9 +177,9 @@ static void print_unix_job(int snum, print_queue_struct *q) fstrcpy(pj.filename, ""); fstrcpy(pj.jobname, q->fs_file); fstrcpy(pj.user, q->fs_user); - fstrcpy(pj.queuename, lp_const_servicename(snum)); + fstrcpy(pj.queuename, lp_servicename(snum)); - pjob_store(snum, jobid, &pj); + print_job_store(jobid, &pj); } @@ -693,20 +196,17 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void { struct traverse_struct *ts = (struct traverse_struct *)state; struct printjob pjob; - uint32 jobid; - int i; + int i, jobid; - if ( key.dsize != sizeof(jobid) ) + if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0; - memcpy(&jobid, key.dptr, sizeof(jobid)); - if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 ) - return 0; - free_nt_devicemode( &pjob.nt_devmode ); - + memcpy(&pjob, data.dptr, sizeof(pjob)); + unix_to_dos(pjob.queuename); if (ts->snum != lp_servicenumber(pjob.queuename)) { - /* this isn't for the queue we are looking at - this cannot happen with the split tdb's. JRA */ + /* this isn't for the queue we are looking at */ + ts->total_jobs++; return 0; } @@ -714,12 +214,11 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void /* remove a unix job if it isn't in the system queue any more */ for (i=0;i<ts->qcount;i++) { - uint32 u_jobid = (ts->queue[i].job + UNIX_JOB_START); - if (jobid == u_jobid) + if (jobid == ts->queue[i].job + UNIX_JOB_START) break; } if (i == ts->qcount) - pjob_delete(ts->snum, jobid); + tdb_delete(tdb, key); else ts->total_jobs++; return 0; @@ -731,15 +230,15 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void exist then kill it. This cleans up after smbd deaths */ if (!process_exists(pjob.pid)) - pjob_delete(ts->snum, jobid); + tdb_delete(tdb, key); else ts->total_jobs++; return 0; } for (i=0;i<ts->qcount;i++) { - uint32 curr_jobid = print_parse_jobid(ts->queue[i].fs_file); - if (jobid == curr_jobid) + int qid = print_parse_jobid(ts->queue[i].fs_file); + if (jobid == qid) break; } @@ -758,7 +257,7 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void submitted less than lp_lpqcachetime() seconds ago. */ if ((cur_t - pjob.starttime) > lp_lpqcachetime()) - pjob_delete(ts->snum, jobid); + tdb_delete(t, key); else ts->total_jobs++; } @@ -775,14 +274,9 @@ static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void static void print_cache_flush(int snum) { fstring key; - const char *printername = lp_const_servicename(snum); - struct tdb_print_db *pdb = get_print_db_byname(printername); - - if (!pdb) - return; - slprintf(key, sizeof(key)-1, "CACHE/%s", printername); - tdb_store_int32(pdb->tdb, key, -1); - release_print_db(pdb); + slprintf(key, sizeof(key)-1, "CACHE/%s", lp_servicename(snum)); + dos_to_unix(key); /* Convert key to unix-codepage */ + tdb_store_int32(tdb, key, -1); } /**************************************************************************** @@ -794,16 +288,12 @@ static pid_t get_updating_pid(fstring printer_name) fstring keystr; TDB_DATA data, key; pid_t updating_pid; - struct tdb_print_db *pdb = get_print_db_byname(printer_name); - if (!pdb) - return (pid_t)-1; slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", printer_name); key.dptr = keystr; key.dsize = strlen(keystr); - data = tdb_fetch(pdb->tdb, key); - release_print_db(pdb); + data = tdb_fetch(tdb, key); if (!data.dptr || data.dsize != sizeof(pid_t)) return (pid_t)-1; @@ -818,39 +308,47 @@ static pid_t get_updating_pid(fstring printer_name) /**************************************************************************** Set the fact that we're doing the update, or have finished doing the update - in the tdb. + in th tdb. ****************************************************************************/ -static void set_updating_pid(const fstring printer_name, BOOL delete) +static void set_updating_pid(fstring printer_name, BOOL delete) { fstring keystr; TDB_DATA key; TDB_DATA data; pid_t updating_pid = sys_getpid(); - struct tdb_print_db *pdb = get_print_db_byname(printer_name); - - if (!pdb) - return; slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", printer_name); key.dptr = keystr; key.dsize = strlen(keystr); if (delete) { - tdb_delete(pdb->tdb, key); - release_print_db(pdb); + tdb_delete(tdb, key); return; } data.dptr = (void *)&updating_pid; data.dsize = sizeof(pid_t); - tdb_store(pdb->tdb, key, data, TDB_REPLACE); - release_print_db(pdb); + tdb_store(tdb, key, data, TDB_REPLACE); } /**************************************************************************** - Update the internal database from the system print queue for a queue. + Send a message saying the queue changed. +****************************************************************************/ + +static void send_queue_message(const char *printer_name, uint32 high, uint32 low) +{ + char msg[8 + sizeof(fstring)]; + SIVAL(msg,0,low); + SIVAL(msg,4,high); + fstrcpy(&msg[8], printer_name); + + message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, msg, 8 + strlen(printer_name) + 1, False, NULL); +} + +/**************************************************************************** +update the internal database from the system print queue for a queue ****************************************************************************/ static void print_queue_update(int snum) @@ -863,31 +361,24 @@ static void print_queue_update(int snum) struct traverse_struct tstruct; fstring keystr, printer_name, cachestr; TDB_DATA data, key; - struct tdb_print_db *pdb; - - fstrcpy(printer_name, lp_const_servicename(snum)); - pdb = get_print_db_byname(printer_name); - if (!pdb) - return; + /* Convert printer name (i.e. share name) to unix-codepage for all of the + * following tdb key generation */ + fstrcpy(printer_name, lp_servicename(snum)); + dos_to_unix(printer_name); + /* * Check to see if someone else is doing this update. * This is essentially a mutex on the update. */ - if (get_updating_pid(printer_name) != -1) { - release_print_db(pdb); + if (get_updating_pid(printer_name) != -1) return; - } /* Lock the queue for the database update */ slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", printer_name); - if (tdb_lock_bystring(pdb->tdb, keystr) == -1) { - DEBUG(0,("print_queue_update: Failed to lock printer %s database\n", printer_name)); - release_print_db(pdb); - return; - } + tdb_lock_bystring(tdb, keystr); /* * Ensure that no one else got in here. @@ -899,8 +390,7 @@ static void print_queue_update(int snum) /* * Someone else is doing the update, exit. */ - tdb_unlock_bystring(pdb->tdb, keystr); - release_print_db(pdb); + tdb_unlock_bystring(tdb, keystr); return; } @@ -916,7 +406,7 @@ static void print_queue_update(int snum) * the update. */ - tdb_unlock_bystring(pdb->tdb, keystr); + tdb_unlock_bystring(tdb, keystr); /* * Update the cache time FIRST ! Stops others even @@ -925,7 +415,7 @@ static void print_queue_update(int snum) */ slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", printer_name); - tdb_store_int32(pdb->tdb, cachestr, (int)time(NULL)); + tdb_store_int32(tdb, cachestr, (int)time(NULL)); /* get the current queue using the appropriate interface */ ZERO_STRUCT(status); @@ -946,16 +436,16 @@ static void print_queue_update(int snum) fill in any system job numbers as we go */ for (i=0; i<qcount; i++) { - uint32 jobid = print_parse_jobid(queue[i].fs_file); + int jobid = print_parse_jobid(queue[i].fs_file); - if (jobid == (uint32)-1) { + if (jobid == -1) { /* assume its a unix print job */ print_unix_job(snum, &queue[i]); continue; } /* we have an active SMB print job - update its status */ - pjob = print_job_find(snum, jobid); + pjob = print_job_find(jobid); if (!pjob) { /* err, somethings wrong. Probably smbd was restarted with jobs in the queue. All we can do is treat them @@ -967,7 +457,7 @@ static void print_queue_update(int snum) pjob->sysjob = queue[i].job; pjob->status = queue[i].status; - pjob_store(snum, jobid, pjob); + print_job_store(jobid, pjob); } /* now delete any queued entries that don't appear in the @@ -977,15 +467,23 @@ static void print_queue_update(int snum) tstruct.snum = snum; tstruct.total_jobs = 0; - tdb_traverse(pdb->tdb, traverse_fn_delete, (void *)&tstruct); + tdb_traverse(tdb, traverse_fn_delete, (void *)&tstruct); - SAFE_FREE(tstruct.queue); + safe_free(tstruct.queue); - tdb_store_int32(pdb->tdb, "INFO/total_jobs", tstruct.total_jobs); + tdb_store_int32(tdb, "INFO/total_jobs", tstruct.total_jobs); + + /* + * Get the old print status. We will use this to compare the + * number of jobs. If they have changed we need to send a + * "changed" message to the smbds. + */ - if( qcount != get_queue_status(snum, &old_status)) + if( qcount != get_queue_status(snum, &old_status)) { DEBUG(10,("print_queue_update: queue status change %d jobs -> %d jobs for printer %s\n", - old_status.qcount, qcount, printer_name )); + old_status.qcount, qcount, printer_name )); + send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB); + } /* store the new queue status structure */ slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printer_name); @@ -995,7 +493,7 @@ static void print_queue_update(int snum) status.qcount = qcount; data.dptr = (void *)&status; data.dsize = sizeof(status); - tdb_store(pdb->tdb, key, data, TDB_REPLACE); + tdb_store(tdb, key, data, TDB_REPLACE); /* * Update the cache time again. We want to do this call @@ -1003,36 +501,43 @@ static void print_queue_update(int snum) */ slprintf(keystr, sizeof(keystr)-1, "CACHE/%s", printer_name); - tdb_store_int32(pdb->tdb, keystr, (int32)time(NULL)); + tdb_store_int32(tdb, keystr, (int32)time(NULL)); /* Delete our pid from the db. */ set_updating_pid(printer_name, True); - release_print_db(pdb); } /**************************************************************************** Check if a jobid is valid. It is valid if it exists in the database. ****************************************************************************/ -BOOL print_job_exists(int snum, uint32 jobid) +BOOL print_job_exists(int jobid) { - struct tdb_print_db *pdb = get_print_db_byname(lp_const_servicename(snum)); - BOOL ret; + return tdb_exists(tdb, print_key(jobid)); +} - if (!pdb) - return False; - ret = tdb_exists(pdb->tdb, print_key(jobid)); - release_print_db(pdb); - return ret; +/**************************************************************************** + Work out which service a jobid is for. + Note that we have to look up by queue name to ensure that it works for + other than the process that started the job. +****************************************************************************/ + +int print_job_snum(int jobid) +{ + struct printjob *pjob = print_job_find(jobid); + if (!pjob) + return -1; + + return find_service(pjob->queuename); } /**************************************************************************** Give the fd used for a jobid. ****************************************************************************/ -int print_job_fd(int snum, uint32 jobid) +int print_job_fd(int jobid) { - struct printjob *pjob = print_job_find(snum, jobid); + struct printjob *pjob = print_job_find(jobid); if (!pjob) return -1; /* don't allow another process to get this info - it is meaningless */ @@ -1047,36 +552,19 @@ int print_job_fd(int snum, uint32 jobid) has not been spooled. ****************************************************************************/ -char *print_job_fname(int snum, uint32 jobid) +char *print_job_fname(int jobid) { - struct printjob *pjob = print_job_find(snum, jobid); + struct printjob *pjob = print_job_find(jobid); if (!pjob || pjob->spooled || pjob->pid != local_pid) return NULL; return pjob->filename; } - -/**************************************************************************** - Give the filename used for a jobid. - Only valid for the process doing the spooling and when the job - has not been spooled. -****************************************************************************/ - -NT_DEVICEMODE *print_job_devmode(int snum, uint32 jobid) -{ - struct printjob *pjob = print_job_find(snum, jobid); - - if ( !pjob ) - return NULL; - - return pjob->nt_devmode; -} - /**************************************************************************** Set the place in the queue for a job. ****************************************************************************/ -BOOL print_job_set_place(int snum, uint32 jobid, int place) +BOOL print_job_set_place(int jobid, int place) { DEBUG(2,("print_job_set_place not implemented yet\n")); return False; @@ -1086,24 +574,24 @@ BOOL print_job_set_place(int snum, uint32 jobid, int place) Set the name of a job. Only possible for owner. ****************************************************************************/ -BOOL print_job_set_name(int snum, uint32 jobid, char *name) +BOOL print_job_set_name(int jobid, char *name) { - struct printjob *pjob = print_job_find(snum, jobid); + struct printjob *pjob = print_job_find(jobid); if (!pjob || pjob->pid != local_pid) return False; fstrcpy(pjob->jobname, name); - return pjob_store(snum, jobid, pjob); + return print_job_store(jobid, pjob); } /**************************************************************************** Delete a print job - don't update queue. ****************************************************************************/ -static BOOL print_job_delete1(int snum, uint32 jobid) +static BOOL print_job_delete1(int jobid) { - struct printjob *pjob = print_job_find(snum, jobid); - int result = 0; + struct printjob *pjob = print_job_find(jobid); + int snum, result = 0; if (!pjob) return False; @@ -1115,17 +603,23 @@ static BOOL print_job_delete1(int snum, uint32 jobid) if (pjob->status == LPQ_DELETING) return True; + snum = print_job_snum(jobid); + if (snum == -1) { + DEBUG(5,("print_job_delete1: unknown service number for jobid %d\n", jobid)); + return False; + } + /* Hrm - we need to be able to cope with deleting a job before it has reached the spooler. */ if (pjob->sysjob == -1) { - DEBUG(5, ("attempt to delete job %u not seen by lpr\n", (unsigned int)jobid)); + DEBUG(5, ("attempt to delete job %d not seen by lpr\n", jobid)); } /* Set the tdb entry to be deleting. */ pjob->status = LPQ_DELETING; - pjob_store(snum, jobid, pjob); + print_job_store(jobid, pjob); if (pjob->spooled && pjob->sysjob != -1) result = (*(current_printif->job_delete))(snum, pjob); @@ -1133,8 +627,9 @@ static BOOL print_job_delete1(int snum, uint32 jobid) /* Delete the tdb entry if the delete suceeded or the job hasn't been spooled. */ - if (result == 0) - pjob_delete(snum, jobid); + if (result == 0) { + tdb_delete(tdb, print_key(jobid)); + } return (result == 0); } @@ -1143,18 +638,20 @@ static BOOL print_job_delete1(int snum, uint32 jobid) Return true if the current user owns the print job. ****************************************************************************/ -static BOOL is_owner(struct current_user *user, int snum, uint32 jobid) +static BOOL is_owner(struct current_user *user, int jobid) { - struct printjob *pjob = print_job_find(snum, jobid); + struct printjob *pjob = print_job_find(jobid); user_struct *vuser; if (!pjob || !user) return False; if ((vuser = get_valid_user_struct(user->vuid)) != NULL) { - return strequal(pjob->user, vuser->user.smb_name); + return strequal(pjob->user, + unix_to_dos_static(vuser->user.smb_name)); } else { - return strequal(pjob->user, uidtoname(user->uid)); + return strequal(pjob->user, + unix_to_dos_static(uidtoname(user->uid))); } } @@ -1162,14 +659,18 @@ static BOOL is_owner(struct current_user *user, int snum, uint32 jobid) Delete a print job. ****************************************************************************/ -BOOL print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR *errcode) +BOOL print_job_delete(struct current_user *user, int jobid, WERROR *errcode) { - BOOL owner, deleted; - char *fname; + int snum = print_job_snum(jobid); + char *printer_name; + BOOL owner; - *errcode = WERR_OK; - - owner = is_owner(user, snum, jobid); + if (snum == -1) { + DEBUG(5,("print_job_delete: unknown service number for jobid %d\n", jobid)); + return False; + } + + owner = is_owner(user, jobid); /* Check access against security descriptor or whether the user owns their job. */ @@ -1181,58 +682,46 @@ BOOL print_job_delete(struct current_user *user, int snum, uint32 jobid, WERROR return False; } - /* - * get the spooled filename of the print job - * if this works, then the file has not been spooled - * to the underlying print system. Just delete the - * spool file & return. - */ - - if ( (fname = print_job_fname( snum, jobid )) != NULL ) - { - /* remove the spool file */ - DEBUG(10,("print_job_delete: Removing spool file [%s]\n", fname )); - if ( unlink( fname ) == -1 ) { - *errcode = map_werror_from_unix(errno); - return False; - } - - return True; - } - - if (!print_job_delete1(snum, jobid)) { - *errcode = WERR_ACCESS_DENIED; + if (!print_job_delete1(jobid)) return False; - } /* force update the database and say the delete failed if the job still exists */ print_queue_update(snum); - - deleted = !print_job_exists(snum, jobid); - if ( !deleted ) - *errcode = WERR_ACCESS_DENIED; - return deleted; + /* Send a printer notify message */ + + printer_name = PRINTERNAME(snum); + + send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB); + + return !print_job_exists(jobid); } /**************************************************************************** Pause a job. ****************************************************************************/ -BOOL print_job_pause(struct current_user *user, int snum, uint32 jobid, WERROR *errcode) +BOOL print_job_pause(struct current_user *user, int jobid, WERROR *errcode) { - struct printjob *pjob = print_job_find(snum, jobid); - int ret = -1; + struct printjob *pjob = print_job_find(jobid); + int snum, ret = -1; + char *printer_name; - if (!pjob || !user) + if (!pjob || !user) + return False; + + if (!pjob->spooled || pjob->sysjob == -1) return False; - if (!pjob->spooled || pjob->sysjob == -1) + snum = print_job_snum(jobid); + if (snum == -1) { + DEBUG(5,("print_job_pause: unknown service number for jobid %d\n", jobid)); return False; + } - if (!is_owner(user, snum, jobid) && + if (!is_owner(user, jobid) && !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { DEBUG(3, ("pause denied by security descriptor\n")); *errcode = WERR_ACCESS_DENIED; @@ -1252,7 +741,9 @@ BOOL print_job_pause(struct current_user *user, int snum, uint32 jobid, WERROR * /* Send a printer notify message */ - notify_job_status(snum, jobid, JOB_STATUS_PAUSED); + printer_name = PRINTERNAME(snum); + + send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB); /* how do we tell if this succeeded? */ @@ -1263,10 +754,11 @@ BOOL print_job_pause(struct current_user *user, int snum, uint32 jobid, WERROR * Resume a job. ****************************************************************************/ -BOOL print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR *errcode) +BOOL print_job_resume(struct current_user *user, int jobid, WERROR *errcode) { - struct printjob *pjob = print_job_find(snum, jobid); - int ret; + struct printjob *pjob = print_job_find(jobid); + char *printer_name; + int snum, ret; if (!pjob || !user) return False; @@ -1274,7 +766,13 @@ BOOL print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR if (!pjob->spooled || pjob->sysjob == -1) return False; - if (!is_owner(user, snum, jobid) && + snum = print_job_snum(jobid); + if (snum == -1) { + DEBUG(5,("print_job_resume: unknown service number for jobid %d\n", jobid)); + return False; + } + + if (!is_owner(user, jobid) && !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) { DEBUG(3, ("resume denied by security descriptor\n")); *errcode = WERR_ACCESS_DENIED; @@ -1293,7 +791,9 @@ BOOL print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR /* Send a printer notify message */ - notify_job_status(snum, jobid, JOB_STATUS_QUEUED); + printer_name = PRINTERNAME(snum); + + send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB); return True; } @@ -1302,10 +802,10 @@ BOOL print_job_resume(struct current_user *user, int snum, uint32 jobid, WERROR Write to a print file. ****************************************************************************/ -int print_job_write(int snum, uint32 jobid, const char *buf, int size) +int print_job_write(int jobid, const char *buf, int size) { int return_code; - struct printjob *pjob = print_job_find(snum, jobid); + struct printjob *pjob = print_job_find(jobid); if (!pjob) return -1; @@ -1316,7 +816,7 @@ int print_job_write(int snum, uint32 jobid, const char *buf, int size) return_code = write(pjob->fd, buf, size); if (return_code>0) { pjob->size += size; - pjob_store(snum, jobid, pjob); + print_job_store(jobid, pjob); } return return_code; } @@ -1329,14 +829,10 @@ static BOOL print_cache_expired(int snum) { fstring key; time_t last_qscan_time, time_now = time(NULL); - const char *printername = lp_const_servicename(snum); - struct tdb_print_db *pdb = get_print_db_byname(printername); - if (!pdb) - return False; - - slprintf(key, sizeof(key), "CACHE/%s", printername); - last_qscan_time = (time_t)tdb_fetch_int32(pdb->tdb, key); + slprintf(key, sizeof(key), "CACHE/%s", lp_servicename(snum)); + dos_to_unix(key); /* Convert key to unix-codepage */ + last_qscan_time = (time_t)tdb_fetch_int32(tdb, key); /* * Invalidate the queue for 3 reasons. @@ -1351,12 +847,10 @@ static BOOL print_cache_expired(int snum) if (last_qscan_time == ((time_t)-1) || (time_now - last_qscan_time) >= lp_lpqcachetime() || last_qscan_time > (time_now + MAX_CACHE_VALID_TIME)) { DEBUG(3, ("print cache expired for queue %s \ -(last_qscan_time = %d, time now = %d, qcachetime = %d)\n", printername, +(last_qscan_time = %d, time now = %d, qcachetime = %d)\n", lp_servicename(snum), (int)last_qscan_time, (int)time_now, (int)lp_lpqcachetime() )); - release_print_db(pdb); return True; } - release_print_db(pdb); return False; } @@ -1368,17 +862,13 @@ static int get_queue_status(int snum, print_status_struct *status) { fstring keystr; TDB_DATA data, key; - const char *printername = lp_const_servicename(snum); - struct tdb_print_db *pdb = get_print_db_byname(printername); - if (!pdb) - return 0; ZERO_STRUCTP(status); - slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printername); + slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", lp_servicename(snum)); + dos_to_unix(keystr); /* Convert key to unix-codepage */ key.dptr = keystr; key.dsize = strlen(keystr); - data = tdb_fetch(pdb->tdb, key); - release_print_db(pdb); + data = tdb_fetch(tdb, key); if (data.dptr) { if (data.dsize == sizeof(print_status_struct)) { memcpy(status, data.dptr, sizeof(print_status_struct)); @@ -1409,37 +899,48 @@ int print_queue_length(int snum, print_status_struct *pstatus) return len; } +/**************************************************************************** + Determine the number of jobs in all queues. +****************************************************************************/ + +static int get_total_jobs(int snum) +{ + int total_jobs; + + /* make sure the database is up to date */ + if (print_cache_expired(snum)) + print_queue_update(snum); + + total_jobs = tdb_fetch_int32(tdb, "INFO/total_jobs"); + if (total_jobs >0) + return total_jobs; + else + return 0; +} + /*************************************************************************** Start spooling a job - return the jobid. ***************************************************************************/ -uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DEVICEMODE *nt_devmode ) +int print_job_start(struct current_user *user, int snum, char *jobname) { - uint32 jobid; + int jobid; char *path; struct printjob pjob; int next_jobid; user_struct *vuser; int njobs = 0; - const char *printername = lp_const_servicename(snum); - struct tdb_print_db *pdb = get_print_db_byname(printername); - BOOL pdb_locked = False; errno = 0; - if (!pdb) - return (uint32)-1; - if (!print_access_check(user, snum, PRINTER_ACCESS_USE)) { DEBUG(3, ("print_job_start: job start denied by security descriptor\n")); - release_print_db(pdb); - return (uint32)-1; + return -1; } if (!print_time_access_check(snum)) { DEBUG(3, ("print_job_start: job start denied by time check\n")); - release_print_db(pdb); - return (uint32)-1; + return -1; } path = lp_pathname(snum); @@ -1450,81 +951,36 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DE if (sys_fsusage(path, &dspace, &dsize) == 0 && dspace < 2*(SMB_BIG_UINT)lp_minprintspace(snum)) { DEBUG(3, ("print_job_start: disk space check failed.\n")); - release_print_db(pdb); errno = ENOSPC; - return (uint32)-1; + return -1; } } /* for autoloaded printers, check that the printcap entry still exists */ - if (lp_autoloaded(snum) && !pcap_printername_ok(lp_const_servicename(snum), NULL)) { - DEBUG(3, ("print_job_start: printer name %s check failed.\n", lp_const_servicename(snum) )); - release_print_db(pdb); + if (lp_autoloaded(snum) && !pcap_printername_ok(lp_servicename(snum), NULL)) { + DEBUG(3, ("print_job_start: printer name %s check failed.\n", lp_servicename(snum) )); errno = ENOENT; - return (uint32)-1; + return -1; } /* Insure the maximum queue size is not violated */ if (lp_maxprintjobs(snum) && (njobs = print_queue_length(snum,NULL)) > lp_maxprintjobs(snum)) { DEBUG(3, ("print_job_start: number of jobs (%d) larger than max printjobs per queue (%d).\n", njobs, lp_maxprintjobs(snum) )); - release_print_db(pdb); errno = ENOSPC; - return (uint32)-1; - } - - /* Lock the database */ - if (tdb_lock_bystring(pdb->tdb, "INFO/nextjob") == -1) { - DEBUG(0,("print_job_start: failed to lock printing database %s\n", printername )); - release_print_db(pdb); - return (uint32)-1; - } - - pdb_locked = True; - - next_jobid = tdb_fetch_int32(pdb->tdb, "INFO/nextjob"); - if (next_jobid == -1) - next_jobid = 1; - - for (jobid = NEXT_JOBID(next_jobid); jobid != next_jobid; jobid = NEXT_JOBID(jobid)) { - if (!print_job_exists(snum, jobid)) - break; - } - - if (jobid == next_jobid) { - DEBUG(3, ("print_job_start: jobid (%d)==next_jobid(%d).\n", - jobid, next_jobid )); - jobid = -1; - goto fail; - } - - /* Store a dummy placeholder. This must be quick as we have the lock. */ - { - TDB_DATA dum; - dum.dptr = NULL; - dum.dsize = 0; - if (tdb_store(pdb->tdb, print_key(jobid), dum, TDB_INSERT) == -1) { - DEBUG(3, ("print_job_start: jobid (%d) failed to store placeholder.\n", - jobid )); - jobid = -1; - goto fail; - } + return -1; } - if (tdb_store_int32(pdb->tdb, "INFO/nextjob", jobid)==-1) { - DEBUG(3, ("print_job_start: failed to store INFO/nextjob.\n")); - jobid = -1; - goto fail; + /* Insure the maximum print jobs in the system is not violated */ + if (lp_totalprintjobs() && get_total_jobs(snum) > lp_totalprintjobs()) { + DEBUG(3, ("print_job_start: number of jobs (%d) larger than max printjobs per system (%d).\n", + njobs, lp_totalprintjobs() )); + errno = ENOSPC; + return -1; } - /* We've finished with the INFO/nextjob lock. */ - tdb_unlock_bystring(pdb->tdb, "INFO/nextjob"); - pdb_locked = False; - /* create the database entry */ - ZERO_STRUCT(pjob); - pjob.pid = local_pid; pjob.sysjob = -1; pjob.fd = -1; @@ -1533,21 +989,40 @@ uint32 print_job_start(struct current_user *user, int snum, char *jobname, NT_DE pjob.size = 0; pjob.spooled = False; pjob.smbjob = True; - pjob.nt_devmode = nt_devmode; - + fstrcpy(pjob.jobname, jobname); if ((vuser = get_valid_user_struct(user->vuid)) != NULL) { - fstrcpy(pjob.user, vuser->user.smb_name); + fstrcpy(pjob.user, unix_to_dos_static(vuser->user.smb_name)); } else { - fstrcpy(pjob.user, uidtoname(user->uid)); + fstrcpy(pjob.user, unix_to_dos_static(uidtoname(user->uid))); } - fstrcpy(pjob.queuename, lp_const_servicename(snum)); + fstrcpy(pjob.queuename, lp_servicename(snum)); + + /* lock the database */ + tdb_lock_bystring(tdb, "INFO/nextjob"); + + next_jobid = tdb_fetch_int32(tdb, "INFO/nextjob"); + if (next_jobid == -1) + next_jobid = 1; + + for (jobid = NEXT_JOBID(next_jobid); jobid != next_jobid; jobid = NEXT_JOBID(jobid)) { + if (!print_job_exists(jobid)) + break; + } + if (jobid == next_jobid || !print_job_store(jobid, &pjob)) { + DEBUG(3, ("print_job_start: either jobid (%d)==next_jobid(%d) or print_job_store failed.\n", + jobid, next_jobid )); + jobid = -1; + goto fail; + } + + tdb_store_int32(tdb, "INFO/nextjob", jobid); /* we have a job entry - now create the spool file */ - slprintf(pjob.filename, sizeof(pjob.filename)-1, "%s/%s%.8u.XXXXXX", - path, PRINT_SPOOL_PREFIX, (unsigned int)jobid); + slprintf(pjob.filename, sizeof(pjob.filename)-1, "%s/%s%.6d.XXXXXX", + path, PRINT_SPOOL_PREFIX, jobid); pjob.fd = smb_mkstemp(pjob.filename); if (pjob.fd == -1) { @@ -1563,9 +1038,9 @@ to open spool file %s.\n", pjob.filename)); goto fail; } - pjob_store(snum, jobid, &pjob); + print_job_store(jobid, &pjob); - release_print_db(pdb); + tdb_unlock_bystring(tdb, "INFO/nextjob"); /* * If the printer is marked as postscript output a leading @@ -1575,18 +1050,17 @@ to open spool file %s.\n", pjob.filename)); * tim@fsg.com 09/06/94 */ if (lp_postscript(snum)) { - print_job_write(snum, jobid, "%!\n",3); + print_job_write(jobid, "%!\n",3); } return jobid; fail: - if (jobid != -1) - pjob_delete(snum, jobid); + if (jobid != -1) { + tdb_delete(tdb, print_key(jobid)); + } - if (pdb_locked) - tdb_unlock_bystring(pdb->tdb, "INFO/nextjob"); - release_print_db(pdb); + tdb_unlock_bystring(tdb, "INFO/nextjob"); DEBUG(3, ("print_job_start: returning fail. Error = %s\n", strerror(errno) )); return -1; @@ -1596,9 +1070,9 @@ to open spool file %s.\n", pjob.filename)); Update the number of pages spooled to jobid ****************************************************************************/ -void print_job_endpage(int snum, uint32 jobid) +void print_job_endpage(int jobid) { - struct printjob *pjob = print_job_find(snum, jobid); + struct printjob *pjob = print_job_find(jobid); if (!pjob) return; /* don't allow another process to get this info - it is meaningless */ @@ -1606,7 +1080,7 @@ void print_job_endpage(int snum, uint32 jobid) return; pjob->page_count++; - pjob_store(snum, jobid, pjob); + print_job_store(jobid, pjob); } /**************************************************************************** @@ -1615,10 +1089,10 @@ void print_job_endpage(int snum, uint32 jobid) error. ****************************************************************************/ -BOOL print_job_end(int snum, uint32 jobid, BOOL normal_close) +BOOL print_job_end(int jobid, BOOL normal_close) { - struct printjob *pjob = print_job_find(snum, jobid); - int ret; + struct printjob *pjob = print_job_find(jobid); + int snum, ret; SMB_STRUCT_STAT sbuf; if (!pjob) @@ -1627,6 +1101,12 @@ BOOL print_job_end(int snum, uint32 jobid, BOOL normal_close) if (pjob->spooled || pjob->pid != local_pid) return False; + snum = print_job_snum(jobid); + if (snum == -1) { + DEBUG(5,("print_job_end: unknown service number for jobid %d\n", jobid)); + return False; + } + if (normal_close && (sys_fstat(pjob->fd, &sbuf) == 0)) { pjob->size = sbuf.st_size; close(pjob->fd); @@ -1643,7 +1123,7 @@ BOOL print_job_end(int snum, uint32 jobid, BOOL normal_close) goto fail; } - /* Technically, this is not quite right. If the printer has a separator + /* Technically, this is not quit right. If the printer has a separator * page turned on, the NT spooler prints the separator page even if the * print job is 0 bytes. 010215 JRR */ if (pjob->size == 0 || pjob->status == LPQ_DELETING) { @@ -1651,7 +1131,7 @@ BOOL print_job_end(int snum, uint32 jobid, BOOL normal_close) DEBUG(5,("print_job_end: canceling spool of %s (%s)\n", pjob->filename, pjob->size ? "deleted" : "zero length" )); unlink(pjob->filename); - pjob_delete(snum, jobid); + tdb_delete(tdb, print_key(jobid)); return True; } @@ -1664,7 +1144,7 @@ BOOL print_job_end(int snum, uint32 jobid, BOOL normal_close) pjob->spooled = True; pjob->status = LPQ_QUEUED; - pjob_store(snum, jobid, pjob); + print_job_store(jobid, pjob); /* make sure the database is up to date */ if (print_cache_expired(snum)) @@ -1677,7 +1157,7 @@ fail: /* The print job was not succesfully started. Cleanup */ /* Still need to add proper error return propagation! 010122:JRR */ unlink(pjob->filename); - pjob_delete(snum, jobid); + tdb_delete(tdb, print_key(jobid)); return False; } @@ -1689,19 +1169,13 @@ static int traverse_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void * { struct traverse_struct *ts = (struct traverse_struct *)state; struct printjob pjob; - int i; - uint32 jobid; + int i, jobid; - /* sanity checks */ - - if ( key.dsize != sizeof(jobid) ) + if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0; - memcpy(&jobid, key.dptr, sizeof(jobid)); - - if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 ) - return 0; - free_nt_devicemode( &pjob.nt_devmode ); + memcpy(&pjob, data.dptr, sizeof(pjob)); + unix_to_dos(pjob.queuename); /* maybe it isn't for this queue */ if (ts->snum != lp_servicenumber(pjob.queuename)) @@ -1738,21 +1212,15 @@ static int traverse_count_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, { struct traverse_count_struct *ts = (struct traverse_count_struct *)state; struct printjob pjob; - uint32 jobid; + int jobid; - /* sanity checks */ - - if ( key.dsize != sizeof(jobid) ) + if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0; - memcpy(&jobid, key.dptr, sizeof(jobid)); - - if ( unpack_pjob( data.dptr, data.dsize, &pjob ) == -1 ) - return 0; - - free_nt_devicemode( &pjob.nt_devmode ); + memcpy(&pjob, data.dptr, sizeof(pjob)); + unix_to_dos(pjob.queuename); - /* maybe it isn't for this queue - this cannot happen with the tdb/printer code. JRA */ + /* maybe it isn't for this queue */ if (ts->snum != lp_servicenumber(pjob.queuename)) return 0; @@ -1795,27 +1263,23 @@ int print_queue_status(int snum, struct traverse_count_struct tsc; fstring keystr; TDB_DATA data, key; - const char *printername = lp_const_servicename(snum); - struct tdb_print_db *pdb = get_print_db_byname(printername); - - *queue = NULL; - - if (!pdb) - return 0; /* make sure the database is up to date */ if (print_cache_expired(snum)) print_queue_update(snum); + *queue = NULL; + /* * Fetch the queue status. We must do this first, as there may * be no jobs in the queue. */ ZERO_STRUCTP(status); - slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printername); + slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", lp_servicename(snum)); + dos_to_unix(keystr); /* Convert key to unix-codepage */ key.dptr = keystr; key.dsize = strlen(keystr); - data = tdb_fetch(pdb->tdb, key); + data = tdb_fetch(tdb, key); if (data.dptr) { if (data.dsize == sizeof(*status)) { memcpy(status, data.dptr, sizeof(*status)); @@ -1830,19 +1294,15 @@ int print_queue_status(int snum, tsc.count = 0; tsc.snum = snum; - tdb_traverse(pdb->tdb, traverse_count_fn_queue, (void *)&tsc); + tdb_traverse(tdb, traverse_count_fn_queue, (void *)&tsc); - if (tsc.count == 0) { - release_print_db(pdb); + if (tsc.count == 0) return 0; - } /* Allocate the queue size. */ if ((tstruct.queue = (print_queue_struct *) - malloc(sizeof(print_queue_struct)*tsc.count)) == NULL) { - release_print_db(pdb); + malloc(sizeof(print_queue_struct)*tsc.count)) == NULL) return 0; - } /* * Fill in the queue. @@ -1853,8 +1313,7 @@ int print_queue_status(int snum, tstruct.maxcount = tsc.count; tstruct.snum = snum; - tdb_traverse(pdb->tdb, traverse_fn_queue, (void *)&tstruct); - release_print_db(pdb); + tdb_traverse(tdb, traverse_fn_queue, (void *)&tstruct); /* Sort the queue by submission time otherwise they are displayed in hash order. */ @@ -1870,7 +1329,7 @@ int print_queue_status(int snum, Turn a queue name into a snum. ****************************************************************************/ -int print_queue_snum(const char *qname) +int print_queue_snum(char *qname) { int snum = lp_servicenumber(qname); if (snum == -1 || !lp_print_ok(snum)) @@ -1884,6 +1343,7 @@ int print_queue_snum(const char *qname) BOOL print_queue_pause(struct current_user *user, int snum, WERROR *errcode) { + char *printer_name; int ret; if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) { @@ -1903,7 +1363,9 @@ BOOL print_queue_pause(struct current_user *user, int snum, WERROR *errcode) /* Send a printer notify message */ - notify_printer_status(snum, PRINTER_STATUS_PAUSED); + printer_name = PRINTERNAME(snum); + + send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB); return True; } @@ -1914,6 +1376,7 @@ BOOL print_queue_pause(struct current_user *user, int snum, WERROR *errcode) BOOL print_queue_resume(struct current_user *user, int snum, WERROR *errcode) { + char *printer_name; int ret; if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) { @@ -1929,12 +1392,13 @@ BOOL print_queue_resume(struct current_user *user, int snum, WERROR *errcode) } /* make sure the database is up to date */ - if (print_cache_expired(snum)) - print_queue_update(snum); + if (print_cache_expired(snum)) print_queue_update(snum); /* Send a printer notify message */ - notify_printer_status(snum, PRINTER_STATUS_OK); + printer_name = PRINTERNAME(snum); + + send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB); return True; } @@ -1947,6 +1411,7 @@ BOOL print_queue_purge(struct current_user *user, int snum, WERROR *errcode) { print_queue_struct *queue; print_status_struct status; + char *printer_name; int njobs, i; BOOL can_job_admin; @@ -1957,14 +1422,20 @@ BOOL print_queue_purge(struct current_user *user, int snum, WERROR *errcode) njobs = print_queue_status(snum, &queue, &status); for (i=0;i<njobs;i++) { - BOOL owner = is_owner(user, snum, queue[i].job); + BOOL owner = is_owner(user, queue[i].job); if (owner || can_job_admin) { - print_job_delete1(snum, queue[i].job); + print_job_delete1(queue[i].job); } } - SAFE_FREE(queue); + safe_free(queue); + + /* Send a printer notify message */ + + printer_name = PRINTERNAME(snum); + + send_queue_message(printer_name, 0, PRINTER_CHANGE_JOB); return True; } |