• No results found

Design och implementering av utskriftsredovisning och statusrapportering för utskriftshanteraren LPRng

N/A
N/A
Protected

Academic year: 2021

Share "Design och implementering av utskriftsredovisning och statusrapportering för utskriftshanteraren LPRng"

Copied!
87
0
0

Loading.... (view fulltext now)

Full text

(1)

Bachelor’s Thesis

Design and Implementation of

Accounting and Status Notification for

the LPRng Print Spooler

Henrik Edlund

2003-11-24

(2)
(3)

Link¨

oping University

Department of Computer and Information Science

Bachelor’s Thesis

Design and Implementation of

Accounting and Status Notification for

the LPRng Print Spooler

Henrik Edlund

2003-11-24

LITH-IDA-EX-ING--03/019--SE

(4)
(5)

Abstract

This thesis presents the design and implementation of an accounting and status

no-tification system for the LPRng print spooler. A solution using SNMP to query for

needed accounting and status data is presented, a design built upon this, and an

im-plementation produced.

As the system derives from the requirements specification, it will make no attempt to

solve all printer accounting problems or to offer compatibility with all printers, database

management systems or print spoolers. However, several solutions for printer

account-ing are discussed and the best solution derived from the requirements specification will

be chosen.

(6)
(7)

Acknowledgments

I would like to extend my gratitude to my advisor Tommy Olsson, my opponent Andreas

Lange and my colleagues at the department for their valuable assistance and support

during all phases of this thesis.

I am deeply grateful to my friends, you know who you are, for their enduring patience,

belief and trust in me. You are all essential in my life.

Thanks must also go to Patrick Powell, author of LPRng, and all members of the

LPRng mailing list for the discussion, feedback and help.

This thesis was set in LYX using the L

A

TEX typesetting system on a computer running

the Slackware Linux operating system. The typefaces used are from the Computer

Modern family. Figure 4.1 and Figure 4.2 were drawn using Graphviz and retouched

using Xfig.

(8)
(9)

Contents

Abstract

iii

Acknowledgments

v

List of Figures

xi

List of Tables

xiii

I.

Preliminaries

1

1. Introduction

3

1.1. Background . . . .

3

1.2. Objective . . . .

3

1.3. Literature . . . .

4

1.4. Terminology . . . .

4

1.5. Overview

. . . .

4

2. Background

5

2.1. Accounting . . . .

5

2.2. Status Notification . . . .

5

3. Requirements

7

3.1. Common . . . .

7

3.2. Accounting . . . .

7

3.3. Status Notification . . . .

8

(10)

II. Design

11

4. Accounting

13

4.1. Security . . . .

13

4.2. Available Solutions . . . .

13

4.2.1. Pre-printing . . . .

14

4.2.2. Proprietary Software . . . .

14

4.2.3. PJL . . . .

14

4.2.4. PostScript . . . .

15

4.2.5. SNMP . . . .

16

4.2.6. Conclusion

. . . .

16

4.3. SNMP . . . .

17

4.4. LPRng . . . .

18

4.5. Database

. . . .

18

5. Status Notification

21

5.1. Security . . . .

21

5.2. Whereabouts . . . .

21

5.3. SNMP . . . .

21

III. Outcome

23

6. Implementation

25

6.1. Accounting and Status Notification Application . . . .

25

6.1.1. Starting and Ending a Job

. . . .

25

6.1.2. Accounting Status . . . .

26

6.2. Accounting Administration Application . . . .

27

6.3. Database

. . . .

27

7. Results

31

(11)

8. Conclusion and Future Work

33

8.1. Conclusion

. . . .

33

8.2. Future Work

. . . .

33

8.2.1. Credit System

. . . .

33

8.2.2. Individual Cost Per Printer . . . .

34

8.2.3. Individual Cost Per User

. . . .

34

8.2.4. And More . . . .

34

IV. Supplements

35

References

37

A. LPRng Integration

39

B. Source Code of the Accounting and Status Notification Application

41

C. Source Code of the Accounting Administration Application

55

(12)
(13)

List of Figures

4.1. ER diagram for the accounting database . . . .

18

4.2. Database schema diagram with referential integrity constraints . . . . .

19

6.1. Rendered example of accounting status in PostScript format . . . .

28

(14)
(15)

List of Tables

4.1. Interesting printer status states . . . .

17

6.1. Database tables . . . .

29

6.2. Database triggers . . . .

29

6.3. Database indexes . . . .

29

6.4. Database functions . . . .

29

6.5. Database users . . . .

30

6.6. Database privileges . . . .

30

(16)
(17)

Part I.

(18)
(19)

1. Introduction

1.1.

Background

This thesis presents part of the work that was done to deploy a completely new print

spooler with associated services at the Department of Computer and Information

Sci-ence at Link¨

oping University. This half-year project consisted of several steps.

First the project involved a look at possible candidates for a new print spooler.

Even-tually the LPRng print spooler was chosen as it could easily be adapted as a drop-in

replacement to the earlier one. Applications for handling accounting, status

notifica-tion, printer initializanotifica-tion, banner creanotifica-tion, content filtering, content conversion and

error handling were written as extensions to the print spooler.

Before deploying the system, it was heavily tested with several existing printers and

with candidate printers that were to be acquired. When this is written, the system has

been in operation with success for about half a year.

This thesis will focus on one part of the larger project, the design and implementation

of accounting and status notification.

1.2.

Objective

The objective of this thesis is to design and implement an accounting and status

notifi-cation system in accordance with the requirements laid out. There are several

require-ments on this system. The requirerequire-ments range from software compatibility to making

sure the accounting data are accurate. A full requirements specification is found in

Chapter 3.

Several solutions for printer accounting will be discussed. The best solution derived

from the requirements specification will be chosen and a system will be implemented.

This system will then be put into actual use at the Department of Computer and

Information Science.

As the system derives from the requirements specification, it will make no attempt to

solve all printer accounting problems or to offer compatibility with all printers, database

management systems or print spoolers.

(20)

1.3.

Literature

This thesis depends on several Internet sources. All of these are either standard

docu-ments, publications by reputable corporations or software manuals. The source

mate-rials were selected and used as reference on the grounds of the information needed to

be retrieved.

A great source of grapevine information, required in both the design and

implementa-tion, was the LPRng mailing list

1

. Through it, many issues were raised, discussed and

solved.

1.4.

Terminology

The audience for this thesis are those with at least an undergraduate degree in

Com-puter Science. Terminology acquired during such studies will not be explained here.

Five words, or concepts if you like, related to the printing world and this thesis, will

be explained here though. The definition given is the one used in this thesis.

Duplex Printing on both sides of a sheet.

Impression A printed side of a sheet. With simplex printing there is one impression

per sheet, while with duplex printing there are two impressions per sheet.

Job A printer job can consist of one or several files, sent as one package to the print

spooler to be printed as a whole.

Quota The number of impressions the user has left to use for printing.

Sheet A rectangular piece of paper with two sides.

Simplex Printing on one side of a sheet.

1.5.

Overview

As this thesis takes off, it will begin with a background of the problem and move on to

a requirements specification from the described problem. A look at possible solutions

