#include "pr_server.h"
#include "Jobs.h"
#include <stdlib.h>
#include <string.h>
#include <kernel/fs_attr.h>
#include <Application.h>
#include <Node.h>
#include <NodeInfo.h>
#include <NodeMonitor.h>
Job::Job(const BEntry& job, Folder* folder)
: fFolder(folder)
, fTime(-1)
, fStatus(kUnknown)
, fValid(false)
, fPrinter(NULL)
{
job.GetRef(&fEntry);
job.GetNodeRef(&fNode);
fValid = IsValidJobFile();
BNode node(&job);
if (node.InitCheck() != B_OK) return;
BString status;
if (node.ReadAttrString(PSRV_SPOOL_ATTR_STATUS, &status) != B_OK) {
status = "";
}
UpdateStatus(status.String());
fTime = 0;
BEntry entry(job);
char name[B_FILE_NAME_LENGTH];
if (entry.InitCheck() == B_OK && entry.GetName(name) == B_OK) {
fName = name;
char* p = NULL, *c = name;
while ((c = strchr(c, '@')) != NULL) {
p = c; c ++;
}
if (p) fTime = atoi(p+1);
}
}
void Job::UpdateStatus(const char* status) {
if (strcmp(status, PSRV_JOB_STATUS_WAITING) == 0) fStatus = kWaiting;
else if (strcmp(status, PSRV_JOB_STATUS_PROCESSING) == 0) fStatus = kProcessing;
else if (strcmp(status, PSRV_JOB_STATUS_FAILED) == 0) fStatus = kFailed;
else if (strcmp(status, PSRV_JOB_STATUS_COMPLETED) == 0) fStatus = kCompleted;
else fStatus = kUnknown;
}
void Job::UpdateStatusAttribute(const char* status) {
BNode node(&fEntry);
if (node.InitCheck() == B_OK) {
node.WriteAttr(PSRV_SPOOL_ATTR_STATUS, B_STRING_TYPE, 0, status, strlen(status)+1);
}
}
bool Job::HasAttribute(BNode* n, const char* name) {
attr_info info;
return n->GetAttrInfo(name, &info) == B_OK;
}
bool Job::IsValidJobFile() {
BNode node(&fEntry);
if (node.InitCheck() != B_OK) return false;
BNodeInfo info(&node);
char mimeType[256];
return (info.InitCheck() == B_OK &&
info.GetType(mimeType) == B_OK &&
strcmp(mimeType, PSRV_SPOOL_FILETYPE) == 0) &&
HasAttribute(&node, PSRV_SPOOL_ATTR_MIMETYPE) &&
HasAttribute(&node, PSRV_SPOOL_ATTR_PAGECOUNT) &&
HasAttribute(&node, PSRV_SPOOL_ATTR_DESCRIPTION) &&
HasAttribute(&node, PSRV_SPOOL_ATTR_PRINTER) &&
HasAttribute(&node, PSRV_SPOOL_ATTR_STATUS);
}
void Job::SetStatus(JobStatus s, bool writeToNode) {
fStatus = s;
if (!writeToNode) return;
switch (s) {
case kWaiting: UpdateStatusAttribute(PSRV_JOB_STATUS_WAITING); break;
case kProcessing: UpdateStatusAttribute(PSRV_JOB_STATUS_PROCESSING); break;
case kFailed: UpdateStatusAttribute(PSRV_JOB_STATUS_FAILED); break;
case kCompleted: UpdateStatusAttribute(PSRV_JOB_STATUS_COMPLETED); break;
default: break;
}
}
void Job::UpdateAttribute() {
fValid = fValid || IsValidJobFile();
BNode node(&fEntry);
BString status;
if (node.InitCheck() == B_OK &&
node.ReadAttrString(PSRV_SPOOL_ATTR_STATUS, &status) == B_OK) {
UpdateStatus(status.String());
}
}
void Job::Remove() {
BEntry entry(&fEntry);
if (entry.InitCheck() == B_OK) entry.Remove();
}
int Folder::AscendingByTime(const Job* a, const Job* b) {
return a->Time() - b->Time();
}
bool Folder::AddJob(BEntry& entry, bool notify) {
Job* job = new Job(entry, this);
if (job->InitCheck() == B_OK) {
fJobs.AddItem(job);
if (notify) Notify(job, kJobAdded);
return true;
} else {
job->Release();
return false;
}
}
Job* Folder::Find(node_ref* node) {
for (int i = 0; i < fJobs.CountItems(); i ++) {
Job* job = fJobs.ItemAt(i);
if (job->NodeRef() == *node) return job;
}
return NULL;
}
void Folder::EntryCreated(node_ref* node, entry_ref* entry) {
BEntry job(entry);
if (job.InitCheck() == B_OK && Lock()) {
if (AddJob(job)) {
fJobs.SortItems(AscendingByTime);
}
Unlock();
}
}
void Folder::EntryRemoved(node_ref* node) {
Job* job = Find(node);
if (job && Lock()) {
fJobs.RemoveItem(job);
Notify(job, kJobRemoved);
job->Release();
Unlock();
}
}
void Folder::AttributeChanged(node_ref* node) {
Job* job = Find(node);
if (job && Lock()) {
job->UpdateAttribute();
Notify(job, kJobAttrChanged);
Unlock();
}
}
void Folder::SetupJobList() {
if (inherited::Folder()->InitCheck() == B_OK) {
inherited::Folder()->Rewind();
BEntry entry;
while (inherited::Folder()->GetNextEntry(&entry) == B_OK) {
AddJob(entry, false);
}
fJobs.SortItems(AscendingByTime);
}
}
Folder::Folder(BLocker* locker, BLooper* looper, const BDirectory& spoolDir)
: FolderWatcher(looper, spoolDir, true)
, fLocker(locker)
, fJobs()
{
SetListener(this);
if (Lock()) {
SetupJobList();
Unlock();
}
}
Folder::~Folder() {
if (!Lock()) return;
for (int i = 0; i < fJobs.CountItems(); i ++) {
Job* job = fJobs.ItemAt(i);
job->Release();
}
Unlock();
}
Job* Folder::GetNextJob() {
for (int i = 0; i < fJobs.CountItems(); i ++) {
Job* job = fJobs.ItemAt(i);
if (job->IsValid() && job->IsWaiting()) {
job->Acquire(); return job;
}
}
return NULL;
}