For Michael Pfeiffer, ready for beta...

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1108 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Phipps 2002-09-21 18:57:19 +00:00
parent dd6a407346
commit 8f13f87bf7
15 changed files with 1037 additions and 156 deletions

View File

@ -7,6 +7,8 @@
// very specific functions, but generally useful (could be here because of a
// lack in the APIs, or just sheer lazyness :))
//
// Author
// Ithamar R. Adema
//
// This application and all source files used in its construction, except
// where noted, are licensed under the MIT License, and have been written

View File

@ -1,10 +1,76 @@
/*****************************************************************************/
// BeUtils.cpp
//
// Version: 1.0.0d1
//
// Several utilities for writing applications for the BeOS. It are small
// very specific functions, but generally useful (could be here because of a
// lack in the APIs, or just sheer lazyness :))
//
// Authors
// Ithamar R. Adema
// 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) 2001 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.
/*****************************************************************************/
#ifndef BEUTILS_H
#define BEUTILS_H
#include <FindDirectory.h>
#include <Path.h>
#include <SupportDefs.h>
status_t TestForAddonExistence(const char* name, directory_which which,
const char* section, BPath& outPath);
// Reference counted object
class Object {
private:
volatile int32 fRefCount;
public:
// After construction reference count is 1
Object() : fRefCount(1) { }
// dtor should be private, but ie. ObjectList requires a public dtor!
virtual ~Object() { };
// thread-safe as long as thread that calls acquire has already
// a reference to the object
void Acquire() {
atomic_add(&fRefCount, 1);
}
bool Release() {
atomic_add(&fRefCount, -1);
if (fRefCount == 0) {
delete this; return true;
} else {
return false;
}
}
};
#endif

View File

@ -17,6 +17,8 @@ Server
PrintServerApp.Scripting.cpp
Printer.Scripting.cpp
Printer.cpp
ResourceManager.cpp
Jobs.cpp
BeUtils.cpp
;

307
src/servers/print/Jobs.cpp Normal file
View File

@ -0,0 +1,307 @@
/*****************************************************************************/
// 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 <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)
, fPrinter(NULL)
{
// store light weight versions of BEntry and BNode
job.GetRef(&fEntry);
job.GetNodeRef(&fNode);
BNode node(&job);
if (node.InitCheck() != B_OK) return;
BNodeInfo info(&node);
char mimeType[256];
BString status;
// Is job a spool file?
if (info.InitCheck() == B_OK /*&&
info.GetType(mimeType) == B_OK &&
strcmp(mimeType, PSRV_SPOOL_FILETYPE) == 0 &&
node.ReadAttr(PSRV_SPOOL_ATTR_STATUS, B_STRING_TYPE, 0, status, sizeof(status))*/) {
if (node.ReadAttrString(PSRV_SPOOL_ATTR_STATUS, &status) != B_OK) {
status = "";
}
// read status attribute
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
fTime = atoi(p+1);
}
// start watching if everything is ok
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);
}
}
// 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() {
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->IsWaiting()) NotifyPrinter();
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->IsWaiting()) NotifyPrinter();
}
}
}
void Folder::HandleNodeMonitorMessage(BMessage* msg) {
BAutolock lock(gLock);
if (!lock.IsLocked()) return;
int32 opcode;
if (msg->FindInt32("opcode", &opcode) != B_OK) return;
switch (opcode) {
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;
}
}
void Folder::NotifyPrinter() {
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->IsWaiting()) {
job->Acquire(); return job;
}
}
return NULL;
}

122
src/servers/print/Jobs.h Normal file
View File