will be done, and after that focusing on the design of the accounting element and then

the status notification element.

Moving on from design, the implementation will then be discussed and the thesis will

conclude with a statement of results and possible future work. As appendixes, details

on LPRng integration, database data definition and source code, can be found.

1The LPRng mailing list is archived at <http://marc.theaimsgroup.com/>.

(21)

2. Background

This chapter gives a brief background to the problem and outlines solution ideas.

2.1.

Accounting

At the Department of Computer and Information Science, it has for many years been

free for students to print. However, in recent years the situation has become

unmain-tainable. There are a lot of things printed that are not related to the department’s

courses or even printed by students not connected with the department.

While the department wants to continue to offer free printing for active students and for

material related to the department’s courses, it also wants to stop the abuse of the print

system by students printing material relating to courses at other departments, and by

students not attending courses or related study programmes at the department. This

way, better service can be offered to current students in terms of printer availability.

Printers and toner cartridges will also last longer. The goal being, that for students

actually printing what they should be printing there should be no noticeable difference,

but the ability for others to print should be limited.

As one knows what courses a student is attending, one could use this information and

award printing credits for each course. Those students not attending any courses at

the moment would then be unable to print anything, or at most use any previously

saved credits if these are not cleared each semester. This should shift the usage of

the printers in a direction where they are used only when necessary and increase the

availability for the students that need them.

It would be more interesting to count impressions than to count sheets. The cost of

the toner for one impression (normal coverage) is more than twice as much as the cost

of the paper. With duplex printing, the cost of the toner will be at least four times as

much as the cost of the paper.

2.2.

Status Notification

When there is a problem with a printer at the start of or during a job, it will not be

taken care of until somebody goes to the printer and notices it. As people tend to send

(22)

jobs to the printer and to pick them up some time later, a printer problem will cause

a stop in the processing of jobs and new jobs will pile up in the printer queue. Until

somebody walks by the printer and corrects the problem nothing will be done. The

problem could be, for example, paper jam, no paper or no toner.

It would be nice if a problem could be detected and the user notified about this. If

the user becomes aware of the problem, she most likely will go to the printer, verify its

condition and take appropriate measures. This benefits both the owner of the halted

job and the owners of the jobs piled up in the queue.

As the users run a diverse multitude of platforms, it is difficult to send some sort of

direct pop-up message. However, most users have a mail client running, a client that

notifies them within minutes of a new message arriving. Sending the problem status

notification by mail ensures it works for the largest group of users and their platforms.

The lp and lpr commands support an m option where a user can request that a message

is sent by mail upon normal completion of a job. By supporting this option, the owner

of the job could continue working at her desk and still be able to pick up the job as

soon as it has finished printing.

(23)

3. Requirements

Here are the requirements for a solution to the problem, including additional

require-ments set down by the department. Each requirement is given an identification number

to the right for later reference.

3.1.

Common

Shall interoperate with printers from different manufacturers

[1]

Printers from several manufacturers may be used and, as long as they meet the

speci-fications, the solution must work with all of them without configuration exceptions.

3.2.

Accounting

Shall interoperate with LPRng

[2]

The system shall receive a user name, a job timestamp, a printer name and a job name

from LPRng. It shall also be possible to notify LPRng of what to do with the job,

which includes allowing it, retrying it later or denying it.

Shall interoperate with PostgreSQL

[3]

All data needed between sessions shall be stored in a database managed by the

depart-ment’s PostgreSQL database management system.

Shall manage access to printing by a user database

[4]

Users with printing access shall be stored in a database. Users that do not exist in the

database shall be denied access to printing. It shall be possible to drop and rename

users from the database. When a user is dropped, all associated data stored in the

database shall also be dropped.

(24)

Shall calculate and store accounting data

[5]

The number of impressions actually used during a job shall be counted in an accurate

way and stored in the database, together with user name, job timestamp, printer name

and job name.

Shall support per user quota to limit printing access

[6]

It shall be possible to enable a quota per user basis. The quota shall be checked before

each job and the user shall not be able to print if her quota is zero or below. The

user shall though be allowed to print, if the quota is above zero and the number of

impressions is unknown until after the job has finished. The number of impressions shall

be deducted from a user’s quota when the job has finished printing and the resulting

quota shall be negative if the result is negative. It shall be possible to increase or

decrease the user’s quota manually.

Shall store quota transactions history per user if quota is active

[7]

For each change to a user’s quota, an entry in the transactions history shall be made

in the database. No transactions history shall be kept for users that do not have a

quota. An entry in the transactions history shall consist of a user name, a transaction

timestamp, the change and a comment about the transaction.

Shall be able to output accounting status in PostScript format on request

[8]

The output shall include current quota (if applicable), a recent printing history (if

available), a monthly summary for the last twelve months and a recent transactions

history (if available). It shall be possible to include the output in a PostScript banner

page.

Shall send a message by mail if a user does not have access to print

[9]

If a user does not have access to print, an attempt shall be made to send the user a

message by mail about this fact.

Shall send a message by mail if a user does not have enough quota to print

[10]

If a user does not have enough quota to print, an attempt shall be made to send the

user a message by mail about this fact. The message shall include a recent transactions

history.

3.3.

Status Notification

Shall notify by mail at start of job if the printer is signaling a down status

[11]

If the printer is signaling a down status at the start of a job, an attempt shall be made

to send the user a message by mail about this. The message shall include printer name,

(25)

job name, job timestamp, and a request that the user should attempt to verify printer

condition and take appropriate measures.

Shall notify by mail during job if the printer is signaling a down status

[12]

If the printer is signaling a down status during the job, an attempt shall be made to

send the user a message by mail about this. The message shall include printer name,

job name, job timestamp, and a request that the user should attempt to verify printer

condition and take appropriate measures.

Shall notify by mail about normal completion of job if requested by the user [13]

If the user request that a message by mail is sent upon normal completion of a job, an

attempt shall be made to send the user such a message. The message shall include the

number of impressions of the job. If the user has a quota, the message shall include

the balance after the job.

(26)
(27)

Part II.

(28)
(29)

4. Accounting

This chapter is about security precautions with accounting, then a look at available

solutions and details about the chosen solution. The chapter ends with on how LPRng

is used and the design of the database.

4.1.

Security

No matter what accounting solution used, one has to make sure there is no way to

bypass it or to fool the accounting mechanism.

It is critical that only the print spooler can send jobs to the printers. The printers

should be located on their own private network or otherwise protected so that they

can only receive jobs from the print spooler. Otherwise users would be able to send

jobs directly to printers and thereby bypass any accounting solution. Printers should

of course also be configured to not listen to any other interfaces (like the USB and

parallel ports) and have their front panels locked so that printer settings cannot be

altered on location.

Further, it is important to be able to separate jobs for accounting purposes. Depending

on solution, this might include not sending the next job from the queue until the

previous has finished and been accounted for.

Part of accounting is connecting some sort of job information to a user. It is important

that one can trust the user name passed to the print spooler from the application that

submitted the job. If the user can hide her true user name or impersonate another

user, then all the accounting is in vain. An example is given in Appendix A on how to

accomplish this kind of trust with the LPRng print spooler.

