#include "printing.h"
struct printif *current_printif = &generic_printif;
static TDB_CONTEXT *tdb;
static pid_t local_pid;
static int get_queue_status(int, print_status_struct *);
BOOL print_backend_init(void)
{
char *sversion = "INFO/version";
if (tdb && local_pid == sys_getpid()) return True;
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. Error = [%s]\n",
tdb_errorstr(tdb)));
return False;
}
local_pid = sys_getpid();
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);
#ifdef HAVE_CUPS
if (strcmp(lp_printcapname(), "cups") == 0)
current_printif = &cups_printif;
#endif
return nt_printing_init();
}
static TDB_DATA print_key(int jobid)
{
static int j;
TDB_DATA ret;
j = jobid;
ret.dptr = (void *)&j;
ret.dsize = sizeof(j);
return ret;
}
static struct printjob *print_job_find(int jobid)
{
static struct printjob pjob;
TDB_DATA ret;
ret = tdb_fetch(tdb, print_key(jobid));
if (!ret.dptr || ret.dsize != sizeof(pjob)) return NULL;
memcpy(&pjob, ret.dptr, sizeof(pjob));
SAFE_FREE(ret.dptr);
return &pjob;
}
static BOOL print_job_store(int jobid, struct printjob *pjob)
{
TDB_DATA d;
d.dptr = (void *)pjob;
d.dsize = sizeof(*pjob);
return (tdb_store(tdb, print_key(jobid), d, TDB_REPLACE) == 0);
}
static int print_parse_jobid(char *fname)
{
int jobid;
if (strncmp(fname,PRINT_SPOOL_PREFIX,strlen(PRINT_SPOOL_PREFIX)) != 0) return -1;
fname += strlen(PRINT_SPOOL_PREFIX);
jobid = atoi(fname);
if (jobid <= 0) return -1;
return jobid;
}
static void print_unix_job(int snum, print_queue_struct *q)
{
int jobid = q->job + UNIX_JOB_START;
struct printjob pj, *old_pj;
old_pj = print_job_find(jobid);
ZERO_STRUCT(pj);
pj.pid = (pid_t)-1;
pj.sysjob = q->job;
pj.fd = -1;
pj.starttime = old_pj ? old_pj->starttime : q->time;
pj.status = q->status;
pj.size = q->size;
pj.spooled = True;
pj.smbjob = False;
fstrcpy(pj.filename, "");
fstrcpy(pj.jobname, q->file);
fstrcpy(pj.user, q->user);
fstrcpy(pj.qname, lp_servicename(snum));
print_job_store(jobid, &pj);
}
struct traverse_struct {
print_queue_struct *queue;
int qcount, snum, maxcount, total_jobs;
};
static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
{
struct traverse_struct *ts = (struct traverse_struct *)state;
struct printjob pjob;
int i, jobid;
if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
memcpy(&jobid, key.dptr, sizeof(jobid));
memcpy(&pjob, data.dptr, sizeof(pjob));
if (strcmp(lp_servicename(ts->snum), pjob.qname)) {
ts->total_jobs++;
return 0;
}
if (!pjob.smbjob) {
for (i=0;i<ts->qcount;i++) {
if (jobid == ts->queue[i].job + UNIX_JOB_START) break;
}
if (i == ts->qcount)
tdb_delete(tdb, key);
else
ts->total_jobs++;
return 0;
}
if (!pjob.spooled) {
if (!process_exists(pjob.pid))
tdb_delete(tdb, key);
else
ts->total_jobs++;
return 0;
}
for (i=0;i<ts->qcount;i++) {
int qid = print_parse_jobid(ts->queue[i].file);
if (jobid == qid) break;
}
if (i == ts->qcount) {
time_t cur_t = time(NULL);
if ((cur_t - pjob.starttime) > lp_lpqcachetime())
tdb_delete(t, key);
else
ts->total_jobs++;
}
else
ts->total_jobs++;
return 0;
}
static void print_cache_flush(int snum)
{
fstring key;
slprintf(key, sizeof(key)-1, "CACHE/%s", lp_servicename(snum));
dos_to_unix(key, True);
tdb_store_int32(tdb, key, -1);
}
static pid_t get_updating_pid(fstring printer_name)
{
fstring keystr;
TDB_DATA data, key;
pid_t updating_pid;
slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", printer_name);
key.dptr = keystr;
key.dsize = strlen(keystr);
data = tdb_fetch(tdb, key);
if (!data.dptr || data.dsize != sizeof(pid_t))
return (pid_t)-1;
memcpy(&updating_pid, data.dptr, sizeof(pid_t));
SAFE_FREE(data.dptr);
if (process_exists(updating_pid))
return updating_pid;
return (pid_t)-1;
}
static void set_updating_pid(fstring printer_name, BOOL delete)
{
fstring keystr;
TDB_DATA key;
TDB_DATA data;
pid_t updating_pid = getpid();
slprintf(keystr, sizeof(keystr)-1, "UPDATING/%s", printer_name);
key.dptr = keystr;
key.dsize = strlen(keystr);
if (delete) {
tdb_delete(tdb, key);
return;
}
data.dptr = (void *)&updating_pid;
data.dsize = sizeof(pid_t);
tdb_store(tdb, key, data, TDB_REPLACE);
}
static void print_queue_update(int snum)
{
int i, qcount;
print_queue_struct *queue = NULL;
print_status_struct status;
print_status_struct old_status;
struct printjob *pjob;
struct traverse_struct tstruct;
fstring keystr, printer_name, cachestr;
TDB_DATA data, key;
fstrcpy(printer_name, lp_servicename(snum));
dos_to_unix(printer_name, True);
if (get_updating_pid(printer_name) != -1)
return;
slprintf(keystr, sizeof(keystr) - 1, "LOCK/%s", printer_name);
tdb_lock_bystring(tdb, keystr);
if (get_updating_pid(printer_name) != -1) {
tdb_unlock_bystring(tdb, keystr);
return;
}
set_updating_pid(printer_name, False);
tdb_unlock_bystring(tdb, keystr);
slprintf(cachestr, sizeof(cachestr)-1, "CACHE/%s", printer_name);
tdb_store_int32(tdb, cachestr, (int)time(NULL));
ZERO_STRUCT(status);
qcount = (*(current_printif->queue_get))(snum, &queue, &status);
DEBUG(3, ("%d job%s in queue for %s\n", qcount, (qcount != 1) ?
"s" : "", printer_name));
for (i=0; i<qcount; i++) {
int jobid = print_parse_jobid(queue[i].file);
if (jobid == -1) {
print_unix_job(snum, &queue[i]);
continue;
}
pjob = print_job_find(jobid);
if (!pjob) {
print_unix_job(snum, &queue[i]);
continue;
}
pjob->sysjob = queue[i].job;
pjob->status = queue[i].status;
print_job_store(jobid, pjob);
}
tstruct.queue = queue;
tstruct.qcount = qcount;
tstruct.snum = snum;
tstruct.total_jobs = 0;
tdb_traverse(tdb, traverse_fn_delete, (void *)&tstruct);
safe_free(tstruct.queue);
tdb_store_int32(tdb, "INFO/total_jobs", tstruct.total_jobs);
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 ));
message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
}
slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", printer_name);
key.dptr = keystr;
key.dsize = strlen(keystr);
status.qcount = qcount;
data.dptr = (void *)&status;
data.dsize = sizeof(status);
tdb_store(tdb, key, data, TDB_REPLACE);
slprintf(keystr, sizeof(keystr)-1, "CACHE/%s", printer_name);
tdb_store_int32(tdb, keystr, (int32)time(NULL));
set_updating_pid(printer_name, True);
}
BOOL print_job_exists(int jobid)
{
return tdb_exists(tdb, print_key(jobid));
}
int print_job_snum(int jobid)
{
struct printjob *pjob = print_job_find(jobid);
if (!pjob) return -1;
return lp_servicenumber(pjob->qname);
}
int print_job_fd(int jobid)
{
struct printjob *pjob = print_job_find(jobid);
if (!pjob) return -1;
if (pjob->pid != local_pid) return -1;
return pjob->fd;
}
char *print_job_fname(int jobid)
{
struct printjob *pjob = print_job_find(jobid);
if (!pjob || pjob->spooled || pjob->pid != local_pid) return NULL;
return pjob->filename;
}
BOOL print_job_set_place(int jobid, int place)
{
DEBUG(2,("print_job_set_place not implemented yet\n"));
return False;
}
BOOL print_job_set_name(int jobid, char *name)
{
struct printjob *pjob = print_job_find(jobid);
if (!pjob || pjob->pid != local_pid) return False;
fstrcpy(pjob->jobname, name);
return print_job_store(jobid, pjob);
}
static BOOL print_job_delete1(int jobid)
{
struct printjob *pjob = print_job_find(jobid);
int snum, result = 0;
if (!pjob) return False;
if (pjob->status == LPQ_DELETING)
return True;
snum = print_job_snum(jobid);
if (pjob->sysjob == -1) {
DEBUG(5, ("attempt to delete job %d not seen by lpr\n",
jobid));
}
pjob->status = LPQ_DELETING;
print_job_store(jobid, pjob);
if (pjob->spooled && pjob->sysjob != -1)
result = (*(current_printif->job_delete))(snum, pjob);
if (result == 0) {
tdb_delete(tdb, print_key(jobid));
}
return (result == 0);
}
static BOOL is_owner(struct current_user *user, int 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,
unix_to_dos(vuser->user.smb_name,False));
} else {
return strequal(pjob->user,
unix_to_dos(uidtoname(user->uid),False));
}
}
BOOL print_job_delete(struct current_user *user, int jobid, WERROR *errcode)
{
int snum = print_job_snum(jobid);
char *printer_name;
BOOL owner;
owner = is_owner(user, jobid);
if (!owner &&
!print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
DEBUG(3, ("delete denied by security descriptor\n"));
*errcode = WERR_ACCESS_DENIED;
return False;
}
if (!print_job_delete1(jobid)) return False;
print_queue_update(snum);
printer_name = PRINTERNAME(snum);
message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
return !print_job_exists(jobid);
}
BOOL print_job_pause(struct current_user *user, int jobid, WERROR *errcode)
{
struct printjob *pjob = print_job_find(jobid);
int snum, ret = -1;
char *printer_name;
if (!pjob || !user) return False;
if (!pjob->spooled || pjob->sysjob == -1) return False;
snum = print_job_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;
return False;
}
ret = (*(current_printif->job_pause))(snum, pjob);
if (ret != 0) {
*errcode = WERR_INVALID_PARAM;
return False;
}
print_cache_flush(snum);
printer_name = PRINTERNAME(snum);
message_send_all(conn_tdb_ctx(), MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
return True;
}
BOOL print_job_resume(struct current_user *user, int jobid, WERROR *errcode)
{
struct printjob *pjob = print_job_find(jobid);
char *printer_name;
int snum, ret;
if (!pjob || !user) return False;
if (!pjob->spooled || pjob->sysjob == -1) return False;
snum = print_job_snum(jobid);
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;
return False;
}
ret = (*(current_printif->job_resume))(snum, pjob);
if (ret != 0) {
*errcode = WERR_INVALID_PARAM;
return False;
}
print_cache_flush(snum);
printer_name = PRINTERNAME(snum);
message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
return True;
}
int print_job_write(int jobid, const char *buf, int size)
{
int fd;
fd = print_job_fd(jobid);
if (fd == -1) return -1;
return write(fd, buf, size);
}
static BOOL print_cache_expired(int snum)
{
fstring key;
time_t t2, t = time(NULL);
slprintf(key, sizeof(key)-1, "CACHE/%s", lp_servicename(snum));
dos_to_unix(key, True);
t2 = (time_t)tdb_fetch_int32(tdb, key);
if (t2 == ((time_t)-1) || (t - t2) >= lp_lpqcachetime()) {
DEBUG(3, ("print cache expired for queue %s \
(last_cache = %d, time now = %d, qcachetime = %d)\n", lp_servicename(snum),
(int)t2, (int)t, (int)lp_lpqcachetime() ));
return True;
}
return False;
}
static int get_queue_status(int snum, print_status_struct *status)
{
fstring keystr;
TDB_DATA data, key;
ZERO_STRUCTP(status);
slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", lp_servicename(snum));
dos_to_unix(keystr, True);
key.dptr = keystr;
key.dsize = strlen(keystr);
data = tdb_fetch(tdb, key);
if (data.dptr) {
if (data.dsize == sizeof(print_status_struct)) {
memcpy(status, data.dptr, sizeof(print_status_struct));
}
SAFE_FREE(data.dptr);
}
return status->qcount;
}
int print_queue_length(int snum, print_status_struct *pstatus)
{
print_status_struct status;
int len;
if (print_cache_expired(snum))
print_queue_update(snum);
memset(&status, 0, sizeof(status));
len = get_queue_status(snum, &status);
if (pstatus)
*pstatus = status;
return len;
}
static int get_total_jobs(int snum)
{
int total_jobs;
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;
}
int print_job_start(struct current_user *user, int snum, char *jobname)
{
int jobid;
char *path;
struct printjob pjob;
int next_jobid;
user_struct *vuser;
int njobs = 0;
errno = 0;
if (!print_access_check(user, snum, PRINTER_ACCESS_USE)) {
DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
return -1;
}
if (!print_time_access_check(snum)) {
DEBUG(3, ("print_job_start: job start denied by time check\n"));
return -1;
}
path = lp_pathname(snum);
if (lp_minprintspace(snum)) {
SMB_BIG_UINT dspace, dsize;
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"));
errno = ENOSPC;
return -1;
}
}
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 -1;
}
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) ));
errno = ENOSPC;
return -1;
}
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;
}
ZERO_STRUCT(pjob);
pjob.pid = local_pid;
pjob.sysjob = -1;
pjob.fd = -1;
pjob.starttime = time(NULL);
pjob.status = LPQ_SPOOLING;
pjob.size = 0;
pjob.spooled = False;
pjob.smbjob = True;
fstrcpy(pjob.jobname, jobname);
if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
fstrcpy(pjob.user, unix_to_dos(vuser->user.smb_name,False));
} else {
fstrcpy(pjob.user, unix_to_dos(uidtoname(user->uid),False));
}
fstrcpy(pjob.qname, lp_servicename(snum));
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);
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) {
if (errno == EACCES) {
DEBUG(0, ("print_job_start: insufficient permissions \
to open spool file %s.\n", pjob.filename));
} else {
DEBUG(3, ("print_job_start: can't open spool file %s,\n", pjob.filename));
DEBUGADD(3, ("errno = %d (%s).\n", errno, strerror(errno)));
}
goto fail;
}
print_job_store(jobid, &pjob);
tdb_unlock_bystring(tdb, "INFO/nextjob");
if (lp_postscript(snum)) {
print_job_write(jobid, "%!\n",3);
}
return jobid;
fail:
if (jobid != -1) {
tdb_delete(tdb, print_key(jobid));
}
tdb_unlock_bystring(tdb, "INFO/nextjob");
DEBUG(3, ("print_job_start: returning fail. Error = %s\n", strerror(errno) ));
return -1;
}
BOOL print_job_end(int jobid, BOOL normal_close)
{
struct printjob *pjob = print_job_find(jobid);
int snum, ret;
SMB_STRUCT_STAT sbuf;
if (!pjob)
return False;
if (pjob->spooled || pjob->pid != local_pid)
return False;
snum = print_job_snum(jobid);
if (normal_close && (sys_fstat(pjob->fd, &sbuf) == 0)) {
pjob->size = sbuf.st_size;
close(pjob->fd);
pjob->fd = -1;
} else {
close(pjob->fd);
pjob->fd = -1;
DEBUG(3,("print_job_end: failed to stat file for jobid %d\n", jobid ));
goto fail;
}
if (pjob->size == 0 || pjob->status == LPQ_DELETING) {
DEBUG(5,("print_job_end: canceling spool of %s (%s)\n",
pjob->filename, pjob->size ? "deleted" : "zero length" ));
unlink(pjob->filename);
tdb_delete(tdb, print_key(jobid));
return True;
}
ret = (*(current_printif->job_submit))(snum, pjob);
if (ret)
goto fail;
pjob->spooled = True;
pjob->status = LPQ_QUEUED;
print_job_store(jobid, pjob);
if (print_cache_expired(snum))
print_queue_update(snum);
return True;
fail:
unlink(pjob->filename);
tdb_delete(tdb, print_key(jobid));
return False;
}
static int traverse_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
{
struct traverse_struct *ts = (struct traverse_struct *)state;
struct printjob pjob;
int i, jobid;
if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
memcpy(&jobid, key.dptr, sizeof(jobid));
memcpy(&pjob, data.dptr, sizeof(pjob));
if (ts->snum != print_queue_snum(pjob.qname)) return 0;
if (ts->qcount >= ts->maxcount) return 0;
i = ts->qcount;
ts->queue[i].job = jobid;
ts->queue[i].size = pjob.size;
ts->queue[i].status = pjob.status;
ts->queue[i].priority = 1;
ts->queue[i].time = pjob.starttime;
fstrcpy(ts->queue[i].user, pjob.user);
fstrcpy(ts->queue[i].file, pjob.jobname);
ts->qcount++;
return 0;
}
struct traverse_count_struct {
int snum, count;
};
static int traverse_count_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
{
struct traverse_count_struct *ts = (struct traverse_count_struct *)state;
struct printjob pjob;
int jobid;
if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
memcpy(&jobid, key.dptr, sizeof(jobid));
memcpy(&pjob, data.dptr, sizeof(pjob));
if (ts->snum != print_queue_snum(pjob.qname)) return 0;
ts->count++;
return 0;
}
static int printjob_comp(print_queue_struct *j1, print_queue_struct *j2)
{
if (!j1 && !j2) return 0;
if (!j1) return -1;
if (!j2) return 1;
if (j1->time == j2->time) return 0;
return (j1->time > j2->time) ? 1 : -1;
}
int print_queue_status(int snum,
print_queue_struct **queue,
print_status_struct *status)
{
struct traverse_struct tstruct;
struct traverse_count_struct tsc;
fstring keystr;
TDB_DATA data, key;
if (print_cache_expired(snum)) print_queue_update(snum);
*queue = NULL;
ZERO_STRUCTP(status);
slprintf(keystr, sizeof(keystr)-1, "STATUS/%s", lp_servicename(snum));
dos_to_unix(keystr, True);
key.dptr = keystr;
key.dsize = strlen(keystr);
data = tdb_fetch(tdb, key);
if (data.dptr) {
if (data.dsize == sizeof(*status)) {
memcpy(status, data.dptr, sizeof(*status));
}
SAFE_FREE(data.dptr);
}
tsc.count = 0;
tsc.snum = snum;
tdb_traverse(tdb, traverse_count_fn_queue, (void *)&tsc);
if (tsc.count == 0)
return 0;
if ((tstruct.queue = (print_queue_struct *)
malloc(sizeof(print_queue_struct)*tsc.count))
== NULL)
return 0;
tstruct.qcount = 0;
tstruct.maxcount = tsc.count;
tstruct.snum = snum;
tdb_traverse(tdb, traverse_fn_queue, (void *)&tstruct);
qsort(tstruct.queue, tstruct.qcount, sizeof(print_queue_struct),
QSORT_CAST(printjob_comp));
*queue = tstruct.queue;
return tstruct.qcount;
}
int print_queue_snum(char *qname)
{
int snum = lp_servicenumber(qname);
if (snum == -1 || !lp_print_ok(snum)) return -1;
return snum;
}
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)) {
*errcode = WERR_ACCESS_DENIED;
return False;
}
ret = (*(current_printif->queue_pause))(snum);
if (ret != 0) {
*errcode = WERR_INVALID_PARAM;
return False;
}
print_cache_flush(snum);
printer_name = PRINTERNAME(snum);
message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
return True;
}
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)) {
*errcode = WERR_ACCESS_DENIED;
return False;
}
ret = (*(current_printif->queue_resume))(snum);
if (ret != 0) {
*errcode = WERR_INVALID_PARAM;
return False;
}
if (print_cache_expired(snum)) print_queue_update(snum);
printer_name = PRINTERNAME(snum);
message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
return True;
}
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;
print_queue_update(snum);
can_job_admin = print_access_check(user, snum, JOB_ACCESS_ADMINISTER);
njobs = print_queue_status(snum, &queue, &status);
for (i=0;i<njobs;i++) {
BOOL owner = is_owner(user, queue[i].job);
if (owner || can_job_admin) {
print_job_delete1(queue[i].job);
}
}
safe_free(queue);
printer_name = PRINTERNAME(snum);
message_send_all(conn_tdb_ctx(),MSG_PRINTER_NOTIFY, printer_name, strlen(printer_name) + 1, False);
return True;
}