When creating a print job entry for the printing backend, use the Windows
[samba.git] / source / 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 current user owns the print job
483 ****************************************************************************/
484 static BOOL is_owner(struct current_user *user, int jobid)
485 {
486         struct printjob *pjob = print_job_find(jobid);
487         user_struct *vuser;
488
489         if (!pjob || !user) return False;
490
491         if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
492                 return strequal(pjob->user, vuser->user.smb_name);
493         } else {
494                 return strequal(pjob->user, uidtoname(user->uid));
495         }
496 }
497
498 /****************************************************************************
499 delete a print job
500 ****************************************************************************/
501 BOOL print_job_delete(struct current_user *user, int jobid)
502 {
503         int snum = print_job_snum(jobid);
504         BOOL owner;
505         
506         if (!user) return False;
507
508         owner = is_owner(user, jobid);
509         
510         /* Check access against security descriptor or whether the user
511            owns their job. */
512
513         if (!owner && 
514             !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
515                 DEBUG(3, ("delete denied by security descriptor\n"));
516                 return False;
517         }
518
519         if (!print_job_delete1(jobid)) return False;
520
521         /* force update the database and say the delete failed if the
522            job still exists */
523
524         print_queue_update(snum);
525
526         return !print_job_exists(jobid);
527 }
528
529
530 /****************************************************************************
531 pause a job
532 ****************************************************************************/
533 BOOL print_job_pause(struct current_user *user, int jobid)
534 {
535         struct printjob *pjob = print_job_find(jobid);
536         int snum, ret = -1;
537         fstring jobstr;
538         BOOL owner;
539         
540
541         if (!pjob || !user) return False;
542
543         if (!pjob->spooled || pjob->sysjob == -1) return False;
544
545         snum = print_job_snum(jobid);
546         owner = is_owner(user, jobid);
547
548         if (!owner &&
549             !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
550                 DEBUG(3, ("pause denied by security descriptor\n"));
551                 return False;
552         }
553
554         /* need to pause the spooled entry */
555         slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob);
556         ret = print_run_command(snum, 
557                                 lp_lppausecommand(snum), NULL,
558                                 "%j", jobstr,
559                                 NULL);
560
561         /* force update the database */
562         print_cache_flush(snum);
563
564         /* how do we tell if this succeeded? */
565         return ret == 0;
566 }
567
568 /****************************************************************************
569 resume a job
570 ****************************************************************************/
571 BOOL print_job_resume(struct current_user *user, int jobid)
572 {
573         struct printjob *pjob = print_job_find(jobid);
574         int snum, ret;
575         fstring jobstr;
576         BOOL owner;
577         
578         if (!pjob || !user) return False;
579
580         if (!pjob->spooled || pjob->sysjob == -1) return False;
581
582         snum = print_job_snum(jobid);
583         owner = is_owner(user, jobid);
584
585         if (!is_owner(user, jobid) &&
586             !print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
587                 DEBUG(3, ("resume denied by security descriptor\n"));
588                 return False;
589         }
590
591         slprintf(jobstr, sizeof(jobstr), "%d", pjob->sysjob);
592         ret = print_run_command(snum, 
593                                 lp_lpresumecommand(snum), NULL,
594                                 "%j", jobstr,
595                                 NULL);
596
597         /* force update the database */
598         print_cache_flush(snum);
599
600         /* how do we tell if this succeeded? */
601         return ret == 0;
602 }
603
604 /****************************************************************************
605 write to a print file
606 ****************************************************************************/
607 int print_job_write(int jobid, const char *buf, int size)
608 {
609         int fd;
610
611         fd = print_job_fd(jobid);
612         if (fd == -1) return -1;
613
614         return write(fd, buf, size);
615 }
616
617
618 /***************************************************************************
619 start spooling a job - return the jobid
620 ***************************************************************************/
621 int print_job_start(struct current_user *user, int snum, char *jobname)
622 {
623         int jobid;
624         char *path;
625         struct printjob pjob;
626         int next_jobid;
627         user_struct *vuser;
628
629         errno = 0;
630
631         if (!print_access_check(user, snum, PRINTER_ACCESS_USE)) {
632                 DEBUG(3, ("print_job_start: job start denied by security descriptor\n"));
633                 return -1;
634         }
635
636         if (!print_time_access_check(snum)) {
637                 DEBUG(3, ("print_job_start: job start denied by time check\n"));
638                 return -1;
639         }
640
641         path = lp_pathname(snum);
642
643         /* see if we have sufficient disk space */
644         if (lp_minprintspace(snum)) {
645                 SMB_BIG_UINT dspace, dsize;
646                 if (sys_fsusage(path, &dspace, &dsize) == 0 &&
647                     dspace < 2*(SMB_BIG_UINT)lp_minprintspace(snum)) {
648                         errno = ENOSPC;
649                         return -1;
650                 }
651         }
652
653         /* for autoloaded printers, check that the printcap entry still exists */
654         if (lp_autoloaded(snum) && !pcap_printername_ok(lp_servicename(snum), NULL)) {
655                 errno = ENOENT;
656                 return -1;
657         }
658
659         /* create the database entry */
660         ZERO_STRUCT(pjob);
661         pjob.pid = local_pid;
662         pjob.sysjob = -1;
663         pjob.fd = -1;
664         pjob.starttime = time(NULL);
665         pjob.status = LPQ_QUEUED;
666         pjob.size = 0;
667         pjob.spooled = False;
668         pjob.smbjob = True;
669
670         fstrcpy(pjob.jobname, jobname);
671
672         if ((vuser = get_valid_user_struct(user->vuid)) != NULL) {
673                 fstrcpy(pjob.user, vuser->user.smb_name);
674         } else {
675                 fstrcpy(pjob.user, uidtoname(user->uid));
676         }
677
678         fstrcpy(pjob.qname, lp_servicename(snum));
679
680         /* lock the database */
681         tdb_writelock(tdb);
682
683  next_jobnum:
684         next_jobid = tdb_fetch_int(tdb, "INFO/nextjob");
685         if (next_jobid == -1) next_jobid = 1;
686
687         for (jobid = next_jobid+1; jobid != next_jobid; ) {
688                 if (!print_job_exists(jobid)) break;
689                 jobid = (jobid + 1) % PRINT_MAX_JOBID;
690                 if (jobid == 0) jobid = 1;
691         }
692         if (jobid == next_jobid || !print_job_store(jobid, &pjob)) {
693                 jobid = -1;
694                 goto fail;
695         }
696
697         tdb_store_int(tdb, "INFO/nextjob", jobid);
698
699         /* we have a job entry - now create the spool file 
700
701            we unlink first to cope with old spool files and also to beat
702            a symlink security hole - it allows us to use O_EXCL 
703            There may be old spool files owned by other users lying around.
704         */
705         slprintf(pjob.filename, sizeof(pjob.filename), "%s/%s%d", 
706                  path, PRINT_SPOOL_PREFIX, jobid);
707         if (unlink(pjob.filename) == -1 && errno != ENOENT) {
708                 goto next_jobnum;
709         }
710         pjob.fd = sys_open(pjob.filename,O_WRONLY|O_CREAT|O_EXCL,0600);
711         if (pjob.fd == -1) goto fail;
712
713         print_job_store(jobid, &pjob);
714
715         tdb_writeunlock(tdb);
716
717         /*
718          * If the printer is marked as postscript output a leading
719          * file identifier to ensure the file is treated as a raw
720          * postscript file.
721          * This has a similar effect as CtrlD=0 in WIN.INI file.
722          * tim@fsg.com 09/06/94
723          */
724         if (lp_postscript(snum)) {
725                 print_job_write(jobid, "%!\n",3);
726         }
727
728         return jobid;
729
730  fail:
731         if (jobid != -1) {
732                 tdb_delete(tdb, print_key(jobid));
733         }
734
735         tdb_writeunlock(tdb);
736         return -1;
737 }
738
739 /****************************************************************************
740  Print a file - called on closing the file. This spools the job.
741 ****************************************************************************/
742
743 BOOL print_job_end(int jobid)
744 {
745         struct printjob *pjob = print_job_find(jobid);
746         int snum;
747         SMB_STRUCT_STAT sbuf;
748         pstring current_directory;
749         pstring print_directory;
750         char *wd, *p;
751         pstring jobname;
752
753         if (!pjob)
754                 return False;
755
756         if (pjob->spooled || pjob->pid != local_pid)
757                 return False;
758
759         snum = print_job_snum(jobid);
760
761         if (sys_fstat(pjob->fd, &sbuf) == 0)
762                 pjob->size = sbuf.st_size;
763
764         close(pjob->fd);
765         pjob->fd = -1;
766
767         if (pjob->size == 0) {
768                 /* don't bother spooling empty files */
769                 unlink(pjob->filename);
770                 tdb_delete(tdb, print_key(jobid));
771                 return True;
772         }
773
774         /* we print from the directory path to give the best chance of
775            parsing the lpq output */
776         wd = sys_getwd(current_directory);
777         if (!wd)
778                 return False;           
779
780         pstrcpy(print_directory, pjob->filename);
781         p = strrchr(print_directory,'/');
782         if (!p)
783                 return False;
784         *p++ = 0;
785
786         if (chdir(print_directory) != 0)
787                 return False;
788
789         pstrcpy(jobname, pjob->jobname);
790         pstring_sub(jobname, "'", "_");
791
792         /* send it to the system spooler */
793         print_run_command(snum, 
794                           lp_printcommand(snum), NULL,
795                           "%s", p,
796                           "%J", jobname,
797                           "%f", p,
798                           NULL);
799
800         chdir(wd);
801
802         pjob->spooled = True;
803         print_job_store(jobid, pjob);
804
805         /* force update the database */
806         print_cache_flush(snum);
807         
808         return True;
809 }
810
811 /****************************************************************************
812  Check if the print queue has been updated recently enough.
813 ****************************************************************************/
814
815 static BOOL print_cache_expired(int snum)
816 {
817         fstring key;
818         time_t t2, t = time(NULL);
819         slprintf(key, sizeof(key), "CACHE/%s", lp_servicename(snum));
820         t2 = tdb_fetch_int(tdb, key);
821         if (t2 == ((time_t)-1) || (t - t2) >= lp_lpqcachetime()) {
822                 return True;
823         }
824         return False;
825 }
826
827 /* utility fn to enumerate the print queue */
828 static int traverse_fn_queue(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
829 {
830         struct traverse_struct *ts = (struct traverse_struct *)state;
831         struct printjob pjob;
832         int i, jobid;
833
834         if (data.dsize != sizeof(pjob) || key.dsize != sizeof(int)) return 0;
835         memcpy(&jobid, key.dptr, sizeof(jobid));
836         memcpy(&pjob,  data.dptr, sizeof(pjob));
837
838         /* maybe it isn't for this queue */
839         if (ts->snum != print_queue_snum(pjob.qname)) return 0;
840
841         ts->queue = Realloc(ts->queue,sizeof(print_queue_struct)*(ts->qcount+1));
842         if (!ts->queue) return -1;
843         i = ts->qcount;
844
845         ts->queue[i].job = jobid;
846         ts->queue[i].size = pjob.size;
847         ts->queue[i].status = pjob.status;
848         ts->queue[i].priority = 1;
849         ts->queue[i].time = pjob.starttime;
850         fstrcpy(ts->queue[i].user, pjob.user);
851         fstrcpy(ts->queue[i].file, pjob.jobname);
852
853         ts->qcount++;
854
855         return 0;
856 }
857
858 /****************************************************************************
859 get a printer queue listing
860 ****************************************************************************/
861 int print_queue_status(int snum, 
862                        print_queue_struct **queue,
863                        print_status_struct *status)
864 {
865         struct traverse_struct tstruct;
866         fstring keystr;
867         TDB_DATA data, key;
868
869         /* make sure the database is up to date */
870         if (print_cache_expired(snum)) print_queue_update(snum);
871         
872         /* fill in the queue */
873         tstruct.queue = NULL;
874         tstruct.qcount = 0;
875         tstruct.snum = snum;
876
877         tdb_traverse(tdb, traverse_fn_queue, (void *)&tstruct);
878
879         /* also fetch the queue status */
880         ZERO_STRUCTP(status);
881         slprintf(keystr, sizeof(keystr), "STATUS/%s", lp_servicename(snum));
882         key.dptr = keystr;
883         key.dsize = strlen(keystr);
884         data = tdb_fetch(tdb, key);
885         if (data.dptr) {
886                 if (data.dsize == sizeof(*status)) {
887                         memcpy(status, data.dptr, sizeof(*status));
888                 }
889                 free(data.dptr);
890         }
891
892         *queue = tstruct.queue;
893         return tstruct.qcount;
894 }
895
896
897 /****************************************************************************
898 turn a queue name into a snum
899 ****************************************************************************/
900 int print_queue_snum(char *qname)
901 {
902         int snum = lp_servicenumber(qname);
903         if (snum == -1 || !lp_print_ok(snum)) return -1;
904         return snum;
905 }
906
907
908 /****************************************************************************
909  pause a queue
910 ****************************************************************************/
911 BOOL print_queue_pause(struct current_user *user, int snum, int *errcode)
912 {
913         int ret;
914         
915         if (!user) return False;
916         
917         if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
918                 *errcode = ERROR_ACCESS_DENIED;
919                 return False;
920         }
921
922         ret = print_run_command(snum, lp_queuepausecommand(snum), NULL, 
923                                 NULL);
924
925         /* force update the database */
926         print_cache_flush(snum);
927
928         return ret == 0;
929 }
930
931 /****************************************************************************
932  resume a queue
933 ****************************************************************************/
934 BOOL print_queue_resume(struct current_user *user, int snum, int *errcode)
935 {
936         int ret;
937
938         if (!print_access_check(user, snum, PRINTER_ACCESS_ADMINISTER)) {
939                 *errcode = ERROR_ACCESS_DENIED;
940                 return False;
941         }
942
943         ret = print_run_command(snum, lp_queueresumecommand(snum), NULL, 
944                                 NULL);
945
946         /* force update the database */
947         print_cache_flush(snum);
948
949         return ret == 0;
950 }
951
952 /****************************************************************************
953  purge a queue - implemented by deleting all jobs that we can delete
954 ****************************************************************************/
955 BOOL print_queue_purge(struct current_user *user, int snum, int *errcode)
956 {
957         print_queue_struct *queue;
958         print_status_struct status;
959         int njobs, i;
960
961         njobs = print_queue_status(snum, &queue, &status);
962         for (i=0;i<njobs;i++) {
963                 if (print_access_check(user, snum, JOB_ACCESS_ADMINISTER)) {
964                         print_job_delete1(queue[i].job);
965                 }
966         }
967
968         print_cache_flush(snum);
969
970         return True;
971 }
972 #undef OLD_NTDOMAIN