4.2.

Available Solutions

There are several ways to do accounting.

A brief overview will here be given of

the solutions available, noting some pros and cons. The solutions discussed are

pre-printing, proprietary software, Hewlett-Packard’s Printer Job Language (PJL), Adobe’s

PostScript language and the Simple Network Management Protocol (SNMP).

(30)

4.2.1.

Pre-printing

These solutions are those where the counting of impressions takes place in pure software

implementations before printing and the actual printer hardware is not involved at all.

Two examples will be given here.

In modern Microsoft Windows operating systems, applications call the Graphics Device

Interface (GDI) to print [1]. The GDI calls the printer driver for information, which is

used to create the job. After job creation, the GDI knows the number of impressions of

the job and then delivers it to the spooler. If print output is produced in RAW format,

the GDI is not used.

The spooler logs the number of impressions in the event log where other software then

can check for accounting information. By bypassing the GDI and sending a RAW job

directly to the spooler, the spooler will log the job with zero impressions.

Ghostscript

1

is a cross-platform interpreter for PostScript. It can be used to count the

number of impressions of a job before it is sent to the printer. It is though possible to

include certain PostScript commands that will trick Ghostscript into thinking that the

job has fewer impressions. This is usually done by testing the PostScript interpreter

to see if it has some special characteristics that are available on the actual printer and

not on the interpreter.

Any pre-printing solution suffers from the fact that the printer may not actually print

the entire job. For example, the printer could jam, or run out of paper or toner. The

user would still get charged. This means that a pre-printing solution does not fulfill

Requirement 5.

4.2.2.

Proprietary Software

Several printer manufacturers offer proprietary software solutions

2

that sometimes only

work with their printers. These run on certain platforms only and often do not offer

open access to data. As a packaged solution, one can say that these do not fulfill

Requirement 2 nor Requirement 3, and sometimes not even Requirement 1.

4.2.3.

PJL

Hewlett-Packard’s Printer Job Language (PJL) is used by many existing accounting

applications

3

. A connection is held open to the printer after the job has been sent to it,

periodically querying for whether the job is done or not. Before the job and when the

job has finished, the total number of impressions reported by the printer is read. The

1Ghostscript is available from <http://www.ghostscript.com/>.

2Examples of proprietary software solutions are Xerox CentreWare Web and Xerox XCounter Page

Accounting. Both are available from <http://www.xerox.com/>.

3An example accounting application using PJL is the ifhp print filter, available from <http://www.

lprng.com/>.

(31)

number of impressions used by the job can then be calculated. The PJL commands

ECHO, EOJ, INFO PAGECOUNT, JOB and USTATUS can be used to retrieve

the total number of impressions and check on printer status [2].

Pros of this solution is that almost all printers on the market today support PJL

according to their specifications. According to the grapevine, the support is in reality

sketchy. What the commands return and when, while clearly specified in the technical

reference manual, differ. One has to make sure that the commands really work and

return what they are supposed to. It is hard to know whether the number of impressions

is actually correct.

Writing a general implementation that works with several printer models from

dif-ferent manufacturers could turn into a game of rules and exceptions. Consequently,

Requirement 1 and Requirement 5 are not clearly fulfilled.

4.2.4.

PostScript

Adobe’s PostScript language is an interpretive programming language with powerful

graphics capabilities [3]. Its primary application is to describe the appearance of text,

graphical shapes, and sampled images on printed or displayed pages.

PostScript language level 2 implementations version 2011 and greater, and PostScript

language level 3 implementations feature a new system parameter PageCount [3]. Not

all products do necessarily support it. PageCount tracks the number of impressions

that have been successfully processed since manufacture, counting the number of copies

for each showpage. Impressions not physically printed are counted, making the count

inaccurate during the job, but accurate after adjustment at the end of the job. This is

what the specification says at least.

Just as with PJL, a connection is held open to the printer after the job has been sent

to it. A control sequence is sent in order to retrieve the status of the printer. Whether

you get the status this way depends on the printer. Some printers, according to reports

on the LPRng mailing list, stop responding when they run out of paper or toner. If

one manages to verify that the printer has finished with the job, commands can be

issued to retrieve the system parameter PageCount. By using the PageCount value

from before the job and the one retrieved after the job, the number of impressions used

during the job can be calculated.

PostScript is often supported by accounting applications as an alternative, or

supple-ment, to PJL. The pro side of this solution is that many printers support PostScript

today, though they have different implementations and support different language

lev-els. Whether they support the needed features may be uncertain. One may have to

use different PostScript code with each printer for it to work correctly. From this, one

can see that Requirement 1 and Requirement 5 are not clearly fulfilled.

(32)

4.2.5.

SNMP

The Simple Network Management Protocol (SNMP) is a definition of a protocol by

which management information for a network element may be inspected or altered by

logically remote users [4]. Together with companion memos which describe the

struc-ture of management information along with the management information base (MIB),

these documents provide a simple, workable architecture and system for managing

TCP/IP-based networks.

Two of these companion memos are of particular interest to us. The Host Resources

MIB provides two status objects, hrDeviceStatus and hrPrinterStatus, which

de-scribe many of the states of a printer [5].

The Printer MIB provides another

ob-ject, prtMarkerLifeCount, which gives us the count of the number of units of

measure counted during the life of the printer using units specified in the object

prtMarkerCounterUnit [6].

SNMP is independent of the process of sending the content of the job to the printer. By

using the two status objects to monitor whether the printer is done printing, and the

counter object to retrieve the number of impressions before and after a job, an accurate

number of actual printed impressions can be calculated. The counter is located in the

printer and counts only the number of impressions actually printed.

Support for SNMP in printers has become more important and has seen an upsurge

since generic SNMP-based monitoring tools have become increasingly popular. Most

printers on the market today support the two MIBs needed for the SNMP solution.

There are exceptions though, but the consensus seems to be that more printers work

with the SNMP solution compared to the PJL solution or the PostScript solution.

Requirement 1 and Requirement 5 are fulfilled as long as one makes sure the printers

in use (or being acquired) have proper SNMP and MIB support.

4.2.6.

Conclusion

With its increasing support in printers, the SNMP solution seems to be the best option.

The same general implementation would work with several printer models from different

manufacturers, as long as the printer supports SNMP and mentioned MIBs properly.

As the SNMP solution is independent of the process of sending the content of the job

to the printer, it reduces the number of places where things could go wrong by not

interfering in that process. However, even the best solution for counting the number

of impressions will fail unless it is used in an accurate and timely manner. The SNMP

solution will be discussed in more detail in Section 4.3.

Some printers only store the total number of impressions in EEPROM at certain

in-tervals. Some of these printers, like some of those from Hewlett-Packard, do not store

in EEPROM if they are powered off and will lose their current impressions count and

go back to the last saved count when powered on again. Other printers, which store

in EEPROM at intervals, return the stored total number of impressions when asked,

(33)

Printer status

hrDeviceStatus

hrPrinterStatus

Normal

running

idle

Busy/temporarily unavailable

running

printing

Non critical alert active

warning

idle or printing

Unavailable

down

other

Moving offline

warning

idle or printing

Offline

down

other

