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