@ -0,0 +1,122 @@
/*****************************************************************************/
// 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.
/*****************************************************************************/
#ifndef _JOBS_H
#define _JOBS_H
#include "BeUtils.h"
#include "ObjectList.h"
#include <Directory.h>
#include <Entry.h>
#include <Handler.h>
#include <String.h>
#include <StorageDefs.h>
enum JobStatus {
kWaiting,
kProcessing,
kFailed,
kUnknown,
};
class Printer;
class Job : public Object {
private:
BHandler* fHandler;
BString fName;
node_ref fNode;
entry_ref fEntry;
JobStatus fStatus;
long fTime;
Printer* fPrinter;
void UpdateStatus(const char* status);
void UpdateStatusAttribute(const char* status);
public:
Job(const BEntry& entry, BHandler* handler);
status_t InitCheck() const { return fTime >= 0 ? B_OK : B_ERROR; }
// accessors
const BString& Name() const { return fName; }
JobStatus Status() const { return fStatus; }
long Time() const { return fTime; }
const node_ref& NodeRef() const { return fNode; }
const entry_ref& EntryRef() const { return fEntry; }
bool IsWaiting() const { return fStatus == kWaiting; }
Printer* GetPrinter() const { return fPrinter; }
// modification
void SetPrinter(Printer* p) { fPrinter = p; }
void SetStatus(JobStatus s, bool writeToNode = true);
void UpdateAttribute();
void Remove();
void StartNodeWatching();
void StopNodeWatching();
};
class Folder : public BHandler {
typedef BHandler inherited;
private:
BDirectory fSpoolDir;
BObjectList<Job> fJobs;
static int AscendingByTime(const Job* a, const Job* b);
bool AddJob(BEntry& entry);
Job* Find(ino_t node);
// node monitor handling
void EntryCreated(BMessage* msg);
void EntryRemoved(BMessage* msg);
void AttributeChanged(BMessage* msg);
void HandleNodeMonitorMessage(BMessage* msg);
void NotifyPrinter();
void SetupJobList();
public:
Folder(const BDirectory& spoolDir);
~Folder();
void MessageReceived(BMessage* msg);
// Caller is responsible to set the status of the job appropriately
// and to release the object when done
Job* GetNextJob();
};
#endif

View File