Moving online

down

warmup

Standby

running

other

Table 4.1.: Interesting printer status states

meaning that the actual impressions count and the stored count may differ

consider-ably. As these flaws affect the total number of impressions reported by the printer,

they most likely also affect all three of the PJL, PostScript and SNMP solutions. One

has to be careful to test printers for this vulnerability before acquiring and using them.

4.3.

SNMP

Table 4.1, based upon a similar table from the Printer MIB, shows some interesting

printer status states [6]. From the table it is possible to deduce that it is safe to use

the prtMarkerLifeCount object for determining the number of impressions when

hrDeviceStatus is running or warning, and hrPrinterStatus is idle or other. In

any other state one can not be certain if the printer is done with a previous or current

job. A printer with standby status is partially powered down and consequently not in

the middle of printing anything.

A hrDeviceStatus of warning indicates that the printer could have low paper or low

toner while a hrDeviceStatus of down indicates that the printer could be jammed,

have no paper, no toner or have the cover open [6]. This means that the former is a

safe state for determining the number of impressions, while the latter is not. The latter

could mean that the job is not finished and will finish as soon as the down state has

recovered. The job most likely still resides in the printer memory.

The value of prtMarkerCounterUnit can for example be impressions, sheets, hours

or meters [6]. It seems that with common home and office printers, impressions is the

common unit, and it can be assumed this is the general case.

(34)

JOB PRINTING TRANSACTION USER (1,1) (0,N) (1,1) (0,N) (1,1) (0,N) Balance User Printer Job Counter Timestamp Job Timestamp Printer Impressions Id Comment Change Id Timestamp

Figure 4.1.: ER diagram for the accounting database

4.4.

LPRng

According to the LPRng Reference Manual, LPRng can call an application at the start

of the job and at the end of the job to determine accounting information [7]. LPRng

will then pass the information needed to this application and the application can use

exit codes to indicate to LPRng what to do with the job. This fulfills Requirement 2.

Details on how to configure LPRng can be found in Appendix A.

4.5.

Database

Requirement 4, second half of Requirement 5, Requirement 6 and Requirement 7 partly

deal with the requirements on the database design. Figure 4.1 shows an ER diagram

for the accounting database.

In Figure 4.2 on the facing page, the ER diagram from Figure 4.1 has been transformed

into a database schema diagram with referential integrity constraints displayed.

(35)

USER BALANCE PRINTER COUNTER USER TIMESTAMP JOB ID USER TIMESTAMP IMPRESSIONS PRINTER JOB ID USER TIMESTAMP CHANGE COMMENT JOBS PRINTING USERS TRANSACTIONS

Figure 4.2.: Database schema diagram with referential integrity constraints

This design fulfills the database design from Requirement 4, second half of Requirement

5, Requirement 6 and Requirement 7. The functional parts of Requirement 4,

Require-ment 5, RequireRequire-ment 6 and RequireRequire-ment 7, as well as RequireRequire-ment 8, RequireRequire-ment 9

and Requirement 10, will be dealt with in the actual implementation.

(36)
(37)

5. Status Notification

Discussion in this chapter is about security considerations when it comes to status

notification, where to implement status notification and how to check printer status.

5.1.

Security

There are no critical security concerns when it comes to status notification.

The goal of status notification is to attempt to notify the user. It is for that reason

good if the user name used to contact the user can be trusted. Otherwise the wrong

user could be notified and in certain cases, personal information, like job names and

number of impressions, could be exposed. An example is given in Appendix A on how

to accomplish this kind of trust with the LPRng print spooler.

5.2.

Whereabouts

SNMP is already used by the accounting process, at the start of the job and at the

end of the job (when the job has been received by the printer and is being printed).

This means that it is possible to do the status checking described in Requirement 11

at the start of the job and the status checking described in Requirement 12 at the end

of the job. Requirement 13 is conveniently fulfilled at the end of the job when the

number of impressions is to be determined as well. LPRng passes a certain option to

the application it calls for accounting, which indicates if the user wants to be notified

of the normal completion of a job.

5.3.

SNMP

As seen in Table 4.1 on page 17, a hrDeviceStatus of down and a hrPrinterStatus

of other indicate that the printer is down. This information can be used to fulfill

Requirement 11 and Requirement 12 in the implementation of the application.

(38)
(39)

Part III.

(40)
(41)

6. Implementation

In this chapter two applications are implemented.

One for accounting and status

notification, and one for accounting administration.

The database is implemented

from the design.

6.1.

Accounting and Status Notification Application

The choice of implementation language for the application fell on Perl. Perl supports a

rapid, incremental development model. It is well known by the implementor and also

by intended future maintainers of the system. Perl has a huge library archive

1

; libraries

for database access, SNMP and mail handling already exist for download and use.

A brief overview of how the implementation works will be given here with some

de-tails on certain interesting aspects. For a detailed view of the application, read the

source code, with its comments, in Appendix B. The functional parts of Requirement

4, Requirement 5, Requirement 6 and Requirement 7, as well as Requirement 8,

Re-quirement 9 and ReRe-quirement 10 will be described here. ReRe-quirement 11, ReRe-quirement

12 and Requirement 13 that relates to status notification will also be handled here.

The application can be launched in three modes; two of these will be discussed in

Section 6.1.1 and the third in Section 6.1.2. Each mode starts with a common part

where some parameters are received from LPRng. These are then verified together with

the mode of operation (which is read from standard input). After this a connection to

the database is made.

6.1.1.

Starting and Ending a Job

The start and end modes are used at the start and the end of a job. Both modes

continue after the common start by fetching an accurate number of impressions from

the printer. It is also in this step that the printer status check for the notification is

done. This step is tricky as it involves looping for a certain number of times, trying to

get an accurate value of the number of impressions, while at the same time not looping

forever. Some printers may for a second or two report a status that does not reflect

(42)

their real state (for example when the cover has been open and just has been closed),

so to make sure the reading can be trusted it has to be stable for a certain number of

readings.

If the printer is down at the start of the job, the user will be sent a message about

this. A fail status will be returned to LPRng and LPRng will eventually remove the

job from the queue after enough attempts. A job can not be allowed to be sent to the

printer without an accurate reading of the prtMarkerLifeCount object.

At the end of the job, the application will try for a longer time if the printer is down,

but will eventually give up and leave the accounting of the job until the next time a

job is started. The user will be sent a message about the down status of the printer.

If a job takes a long time to finish, the loop will be aborted and accounting for the job

will be postponed until the start of the next job.

If an accurate reading of the prtMarkerLifeCount object can be made (according

to Section 4.3 on page 17), then the application moves on to the next step. Here any

ongoing job (either left from earlier if in start mode or the current if in end mode) will

be accounted for using the value of the prtMarkerLifeCount object and a job credit

value. The job credit is either zero or one depending on if a banner page has been

printed or not. This works even if the job is printed in duplex mode, if duplex printing

is turned on during printer initialization (or in the job itself) after the banner page has

been sent in simplex mode.

If the job was a current one and the user requested to be notified at a normal completion,

then a message is sent to the user. No message is sent if a job from an earlier session

was accounted for.

If in end mode, the application now exits as the current job has been accounted for.

