xref: /haiku/src/kits/print/Jobs.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
1 /*****************************************************************************/
2 // Jobs
3 //
4 // Author
5 //   Michael Pfeiffer
6 //
7 // This application and all source files used in its construction, except
8 // where noted, are licensed under the MIT License, and have been written
9 // and are:
10 //
11 // Copyright (c) 2002 OpenBeOS Project
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 /*****************************************************************************/
31 
32 
33 #include "pr_server.h"
34 #include "Jobs.h"
35 // #include "PrintServerApp.h"
36 
37 // posix
38 #include <stdlib.h>
39 #include <string.h>
40 
41 // BeOS
42 #include <kernel/fs_attr.h>
43 #include <Application.h>
44 #include <Node.h>
45 #include <NodeInfo.h>
46 #include <NodeMonitor.h>
47 
48 
49 // Implementation of Job
50 
51 Job::Job(const BEntry& job, Folder* folder)
52 	: fFolder(folder)
53 	, fTime(-1)
54 	, fStatus(kUnknown)
55 	, fValid(false)
56 	, fPrinter(NULL)
57 {
58 	// store light weight versions of BEntry and BNode
59 	job.GetRef(&fEntry);
60 	job.GetNodeRef(&fNode);
61 
62 	fValid = IsValidJobFile();
63 
64 	BNode node(&job);
65 	if (node.InitCheck() != B_OK) return;
66 
67 	BString status;
68 		// read status attribute
69 	if (node.ReadAttrString(PSRV_SPOOL_ATTR_STATUS, &status) != B_OK) {
70 		status = "";
71 	}
72     UpdateStatus(status.String());
73 
74     	// Now get file name and creation time from file name
75     fTime = 0;
76     BEntry entry(job);
77     char name[B_FILE_NAME_LENGTH];
78     if (entry.InitCheck() == B_OK && entry.GetName(name) == B_OK) {
79     	fName = name;
80     		// search for last '@' in file name
81 		char* p = NULL, *c = name;
82 		while ((c = strchr(c, '@')) != NULL) {
83 			p = c; c ++;
84 		}
85 			// and get time from file name
86 		if (p) fTime = atoi(p+1);
87     }
88 }
89 
90 // conversion from string representation of status to JobStatus constant
91 void Job::UpdateStatus(const char* status) {
92 	if (strcmp(status, PSRV_JOB_STATUS_WAITING) == 0) fStatus = kWaiting;
93 	else if (strcmp(status, PSRV_JOB_STATUS_PROCESSING) == 0) fStatus = kProcessing;
94 	else if (strcmp(status, PSRV_JOB_STATUS_FAILED) == 0) fStatus = kFailed;
95 	else if (strcmp(status, PSRV_JOB_STATUS_COMPLETED) == 0) fStatus = kCompleted;
96 	else fStatus = kUnknown;
97 }
98 
99 // Write to status attribute of node
100 void Job::UpdateStatusAttribute(const char* status) {
101 	BNode node(&fEntry);
102 	if (node.InitCheck() == B_OK) {
103 		node.WriteAttr(PSRV_SPOOL_ATTR_STATUS, B_STRING_TYPE, 0, status, strlen(status)+1);
104 	}
105 }
106 
107 
108 bool Job::HasAttribute(BNode* n, const char* name) {
109 	attr_info info;
110 	return n->GetAttrInfo(name, &info) == B_OK;
111 }
112 
113 
114 bool Job::IsValidJobFile() {
115 	BNode node(&fEntry);
116 	if (node.InitCheck() != B_OK) return false;
117 
118 	BNodeInfo info(&node);
119 	char mimeType[256];
120 
121 		// Is job a spool file?
122 	return (info.InitCheck() == B_OK &&
123 	    info.GetType(mimeType) == B_OK &&
124 	    strcmp(mimeType, PSRV_SPOOL_FILETYPE) == 0) &&
125 	    HasAttribute(&node, PSRV_SPOOL_ATTR_MIMETYPE) &&
126 	    HasAttribute(&node, PSRV_SPOOL_ATTR_PAGECOUNT) &&
127 	    HasAttribute(&node, PSRV_SPOOL_ATTR_DESCRIPTION) &&
128 	    HasAttribute(&node, PSRV_SPOOL_ATTR_PRINTER) &&
129 	    HasAttribute(&node, PSRV_SPOOL_ATTR_STATUS);
130 }
131 
132 
133 // Set status of object and optionally write to attribute of node
134 void Job::SetStatus(JobStatus s, bool writeToNode) {
135 	fStatus = s;
136 	if (!writeToNode) return;
137 	switch (s) {
138 		case kWaiting: UpdateStatusAttribute(PSRV_JOB_STATUS_WAITING); break;
139 		case kProcessing: UpdateStatusAttribute(PSRV_JOB_STATUS_PROCESSING); break;
140 		case kFailed: UpdateStatusAttribute(PSRV_JOB_STATUS_FAILED); break;
141 		case kCompleted: UpdateStatusAttribute(PSRV_JOB_STATUS_COMPLETED); break;
142 		default: break;
143 	}
144 }
145 
146 // Synchronize file attribute with member variable
147 void Job::UpdateAttribute() {
148 	fValid = fValid || IsValidJobFile();
149 	BNode node(&fEntry);
150 	BString status;
151 	if (node.InitCheck() == B_OK &&
152 		node.ReadAttrString(PSRV_SPOOL_ATTR_STATUS, &status) == B_OK) {
153 		UpdateStatus(status.String());
154 	}
155 }
156 
157 void Job::Remove() {
158 	BEntry entry(&fEntry);
159 	if (entry.InitCheck() == B_OK) entry.Remove();
160 }
161 
162 // Implementation of Folder
163 
164 // BObjectList CompareFunction
165 int Folder::AscendingByTime(const Job* a, const Job* b) {
166 	return a->Time() - b->Time();
167 }
168 
169 bool Folder::AddJob(BEntry& entry, bool notify) {
170 	Job* job = new Job(entry, this);
171 	if (job->InitCheck() == B_OK) {
172 		fJobs.AddItem(job);
173 		if (notify) Notify(job, kJobAdded);
174 		return true;
175 	} else {
176 		job->Release();
177 		return false;
178 	}
179 }
180 
181 // simplified assumption that ino_t identifies job file
182 // will probabely not work in all cases with link to a file on another volume???
183 Job* Folder::Find(node_ref* node) {
184 	for (int i = 0; i < fJobs.CountItems(); i ++) {
185 		Job* job = fJobs.ItemAt(i);
186 		if (job->NodeRef() == *node) return job;
187 	}
188 	return NULL;
189 }
190 
191 void Folder::EntryCreated(node_ref* node, entry_ref* entry) {
192 	BEntry job(entry);
193 	if (job.InitCheck() == B_OK && Lock()) {
194 		if (AddJob(job)) {
195 			fJobs.SortItems(AscendingByTime);
196 		}
197 		Unlock();
198 	}
199 }
200 
201 void Folder::EntryRemoved(node_ref* node) {
202 	Job* job = Find(node);
203 	if (job && Lock()) {
204 		fJobs.RemoveItem(job);
205 		Notify(job, kJobRemoved);
206 		job->Release();
207 		Unlock();
208 	}
209 }
210 
211 void Folder::AttributeChanged(node_ref* node) {
212 	Job* job = Find(node);
213 	if (job && Lock()) {
214 		job->UpdateAttribute();
215 		Notify(job, kJobAttrChanged);
216 		Unlock();
217 	}
218 }
219 
220 // initial setup of job list
221 void Folder::SetupJobList() {
222 	if (inherited::Folder()->InitCheck() == B_OK) {
223 		inherited::Folder()->Rewind();
224 
225 		BEntry entry;
226 		while (inherited::Folder()->GetNextEntry(&entry) == B_OK) {
227 			AddJob(entry, false);
228 		}
229 		fJobs.SortItems(AscendingByTime);
230 	}
231 }
232 
233 Folder::Folder(BLocker* locker, BLooper* looper, const BDirectory& spoolDir)
234 	: FolderWatcher(looper, spoolDir, true)
235 	, fLocker(locker)
236 	, fJobs()
237 {
238 	SetListener(this);
239 	if (Lock()) {
240 		SetupJobList();
241 		Unlock();
242 	}
243 }
244 
245 
246 Folder::~Folder() {
247 	if (!Lock()) return;
248 		// release jobs
249 	for (int i = 0; i < fJobs.CountItems(); i ++) {
250 		Job* job = fJobs.ItemAt(i);
251 		job->Release();
252 	}
253 	Unlock();
254 }
255 
256 Job* Folder::GetNextJob() {
257 	for (int i = 0; i < fJobs.CountItems(); i ++) {
258 		Job* job = fJobs.ItemAt(i);
259 		if (job->IsValid() && job->IsWaiting()) {
260 			job->Acquire(); return job;
261 		}
262 	}
263 	return NULL;
264 }
265 
266