3 Unix SMB/Netbios implementation.
5 printing backend routines
6 Copyright (C) Andrew Tridgell 1992-2000
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 extern int DEBUGLEVEL;
27 the printing backend revolves around a tdb database that stores the
28 SMB view of the print queue
30 The key for this database is a jobid - a internally generated number that
31 uniquely identifies a print job
33 reading the print queue involves two steps:
34 - possibly running lpq and updating the internal database from that
35 - reading entries from the database
37 jobids are assigned when a job starts spooling.
41 pid_t pid; /* which process launched the job */
42 int sysjob; /* the system (lp) job number */
43 int fd; /* file descriptor of open file if open */
44 time_t starttime; /* when the job started spooling */
45 int status; /* the status of this job */
46 size_t size; /* the size of the job so far */
47 BOOL spooled; /* has it been sent to the spooler yet? */
48 BOOL smbjob; /* set if the job is a SMB job */
49 fstring filename; /* the filename used to spool the file */
50 fstring jobname; /* the job name given to us by the client */
51 fstring user; /* the user who started the job */
52 fstring qname; /* name of the print queue the job was sent to */
55 /* the open printing.tdb database */
56 static TDB_CONTEXT *tdb;
57 static pid_t local_pid;
59 #define PRINT_MAX_JOBID 10000
60 #define UNIX_JOB_START PRINT_MAX_JOBID
62 #define PRINT_SPOOL_PREFIX "smbprn."
63 #define PRINT_DATABASE_VERSION 1
65 /****************************************************************************
66 initialise the printing backend. Called once at startup.
67 Does not survive a fork
68 ****************************************************************************/
69 BOOL print_backend_init(void)
71 char *sversion = "INFO/version";
73 if (tdb && local_pid == sys_getpid()) return True;
74 tdb = tdb_open(lock_path("printing.tdb"), 0, 0, O_RDWR|O_CREAT, 0600);
76 DEBUG(0,("Failed to open printing backend database\n"));
78 local_pid = sys_getpid();
80 /* handle a Samba upgrade */
81 tdb_lock_bystring(tdb, sversion);
82 if (tdb_fetch_int(tdb, sversion) != PRINT_DATABASE_VERSION) {
83 tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
84 tdb_store_int(tdb, sversion, PRINT_DATABASE_VERSION);
86 tdb_unlock_bystring(tdb, sversion);
88 return nt_printing_init();
91 /****************************************************************************
92 useful function to generate a tdb key
93 ****************************************************************************/
94 static TDB_DATA print_key(int jobid)
100 ret.dptr = (void *)&j;
101 ret.dsize = sizeof(j);
105 /****************************************************************************
106 useful function to find a print job in the database
107 ****************************************************************************/
108 static struct printjob *print_job_find(int jobid)
110 static struct printjob pjob;
113 ret = tdb_fetch(tdb, print_key(jobid));
114 if (!ret.dptr || ret.dsize != sizeof(pjob)) return NULL;
116 memcpy(&pjob, ret.dptr, sizeof(pjob));
121 /****************************************************************************
122 store a job structure back to the database
123 ****************************************************************************/
124 static BOOL print_job_store(int jobid, struct printjob *pjob)
127 d.dptr = (void *)pjob;
128 d.dsize = sizeof(*pjob);
129 return (0 == tdb_store(tdb, print_key(jobid), d, TDB_REPLACE));
132 /****************************************************************************
133 run a given print command
134 a null terminated list of value/substitute pairs is provided
135 for local substitution strings
136 ****************************************************************************/
137 static int print_run_command(int snum,char *command,
146 if (!command || !*command) return -1;
148 if (!VALID_SNUM(snum)) {
149 DEBUG(0,("Invalid snum %d for command %s\n", snum, command));
153 pstrcpy(syscmd, command);
155 va_start(ap, outfile);
156 while ((arg = va_arg(ap, char *))) {
157 char *value = va_arg(ap,char *);
158 pstring_sub(syscmd, arg, value);
162 p = PRINTERNAME(snum);
163 if (!p || !*p) p = SERVICE(snum);
165 pstring_sub(syscmd, "%p", p);
166 standard_sub_snum(snum,syscmd);
168 ret = smbrun(syscmd,outfile,False);
170 DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
175 /****************************************************************************
176 parse a file name from the system spooler to generate a jobid
177 ****************************************************************************/
178 static int print_parse_jobid(char *fname)
182 if (strncmp(fname,PRINT_SPOOL_PREFIX,strlen(PRINT_SPOOL_PREFIX)) != 0) return -1;
183 fname += strlen(PRINT_SPOOL_PREFIX);
186 if (jobid <= 0) return -1;
192 /****************************************************************************
193 list a unix job in the print database
194 ****************************************************************************/
195 static void print_unix_job(int snum, print_queue_struct *q)
197 int jobid = q->job + UNIX_JOB_START;
205 pj.starttime = q->time;
206 pj.status = q->status;
210 fstrcpy(pj.filename, "");
211 fstrcpy(pj.jobname, q->file);
212 fstrcpy(pj.user, q->user);
213 fstrcpy(pj.qname, lp_servicename(snum));
215 print_job_store(jobid, &pj);
219 struct traverse_struct {
220 print_queue_struct *queue;
221 int qcount, snum, maxcount;
224 /* utility fn to delete any jobs that are no longer active */
225 static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
227 struct traverse_struct *ts = (struct traverse_struct *)state;
228 struct printjob pjob;
231 if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
232 memcpy(&jobid, key.dptr, sizeof(jobid));
233 memcpy(&pjob, data.dptr, sizeof(pjob));
235 if (strcmp(lp_servicename(ts->snum), pjob.qname)) {
236 /* this isn't for the queue we are looking at */
241 /* remove a unix job if it isn't in the system queue
243 for (i=0;i<ts->qcount;i++) {
244 if (jobid == ts->queue[i].job + UNIX_JOB_START) break;
246 if (i == ts->qcount) tdb_delete(tdb, key);
250 /* maybe it hasn't been spooled yet */
252 /* if a job is not spooled and the process doesn't
253 exist then kill it. This cleans up after smbd
255 if (!process_exists(pjob.pid)) {
256 tdb_delete(tdb, key);
261 for (i=0;i<ts->qcount;i++) {
262 int qid = print_parse_jobid(ts->queue[i].file);
263 if (jobid == qid) break;
266 if (i == ts->qcount) {
267 /* the job isn't in the system queue - we have to
268 assume it has completed, so delete the database
276 /****************************************************************************
277 check if the print queue has been updated recently enough
278 ****************************************************************************/
279 static void print_cache_flush(int snum)
282 slprintf(key, sizeof(key), "CACHE/%s", lp_servicename(snum));
283 tdb_store_int(tdb, key, -1);
286 /****************************************************************************
287 update the internal database from the system print queue for a queue
288 ****************************************************************************/
289 static void print_queue_update(int snum)
291 char *path = lp_pathname(snum);
292 char *cmd = lp_lpqcommand(snum);
295 int numlines, i, qcount;
296 print_queue_struct *queue = NULL;
297 print_status_struct status;
298 struct printjob *pjob;
299 struct traverse_struct tstruct;
304 * Update the cache time FIRST ! Stops others doing this
305 * if the lpq takes a long time.
308 slprintf(keystr, sizeof(keystr), "CACHE/%s", lp_servicename(snum));
309 tdb_store_int(tdb, keystr, (int)time(NULL));
311 slprintf(tmp_file, sizeof(tmp_file), "%s/smblpq.%d", path, local_pid);
314 print_run_command(snum, cmd, tmp_file,
318 qlines = file_lines_load(tmp_file, &numlines);
321 /* turn the lpq output into a series of job structures */
325 queue = (print_queue_struct *)malloc(sizeof(print_queue_struct)*(numlines+1));
328 for (i=0; i<numlines; i++) {
330 if (parse_lpq_entry(snum,qlines[i],
331 &queue[qcount],&status,qcount==0)) {
336 file_lines_free(qlines);
339 any job in the internal database that is marked as spooled
340 and doesn't exist in the system queue is considered finished
341 and removed from the database
343 any job in the system database but not in the internal database
344 is added as a unix job
346 fill in any system job numbers as we go
348 for (i=0; i<qcount; i++) {
349 int jobid = print_parse_jobid(queue[i].file);
352 /* assume its a unix print job */
353 print_unix_job(snum, &queue[i]);
357 /* we have an active SMB print job - update its status */
358 pjob = print_job_find(jobid);
360 /* err, somethings wrong. Probably smbd was restarted
361 with jobs in the queue. All we can do is treat them
362 like unix jobs. Pity. */
363 print_unix_job(snum, &queue[i]);
367 pjob->sysjob = queue[i].job;
368 pjob->status = queue[i].status;
370 print_job_store(jobid, pjob);
373 /* now delete any queued entries that don't appear in the
375 tstruct.queue = queue;
376 tstruct.qcount = qcount;
379 tdb_traverse(tdb, traverse_fn_delete, (void *)&tstruct);
381 safe_free(tstruct.queue);
383 /* store the queue status structure */
384 slprintf(keystr, sizeof(keystr), "STATUS/%s", lp_servicename(snum));
385 data.dptr = (void *)&status;
386 data.dsize = sizeof(status);
388 key.dsize = strlen(keystr);
389 tdb_store(tdb, key, data, TDB_REPLACE);
392 * Update the cache time again. We want to do this call
393 * as little as possible...
396 slprintf(keystr, sizeof(keystr), "CACHE/%s", lp_servicename(snum));
397 tdb_store_int(tdb, keystr, (int)time(NULL));
400 /****************************************************************************
401 check if a jobid is valid. It is valid if it exists in the database
402 ****************************************************************************/
403 BOOL print_job_exists(int jobid)
405 return tdb_exists(tdb, print_key(jobid));
409 /****************************************************************************
410 work out which service a jobid is for
411 note that we have to look up by queue name to ensure that it works for
412 other than the process that started the job
413 ****************************************************************************/
414 int print_job_snum(int jobid)
416 struct printjob *pjob = print_job_find(jobid);
417 if (!pjob) return -1;
419 return lp_servicenumber(pjob->qname);
422 /****************************************************************************
423 give the fd used for a jobid
424 ****************************************************************************/
425 int print_job_fd(int jobid)
427 struct printjob *pjob = print_job_find(jobid);
428 if (!pjob) return -1;
429 /* don't allow another process to get this info - it is meaningless */
430 if (pjob->pid != local_pid) return -1;
434 /****************************************************************************
435 give the filename used for a jobid
436 only valid for the process doing the spooling and when the job
438 ****************************************************************************/
439 char *print_job_fname(int jobid)
441 struct printjob *pjob = print_job_find(jobid);
442 if (!pjob || pjob->spooled || pjob->pid != local_pid) return NULL;
443 return pjob->filename;
447 /****************************************************************************
448 set the place in the queue for a job
449 ****************************************************************************/
450 BOOL print_job_set_place(int jobid, int place)
452 DEBUG(2,("print_job_set_place not implemented yet\n"));
456 /****************************************************************************
457 set the name of a job. Only possible for owner
458 ****************************************************************************/
459 BOOL print_job_set_name(int jobid, char *name)
461 struct printjob *pjob = print_job_find(jobid);
462 if (!pjob || pjob->pid != local_pid) return False;
464 fstrcpy(pjob->jobname, name);
465 return print_job_store(jobid, pjob);
469 /****************************************************************************
470 delete a print job - don't update queue
471 ****************************************************************************/
472 static BOOL print_job_delete1(int jobid)
474 struct printjob *pjob = print_job_find(jobid);
477 if (!pjob) return False;
479 snum = print_job_snum(jobid);
481 if (pjob->spooled && pjob->sysjob != -1) {
482 /* need to delete the spooled entry */
484 slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob);
485 print_run_command(snum,
486 lp_lprmcommand(snum), NULL,
488 "%T", http_timestring(pjob->starttime),
495 /****************************************************************************
496 return true if the current user owns the print job
497 ****************************************************************************/
498 static BOOL is_owner(struct current_user *user, int jobid)
500 struct printjob *pjob = print_job_find(jobid);
503 if (!pjob || !user) return False;
505 if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
506 return strequal(pjob->user, vuser->user.smb_name);
508 return strequal(pjob->user, uidtoname(user->uid));
512 /****************************************************************************
514 ****************************************************************************/
515 BOOL print_job_delete(struct current_user *user, int jobid)
517 int snum = print_job_snum(jobid);
520 if (!user) return False;
522 owner = is_owner(user, jobid);
524 /* Check access against security descriptor or whether the user
528 !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
529 DEBUG(3, ("delete denied by security descriptor\n"));
533 if (!print_job_delete1(jobid)) return False;
535 /* force update the database and say the delete failed if the
538 print_queue_update(snum);
540 return !print_job_exists(jobid);
544 /****************************************************************************
546 ****************************************************************************/
547 BOOL print_job_pause(struct current_user *user, int jobid)
549 struct printjob *pjob = print_job_find(jobid);
555 if (!pjob || !user) return False;
557 if (!pjob->spooled || pjob->sysjob == -1) return False;
559 snum = print_job_snum(jobid);
560 owner = is_owner(user, jobid);
563 !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
564 DEBUG(3, ("pause denied by security descriptor\n"));
568 /* need to pause the spooled entry */
569 slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob);
570 ret = print_run_command(snum,
571 lp_lppausecommand(snum), NULL,
575 /* force update the database */
576 print_cache_flush(snum);
578 /* how do we tell if this succeeded? */
582 /****************************************************************************
584 ****************************************************************************/
585 BOOL print_job_resume(struct current_user *user, int jobid)
587 struct printjob *pjob = print_job_find(jobid);
592 if (!pjob || !user) return False;
594 if (!pjob->spooled || pjob->sysjob == -1) return False;
596 snum = print_job_snum(jobid);
597 owner = is_owner(user, jobid);
599 if (!is_owner(user, jobid) &&
600 !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
601 DEBUG(3, ("resume denied by security descriptor\n"));
605 slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob);
606 ret = print_run_command(snum,
607 lp_lpresumecommand(snum), NULL,
611 /* force update the database */
612 print_cache_flush(snum);
614 /* how do we tell if this succeeded? */
618 /****************************************************************************
619 write to a print file
620 ****************************************************************************/
621 int print_job_write(int jobid, const char *buf, int size)
625 fd = print_job_fd(jobid);
626 if (fd == -1) return -1;
628 return write(fd, buf, size);
632 /***************************************************************************
633 start spooling a job - return the jobid
634 ***************************************************************************/
635 int print_job_start(struct current_user *user, int snum, char *jobname)
639 struct printjob pjob;
645 if (!print_access_check(user, snum, PRINTER_ACCESS_USE)) {
646 DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
650 if (!print_time_access_check(snum)) {
651 DEBUG(3, ("print_job_start: job start denied by time check\n"));
655 path = lp_pathname(snum);
657 /* see if we have sufficient disk space */
658 if (lp_minprintspace(snum)) {
659 SMB_BIG_UINT dspace, dsize;
660 if (sys_fsusage(path, &dspace, &dsize) == 0 &&
661 dspace < 2*(SMB_BIG_UINT)lp_minprintspace(snum)) {
667 /* for autoloaded printers, check that the printcap entry still exists */
668 if (lp_autoloaded(snum) && !pcap_printername_ok(lp_servicename(snum), NULL)) {
673 /* create the database entry */
675 pjob.pid = local_pid;
678 pjob.starttime = time(NULL);
679 pjob.status = LPQ_QUEUED;
681 pjob.spooled = False;
684 fstrcpy(pjob.jobname, jobname);
686 if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
687 fstrcpy(pjob.user, vuser->user.smb_name);
689 fstrcpy(pjob.user, uidtoname(user->uid));
692 fstrcpy(pjob.qname, lp_servicename(snum));
694 /* lock the database */
695 tdb_lock_bystring(tdb, "INFO/nextjob");
698 next_jobid = tdb_fetch_int(tdb, "INFO/nextjob");
699 if (next_jobid == -1) next_jobid = 1;
701 for (jobid = next_jobid+1; jobid != next_jobid; ) {
702 if (!print_job_exists(jobid)) break;
703 jobid = (jobid + 1) % PRINT_MAX_JOBID;
704 if (jobid == 0) jobid = 1;
706 if (jobid == next_jobid || !print_job_store(jobid, &pjob)) {
711 tdb_store_int(tdb, "INFO/nextjob", jobid);
713 /* we have a job entry - now create the spool file
715 we unlink first to cope with old spool files and also to beat
716 a symlink security hole - it allows us to use O_EXCL
717 There may be old spool files owned by other users lying around.
719 slprintf(pjob.filename, sizeof(pjob.filename), "%s/%s%d",
720 path, PRINT_SPOOL_PREFIX, jobid);
721 if (unlink(pjob.filename) == -1 && errno != ENOENT) {
724 pjob.fd = sys_open(pjob.filename,O_WRONLY|O_CREAT|O_EXCL,0600);
725 if (pjob.fd == -1) goto fail;
727 print_job_store(jobid, &pjob);
729 tdb_unlock_bystring(tdb, "INFO/nextjob");
732 * If the printer is marked as postscript output a leading
733 * file identifier to ensure the file is treated as a raw
735 * This has a similar effect as CtrlD=0 in WIN.INI file.
736 * tim@fsg.com 09/06/94
738 if (lp_postscript(snum)) {
739 print_job_write(jobid, "%!\n",3);
746 tdb_delete(tdb, print_key(jobid));
749 tdb_unlock_bystring(tdb, "INFO/nextjob");
753 /****************************************************************************
754 Print a file - called on closing the file. This spools the job.
755 ****************************************************************************/
757 BOOL print_job_end(int jobid)
759 struct printjob *pjob = print_job_find(jobid);
761 SMB_STRUCT_STAT sbuf;
762 pstring current_directory;
763 pstring print_directory;
770 if (pjob->spooled || pjob->pid != local_pid)
773 snum = print_job_snum(jobid);
775 if (sys_fstat(pjob->fd, &sbuf) == 0)
776 pjob->size = sbuf.st_size;
781 if (pjob->size == 0) {
782 /* don't bother spooling empty files */
783 unlink(pjob->filename);
784 tdb_delete(tdb, print_key(jobid));
788 /* we print from the directory path to give the best chance of
789 parsing the lpq output */
790 wd = sys_getwd(current_directory);
794 pstrcpy(print_directory, pjob->filename);
795 p = strrchr(print_directory,'/');
800 if (chdir(print_directory) != 0)
803 pstrcpy(jobname, pjob->jobname);
804 pstring_sub(jobname, "'", "_");
806 /* send it to the system spooler */
807 print_run_command(snum,
808 lp_printcommand(snum), NULL,
816 pjob->spooled = True;
817 print_job_store(jobid, pjob);
819 /* force update the database */
820 print_cache_flush(snum);
825 /****************************************************************************
826 Check if the print queue has been updated recently enough.
827 ****************************************************************************/
829 static BOOL print_cache_expired(int snum)
832 time_t t2, t = time(NULL);
833 slprintf(key, sizeof(key), "CACHE/%s", lp_servicename(snum));
834 t2 = tdb_fetch_int(tdb, key);
835 if (t2 == ((time_t)-1) || (t - t2) >= lp_lpqcachetime()) {
841 /* utility fn to enumerate the print queue */
842 static int traverse_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
844 struct traverse_struct *ts = (struct traverse_struct *)state;
845 struct printjob pjob;
848 if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
849 memcpy(&jobid, key.dptr, sizeof(jobid));
850 memcpy(&pjob, data.dptr, sizeof(pjob));
852 /* maybe it isn't for this queue */
853 if (ts->snum != print_queue_snum(pjob.qname)) return 0;
855 if (ts->qcount >= ts->maxcount) return 0;
859 ts->queue[i].job = jobid;
860 ts->queue[i].size = pjob.size;
861 ts->queue[i].status = pjob.status;
862 ts->queue[i].priority = 1;
863 ts->queue[i].time = pjob.starttime;
864 fstrcpy(ts->queue[i].user, pjob.user);
865 fstrcpy(ts->queue[i].file, pjob.jobname);
872 struct traverse_count_struct {
876 /* utility fn to count the number of entries in the print queue */
877 static int traverse_count_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
879 struct traverse_count_struct *ts = (struct traverse_count_struct *)state;
880 struct printjob pjob;
883 if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
884 memcpy(&jobid, key.dptr, sizeof(jobid));
885 memcpy(&pjob, data.dptr, sizeof(pjob));
887 /* maybe it isn't for this queue */
888 if (ts->snum != print_queue_snum(pjob.qname)) return 0;
895 /****************************************************************************
896 get a printer queue listing
897 ****************************************************************************/
898 int print_queue_status(int snum,
899 print_queue_struct **queue,
900 print_status_struct *status)
902 struct traverse_struct tstruct;
903 struct traverse_count_struct tsc;
907 /* make sure the database is up to date */
908 if (print_cache_expired(snum)) print_queue_update(snum);
911 * Count the number of entries.
915 tdb_traverse(tdb, traverse_count_fn_queue, (void *)&tsc);
917 /* Allocate the queue size. */
918 if (( tstruct.queue = (print_queue_struct *)malloc(sizeof(print_queue_struct)*tsc.count))
924 * We need maxcount as the queue size may have changed between
925 * the two calls to tdb_traverse.
928 tstruct.maxcount = tsc.count;
931 tdb_traverse(tdb, traverse_fn_queue, (void *)&tstruct);
933 /* also fetch the queue status */
934 ZERO_STRUCTP(status);
935 slprintf(keystr, sizeof(keystr), "STATUS/%s", lp_servicename(snum));
937 key.dsize = strlen(keystr);
938 data = tdb_fetch(tdb, key);
940 if (data.dsize == sizeof(*status)) {
941 memcpy(status, data.dptr, sizeof(*status));
946 *queue = tstruct.queue;
947 return tstruct.qcount;
951 /****************************************************************************
952 turn a queue name into a snum
953 ****************************************************************************/
954 int print_queue_snum(char *qname)
956 int snum = lp_servicenumber(qname);
957 if (snum == -1 || !lp_print_ok(snum)) return -1;
962 /****************************************************************************
964 ****************************************************************************/
965 BOOL print_queue_pause(struct current_user *user, int snum, int *errcode)
969 if (!user) return False;
971 if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
972 *errcode = ERROR_ACCESS_DENIED;
976 ret = print_run_command(snum, lp_queuepausecommand(snum), NULL,
979 /* force update the database */
980 print_cache_flush(snum);
985 /****************************************************************************
987 ****************************************************************************/
988 BOOL print_queue_resume(struct current_user *user, int snum, int *errcode)
992 if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
993 *errcode = ERROR_ACCESS_DENIED;
997 ret = print_run_command(snum, lp_queueresumecommand(snum), NULL,
1000 /* force update the database */
1001 print_cache_flush(snum);
1006 /****************************************************************************
1007 purge a queue - implemented by deleting all jobs that we can delete
1008 ****************************************************************************/
1009 BOOL print_queue_purge(struct current_user *user, int snum, int *errcode)
1011 print_queue_struct *queue;
1012 print_status_struct status;
1015 njobs = print_queue_status(snum, &queue, &status);
1016 for (i=0;i<njobs;i++) {
1017 if (print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
1018 print_job_delete1(queue[i].job);
1022 print_cache_flush(snum);
1028 /****************************************************************************
1029 Periodically run a status on all the queues to ensure the tdb doesn't grow.
1030 Note that this will have no effect if the client is doing its own status
1031 queries. This code is here to clean up jobs submitted by non-Windows printer
1032 clients (eg. smbclient) that never do a status check.
1033 ****************************************************************************/
1035 void process_print_queue(time_t t)
1037 static time_t last_check_time;
1038 int services = lp_numservices();
1039 print_queue_struct *queue;
1040 print_status_struct status;
1043 if ((t != (time_t)-1) && ((t - last_check_time) < lp_lpqcachetime()))
1046 last_check_time = t;
1048 for (snum = 0; snum < services; snum++) {
1049 if (lp_snum_ok(snum) && lp_print_ok(snum) && lp_browseable(snum)) {
1050 (void)print_queue_status(snum, &queue,&status);