In start mode, the application continues. If the user is not allowed to print

(Require-ment 4), a message is sent about denied access. Then the user’s quota is checked, and

if not enough (Requirement 6) the user is denied and notified about it. As the user

now will be allowed to print, all data needed in the end mode, after the job has been

sent off to the printer, are stored in the database. These are some of the job meta data

and the value of the prtMarkerLifeCount object.

6.1.2.

Accounting Status

The accounting application can output accounting status in PostScript format, as

de-scribed in the PostScript Language Reference [3]. By calling the accounting application

with status on standard input, the standard output can be included as part of a banner

page at the current location on that page.

The PostScript command rmove is used to make relative moves [3]. Before calling the

accounting application and requesting status, the banner creation application should

move to where it wants the status. After including the status, the current point is set

(43)

in the bottom left corner of it, so that the calling application can continue working on

the banner there.

Figure 6.1 on the following page shows the rendered example of a complete

account-ing status, where current quota, printaccount-ing history, monthly summary and transactions

history are available. Each element (of the four) is only displayed when there are data

available for it.

6.2.

Accounting Administration Application

This utility application fulfills parts of Requirement 4 and Requirement 6. It enables

the administrator to create, drop and rename users. It is possible to display quota,

have it enabled or disabled, and increased or decreased manually. A simple interface

to display printing history, printing summary and transactions history is also given.

Commands are given on standard input and information is returned on standard output

(errors on standard error). Help on the syntax is given if run in interactive mode, but

data can also be piped directly to and from the application. For a detailed view of the

application, read the source code, with its comments, in Appendix C.

6.3.

Database

The implementation of the database design is done so that Requirement 3 is fulfilled.

The database data definition in SQL is written in accordance with the PostgreSQL

7.3 Reference Manual [8]. The functions are written in PL/pgSQL in accordance with

the PostgreSQL 7.3 Programmer’s Guide [9]. The entire accounting database data

definition can be found in Appendix D.

The database tables (derived from Figure 4.2 on page 19) and their assertions, described

in Table 6.1 on page 29, are created. Entity integrity and referential integrity are not

indicated in Table 6.1 but can be seen in Figure 4.2. No attributes are allowed to be

null, except for the balance attribute which uses null to indicate a state of no quota.

A trigger, to fulfill part of Requirement 7, is described in Table 6.2 on page 29.

A number of indexes are also needed to enable fast search and sorting. They are

described in Table 6.3 on page 29. Some of them are implicitly defined as part of the

entity integrity constraints.

In order to abstract some functionality from the application layer to the database layer,

a number of functions are created. These, together with the trigger function from Table

6.2, are described in Table 6.4 on page 29.

Two database users are needed, one for the accounting application and one for the

accounting administration application. Each of these users will only have the privileges

that are necessary. These users are shown in Table 6.5 on page 30 and their database

privileges are shown in Table 6.6 on page 30.

(44)

688 impressions left before this job

Printing History

Timestamp

Impressions

Printer

Job

2003−08−09 16:20:23

3

lp4

dbtech−exam−04.ps

2003−08−09 16:19:56

3

lp4

standard input

2003−08−09 16:13:47

3

lp4

dbtech−exam−08.ps

2003−08−09 16:13:16

1

lp4

dbtech−labs.pdf

2003−08−09 16:13:10

1

lp4

dbtech−info.pdf

2003−08−09 16:13:05

1

lp4

cc−info.ps.gz

2003−08−09 16:09:17

10

lp4

report.ps

2003−08−09 16:09:13

3

lp4

index.html

2003−08−09 16:09:09

1

lp4

registration.fm

2003−08−09 16:09:05

5

lp4

email.txt

Monthly Summary

Year Month

Impressions

Jobs

2003 August

421

78

2003 July

181

90

2003 June

166

121

Transactions History (Quota)

Timestamp

Before

Change

After

Comment

2003−08−09 16:20:45

691

−3

688

Job "dbtech−exam−04.ps" on printer "lp4"

2003−08−09 16:20:10

694

−3

691

Job "standard input" on printer "lp4"

2003−08−09 16:14:48

697

−3

694

Job "dbtech−exam−08.ps" on printer "lp4"

2003−08−09 16:14:20

698

−1

697

Job "dbtech−labs.pdf" on printer "lp4"

2003−08−09 16:13:48

699

−1

698

Job "dbtech−info.pdf" on printer "lp4"

2003−08−09 16:13:17

700

−1

699

Job "cc−info.ps.gz" on printer "lp4"

2003−08−09 16:12:54

550

150

700

Database Technology

2003−08−09 16:12:53

450

100

550

Compiler Construction

2003−08−09 16:11:06

460

−10

450

Job "report.ps" on printer "lp4"

2003−08−09 16:10:27

463

−3

460

Job "index.html" on printer "lp4"

Figure 6.1.: Rendered example of accounting status in PostScript format

(45)

Name

Assertions

Description

users

Users and their quota

jobs

Active print jobs

printing

(impressions >= 0)

Printing history

transactions

Transactions history

Table 6.1.: Database tables

Name

Table

Triggers

Granularity

Executes function

delete transactions

users

After update

Row

delete transactions

Table 6.2.: Database triggers

Name

Table

Columns

Definition

users pkey

users

user

Implicit (primary key)

jobs pkey

jobs

printer

Implicit (primary key)

printing pkey

printing

id

Implicit (primary key)

printing user

printing

user

Explicit

printing timestamp

printing

timestamp

Explicit

transactions pkey

transactions

id

Implicit (primary key)

transactions user

transactions

user

Explicit

transactions timestamp

transactions

timestamp

Explicit

Table 6.3.: Database indexes

Name

Result data type

Argument data types

Language

delete transactions

trigger

plpgsql

end job

integer

text, integer, integer

plpgsql

start job

boolean

text, integer, text,

timestamp with time

zone, text

plpgsql

change balance

boolean

text, integer

plpgsql

change balance

boolean

text, integer, text

plpgsql

create user

boolean

text

plpgsql

drop user

boolean

text

plpgsql

rename user

boolean

text, text

plpgsql

(46)

Name

Purpose

accounting

Access from the accounting application

accounting admin

Access from the accounting administration application

Table 6.5.: Database users

User

Object type

Object name

Privileges

accounting

table

users

select

accounting admin

table

users

select

accounting

function

delete transactions

execute

accounting admin

function

delete transactions

execute

accounting

table

printing

select

accounting admin

table

printing

select

accounting

table

transactions

select

accounting admin

table

transactions

select

accounting

function

end job

execute

accounting

function

start job

execute

accounting admin

function

change balance

execute

accounting admin

function

create user

execute

accounting admin

function

drop user

execute

accounting admin

function

rename user

execute

Table 6.6.: Database privileges

(47)

7. Results

The aim of this thesis was to design and implement an accounting and status

notifica-tion system for the LPRng print spooler. The implementanotifica-tion and the design behind it

constitute the result and accomplishment. The implementation fulfills all the

require-ments laid out in Chapter 3. The full source code can be found in Appendix B and

Appendix C, and the entire database data definition can be found in Appendix D.

