File moved to servers/print/shared

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2199 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Pfeiffer 2002-12-09 04:32:49 +00:00
parent 1c1ba0eb0e
commit 4dc43683c9

View File

@ -1,343 +0,0 @@
/*****************************************************************************/
// Jobs
//
// Author
// Michael Pfeiffer
//
// This application and all source files used in its construction, except
// where noted, are licensed under the MIT License, and have been written
// and are:
//
// Copyright (c) 2002 OpenBeOS Project
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
/*****************************************************************************/
#include "pr_server.h"
#include "Jobs.h"
#include "PrintServerApp.h"
// posix
#include <stdlib.h>
#include <string.h>
// BeOS
#include <kernel/fs_attr.h>
#include <Application.h>
#include <Autolock.h>
#include <Node.h>
#include <NodeInfo.h>
#include <NodeMonitor.h>
Job::Job(const BEntry& job, BHandler* handler)
: fHandler(handler)
, fTime(-1)
, fStatus(kUnknown)
, fValid(false)
, fPrinter(NULL)
{
// store light weight versions of BEntry and BNode
job.GetRef(&fEntry);
job.GetNodeRef(&fNode);
fValid = IsValidJobFile();
BNode node(&job);
if (node.InitCheck() != B_OK) return;
BString status;
// read status attribute
if (node.ReadAttrString(PSRV_SPOOL_ATTR_STATUS, &status) != B_OK) {
status = "";
}
UpdateStatus(status.String());
// Now get file name and creation time from file name
fTime = 0;
BEntry entry(job);
char name[B_FILE_NAME_LENGTH];
if (entry.InitCheck() == B_OK && entry.GetName(name) == B_OK) {
fName = name;
// search for last '@' in file name
char* p = NULL, *c = name;
while ((c = strchr(c, '@')) != NULL) {
p = c; c ++;
}
// and get time from file name
if (p) fTime = atoi(p+1);
}
// start watching the node
StartNodeWatching();
}
// conversion from string representation of status to JobStatus constant
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 fStatus = kUnknown;
}
// Write to status attribute of node
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];
// Is job a spool file?
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);
}
// Set status of object and optionally write to attribute of node
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;
default: break;
}
}
// Synchronize file attribute with member variable
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();
}
void Job::StartNodeWatching() {
watch_node(&fNode, B_WATCH_ATTR, fHandler, be_app);
}
void Job::StopNodeWatching() {
watch_node(&fNode, B_STOP_WATCHING, fHandler, be_app);
}
// Implementation of Folder
// BObjectList CompareFunction
int Folder::AscendingByTime(const Job* a, const Job* b) {
return a->Time() - b->Time();
}
bool Folder::AddJob(BEntry& entry) {
Job* job = new Job(entry, this);
if (job->InitCheck() == B_OK) {
fJobs.AddItem(job);
if (job->IsValid() && job->IsWaiting()) NotifyPrintServer();
return true;
} else {
job->Release();
return false;
}
}
// simplified assumption that ino_t identifies job file
// will probabely not work in all cases with link to a file on another volume???
Job* Folder::Find(ino_t node) {
for (int i = 0; i < fJobs.CountItems(); i ++) {
Job* job = fJobs.ItemAt(i);
if (job->NodeRef().node == node) return job;
}
return NULL;
}
void Folder::EntryCreated(BMessage* msg) {
BString name;
BEntry entry;
if (msg->FindString("name", &name) == B_OK &&
fSpoolDir.FindEntry(name.String(), &entry) == B_OK) {
BAutolock lock(gLock);
if (lock.IsLocked() && AddJob(entry)) {
fJobs.SortItems(AscendingByTime);
}
}
}
void Folder::EntryRemoved(BMessage* msg) {
ino_t node;
if (msg->FindInt64("node", &node) == B_OK) {
Job* job = Find(node);
if (job) {
fJobs.RemoveItem(job);
job->StopNodeWatching();
job->Release();
}
}
}
void Folder::AttributeChanged(BMessage* msg) {
ino_t node;
if (msg->FindInt64("node", &node) == B_OK) {
Job* job = Find(node);
if (job) {
job->UpdateAttribute();
if (job->IsValid() && job->IsWaiting()) NotifyPrintServer();
}
}
}
void Folder::HandleNodeMonitorMessage(BMessage* msg) {
ino_t node; node_ref ref;
BAutolock lock(gLock);
if (!lock.IsLocked()) return;
int32 opcode;
if (msg->FindInt32("opcode", &opcode) != B_OK) return;
switch (opcode) {
case B_ENTRY_MOVED:
fSpoolDir.GetNodeRef(&ref);
if (msg->FindInt64("to directory", &node) == B_OK &&
ref.node == node) {
EntryCreated(msg);
} else if (msg->FindInt64("from directory", &node) == B_OK &&
ref.node == node) {
EntryRemoved(msg);
}
break;
case B_ENTRY_CREATED: // add to fJobs
EntryCreated(msg);
break;
case B_ENTRY_REMOVED: // remove from fJobs
EntryRemoved(msg);
break;
case B_ATTR_CHANGED: // notify Printer if status has changed to Waiting
AttributeChanged(msg);
break;
default: // nothing to do
break;
}
}
// Notify print_server that there is a job file waiting for printing
void Folder::NotifyPrintServer() {
be_app_messenger.SendMessage(PSRV_PRINT_SPOOLED_JOB);
}
// initial setup of job list
void Folder::SetupJobList() {
if (fSpoolDir.InitCheck() == B_OK) {
fSpoolDir.Rewind();
BEntry entry;
while (fSpoolDir.GetNextEntry(&entry) == B_OK) {
AddJob(entry);
}
fJobs.SortItems(AscendingByTime);
}
}
Folder::Folder(const BDirectory& spoolDir)
: fSpoolDir(spoolDir)
, fJobs()
{
BAutolock lock(gLock);
if (!lock.IsLocked()) return;
// add this handler to the application for node monitoring
be_app->AddHandler(this);
SetupJobList();
// start watching the spooler directory
node_ref ref;
spoolDir.GetNodeRef(&ref);
watch_node(&ref, B_WATCH_DIRECTORY, this, be_app);
}
Folder::~Folder() {
if (!gLock->Lock()) return;
// stop node watching for jobs
for (int i = 0; i < fJobs.CountItems(); i ++) {
Job* job = fJobs.ItemAt(i);
job->StopNodeWatching();
job->Release();
}
// stop node watching for spooler directory
node_ref ref;
fSpoolDir.GetNodeRef(&ref);
watch_node(&ref, B_STOP_WATCHING, this, be_app);
// stop sending notifications to this handler
stop_watching(this, be_app);
gLock->Unlock();
if (be_app->Lock()) {
// and remove it from application
be_app->RemoveHandler(this);
be_app->Unlock();
}
}
void Folder::MessageReceived(BMessage* msg) {
if (msg->what == B_NODE_MONITOR) {
HandleNodeMonitorMessage(msg);
} else {
inherited::MessageReceived(msg);
}
}
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;
}