@ -6,12 +6,9 @@
// The print_server manages the communication between applications and the
// printer and transport drivers.
//
//
//
// TODO:
// Handle spooled jobs at startup
// Handle printer status (asked to print a spooled job but printer busy)
//
// Authors
// Ithamar R. Adema
// 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
@ -53,12 +50,16 @@
struct AsyncThreadParams {
Printer* printer;
BMessage message;
BMessage* message;
AsyncThreadParams(Printer* p, BMessage* m)
: printer(p)
, message(*m)
, message(m)
{ }
~AsyncThreadParams() {
delete message;
}
};
status_t PrintServerApp::async_thread(void* data)
@ -66,7 +67,7 @@ status_t PrintServerApp::async_thread(void* data)
AsyncThreadParams* p = (AsyncThreadParams*)data;
Printer* printer = p->printer;
BMessage* msg = &p->message;
BMessage* msg = p->message;
switch (msg->what) {
// Handle showing the page config dialog
@ -131,10 +132,6 @@ void PrintServerApp::AsyncHandleMessage(BMessage* msg)
void PrintServerApp::Handle_BeOSR5_Message(BMessage* msg)
{
printf("PrintServerApp::Handle_BeOSR5_Message\n");
msg->PrintToStream();
fflush(stdout);
switch(msg->what) {
// Get currently selected printer
case PSRV_GET_ACTIVE_PRINTER: {
@ -186,18 +183,12 @@ void PrintServerApp::Handle_BeOSR5_Message(BMessage* msg)
case PSRV_SHOW_PAGE_SETUP:
case PSRV_SHOW_PRINT_SETUP:
AsyncHandleMessage(msg);
AsyncHandleMessage(DetachCurrentMessage());
break;
// Tell printer addon to print a spooled job
case PSRV_PRINT_SPOOLED_JOB: {
BString name, jobpath;
if (msg->FindString("Spool File",&jobpath) == B_OK &&
msg->FindString("JobName", &name) == B_OK) {
// Handle the spooled job
HandleSpooledJob(name.String(), jobpath.String());
}
}
case PSRV_PRINT_SPOOLED_JOB:
HandleSpooledJobs();
break;
}
}

View File

@ -6,6 +6,8 @@
// The print_server manages the communication between applications and the
// printer and transport drivers.
//
// Author
// Ithamar R. Adema
//
// This application and all source files used in its construction, except
// where noted, are licensed under the MIT License, and have been written
@ -105,7 +107,7 @@ PrintServerApp::HandleScriptingCommand(BMessage* msg)
case B_DELETE_PROPERTY: {
Printer* printer = GetPrinterFromSpecifier(&spec);
status_t rc = B_BAD_VALUE;
if (printer != NULL && (rc=printer->Remove()) == B_OK) {
printer->Release();
}

View File

@ -6,12 +6,9 @@
// The print_server manages the communication between applications and the
// printer and transport drivers.
//
//
//
// TODO:
// Handle spooled jobs at startup
// Handle printer status (asked to print a spooled job but printer busy)
//
// Authors
// Ithamar R. Adema
// 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
@ -45,23 +42,26 @@
#include "pr_server.h"
// BeOS API
#include <FindDirectory.h>
#include <NodeMonitor.h>
#include <Directory.h>
#include <PrintJob.h>
#include <NodeInfo.h>
#include <String.h>
#include <Roster.h>
#include <image.h>
#include <Alert.h>
#include <Path.h>
#include <Autolock.h>
#include <Directory.h>
#include <File.h>
#include <image.h>
#include <FindDirectory.h>
#include <Mime.h>
#include <NodeInfo.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <Roster.h>
#include <PrintJob.h>
#include <String.h>
// ANSI C
#include <stdio.h> //for printf
#include <unistd.h> //for unlink
BLocker *gLock = NULL;
// ---------------------------------------------------------------
typedef struct _printer_data {
char defaultPrinterName[256];
@ -83,16 +83,17 @@ typedef char* (*add_printer_func_t)(const char* printer_name);
int
main()
{
gLock = new BLocker();
// Create our application object
status_t rc = B_OK;
new PrintServerApp(&rc);
PrintServerApp print_server(&rc);
// If all went fine, let's start it
if (rc == B_OK) {
be_app->Run();
print_server.Run();
}
delete be_app;
delete gLock;
return rc;
}
@ -111,10 +112,14 @@ main()
PrintServerApp::PrintServerApp(status_t* err)
: Inherited(PSRV_SIGNATURE_TYPE, err),
fSelectedIconMini(BRect(0,0,B_MINI_ICON-1,B_MINI_ICON-1), B_CMAP8),
fSelectedIconLarge(BRect(0,0,B_LARGE_ICON-1,B_LARGE_ICON-1), B_CMAP8)
fSelectedIconLarge(BRect(0,0,B_LARGE_ICON-1,B_LARGE_ICON-1), B_CMAP8),
fNumberOfPrinters(0),
fNoPrinterAvailable(0)
{
// If our superclass initialized ok
if (*err == B_OK) {
fNoPrinterAvailable = create_sem(1, "");
// let us try as well
SetupPrinterList();
RetrieveDefaultPrinter();
@ -123,6 +128,9 @@ PrintServerApp::PrintServerApp(status_t* err)
BMimeType type(PRNT_SIGNATURE_TYPE);
type.GetIcon(&fSelectedIconMini, B_MINI_ICON);
type.GetIcon(&fSelectedIconLarge, B_LARGE_ICON);
// Start handling of spooled files
PostMessage(PSRV_PRINT_SPOOLED_JOB);
}
}
@ -141,11 +149,69 @@ bool PrintServerApp::QuitRequested()
::watch_node(&nref, B_STOP_WATCHING, be_app_messenger);
}
}
// Release all printers
Printer* printer;
while ((printer = Printer::At(0)) != NULL) {
Printer::Remove(printer);
printer->AbortPrintThread();
printer->Release();
}
// Wait for printers
if (fNoPrinterAvailable > 0) {
acquire_sem(fNoPrinterAvailable);
delete_sem(fNoPrinterAvailable);
fNoPrinterAvailable = 0;
}
}
return rc;
}
void PrintServerApp::RegisterPrinter(BDirectory* printer) {
BString transport, address, connection;
printer->ReadAttrString(PSRV_PRINTER_ATTR_TRANSPORT, &transport);
printer->ReadAttrString(PSRV_PRINTER_ATTR_TRANSPORT_ADDR, &address);
printer->ReadAttrString(PSRV_PRINTER_ATTR_CNX, &connection);
BAutolock lock(gLock);
if (lock.IsLocked()) {
Resource* r = fResourceManager.Allocate(transport.String(), address.String(), connection.String());
new Printer(printer, r);
if (fNumberOfPrinters == 0) acquire_sem(fNoPrinterAvailable);
fNumberOfPrinters ++;
}
}
void PrintServerApp::NotifyPrinterDeletion(Resource* res) {
BAutolock lock(gLock);
if (lock.IsLocked()) {
fNumberOfPrinters --;
fResourceManager.Free(res);
if (fNumberOfPrinters == 0) release_sem(fNoPrinterAvailable);
}
}
void PrintServerApp::HandleRemovedPrinter(BMessage* msg) {
int32 opcode;
dev_t device;
ino_t node;
Printer* printer;
if (msg->FindInt32("opcode", &opcode) == B_OK && opcode == B_ENTRY_REMOVED &&
msg->FindInt32("device", &device) == B_OK &&
msg->FindInt64("node", &node) == B_OK &&
(printer = Printer::Find(device, node)) != NULL) {
if (printer == fDefaultPrinter) fDefaultPrinter = NULL;
Printer::Remove(printer);
printer->Release();
}
}
// ---------------------------------------------------------------
// SetupPrinterList
//
@ -176,14 +242,14 @@ status_t PrintServerApp::SetupPrinterList()
// If the entry is a directory
if (entry.IsDirectory()) {
// Check it's Mime type for a spool director
BNode node(&entry);
BDirectory node(&entry);
BNodeInfo info(&node);
char buffer[256];
if (info.GetType(buffer) == B_OK &&
strcmp(buffer, PSRV_PRINTER_FILETYPE) == 0) {
// Yes, it is a printer definition node
new Printer(&node);
RegisterPrinter(&node);
}
}
}
@ -234,10 +300,12 @@ PrintServerApp::MessageReceived(BMessage* msg)
case B_EXECUTE_PROPERTY:
HandleScriptingCommand(msg);
break;
case B_NODE_MONITOR:
HandleRemovedPrinter(msg);
break;
default:
printf("PrintServerApp::MessageReceived(): ");
msg->PrintToStream();
Inherited::MessageReceived(msg);
}
}
@ -298,10 +366,12 @@ PrintServerApp::CreatePrinter(const char* printerName, const char* driverName,
// call the function and check its result
if ((*func)(printerName) == NULL) {
BEntry entry;
if (printer.GetEntry(&entry) == B_OK && entry.GetPath(&path) == B_OK) {
if (printer.GetEntry(&entry) == B_OK) {
// Delete the printer if function failed
::rmdir(path.Path());
entry.Remove();
}
} else {
RegisterPrinter(&printer);
}
}
@ -360,55 +430,19 @@ PrintServerApp::SelectPrinter(const char* printerName)
}
// ---------------------------------------------------------------
// HandleSpooledJob(const char* jobname, const char* filepath)
// HandleSpooledJobs()
//
// Handles calling the printer driver for printing a spooled job.
// Handles calling the printer drivers for printing a spooled job.
//
// Parameters:
// msg - A copy of the message received, will be accessible
// to the printer driver for reading job config
// details.
// Returns:
// BMessage containing new job data, or NULL pointer if not
// successfull.
// ---------------------------------------------------------------
status_t
PrintServerApp::HandleSpooledJob(const char* jobname, const char* filepath)
void
PrintServerApp::HandleSpooledJobs()
{
BFile spoolFile(filepath, B_READ_ONLY);
print_file_header header;
BString driverName;
BMessage settings;
Printer* printer;
status_t rc;
BPath path;
// Open the spool file
if ((rc=spoolFile.InitCheck()) == B_OK) {
// Read header from filestream
spoolFile.Seek(0, SEEK_SET);
spoolFile.Read(&header, sizeof(header));
// Get the printer settings
settings.Unflatten(&spoolFile);
// Get name of printer from settings
const char* printerName;
if ((rc=settings.FindString("current_printer", &printerName)) == B_OK) {
// Find printer definition for this printer
if ((printer=Printer::Find(printerName)) != NULL) {
// and tell the printer to print the spooled job
printer->PrintSpooledJob(&spoolFile, settings);
}
}
// Remove spool file if printing was successfull.
if (rc == B_OK) {
::unlink(filepath);
}
const int n = Printer::CountPrinters();
for (int i = 0; i < n; i ++) {
Printer* printer = Printer::At(i);
printer->HandleSpooledJob();
}
return rc;
}
// ---------------------------------------------------------------

View File

@ -6,6 +6,9 @@
// The print_server manages the communication between applications and the
// printer and transport drivers.
//
// Authors
// Ithamar R. Adema
// 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
@ -35,12 +38,18 @@
#ifndef PRINTSERVERAPP_H
#define PRINTSERVERAPP_H
#include "ResourceManager.h"
class PrintServerApp;
#include <Application.h>
#include <Bitmap.h>
#include <OS.h>
#include <String.h>
// global BLocker for synchronisation
extern BLocker* gLock;
/*****************************************************************************/
// PrintServerApp
//
@ -52,8 +61,10 @@ class PrintServerApp : public BApplication
typedef BApplication Inherited;
public:
PrintServerApp(status_t* err);
bool QuitRequested();
void MessageReceived(BMessage* msg);
void NotifyPrinterDeletion(Resource* res);
// Scripting support, see PrintServerApp.Scripting.cpp
status_t GetSupportedSuites(BMessage* msg);
@ -64,12 +75,15 @@ public:
private:
status_t SetupPrinterList();
status_t HandleSpooledJob(const char* jobname, const char* filepath);
void HandleSpooledJobs();
status_t SelectPrinter(const char* printerName);
status_t CreatePrinter( const char* printerName, const char* driverName,
const char* connection, const char* transportName,
const char* transportPath);
void RegisterPrinter(BDirectory* node);
void HandleRemovedPrinter(BMessage* msg);
status_t StoreDefaultPrinter();
status_t RetrieveDefaultPrinter();
@ -77,14 +91,18 @@ private:
status_t FindPrinterNode(const char* name, BNode& node);
status_t FindPrinterDriver(const char* name, BPath& outPath);
ResourceManager fResourceManager;
Printer* fDefaultPrinter;
BBitmap fSelectedIconMini;
BBitmap fSelectedIconLarge;
int fNumberOfPrinters;
sem_id fNoPrinterAvailable;
// "Classic" BeOS R5 support, see PrintServerApp.R5.cpp
static status_t async_thread(void* data);
void AsyncHandleMessage(BMessage* msg);
void Handle_BeOSR5_Message(BMessage* msg);
};
#endif