During the testing and deployment of the system, it should be noted that it worked

flawlessly with the Xerox DocuPrint N32 and the Xerox Phaser 4400 printer models,

both of which the department use.

While the system works with the listed printers, it must be noted that it may or may

not work with other printers. A prerequisite is of course that the printer correctly

supports SNMP and the mentioned MIBs.

(48)
(49)

8. Conclusion and Future Work

8.1.

Conclusion

After nearly six months of operation, the system is stable and still operating fast. It

handles the production environment of about 20 printers with over 4,000 active users

without problems. More than 230,000 jobs, consisting of nearly 1.8 million impressions

(not including banner pages), have been printed.

Hopefully this system can inspire the authors of similar systems, give them new ideas

and solutions to common problems. The implementation is clean and simple, bringing

several fields together into a complete solution. The full use of the capabilities of

PostgreSQL abstracts complexity from the applications. Using existing libraries when

available limits the amount of new code that needs to be written. Focus was put on

using one accounting solution, instead of attempting to use several in combination and

consequently making the system complex and failure prone.

Four formal languages are used. SQL to perform database queries, PL/pgSQL for

the functions in the database and PostScript to display the accounting status. Perl

ties together database access, SNMP communication with printers, communication

with LPRng and output of accounting status. This shows that it is possible to select

different languages for different purposes and tie them together in a complete software

solution. This will hopefully serve as further inspiration for future work.

8.2.

Future Work

The implementation presented in this thesis built upon the requirements presented.

On the way there, precaution was taken to ensure that the system would be easy to

extend in the future. One can think of several interesting extensions to this system,

described in the following sections.

8.2.1.

Credit System

Instead of having impressions as the currency for credits, one could add an option to

specify a cost in a number of credits. Then credits could be awarded to a user whenever,

(50)

but the cost of printing could change over time. The only change needed here is to add

a multiplication to the database function end job (see Table 6.4 on page 29).

8.2.2.

Individual Cost Per Printer

An even further extension to the credit system would be to have a cost per impression

per printer. This might be useful in a mixed environment of printers with varying

toner costs. The changes needed for this, on top of the one described in Section 8.2.1,

would be to add a new table to the database for this cost and a table lookup to get the

variable used in the multiplication.

8.2.3.

Individual Cost Per User

Different users could be charged a different number of credits. One could multiply

the cost per printer (as described in Section 8.2.2) with a variable fetched from a new

column in the database table users (see Figure 4.2 on page 19).

8.2.4.

And More

As seen in the three given examples, it is easy to extend the system by only small

changes. More eccentric extensions could be cost depending on time of day (one new

table and one new lookup) or cost depending on the number of jobs in the last hour

(one new lookup). Only imagination sets the limits.

(51)

Part IV.

(52)
(53)

References

[1] Microsoft Corporation. Microsoft Windows 2000 Professional Resource Kit.

Red-mond, Washington, USA. Microsoft Press. 2000. Chapter 14. Printing. ISBN

1-57231-808-2.

[2] Hewlett-Packard Development Company, LP. Printer Job Language Technical

Ref-erence Manual [online]. 12th edition. June 2003 [cited 29 October 2003].

Publica-tion number 5021-0380. Available from <http://h20000.www2.hp.com/bc/docs/

support/SupportManual/bpl13208/bpl13208.pdf>.

[3] Adobe Systems Incorporated. PostScript Language Reference [online]. 3rd edition.

Addison-Wesley Publishing Company. 1999 [cited 29 October 2003]. Available from

<http://www.adobe.com/products/postscript/pdfs/PLRM.pdf>. ISBN

0-201-37922-8.

[4] Case, J & Fedor, M & Schoffstall, M & Davin, J. Simple Network Management

Protocol (SNMP) [online]. RFC 1157. Network Working Group. May 1990 [cited 30

October 2003]. Available from <http://www.ietf.org/rfc/rfc1157.txt>.

[5] Waldbusser, S & Grillo, P. Host Resources MIB [online]. RFC 2790. Network

Working Group. March 2000 [cited 27 October 2003]. Available from <http:

//www.ietf.org/rfc/rfc2790.txt>.

[6] Smith, R & Wright, F & Hastings, T & Zilles, S & Gyllenskog, J. Printer MIB

[online]. RFC 1759. Network Working Group. March 1995 [cited 27 October 2003].

Available from <http://www.ietf.org/rfc/rfc1759.txt>.

[7] Powell, Patrick A. LPRng Reference Manual [online]. San Diego, California,

USA. AStArt Technologies. 5 September 2003 [cited 31 October 2003].

Chap-ter 18. Accounting. Available from <http://www.lprng.com/LPRng-Reference/

LPRng-Reference.html>.

[8] The PostgreSQL Global Development Group. PostgreSQL 7.3 Reference Manual

[online]. 2002 [cited 1 November 2003]. Part I. SQL Commands. Available from

<http://www.postgresql.org/docs/7.3/static/reference.html>.

[9] The PostgreSQL Global Development Group. PostgreSQL 7.3 Programmer’s Guide

[online]. 2002 [cited 1 November 2003]. Chapter 19. PL/pgSQL - SQL

Procedu-ral Language. Available from <http://www.postgresql.org/docs/7.3/static/

programmer.html>.

(54)
(55)

A. LPRng Integration

LPRng can be configured so that an accounting application is executed before and

after the job is sent to the printer [7]. This can be accomplished by using the variables

af, as and ae. Add to lpd.conf the following directives, adjusting the path when

appropriate:

af=|/usr/local/libexec/filters/accounting.pl

as=start

ae=end

In order to be able to trust the name of the user, the workstations that submit jobs

have to be trusted. One way of trusting them is to only allow the administrator to have

superuser access and to let the application that submit print requests (lp or lpr) to have

its user id set to superuser on execution. Then tell LPRng to only allow connections

from ports 1 to 1023, ports that only the superuser can open on the workstations. In

lpd.perms, one could write:

REJECT SERVICE=X NOT PORT=1-1023

Use the accounting namefixup variable in lpd.conf to tell from which workstations

the user name is trusted. This will set the accounting name parameter that LPRng

then passes to the accounting application. As an example, to trust the workstations

on a local subnet and make sure that any other workstation will always get a

non-existing user name ( untrusted), and hence fail due to that it does not exist in the

user database, one could write:

accounting_namefixup=10.0.0.0/24=${L},_unknown;0.0.0.0/0=_untrusted

Of course, one should be more restrictive than this and only allow connections (in

lpd.perms) from the trusted workstations in the first place.

(56)
(57)

B. Source Code of the Accounting and

Status Notification Application

