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