Allow job owner to delete own print job.
[samba.git] / source / printing / printing.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    printing backend routines
5    Copyright (C) Andrew Tridgell 1992-2000
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 extern int DEBUGLEVEL;
24
25 /* 
26    the printing backend revolves around a tdb database that stores the
27    SMB view of the print queue 
28    
29    The key for this database is a jobid - a internally generated number that
30    uniquely identifies a print job
31
32    reading the print queue involves two steps:
33      - possibly running lpq and updating the internal database from that
34      - reading entries from the database
35
36    jobids are assigned when a job starts spooling. 
37 */
38
39 struct printjob {
40         pid_t pid; /* which process launched the job */
41         int sysjob; /* the system (lp) job number */
42         int fd; /* file descriptor of open file if open */
43         time_t starttime; /* when the job started spooling */
44         int status; /* the status of this job */
45         size_t size; /* the size of the job so far */
46         BOOL spooled; /* has it been sent to the spooler yet? */
47         BOOL smbjob; /* set if the job is a SMB job */
48         fstring filename; /* the filename used to spool the file */
49         fstring jobname; /* the job name given to us by the client */
50         fstring user; /* the user who started the job */
51         fstring qname; /* name of the print queue the job was sent to */
52 };
53
54 /* the open printing.tdb database */
55 static TDB_CONTEXT *tdb;
56 static pid_t local_pid;
57
58 #define PRINT_MAX_JOBID 10000
59 #define UNIX_JOB_START PRINT_MAX_JOBID
60
61 #define PRINT_SPOOL_PREFIX "smbprn."
62 #define PRINT_DATABASE_VERSION 1
63
64 /****************************************************************************
65 initialise the printing backend. Called once at startup. 
66 Does not survive a fork
67 ****************************************************************************/
68 BOOL print_backend_init(void)
69 {
70         if (tdb && local_pid == sys_getpid()) return True;
71         tdb = tdb_open(lock_path("printing.tdb"), 0, 0, O_RDWR|O_CREAT, 0600);
72         if (!tdb) {
73                 DEBUG(0,("Failed to open printing backend database\n"));
74         }
75         local_pid = sys_getpid();
76
77         /* handle a Samba upgrade */
78         tdb_writelock(tdb);
79         if (tdb_fetch_int(tdb, "INFO/version") != PRINT_DATABASE_VERSION) {
80                 tdb_traverse(tdb, (tdb_traverse_func)tdb_delete, NULL);
81                 tdb_store_int(tdb, "INFO/version", PRINT_DATABASE_VERSION);
82         }
83         tdb_writeunlock(tdb);
84
85         return nt_printing_init();
86 }
87
88 /****************************************************************************
89 useful function to generate a tdb key
90 ****************************************************************************/
91 static TDB_DATA print_key(int jobid)
92 {
93         static int j;
94         TDB_DATA ret;
95
96         j = jobid;
97         ret.dptr = (void *)&j;
98         ret.dsize = sizeof(j);
99         return ret;
100 }
101
102 /****************************************************************************
103 useful function to find a print job in the database
104 ****************************************************************************/
105 static struct printjob *print_job_find(int jobid)
106 {
107         static struct printjob pjob;
108         TDB_DATA ret;
109
110         ret = tdb_fetch(tdb, print_key(jobid));
111         if (!ret.dptr || ret.dsize != sizeof(pjob)) return NULL;
112
113         memcpy(&pjob, ret.dptr, sizeof(pjob));
114         free(ret.dptr);
115         return &pjob;
116 }
117
118 /****************************************************************************
119 store a job structure back to the database
120 ****************************************************************************/
121 static BOOL print_job_store(int jobid, struct printjob *pjob)
122 {
123         TDB_DATA d;
124         d.dptr = (void *)pjob;
125         d.dsize = sizeof(*pjob);
126         return (0 == tdb_store(tdb, print_key(jobid), d, TDB_REPLACE));
127 }
128
129 /****************************************************************************
130 run a given print command 
131 a null terminated list of value/substitute pairs is provided
132 for local substitution strings
133 ****************************************************************************/
134 static int print_run_command(int snum,char *command, 
135                              char *outfile,
136                              ...)
137 {
138         pstring syscmd;
139         char *p, *arg;
140         int ret;
141         va_list ap;
142
143         if (!command || !*command) return -1;
144
145         if (!VALID_SNUM(snum)) {
146                 DEBUG(0,("Invalid snum %d for command %s\n", snum, command));
147                 return -1;
148         }
149
150         pstrcpy(syscmd, command);
151
152         va_start(ap, outfile);
153         while ((arg = va_arg(ap, char *))) {
154                 char *value = va_arg(ap,char *);
155                 pstring_sub(syscmd, arg, value);
156         }
157         va_end(ap);
158   
159         p = PRINTERNAME(snum);
160         if (!p || !*p) p = SERVICE(snum);
161   
162         pstring_sub(syscmd, "%p", p);
163         standard_sub_snum(snum,syscmd);
164   
165         ret = smbrun(syscmd,outfile,False);
166
167         DEBUG(3,("Running the command `%s' gave %d\n",syscmd,ret));
168         return ret;
169 }
170
171
172 /****************************************************************************
173 parse a file name from the system spooler to generate a jobid
174 ****************************************************************************/
175 static int print_parse_jobid(char *fname)
176 {
177         int jobid;
178
179         if (strncmp(fname,PRINT_SPOOL_PREFIX,strlen(PRINT_SPOOL_PREFIX)) != 0) return -1;
180         fname += strlen(PRINT_SPOOL_PREFIX);
181
182         jobid = atoi(fname);
183         if (jobid <= 0) return -1;
184
185         return jobid;
186 }
187
188
189 /****************************************************************************
190 list a unix job in the print database
191 ****************************************************************************/
192 static void print_unix_job(int snum, print_queue_struct *q)
193 {
194         int jobid = q->job + UNIX_JOB_START;
195         struct printjob pj;
196
197         ZERO_STRUCT(pj);
198
199         pj.pid = (pid_t)-1;
200         pj.sysjob = q->job;
201         pj.fd = -1;
202         pj.starttime = q->time;
203         pj.status = q->status;
204         pj.size = q->size;
205         pj.spooled = True;
206         pj.smbjob = False;
207         fstrcpy(pj.filename, "");
208         fstrcpy(pj.jobname, q->file);
209         fstrcpy(pj.user, q->user);
210         fstrcpy(pj.qname, lp_servicename(snum));
211
212         print_job_store(jobid, &pj);
213 }
214
215
216 struct traverse_struct {
217         print_queue_struct *queue;
218         int qcount, snum;
219 };
220
221 /* utility fn to delete any jobs that are no longer active */
222 static int traverse_fn_delete(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
223 {
224         struct traverse_struct *ts = (struct traverse_struct *)state;
225         struct printjob pjob;
226         int i, jobid;
227
228         if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
229         memcpy(&jobid, key.dptr, sizeof(jobid));
230         memcpy(&pjob,  data.dptr, sizeof(pjob));
231
232         if (strcmp(lp_servicename(ts->snum), pjob.qname)) {
233                 /* this isn't for the queue we are looking at */
234                 return 0;
235         }
236
237         if (!pjob.smbjob) {
238                 /* remove a unix job if it isn't in the system queue
239                    any more */
240                 for (i=0;i<ts->qcount;i++) {
241                         if (jobid == ts->queue[i].job + UNIX_JOB_START) break;
242                 }
243                 if (i == ts->qcount) tdb_delete(tdb, key);
244                 return 0;
245         }
246
247         /* maybe it hasn't been spooled yet */
248         if (!pjob.spooled) {
249                 /* if a job is not spooled and the process doesn't
250                    exist then kill it. This cleans up after smbd
251                    deaths */
252                 if (!process_exists(pjob.pid)) {
253                         tdb_delete(tdb, key);
254                 }
255                 return 0;
256         }
257
258         for (i=0;i<ts->qcount;i++) {
259                 int qid = print_parse_jobid(ts->queue[i].file);
260                 if (jobid == qid) break;
261         }
262         
263         if (i == ts->qcount) {
264                 /* the job isn't in the system queue - we have to
265                    assume it has completed, so delete the database
266                    entry */
267                 tdb_delete(t, key);
268         }
269
270         return 0;
271 }
272
273 /****************************************************************************
274 check if the print queue has been updated recently enough
275 ****************************************************************************/
276 static void print_cache_flush(int snum)
277 {
278         fstring key;
279         slprintf(key, sizeof(key), "CACHE/%s", lp_servicename(snum));
280         tdb_store_int(tdb, key, -1);
281 }
282
283 /****************************************************************************
284 update the internal database from the system print queue for a queue
285 ****************************************************************************/
286 static void print_queue_update(int snum)
287 {
288         char *path = lp_pathname(snum);
289         char *cmd = lp_lpqcommand(snum);
290         char **qlines;
291         pstring tmp_file;
292         int numlines, i, qcount;
293         print_queue_struct *queue = NULL;
294         print_status_struct status;
295         struct printjob *pjob;
296         struct traverse_struct tstruct;
297         fstring keystr;
298         TDB_DATA data, key;
299  
300         slprintf(tmp_file, sizeof(tmp_file), "%s/smblpq.%d", path, local_pid);
301
302         unlink(tmp_file);
303         print_run_command(snum, cmd, tmp_file,
304                           NULL);
305
306         numlines = 0;
307         qlines = file_lines_load(tmp_file, &numlines);
308         unlink(tmp_file);
309
310         /* turn the lpq output into a series of job structures */
311         qcount = 0;
312         ZERO_STRUCT(status);
313         for (i=0; i<numlines; i++) {
314                 queue = Realloc(queue,sizeof(print_queue_struct)*(qcount+1));
315                 if (!queue) {
316                         qcount = 0;
317                         break;
318                 }
319                 /* parse the line */
320                 if (parse_lpq_entry(snum,qlines[i],
321                                     &queue[qcount],&status,qcount==0)) {
322                         qcount++;
323                 }
324         }               
325         file_lines_free(qlines);
326
327         /*
328           any job in the internal database that is marked as spooled
329           and doesn't exist in the system queue is considered finished
330           and removed from the database
331
332           any job in the system database but not in the internal database 
333           is added as a unix job
334
335           fill in any system job numbers as we go
336         */
337         for (i=0; i<qcount; i++) {
338                 int jobid = print_parse_jobid(queue[i].file);
339
340                 if (jobid == -1) {
341                         /* assume its a unix print job */
342                         print_unix_job(snum, &queue[i]);
343                         continue;
344                 }
345
346                 /* we have an active SMB print job - update its status */
347                 pjob = print_job_find(jobid);
348                 if (!pjob) {
349                         /* err, somethings wrong. Probably smbd was restarted
350                            with jobs in the queue. All we can do is treat them
351                            like unix jobs. Pity. */
352                         print_unix_job(snum, &queue[i]);
353                         continue;
354                 }
355
356                 pjob->sysjob = queue[i].job;
357                 pjob->status = queue[i].status;
358
359                 print_job_store(jobid, pjob);
360         }
361
362         /* now delete any queued entries that don't appear in the
363            system queue */
364         tstruct.queue = queue;
365         tstruct.qcount = qcount;
366         tstruct.snum = snum;
367
368         tdb_traverse(tdb, traverse_fn_delete, (void *)&tstruct);
369
370         safe_free(tstruct.queue);
371
372         /* store the queue status structure */
373         slprintf(keystr, sizeof(keystr), "STATUS/%s", lp_servicename(snum));
374         data.dptr = (void *)&status;
375         data.dsize = sizeof(status);
376         key.dptr = keystr;
377         key.dsize = strlen(keystr);
378         tdb_store(tdb, key, data, TDB_REPLACE); 
379
380         /* update the cache time */
381         slprintf(keystr, sizeof(keystr), "CACHE/%s", lp_servicename(snum));
382         tdb_store_int(tdb, keystr, (int)time(NULL));
383 }
384
385 /****************************************************************************
386 check if a jobid is valid. It is valid if it exists in the database
387 ****************************************************************************/
388 BOOL print_job_exists(int jobid)
389 {
390         return tdb_exists(tdb, print_key(jobid));
391 }
392
393
394 /****************************************************************************
395 work out which service a jobid is for
396 note that we have to look up by queue name to ensure that it works for 
397 other than the process that started the job
398 ****************************************************************************/
399 int print_job_snum(int jobid)
400 {
401         struct printjob *pjob = print_job_find(jobid);
402         if (!pjob) return -1;
403
404         return lp_servicenumber(pjob->qname);
405 }
406
407 /****************************************************************************
408 give the fd used for a jobid
409 ****************************************************************************/
410 int print_job_fd(int jobid)
411 {
412         struct printjob *pjob = print_job_find(jobid);
413         if (!pjob) return -1;
414         /* don't allow another process to get this info - it is meaningless */
415         if (pjob->pid != local_pid) return -1;
416         return pjob->fd;
417 }
418
419 /****************************************************************************
420 give the filename used for a jobid
421 only valid for the process doing the spooling and when the job
422 has not been spooled
423 ****************************************************************************/
424 char *print_job_fname(int jobid)
425 {
426         struct printjob *pjob = print_job_find(jobid);
427         if (!pjob || pjob->spooled || pjob->pid != local_pid) return NULL;
428         return pjob->filename;
429 }
430
431
432 /****************************************************************************
433 set the place in the queue for a job
434 ****************************************************************************/
435 BOOL print_job_set_place(int jobid, int place)
436 {
437         DEBUG(2,("print_job_set_place not implemented yet\n"));
438         return False;
439 }
440
441 /****************************************************************************
442 set the name of a job. Only possible for owner
443 ****************************************************************************/
444 BOOL print_job_set_name(int jobid, char *name)
445 {
446         struct printjob *pjob = print_job_find(jobid);
447         if (!pjob || pjob->pid != local_pid) return False;
448
449         fstrcpy(pjob->jobname, name);
450         return print_job_store(jobid, pjob);
451 }
452
453
454 /****************************************************************************
455 delete a print job - don't update queue
456 ****************************************************************************/
457 static BOOL print_job_delete1(int jobid)
458 {
459         struct printjob *pjob = print_job_find(jobid);
460         int snum;
461
462         if (!pjob) return False;
463
464         snum = print_job_snum(jobid);
465
466         if (pjob->spooled && pjob->sysjob != -1) {
467                 /* need to delete the spooled entry */
468                 fstring jobstr;
469                 slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob);
470                 print_run_command(snum, 
471                                   lp_lprmcommand(snum), NULL,
472                                   "%j", jobstr,
473                                   "%T", http_timestring(pjob->starttime),
474                                   NULL);
475         }
476
477         return True;
478 }
479
480 /****************************************************************************
481 return true if the uid owns the print job
482 ****************************************************************************/
483 static BOOL is_owner(uid_t uid, int jobid)
484 {
485         struct printjob *pjob = print_job_find(jobid);
486         struct passwd *pw;
487
488         if (!pjob || !(pw = sys_getpwuid(uid))) return False;
489
490         return (pw && pjob && strequal(pw->pw_name, pjob->user));
491 }
492
493 /****************************************************************************
494 delete a print job
495 ****************************************************************************/
496 BOOL print_job_delete(struct current_user *user, int jobid)
497 {
498         int snum = print_job_snum(jobid);
499         BOOL owner;
500         
501         if (!user) return False;
502
503         owner = is_owner(user->uid, jobid);
504         
505         /* Check access against security descriptor or whether the user
506            owns their job. */
507
508         if (!owner && 
509             !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
510                 DEBUG(3, ("delete denied by security descriptor\n"));
511                 return False;
512         }
513
514         if (!print_job_delete1(jobid)) return False;
515
516         /* force update the database and say the delete failed if the
517            job still exists */
518
519         print_queue_update(snum);
520
521         return !print_job_exists(jobid);
522 }
523
524
525 /****************************************************************************
526 pause a job
527 ****************************************************************************/
528 BOOL print_job_pause(struct current_user *user, int jobid)
529 {
530         struct printjob *pjob = print_job_find(jobid);
531         int snum, ret = -1;
532         fstring jobstr;
533         BOOL owner;
534         
535
536         if (!pjob || !user) return False;
537
538         if (!pjob->spooled || pjob->sysjob == -1) return False;
539
540         snum = print_job_snum(jobid);
541         owner = is_owner(user->uid, jobid);
542
543         if (!owner &&
544             !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
545                 DEBUG(3, ("pause denied by security descriptor\n"));
546                 return False;
547         }
548
549         /* need to pause the spooled entry */
550         slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob);
551         ret = print_run_command(snum, 
552                                 lp_lppausecommand(snum), NULL,
553                                 "%j", jobstr,
554                                 NULL);
555
556         /* force update the database */
557         print_cache_flush(snum);
558
559         /* how do we tell if this succeeded? */
560         return ret == 0;
561 }
562
563 /****************************************************************************
564 resume a job
565 ****************************************************************************/
566 BOOL print_job_resume(struct current_user *user, int jobid)
567 {
568         struct printjob *pjob = print_job_find(jobid);
569         int snum, ret;
570         fstring jobstr;
571         BOOL owner;
572         
573         if (!pjob || !user) return False;
574
575         if (!pjob->spooled || pjob->sysjob == -1) return False;
576
577         snum = print_job_snum(jobid);
578         owner = is_owner(user->uid, jobid);
579
580         if (!is_owner(user->uid, jobid) &&
581             !print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
582                 DEBUG(3, ("resume denied by security descriptor\n"));
583                 return False;
584         }
585
586         slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob);
587         ret = print_run_command(snum, 
588                                 lp_lpresumecommand(snum), NULL,
589                                 "%j", jobstr,
590                                 NULL);
591
592         /* force update the database */
593         print_cache_flush(snum);
594
595         /* how do we tell if this succeeded? */
596         return ret == 0;
597 }
598
599 /****************************************************************************
600 write to a print file
601 ****************************************************************************/
602 int print_job_write(int jobid, const char *buf, int size)
603 {
604         int fd;
605
606         fd = print_job_fd(jobid);
607         if (fd == -1) return -1;
608
609         return write(fd, buf, size);
610 }
611
612
613 /***************************************************************************
614 start spooling a job - return the jobid
615 ***************************************************************************/
616 int print_job_start(struct current_user *user, int snum, char *jobname)
617 {
618         int jobid;
619         char *path;
620         struct printjob pjob;
621         int next_jobid;
622         extern struct current_user current_user;
623
624         if (!print_access_check(user, snum, PRINTER_ACE_PRINT)) {
625                 DEBUG(3, ("job start denied by security descriptor\n"));
626                 return False;
627         }
628
629         path = lp_pathname(snum);
630
631         /* see if we have sufficient disk space */
632         if (lp_minprintspace(snum)) {
633                 SMB_BIG_UINT dspace, dsize;
634                 if (sys_fsusage(path, &dspace, &dsize) == 0 &&
635                     dspace < 2*(SMB_BIG_UINT)lp_minprintspace(snum)) {
636                         errno = ENOSPC;
637                         return -1;
638                 }
639         }
640
641         /* for autoloaded printers, check that the printcap entry still exists */
642         if (lp_autoloaded(snum) && !pcap_printername_ok(lp_servicename(snum), NULL)) {
643                 errno = ENOENT;
644                 return -1;
645         }
646
647         /* create the database entry */
648         ZERO_STRUCT(pjob);
649         pjob.pid = local_pid;
650         pjob.sysjob = -1;
651         pjob.fd = -1;
652         pjob.starttime = time(NULL);
653         pjob.status = LPQ_QUEUED;
654         pjob.size = 0;
655         pjob.spooled = False;
656         pjob.smbjob = True;
657
658         fstrcpy(pjob.jobname, jobname);
659         fstrcpy(pjob.user, uidtoname(current_user.uid));
660         fstrcpy(pjob.qname, lp_servicename(snum));
661
662         /* lock the database */
663         tdb_writelock(tdb);
664
665         next_jobid = tdb_fetch_int(tdb, "INFO/nextjob");
666         if (next_jobid == -1) next_jobid = 1;
667
668         for (jobid = next_jobid+1; jobid != next_jobid; ) {
669                 if (!print_job_exists(jobid)) break;
670                 jobid = (jobid + 1) % PRINT_MAX_JOBID;
671                 if (jobid == 0) jobid = 1;
672         }
673         if (jobid == next_jobid || !print_job_store(jobid, &pjob)) {
674                 jobid = -1;
675                 goto fail;
676         }
677
678         tdb_store_int(tdb, "INFO/nextjob", jobid);
679
680         /* we have a job entry - now create the spool file 
681
682            we unlink first to cope with old spool files and also to beat
683            a symlink security hole - it allows us to use O_EXCL 
684         */
685         slprintf(pjob.filename, sizeof(pjob.filename), "%s/%s%d", 
686                  path, PRINT_SPOOL_PREFIX, jobid);
687         if (unlink(pjob.filename) == -1 && errno != ENOENT) {
688                 goto fail;
689         }
690         pjob.fd = sys_open(pjob.filename,O_WRONLY|O_CREAT|O_EXCL,0600);
691         if (pjob.fd == -1) goto fail;
692
693         print_job_store(jobid, &pjob);
694
695         /*
696          * If the printer is marked as postscript output a leading
697          * file identifier to ensure the file is treated as a raw
698          * postscript file.
699          * This has a similar effect as CtrlD=0 in WIN.INI file.
700          * tim@fsg.com 09/06/94
701          */
702         if (lp_postscript(snum)) {
703                 print_job_write(jobid, "%!\n",3);
704         }
705
706         tdb_writeunlock(tdb);
707         return jobid;
708
709  fail:
710         if (jobid != -1) {
711                 tdb_delete(tdb, print_key(jobid));
712         }
713
714         tdb_writeunlock(tdb);
715         return jobid;
716 }
717
718 /****************************************************************************
719 print a file - called on closing the file. This spools the job
720 ****************************************************************************/
721 BOOL print_job_end(int jobid)
722 {
723         struct printjob *pjob = print_job_find(jobid);
724         int snum;
725         SMB_STRUCT_STAT sbuf;
726         pstring current_directory;
727         pstring print_directory;
728         char *wd, *p;
729         pstring jobname;
730
731         if (!pjob) return False;
732
733         if (pjob->spooled || pjob->pid != local_pid) return False;
734
735         snum = print_job_snum(jobid);
736
737         if (sys_fstat(pjob->fd, &sbuf) == 0) pjob->size = sbuf.st_size;
738
739         close(pjob->fd);
740         pjob->fd = -1;
741
742         if (pjob->size == 0) {
743                 /* don't bother spooling empty files */
744                 unlink(pjob->filename);
745                 tdb_delete(tdb, print_key(jobid));
746                 return True;
747         }
748
749         /* we print from the directory path to give the best chance of
750            parsing the lpq output */
751         wd = sys_getwd(current_directory);
752         if (!wd) return False;          
753
754         pstrcpy(print_directory, pjob->filename);
755         p = strrchr(print_directory,'/');
756         if (!p) return False;
757         *p++ = 0;
758
759         if (chdir(print_directory) != 0) return False;
760
761         pstrcpy(jobname, pjob->jobname);
762         pstring_sub(jobname, "'", "_");
763
764         /* send it to the system spooler */
765         print_run_command(snum, 
766                           lp_printcommand(snum), NULL,
767                           "%s", p,
768                           "%J", jobname,
769                           "%f", p,
770                           NULL);
771
772         chdir(wd);
773
774         pjob->spooled = True;
775         print_job_store(jobid, pjob);
776
777         /* force update the database */
778         print_cache_flush(snum);
779         
780         return True;
781 }
782
783
784 /****************************************************************************
785 check if the print queue has been updated recently enough
786 ****************************************************************************/
787 static BOOL print_cache_expired(int snum)
788 {
789         fstring key;
790         time_t t2, t = time(NULL);
791         slprintf(key, sizeof(key), "CACHE/%s", lp_servicename(snum));
792         t2 = tdb_fetch_int(tdb, key);
793         if (t2 == ((time_t)-1) || (t - t2) >= lp_lpqcachetime()) {
794                 return True;
795         }
796         return False;
797 }
798
799 /* utility fn to enumerate the print queue */
800 static int traverse_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
801 {
802         struct traverse_struct *ts = (struct traverse_struct *)state;
803         struct printjob pjob;
804         int i, jobid;
805
806         if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
807         memcpy(&jobid, key.dptr, sizeof(jobid));
808         memcpy(&pjob,  data.dptr, sizeof(pjob));
809
810         /* maybe it isn't for this queue */
811         if (ts->snum != print_queue_snum(pjob.qname)) return 0;
812
813         ts->queue = Realloc(ts->queue,sizeof(print_queue_struct)*(ts->qcount+1));
814         if (!ts->queue) return -1;
815         i = ts->qcount;
816
817         ts->queue[i].job = jobid;
818         ts->queue[i].size = pjob.size;
819         ts->queue[i].status = pjob.status;
820         ts->queue[i].priority = 1;
821         ts->queue[i].time = pjob.starttime;
822         fstrcpy(ts->queue[i].user, pjob.user);
823         fstrcpy(ts->queue[i].file, pjob.jobname);
824
825         ts->qcount++;
826
827         return 0;
828 }
829
830 /****************************************************************************
831 get a printer queue listing
832 ****************************************************************************/
833 int print_queue_status(int snum, 
834                        print_queue_struct **queue,
835                        print_status_struct *status)
836 {
837         struct traverse_struct tstruct;
838         fstring keystr;
839         TDB_DATA data, key;
840
841         /* make sure the database is up to date */
842         if (print_cache_expired(snum)) print_queue_update(snum);
843         
844         /* fill in the queue */
845         tstruct.queue = NULL;
846         tstruct.qcount = 0;
847         tstruct.snum = snum;
848
849         tdb_traverse(tdb, traverse_fn_queue, (void *)&tstruct);
850
851         /* also fetch the queue status */
852         ZERO_STRUCTP(status);
853         slprintf(keystr, sizeof(keystr), "STATUS/%s", lp_servicename(snum));
854         key.dptr = keystr;
855         key.dsize = strlen(keystr);
856         data = tdb_fetch(tdb, key);
857         if (data.dptr) {
858                 if (data.dsize == sizeof(*status)) {
859                         memcpy(status, data.dptr, sizeof(*status));
860                 }
861                 free(data.dptr);
862         }
863
864         *queue = tstruct.queue;
865         return tstruct.qcount;
866 }
867
868
869 /****************************************************************************
870 turn a queue name into a snum
871 ****************************************************************************/
872 int print_queue_snum(char *qname)
873 {
874         int snum = lp_servicenumber(qname);
875         if (snum == -1 || !lp_print_ok(snum)) return -1;
876         return snum;
877 }
878
879
880 /****************************************************************************
881  pause a queue
882 ****************************************************************************/
883 BOOL print_queue_pause(struct current_user *user, int snum)
884 {
885         int ret;
886         
887         if (!user) return False;
888         
889         if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
890                 return False;
891         }
892
893         ret = print_run_command(snum, lp_queuepausecommand(snum), NULL, 
894                                 NULL);
895
896         /* force update the database */
897         print_cache_flush(snum);
898
899         return ret == 0;
900 }
901
902 /****************************************************************************
903  resume a queue
904 ****************************************************************************/
905 BOOL print_queue_resume(struct current_user *user, int snum)
906 {
907         int ret;
908
909         if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
910                 return False;
911         }
912
913         ret = print_run_command(snum, lp_queueresumecommand(snum), NULL, 
914                                 NULL);
915
916         /* force update the database */
917         print_cache_flush(snum);
918
919         return ret == 0;
920 }
921
922 /****************************************************************************
923  purge a queue - implemented by deleting all jobs that we can delete
924 ****************************************************************************/
925 BOOL print_queue_purge(struct current_user *user, int snum)
926 {
927         print_queue_struct *queue;
928         print_status_struct status;
929         int njobs, i;
930
931         if (!print_access_check(user, snum, PRINTER_ACE_MANAGE_DOCUMENTS)) {
932                 return False;
933         }
934
935         njobs = print_queue_status(snum, &queue, &status);
936         for (i=0;i<njobs;i++) {
937                 print_job_delete1(queue[i].job);
938         }
939
940         print_cache_flush(snum);
941
942         return True;
943 }