#!/ usr / l o c a l / bin / p e r l use s t r i c t ; use w a r n i n g s ; use DBI ; use M I M E :: L i t e ; use Net :: S N M P ; use T e x t :: W r a p ; my $ d a t e ; my $ t i m e ; my $ t i m e _ m i l l i s e c o n d s ; my $ j o b ; my $ m a i l ; my $ p r i n t e r ; my $ a c c o u n t i n g _ n a m e ; my $ u s e r ; my $ e x i t _ j o b _ f a i l = 1 ; my $ w r a p _ c o l u m n s = 8 0 ; my $ m a i l _ n o _ e n d _ j o b _ s u b j e c t ; my $ m a i l _ n o _ e n d _ j o b _ b o d y ; my $ m a i l _ d o w n _ a t _ s t a r t _ s u b j e c t ; my $ m a i l _ d o w n _ a t _ s t a r t _ b o d y ; my $ m a i l _ d o w n _ a t _ e n d _ s u b j e c t ; my $ m a i l _ d o w n _ a t _ e n d _ b o d y ; my $ m a i l _ e n d _ j o b _ s u b j e c t ; my $ m a i l _ e n d _ j o b _ b o d y ; my $ m a i l _ n o _ a c c e s s _ s u b j e c t ; my $ m a i l _ n o _ a c c e s s _ b o d y ; my $ m a i l _ n o _ q u o t a _ s u b j e c t ; my $ m a i l _ n o _ q u o t a _ b o d y ; my $ a c t i o n ; my $ d b h ; my $ s t h ; my $ s q l _ s e l e c t _ b a l a n c e = q / S E L E C T " b a l a n c e " F R O M " a c c o u n t i n g " . " u s e r s " / . q / W H E R E " u s e r " = ? / ; my $ a r y _ r e f ; my $ b a l a n c e ; my $ s t r i n g ; my $ s q l _ s e l e c t _ p r i n t i n g = q / S E L E C T / . q / t o _ c h a r ( " t i m e s t a m p " , ’ Y Y Y Y - MM - DD H H 2 4 : MI : SS ’ ), " i m p r e s s i o n s " , / . q / " p r i n t e r " , " job " F R O M " a c c o u n t i n g " . " p r i n t i n g " W H E R E " u s e r " =? O R D E R / . q / BY " t i m e s t a m p " D E S C L I M I T 1 0 / ; my $ t b l _ a r y _ r e f ; my $ r o w ; my $ s q l _ s e l e c t _ s u m m a r y = q / S E L E C T t o _ c h a r ( " t i m e s t a m p " , ’ Y Y Y Y ’ ) AS " y e a r " , / . q / t o _ c h a r ( " t i m e s t a m p " , ’ M o n t h ’ ) AS " m o n t h " , sum ( " i m p r e s s i o n s " ) AS / . q / " i m p r e s s i o n s " , c o u n t ( * ) AS " j o b s " , d a t e _ t r u n c ( ’ m o n t h ’ , " t i m e s t a m p " ) / . q / AS " t i m e s t a m p _ t r u n c " F R O M " a c c o u n t i n g " . " p r i n t i n g " W H E R E " u s e r " =? AND / .

(58)

q / age ( d a t e _ t r u n c ( ’ m o n t h ’ , " t i m e s t a m p " ) ) < i n t e r v a l ’ 1 2 m o n t h s ’ G R O U P / . q / BY " y e a r " , " m o n t h " , " t i m e s t a m p _ t r u n c " O R D E R BY t i m e s t a m p _ t r u n c D E S C /; my $ s q l _ s e l e c t _ t r a n s a c t i o n s = q / S E L E C T / . q / t o _ c h a r ( " t i m e s t a m p " , ’ Y Y Y Y - MM - DD H H 2 4 : MI : SS ’ ), " c h a n g e " , " c o m m e n t " / . q / F R O M " a c c o u n t i n g " . " t r a n s a c t i o n s " W H E R E " u s e r " =? O R D E R BY " t i m e s t a m p " / . q / D E S C L I M I T ? / ; my $ t r a n s a c t i o n s _ b a n n e r = 1 0 ; my $ e x i t _ j o b _ s u c c e s s = 0 ; my $ s n m p _ s e s s i o n ; my $ s n m p _ e r r o r ; my $ s n m p _ t i m e o u t = 3 ; # s e c o n d s my $ s n m p _ c o u n t e r _ a v a i l a b l e ; my $ s n m p _ c o u n t e r _ l o o p ; my $ s n m p _ c o u n t e r _ f a i l u r e ; my $ m a i l e d _ a b o u t _ d o w n _ s t a t u s ; my $ s n m p _ c o u n t e r _ d o w n ; my $ s n m p _ c o u n t e r _ l a s t ; my $ s n m p _ m i n _ a v a i l a b l e = 5 ; # t i m e s my $ s n m p _ w a i t = 1 ; # s e c o n d s my $ s n m p _ r e s u l t ; my $ s n m p _ h r _ d e v i c e _ s t a t u s = ’ 1 . 3 . 6 . 1 . 2 . 1 . 2 5 . 3 . 2 . 1 . 5 . 1 ’ ; my $ s n m p _ h r _ p r i n t e r _ s t a t u s = ’ 1 . 3 . 6 . 1 . 2 . 1 . 2 5 . 3 . 5 . 1 . 1 . 1 ’ ; my $ s n m p _ p r t _ m a r k e r _ l i f e _ c o u n t = ’ 1 . 3 . 6 . 1 . 2 . 1 . 4 3 . 1 0 . 2 . 1 . 4 . 1 . 1 ’ ; my $ s n m p _ m a x _ l o o p s = 3 6 0 0 ; # t i m e s my $ s n m p _ m a x _ f a i l u r e s _ a t _ s t a r t = 6 ; # t i m e s in a row my $ s n m p _ m a x _ d o w n s = 1 2 0 ; # t i m e s in a row my $ p r i n t c a p _ e n t r y = $ E N V { ’ P R I N T C A P _ E N T R Y ’ }; my $ j o b _ c r e d i t = 1 ; my $ s q l _ e n d _ j o b = q / S E L E C T " a c c o u n t i n g " . " e n d _ j o b " ( ? , ? , ? ) / ; my $ i m p r e s s i o n s ; my $ t r a n s a c t i o n s _ m a i l = 3 0 ; my $ m s g ; my $ m a i l _ f r o m = ’ P r i n t S p o o l e r < n o b o d y @ e x a m p l e . com >’ ; my $ m a i l _ h o s t = ’ m a i l h o s t ’ ; my $ s m t p _ t i m e o u t = 1 5 ; # s e c o n d s my $ e x i t _ j o b _ r e m o v e = 3 ; my $ t r a n s a c t i o n s ; my $ t r a n s a c t i o n s _ l i n e ; my $ f i l l ; my $ s q l _ s t a r t _ j o b = q / S E L E C T " a c c o u n t i n g " . " s t a r t _ j o b " ( ? , ? , ? , ? , ? ) / ; # get p a r a m e t e r s f o r e a c h ( @ A R G V ) { if ( / ^ - D (\ d { 4 } - \ d { 2 } - \ d { 2 } ) - ( \ d { 2 } : \ d { 2 } : \ d { 2 } ) \ . ( \ d + ) / ) { $ d a t e = $1 ; $ t i m e = $2 ; $ t i m e _ m i l l i s e c o n d s = $3 ; n e x t (); } if ( / ^ - J ( . + ) $ / ) { $ j o b = $1 ; n e x t ( ) ; } if ( / ^ - M ( . + ) $ / ) { $ m a i l = $1 ; n e x t ( ) ; } if ( / ^ - P ( . + ) $ / ) { $ p r i n t e r = $1 ; n e x t ( ) ; } if ( / ^ - R ( . + ) $ / ) { $ a c c o u n t i n g _ n a m e = $1 ; n e x t ( ) ; } if ( / ^ - n ( . + ) $ / ) { $ u s e r = $1 ; n e x t ( ) ; } } # v e r i f y p a r a m e t e r s if ( not ( d e f i n e d ( $ d a t e ) ) ) { w a r n ( ’ Bad or m i s s i n g - D p a r a m e t e r ’ ); e x i t ( $ e x i t _ j o b _ f a i l ); } if ( not ( d e f i n e d ( $ j o b ) ) ) { w a r n ( ’ Bad or m i s s i n g - J p a r a m e t e r ’ ); $ j o b = ’( Job n a m e not a v a i l a b l e )’ ; } if ( not ( d e f i n e d ( $ p r i n t e r ) ) ) { w a r n ( ’ Bad or m i s s i n g - P p a r a m e t e r ’ );