View File

@ -1,3 +1,39 @@
/*****************************************************************************/
// print_server Background Application.
//
// Version: 1.0.0d1
//
// The print_server manages the communication between applications and the
// printer and transport drivers.
//
// Author
// Ithamar R. Adema
//
// 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) 2001 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 "Printer.h"

View File

@ -6,18 +6,15 @@
// The print_server manages the communication between applications and the
// printer and transport drivers.
//
//
//
// TODO:
// Handle spooled jobs at startup
// Handle printer status (asked to print a spooled job but printer busy)
//
// Authors
// Ithamar R. Adema
// 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) 2001 OpenBeOS Project
// Copyright (c) 2001,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"),
@ -42,13 +39,21 @@
#include "pr_server.h"
#include "BeUtils.h"
#include "PrintServerApp.h"
// posix
#include <limits.h>
#include <stdlib.h>
#include <string.h>
// BeOS API
#include <Application.h>
#include <Autolock.h>
#include <Message.h>
#include <NodeMonitor.h>
#include <String.h>
#include <File.h>
#include <Path.h>
#include <StorageKit.h>
#include <SupportDefs.h>
// ---------------------------------------------------------------
typedef BMessage* (*config_func_t)(BNode*, const BMessage*);
@ -84,9 +89,18 @@ Printer* Printer::Find(const BString& name)
return NULL;
}
int32 Printer::CountPrinters()
Printer* Printer::Find(dev_t dev, ino_t node)
{
return sPrinters.CountItems();
// Look in list to find printer definition
for (int32 idx=0; idx < sPrinters.CountItems(); idx++) {
Printer* printer = sPrinters.ItemAt(idx);
node_ref ref;
printer->fNode.GetNodeRef(&ref);
if (ref.device == dev && ref.node == node) return printer;
}
// None found, so return NULL
return NULL;
}
Printer* Printer::At(int32 idx)
@ -94,6 +108,15 @@ Printer* Printer::At(int32 idx)
return sPrinters.ItemAt(idx);
}
void Printer::Remove(Printer* printer) {
sPrinters.RemoveItem(printer);
}
int32 Printer::CountPrinters()
{
return sPrinters.CountItems();
}
// ---------------------------------------------------------------
// Printer [constructor]
//
@ -106,15 +129,22 @@ Printer* Printer::At(int32 idx)
// Returns:
// none.
// ---------------------------------------------------------------
Printer::Printer(const BNode* node)
Printer::Printer(const BDirectory* node, Resource* res)
: Inherited(B_EMPTY_STRING),
fFolder(*node),
fResource(res),
fNode(*node),
fRefCount(1)
fSinglePrintThread(true),
fJob(NULL),
fProcessing(0),
fAbort(false)
{
// Set our name to the name of the passed node
BString name;
fNode.ReadAttrString(PSRV_PRINTER_ATTR_PRT_NAME, &name);
SetName(name.String());
if (name == "Preview") fSinglePrintThread = false;
// Add us to the global list of known printer definitions
sPrinters.AddItem(this);
@ -123,19 +153,7 @@ Printer::Printer(const BNode* node)
Printer::~Printer()
{
sPrinters.RemoveItem(this);
be_app->RemoveHandler(this);
}
void Printer::Acquire()
{
fRefCount ++;
}
void Printer::Release()
{
fRefCount --;
if (fRefCount == 0) delete this;
((PrintServerApp*)be_app)->NotifyPrinterDeletion(fResource);
}
status_t Printer::Remove()
@ -144,6 +162,8 @@ status_t Printer::Remove()
BPath path;
if ((rc=::find_directory(B_USER_PRINTERS_DIRECTORY, &path)) == B_OK) {
sPrinters.RemoveItem(this);
be_app->RemoveHandler(this);
path.Append(Name());
rc = rmdir(path.Path());
}
@ -242,29 +262,11 @@ status_t Printer::ConfigureJob(BMessage& settings)
if ((rc=get_image_symbol(id, "config_job", B_SYMBOL_TYPE_TEXT, (void**)&func)) == B_OK) {
// call the function and check its result
BMessage* new_settings = (*func)(&fNode, &settings);
if (new_settings != NULL && new_settings->what != 'baad')
if ((new_settings != NULL) && (new_settings->what != 'baad'))
settings = *new_settings;
}
::unload_add_on(id);
}
return rc;
}
status_t Printer::PrintSpooledJob(BFile* spoolFile, const BMessage& settings)
{
take_job_func_t func;
image_id id;
status_t rc;
if ((rc=LoadPrinterAddon(id)) == B_OK) {
// Addon was loaded, so try and get the take_job symbol
if ((rc=get_image_symbol(id, "take_job", B_SYMBOL_TYPE_TEXT, (void**)&func)) == B_OK) {
// call the function and check its result
BMessage* result = (*func)(spoolFile, &fNode, &settings);
if (result == NULL || result->what == 'baad')
else
rc = B_ERROR;
delete new_settings;
}
::unload_add_on(id);
@ -273,6 +275,23 @@ status_t Printer::PrintSpooledJob(BFile* spoolFile, const BMessage& settings)
return rc;
}
// ---------------------------------------------------------------
// HandleSpooledJobs
//
// Print spooled jobs in a new thread.
// ---------------------------------------------------------------
void Printer::HandleSpooledJob() {
BAutolock lock(gLock);
if (lock.IsLocked() && (!fSinglePrintThread || fProcessing == 0) && FindSpooledJob()) {
StartPrintThread();
}
}
void Printer::AbortPrintThread() {
fAbort = true;
}
// ---------------------------------------------------------------
// LoadPrinterAddon
//
@ -310,6 +329,10 @@ status_t Printer::LoadPrinterAddon(image_id& id)
void Printer::MessageReceived(BMessage* msg)
{
printf("Printer::MessageReceived(): ");
msg->PrintToStream();
switch(msg->what) {
case B_GET_PROPERTY:
case B_SET_PROPERTY:
@ -324,3 +347,84 @@ void Printer::MessageReceived(BMessage* msg)
Inherited::MessageReceived(msg);
}
}
bool Printer::FindSpooledJob() {
fJob = fFolder.GetNextJob();
if (fJob) fJob->SetPrinter(this);
return fJob;
}
void Printer::CloseJob() {
fJob->Release();
}
status_t Printer::PrintSpooledJob(BFile* spoolFile, const BMessage& settings)
{
take_job_func_t func;
image_id id;
status_t rc;
if ((rc=LoadPrinterAddon(id)) == B_OK) {
// Addon was loaded, so try and get the take_job symbol
if ((rc=get_image_symbol(id, "take_job", B_SYMBOL_TYPE_TEXT, (void**)&func)) == B_OK) {
// call the function and check its result
BMessage* result = (*func)(spoolFile, &fNode, &settings);
if (result == NULL || result->what == 'baad')
rc = B_ERROR;
}
::unload_add_on(id);
}
return rc;
}
void Printer::PrintThread(Job* job) {
fResource->Lock();
if (!fAbort) {
BFile jobFile(&job->EntryRef(), B_READ_ONLY);
print_file_header header;
BMessage settings;
// Read header from filestream
jobFile.Seek(0, SEEK_SET);
jobFile.Read(&header, sizeof(header));
// Get the printer settings
settings.Unflatten(&jobFile);
// and tell the printer to print the spooled job
if (PrintSpooledJob(&jobFile, settings) == B_OK) {
// Remove spool file if printing was successfull.
job->Remove();
} else {
job->SetStatus(kFailed);
}
} else {
job->SetStatus(kFailed);
}
fResource->Unlock();
job->Release();
atomic_add(&fProcessing, -1);
Release();
be_app_messenger.SendMessage(PSRV_PRINT_SPOOLED_JOB);
}
status_t Printer::print_thread(void* data) {
Job* job = static_cast<Job*>(data);
job->GetPrinter()->PrintThread(job);
return 0;
}
status_t Printer::StartPrintThread() {
Acquire();
thread_id tid = spawn_thread(print_thread, "print", B_NORMAL_PRIORITY, (void*)fJob);
if (tid > 0) {
fJob->SetStatus(kProcessing);
atomic_add(&fProcessing, 1);
resume_thread(tid);
} else {
CloseJob(); Release();
}
}

View File

@ -5,13 +5,10 @@
//
// The print_server manages the communication between applications and the
// printer and transport drivers.
//
//
//
// TODO:
// Handle spooled jobs at startup
// Handle printer status (asked to print a spooled job but printer busy)
//
// Authors
// Ithamar R. Adema
// 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
@ -43,11 +40,17 @@
class Printer;
#include "BeUtils.h"
#include "ResourceManager.h"
#include "Jobs.h"
// BeOS API
#include <Directory.h>
#include <Handler.h>
#include <String.h>
#include <image.h>
#include <Node.h>
#include <Locker.h>
#include <PrintJob.h>
#include <String.h>
// OpenTracker shared sources
#include "ObjectList.h"
@ -58,27 +61,27 @@ class Printer;
// This class represents one printer definition. It is manages all actions &
// data related to that printer.
/*****************************************************************************/
class Printer : public BHandler
class Printer : public BHandler, public Object
{
typedef BHandler Inherited;
public:
Printer(const BNode* node);
Printer(const BDirectory* node, Resource* res);
~Printer();
void Acquire();
void Release();
// Static helper functions
static Printer* Find(const BString& name);
static Printer* Find(dev_t device, ino_t node);
static Printer* At(int32 idx);
static void Remove(Printer* printer);
static int32 CountPrinters();
status_t Remove();
status_t ConfigurePrinter();
status_t ConfigureJob(BMessage& ioSettings);
status_t ConfigurePage(BMessage& ioSettings);
status_t PrintSpooledJob(BFile* spoolFile, const BMessage& settings);
void HandleSpooledJob();
void AbortPrintThread();
void MessageReceived(BMessage* msg);
@ -90,10 +93,22 @@ public:
private:
status_t LoadPrinterAddon(image_id& id);
BNode fNode;
int32 fRefCount;
Folder fFolder;
Resource* fResource;
BDirectory fNode;
bool fSinglePrintThread;
Job* fJob;
volatile vint32 fProcessing;
bool fAbort;
static BObjectList<Printer> sPrinters;
bool FindSpooledJob();
void CloseJob();
status_t PrintSpooledJob(BFile* spoolFile, const BMessage& settings);
void PrintThread(Job* job);
static status_t print_thread(void* data);
status_t StartPrintThread();
};
#endif

View File

@ -0,0 +1,104 @@
/*****************************************************************************/
// ResourceManager
//
// 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 "ResourceManager.h"
#include <Debug.h>
#include <Autolock.h>
Resource::Resource(const char* transport, const char* address, const char* connection)
: fTransport(transport)
, fTransportAddress(address)
, fConnection(connection)
, fResourceAvailable(0)
{
if (NeedsLocking()) {
fResourceAvailable = create_sem(1, "resource");
}
}
Resource::~Resource() {
if (fResourceAvailable > 0) delete_sem(fResourceAvailable);
}
bool Resource::NeedsLocking() {
return !(fTransport == "Print to File" || fTransport == "NONE");
}
bool Resource::Equals(const char* transport, const char* address, const char* connection) {
return fTransport == transport &&
fTransportAddress == address &&
fConnection == connection;
}
bool Resource::Lock() {
if (fResourceAvailable > 0) {
return acquire_sem(fResourceAvailable) == B_NO_ERROR;
}
return true;
}
void Resource::Unlock() {
if (fResourceAvailable > 0) {
release_sem(fResourceAvailable);
}
}
ResourceManager::~ResourceManager() {
ASSERT(fResources.CountItems() == 0);
}
Resource* ResourceManager::Find(const char* transport, const char* address, const char* connection) {
for (int i = 0; i < fResources.CountItems(); i ++) {
Resource* r = fResources.ItemAt(i);
if (r->Equals(transport, address, connection)) return r;
}
return NULL;
}
Resource* ResourceManager::Allocate(const char* transport, const char* address, const char* connection) {
Resource* r = Find(transport, address, connection);
if (r == NULL) {
r = new Resource(transport, address, connection);
fResources.AddItem(r);
} else {
r->Acquire();
}
return r;
}
void ResourceManager::Free(Resource* r) {
if (r->Release()) {
fResources.RemoveItem(r);
}
}

View File

@ -0,0 +1,78 @@
/*****************************************************************************/
// ResourceManager
//
// 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.
/*****************************************************************************/
#ifndef RESOURCE_MANAGER_H
#define RESOURCE_MANAGER_H
#include "ObjectList.h"
#include <Locker.h>
#include <String.h>
#include "BeUtils.h"
class Resource : public Object {
private:
BString fTransport;
BString fTransportAddress;
BString fConnection;
sem_id fResourceAvailable;
bool NeedsLocking();
public:
Resource(const char* transport, const char* address, const char* connection);
~Resource();
bool Equals(const char* transport, const char* address, const char* connection);
const BString& Transport() const { return fTransport; }
bool Lock();
void Unlock();
};
class ResourceManager {
private:
BObjectList<Resource> fResources;
Resource* Find(const char* transport, const char* address, const char* connection);
public:
~ResourceManager();
Resource* Allocate(const char* transport, const char* address, const char* connection);
void Free(Resource* r);
};
#endif