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 Haiku 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 51Job::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 91void 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 100void 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 108bool Job::HasAttribute(BNode* n, const char* name) { 109 attr_info info; 110 return n->GetAttrInfo(name, &info) == B_OK; 111} 112 113 114bool 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 134void 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 147void 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 157void Job::Remove() { 158 BEntry entry(&fEntry); 159 if (entry.InitCheck() == B_OK) entry.Remove(); 160} 161 162// Implementation of Folder 163 164// BObjectList CompareFunction 165int Folder::AscendingByTime(const Job* a, const Job* b) { 166 return a->Time() - b->Time(); 167} 168 169bool 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??? 183Job* 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 191void 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 201void 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 211void 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 221void 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 233Folder::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 246Folder::~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 256Job* 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