42

(59)

e x i t ( $ e x i t _ j o b _ f a i l ); } if ( not ( d e f i n e d ( $ a c c o u n t i n g _ n a m e ) ) ) { w a r n ( ’ Bad or m i s s i n g - R p a r a m e t e r ’ ); e x i t ( $ e x i t _ j o b _ f a i l ); } if ( not ( d e f i n e d ( $ u s e r ) ) ) { w a r n ( ’ Bad or m i s s i n g - n p a r a m e t e r ’ ); e x i t ( $ e x i t _ j o b _ f a i l ); } # set d e f a u l t s for t e x t w r a p p i n g l o c a l ( $ T e x t :: W r a p :: c o l u m n s ) = $ w r a p _ c o l u m n s ; l o c a l ( $ T e x t :: W r a p :: h u g e ) = ’ o v e r f l o w ’ ;

# s e n t w h e n no m e s s a g e can be s e n t w h e n job has c o m p l e t e d $ m a i l _ n o _ e n d _ j o b _ s u b j e c t =

qq / Job " $ j o b " has not yet c o m p l e t e d on p r i n t e r " $ p r i n t e r " /; $ m a i l _ n o _ e n d _ j o b _ b o d y =

w r a p ( ’’ , ’’ ,

qq / T h i s is an a u t o m a t i c m e s s a g e f r o m the p r i n t s p o o l e r c o n c e r n i n g / . qq / p r i n t e r " $ p r i n t e r " .\ n / .

qq /\ n / .

qq / Job " $ j o b " , f r o m $ d a t e at $ t i m e , has not yet c o m p l e t e d . G i v e n / . qq / up w a i t i n g for job to c o m p l e t e . You w i l l not r e c e i v e a m e s s a g e / . qq / w h e n " $ j o b " has c o m p l e t e d .\ n / .

qq /\ n / .

qq / Do not r e p l y to t h i s m e s s a g e ; all r e p l i e s w i l l b o u n c e .\ n /); # s e n t w h e n d o w n s t a t u s at s t a r t of job

$ m a i l _ d o w n _ a t _ s t a r t _ s u b j e c t =

qq / Job " $ j o b " has not s t a r t e d on p r i n t e r " $ p r i n t e r " /; $ m a i l _ d o w n _ a t _ s t a r t _ b o d y =

w r a p ( ’’ , ’’ ,

qq / T h i s is an a u t o m a t i c m e s s a g e f r o m the p r i n t s p o o l e r c o n c e r n i n g / . qq / p r i n t e r " $ p r i n t e r " .\ n / .

qq /\ n / .

qq / Job " $ j o b " , f r o m $ d a t e at $ t i m e , has not s t a r t e d as p r i n t e r is / . qq / s i g n a l i n g a d o w n s t a t u s . T h i s c o u l d m e a n no p a p e r , p a p e r jam / . qq / or t o n e r out . W i l l k e e p t r y i n g for a w h i l e to s u b m i t " $ j o b " to / . qq / p r i n t e r " $ p r i n t e r " but w i l l e v e n t u a l l y g i v e up .\ n / . qq /\ n / . qq / P l e a s e v e r i f y p r i n t e r c o n d i t i o n and t a k e a p p r o p r i a t e / . qq / m e a s u r e s .\ n / . qq /\ n / . qq / Do not r e p l y to t h i s m e s s a g e ; all r e p l i e s w i l l b o u n c e .\ n /); # s e n t w h e n d o w n s t a t u s at end of job $ m a i l _ d o w n _ a t _ e n d _ s u b j e c t =

qq / Job " $ j o b " has not c o m p l e t e d on p r i n t e r " $ p r i n t e r " /; $ m a i l _ d o w n _ a t _ e n d _ b o d y =

w r a p ( ’’ , ’’ ,

qq / T h i s is an a u t o m a t i c m e s s a g e f r o m the p r i n t s p o o l e r c o n c e r n i n g / . qq / p r i n t e r " $ p r i n t e r " .\ n / .

qq /\ n / .

qq / Job " $ j o b " , f r o m $ d a t e at $ t i m e , has not c o m p l e t e d as p r i n t e r / . qq / is s i g n a l i n g a d o w n s t a t u s . T h i s c o u l d m e a n no p a p e r , p a p e r / . qq / jam or t o n e r out . Y o u r job w i l l not c o m p l e t e u n t i l t h i s is / . qq / t a k e n c a r e of .\ n / . qq /\ n / . qq / P l e a s e v e r i f y p r i n t e r c o n d i t i o n and t a k e a p p r o p r i a t e / . qq / m e a s u r e s .\ n / . qq /\ n / . qq / Do not r e p l y to t h i s m e s s a g e ; all r e p l i e s w i l l b o u n c e .\ n /); # s e n t w h e n job has c o m p l e t e d and u s e r w a n t e d to k n o w a b o u t t h a t

References

Related documents

The increasing availability of data and attention to services has increased the understanding of the contribution of services to innovation and productivity in

Tillväxtanalys har haft i uppdrag av rege- ringen att under år 2013 göra en fortsatt och fördjupad analys av följande index: Ekono- miskt frihetsindex (EFW), som

Närmare 90 procent av de statliga medlen (intäkter och utgifter) för näringslivets klimatomställning går till generella styrmedel, det vill säga styrmedel som påverkar

• Utbildningsnivåerna i Sveriges FA-regioner varierar kraftigt. I Stockholm har 46 procent av de sysselsatta eftergymnasial utbildning, medan samma andel i Dorotea endast

I dag uppgår denna del av befolkningen till knappt 4 200 personer och år 2030 beräknas det finnas drygt 4 800 personer i Gällivare kommun som är 65 år eller äldre i

Det har inte varit möjligt att skapa en tydlig överblick över hur FoI-verksamheten på Energimyndigheten bidrar till målet, det vill säga hur målen påverkar resursprioriteringar

Detta projekt utvecklar policymixen för strategin Smart industri (Näringsdepartementet, 2016a). En av anledningarna till en stark avgränsning är att analysen bygger på djupa

Det finns många initiativ och aktiviteter för att främja och stärka internationellt samarbete bland forskare och studenter, de flesta på initiativ av och med budget från departementet