summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/Makefile1
-rw-r--r--usr/src/cmd/lp/Makefile125
-rw-r--r--usr/src/cmd/lp/Makefile.lp121
-rw-r--r--usr/src/cmd/lp/Makefile.lp.msg33
-rw-r--r--usr/src/cmd/lp/cmd/Makefile95
-rw-r--r--usr/src/cmd/lp/cmd/Makefile.msg35
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/Makefile104
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/chkopts.c1200
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/default.c79
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/do_align.c677
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/do_fault.c46
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/do_mount.c336
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/do_printer.c781
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/do_pwheel.c199
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/done.c44
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/fromclass.c149
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/ismodel.c40
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/lpadmin.c231
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/lpadmin.h139
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/options.c775
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/output.c146
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/pick_opts.c107
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/rmdest.c127
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/send_message.c88
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/signals.c119
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/startup.c50
-rw-r--r--usr/src/cmd/lp/cmd/lpadmin/usage.c139
-rw-r--r--usr/src/cmd/lp/cmd/lpfilter.c916
-rw-r--r--usr/src/cmd/lp/cmd/lpforms.c1438
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/Makefile139
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/alerts.c349
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/cancel.c62
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/daisyforms.c470
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/disena.c129
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/disp1.c1177
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/disp2.c613
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/disp3.c804
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/disp4.c529
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/disp5.c78
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/dispatch.h107
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/disptab.c349
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/dowait.c590
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/exec.c1435
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/faults.c220
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/files.c456
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/flt.c183
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/fncs.c996
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/getkey.c44
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/init.c281
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/log.c220
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/lpfsck.c397
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/lpsched.c441
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/lpsched.h417
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/msgs.c253
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/nodes.h212
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/notify.c215
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/pickfilter.c496
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/ports.c330
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/print-svc167
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/requeue.c271
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/rstatus.c203
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/schedule.c605
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/server.xml136
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/status.c721
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/terminate.c115
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/validate.c1075
-rw-r--r--usr/src/cmd/lp/cmd/lpsched/validate.h80
-rw-r--r--usr/src/cmd/lp/cmd/lpshut.c204
-rw-r--r--usr/src/cmd/lp/cmd/lptest/Makefile71
-rw-r--r--usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE32
-rw-r--r--usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/cmd/lp/cmd/lptest/lptest.c54
-rw-r--r--usr/src/cmd/lp/cmd/lpusers.c215
-rw-r--r--usr/src/cmd/lp/cmd/scripts/Makefile80
-rw-r--r--usr/src/cmd/lp/cmd/scripts/lpsched134
-rw-r--r--usr/src/cmd/lp/cmd/scripts/lpshut41
-rw-r--r--usr/src/cmd/lp/crontab/Makefile46
-rw-r--r--usr/src/cmd/lp/crontab/lp35
-rw-r--r--usr/src/cmd/lp/filter/Makefile56
-rw-r--r--usr/src/cmd/lp/filter/postscript/Makefile64
-rw-r--r--usr/src/cmd/lp/filter/postscript/Makefile.msg35
-rw-r--r--usr/src/cmd/lp/filter/postscript/README306
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/Makefile64
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/README26
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/comments.h154
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/dev.h75
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/ext.h59
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/gen.h69
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/glob.c50
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/misc.c283
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/path.h42
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/request.c158
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/request.h52
-rw-r--r--usr/src/cmd/lp/filter/postscript/common/tempnam.c55
-rw-r--r--usr/src/cmd/lp/filter/postscript/download/Makefile77
-rw-r--r--usr/src/cmd/lp/filter/postscript/download/README31
-rw-r--r--usr/src/cmd/lp/filter/postscript/download/download.c574
-rw-r--r--usr/src/cmd/lp/filter/postscript/download/download.h57
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/Makefile85
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/README53
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/color.c251
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/dpost.c2826
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/dpost.h196
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/draw.c777
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/pictures.c325
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/ps_include.awk31
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/ps_include.c204
-rw-r--r--usr/src/cmd/lp/filter/postscript/dpost/ps_include.ps139
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/Makefile62
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/README30
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/catv.fd34
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/download.fd30
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/dpost.fd39
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/postio.fd29
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/postior.fd29
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/postpages.fd34
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/postprint.fd43
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/postreverse.fd30
-rw-r--r--usr/src/cmd/lp/filter/postscript/filtdesc/pr.fd36
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/Makefile91
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/README139
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/AB122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/AB.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/AI122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/AI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/AR122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/AR.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/AX122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/AX.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/B134
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/B.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/BI130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/BI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CB134
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CB.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CI142
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CO134
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CO.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CW142
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CW.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CX142
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/CX.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/DESC57
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/DESC.big48
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/DESC.small52
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/GR83
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/GR.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/H130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/H.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/HB130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/HB.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/HI130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/HI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/HX130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/HX.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Hb122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Hb.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Hi122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Hi.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Hr122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Hr.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Hx122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Hx.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/I134
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/I.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/KB122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/KB.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/KI122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/KI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/KR122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/KR.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/KX122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/KX.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/LINKFILE51
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/Makefile98
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/NB122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/NB.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/NI122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/NI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/NR122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/NR.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/NX122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/NX.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/PA130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/PA.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/PB130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/PB.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/PI130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/PI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/PX130
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/PX.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/R134
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/R.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/S236
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/S.big228
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/S.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/S.small155
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/S162
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/S1.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/VB126
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/VB.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/VI126
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/VI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/VR126
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/VR.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/VX126
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/VX.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/ZD214
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/ZD.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/ZI122
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/ZI.name1
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/1240
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/1440
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/3440
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/BRACKETS_NOTE58
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Fi26
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Fl26
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/L134
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/L1.map150
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/LH23
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/LH.map871
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Lb34
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Lb.map150
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Makefile62
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/OLD_LH34
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/OLD_LH.map150
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/README47
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Sl126
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/bx34
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ci30
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ff26
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lc58
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lf58
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lh188
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ob30
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rc58
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rf58
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rh179
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/sq34
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/devpost/charlib/~=26
-rw-r--r--usr/src/cmd/lp/filter/postscript/font/makedev.c353
-rw-r--r--usr/src/cmd/lp/filter/postscript/postcomm/Makefile61
-rw-r--r--usr/src/cmd/lp/filter/postscript/postcomm/postcomm.c717
-rw-r--r--usr/src/cmd/lp/filter/postscript/postcomm/postcomm.h211
-rw-r--r--usr/src/cmd/lp/filter/postscript/postio/Makefile71
-rw-r--r--usr/src/cmd/lp/filter/postscript/postio/README75
-rw-r--r--usr/src/cmd/lp/filter/postscript/postio/ifdef.c967
-rw-r--r--usr/src/cmd/lp/filter/postscript/postio/ifdef.h96
-rw-r--r--usr/src/cmd/lp/filter/postscript/postio/parallel.c386
-rw-r--r--usr/src/cmd/lp/filter/postscript/postio/postio.c1246
-rw-r--r--usr/src/cmd/lp/filter/postscript/postio/postio.h251
-rw-r--r--usr/src/cmd/lp/filter/postscript/postio/slowsend.c161
-rw-r--r--usr/src/cmd/lp/filter/postscript/postprint/Makefile77
-rw-r--r--usr/src/cmd/lp/filter/postscript/postprint/README61
-rw-r--r--usr/src/cmd/lp/filter/postscript/postprint/postprint.c926
-rw-r--r--usr/src/cmd/lp/filter/postscript/postprint/postprint.h78
-rw-r--r--usr/src/cmd/lp/filter/postscript/postreverse/Makefile66
-rw-r--r--usr/src/cmd/lp/filter/postscript/postreverse/README32
-rw-r--r--usr/src/cmd/lp/filter/postscript/postreverse/postreverse.c720
-rw-r--r--usr/src/cmd/lp/filter/postscript/postreverse/postreverse.h83
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/Makefile58
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/README31
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/aps.ps149
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/banner.ps64
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/baseline.ps178
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/color.ps87
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/dpost.ps223
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/draw.ps97
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/fatcourier.ps48
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/forms.ps218
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/postprint.ps437
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/ps.requests36
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/tsol_banner.ps30
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/tsol_separator.ps687
-rw-r--r--usr/src/cmd/lp/filter/postscript/postscript/tsol_trailer.ps29
-rw-r--r--usr/src/cmd/lp/filter/slow.filter115
-rw-r--r--usr/src/cmd/lp/include/access.h69
-rw-r--r--usr/src/cmd/lp/include/class.h74
-rw-r--r--usr/src/cmd/lp/include/filters.h248
-rw-r--r--usr/src/cmd/lp/include/form.h111
-rw-r--r--usr/src/cmd/lp/include/lp.h606
-rw-r--r--usr/src/cmd/lp/include/lp.set.h67
-rw-r--r--usr/src/cmd/lp/include/msgs.h442
-rw-r--r--usr/src/cmd/lp/include/oam.h174
-rw-r--r--usr/src/cmd/lp/include/printers.h215
-rw-r--r--usr/src/cmd/lp/include/requests.h141
-rw-r--r--usr/src/cmd/lp/include/secure.h76
-rw-r--r--usr/src/cmd/lp/include/users.h65
-rw-r--r--usr/src/cmd/lp/lib/Makefile74
-rw-r--r--usr/src/cmd/lp/lib/Makefile.msg35
-rw-r--r--usr/src/cmd/lp/lib/access/Makefile67
-rw-r--r--usr/src/cmd/lp/lib/access/allowed.c219
-rw-r--r--usr/src/cmd/lp/lib/access/bang.c238
-rw-r--r--usr/src/cmd/lp/lib/access/change.c220
-rw-r--r--usr/src/cmd/lp/lib/access/dumpaccess.c105
-rw-r--r--usr/src/cmd/lp/lib/access/files.c88
-rw-r--r--usr/src/cmd/lp/lib/access/llib-llpacc58
-rw-r--r--usr/src/cmd/lp/lib/access/loadaccess.c200
-rw-r--r--usr/src/cmd/lp/lib/class/Makefile67
-rw-r--r--usr/src/cmd/lp/lib/class/delclass.c89
-rw-r--r--usr/src/cmd/lp/lib/class/freeclass.c61
-rw-r--r--usr/src/cmd/lp/lib/class/getclass.c124
-rw-r--r--usr/src/cmd/lp/lib/class/llib-llpcls44
-rw-r--r--usr/src/cmd/lp/lib/class/putclass.c84
-rw-r--r--usr/src/cmd/lp/lib/filters/Makefile73
-rw-r--r--usr/src/cmd/lp/lib/filters/conv.c494
-rw-r--r--usr/src/cmd/lp/lib/filters/delfilter.c91
-rw-r--r--usr/src/cmd/lp/lib/filters/dumpfilters.c224
-rw-r--r--usr/src/cmd/lp/lib/filters/filtertable.c85
-rw-r--r--usr/src/cmd/lp/lib/filters/freefilter.c134
-rw-r--r--usr/src/cmd/lp/lib/filters/getfilter.c98
-rw-r--r--usr/src/cmd/lp/lib/filters/insfilter.c869
-rw-r--r--usr/src/cmd/lp/lib/filters/llib-llpflt120
-rw-r--r--usr/src/cmd/lp/lib/filters/loadfilters.c271
-rw-r--r--usr/src/cmd/lp/lib/filters/putfilter.c124
-rw-r--r--usr/src/cmd/lp/lib/filters/regex.c164
-rw-r--r--usr/src/cmd/lp/lib/filters/regex.h39
-rw-r--r--usr/src/cmd/lp/lib/filters/search.c54
-rw-r--r--usr/src/cmd/lp/lib/filters/trash.c50
-rw-r--r--usr/src/cmd/lp/lib/forms/Makefile69
-rw-r--r--usr/src/cmd/lp/lib/forms/delform.c114
-rw-r--r--usr/src/cmd/lp/lib/forms/f_head.c92
-rw-r--r--usr/src/cmd/lp/lib/forms/freeform.c64
-rw-r--r--usr/src/cmd/lp/lib/forms/getform.c153
-rw-r--r--usr/src/cmd/lp/lib/forms/llib-llpfrm62
-rw-r--r--usr/src/cmd/lp/lib/forms/putform.c148
-rw-r--r--usr/src/cmd/lp/lib/forms/rdform.c379
-rw-r--r--usr/src/cmd/lp/lib/forms/wrform.c209
-rw-r--r--usr/src/cmd/lp/lib/lp/Makefile106
-rw-r--r--usr/src/cmd/lp/lib/lp/Sys_malloc.c189
-rw-r--r--usr/src/cmd/lp/lib/lp/Syscalls.c425
-rw-r--r--usr/src/cmd/lp/lib/lp/addlist.c92
-rw-r--r--usr/src/cmd/lp/lib/lp/addstring.c74
-rw-r--r--usr/src/cmd/lp/lib/lp/alerts.c513
-rw-r--r--usr/src/cmd/lp/lib/lp/appendlist.c83
-rw-r--r--usr/src/cmd/lp/lib/lp/charset.c69
-rw-r--r--usr/src/cmd/lp/lib/lp/cs_strcmp.c53
-rw-r--r--usr/src/cmd/lp/lib/lp/cs_strncmp.c55
-rw-r--r--usr/src/cmd/lp/lib/lp/dashos.c83
-rw-r--r--usr/src/cmd/lp/lib/lp/dellist.c85
-rw-r--r--usr/src/cmd/lp/lib/lp/dirs.c63
-rw-r--r--usr/src/cmd/lp/lib/lp/duplist.c75
-rw-r--r--usr/src/cmd/lp/lib/lp/files.c332
-rw-r--r--usr/src/cmd/lp/lib/lp/freelist.c56
-rw-r--r--usr/src/cmd/lp/lib/lp/getlist.c209
-rw-r--r--usr/src/cmd/lp/lib/lp/getname.c106
-rw-r--r--usr/src/cmd/lp/lib/lp/getpaths.c161
-rw-r--r--usr/src/cmd/lp/lib/lp/getspooldir.c41
-rw-r--r--usr/src/cmd/lp/lib/lp/isterminfo.c225
-rw-r--r--usr/src/cmd/lp/lib/lp/joinlist.c55
-rw-r--r--usr/src/cmd/lp/lib/lp/lenlist.c50
-rw-r--r--usr/src/cmd/lp/lib/lp/llib-llp173
-rw-r--r--usr/src/cmd/lp/lib/lp/lp_errno.c28
-rw-r--r--usr/src/cmd/lp/lib/lp/makepath.c113
-rw-r--r--usr/src/cmd/lp/lib/lp/makestr.c108
-rw-r--r--usr/src/cmd/lp/lib/lp/mergelist.c52
-rw-r--r--usr/src/cmd/lp/lib/lp/next.c122
-rw-r--r--usr/src/cmd/lp/lib/lp/printlist.c127
-rw-r--r--usr/src/cmd/lp/lib/lp/sdn.c202
-rw-r--r--usr/src/cmd/lp/lib/lp/searchlist.c111
-rw-r--r--usr/src/cmd/lp/lib/lp/set_charset.c237
-rw-r--r--usr/src/cmd/lp/lib/lp/set_pitch.c210
-rw-r--r--usr/src/cmd/lp/lib/lp/set_size.c428
-rw-r--r--usr/src/cmd/lp/lib/lp/sop.c82
-rw-r--r--usr/src/cmd/lp/lib/lp/sprintlist.c80
-rw-r--r--usr/src/cmd/lp/lib/lp/strip.c58
-rw-r--r--usr/src/cmd/lp/lib/lp/syntax.c172
-rw-r--r--usr/src/cmd/lp/lib/lp/tidbit.c458
-rw-r--r--usr/src/cmd/lp/lib/lp/tx.c151
-rw-r--r--usr/src/cmd/lp/lib/lp/wherelist.c58
-rw-r--r--usr/src/cmd/lp/lib/lp/which.c168
-rw-r--r--usr/src/cmd/lp/lib/msgs/Makefile86
-rw-r--r--usr/src/cmd/lp/lib/msgs/_getmessage.c165
-rw-r--r--usr/src/cmd/lp/lib/msgs/_putmessage.c136
-rw-r--r--usr/src/cmd/lp/lib/msgs/fifo_buffs.c149
-rw-r--r--usr/src/cmd/lp/lib/msgs/getmessage.c60
-rw-r--r--usr/src/cmd/lp/lib/msgs/hslconv.c105
-rw-r--r--usr/src/cmd/lp/lib/msgs/llib-llpmsg116
-rw-r--r--usr/src/cmd/lp/lib/msgs/mclose.c45
-rw-r--r--usr/src/cmd/lp/lib/msgs/mconnect.c204
-rw-r--r--usr/src/cmd/lp/lib/msgs/mcreate.c82
-rw-r--r--usr/src/cmd/lp/lib/msgs/mdestroy.c73
-rw-r--r--usr/src/cmd/lp/lib/msgs/mdisconnect.c141
-rw-r--r--usr/src/cmd/lp/lib/msgs/mgetputm.c186
-rw-r--r--usr/src/cmd/lp/lib/msgs/mlisten.c555
-rw-r--r--usr/src/cmd/lp/lib/msgs/mneeds.c43
-rw-r--r--usr/src/cmd/lp/lib/msgs/mopen.c58
-rw-r--r--usr/src/cmd/lp/lib/msgs/mread.c124
-rw-r--r--usr/src/cmd/lp/lib/msgs/mrecv.c63
-rw-r--r--usr/src/cmd/lp/lib/msgs/msend.c69
-rw-r--r--usr/src/cmd/lp/lib/msgs/msgfmts.c141
-rw-r--r--usr/src/cmd/lp/lib/msgs/mwrite.c209
-rw-r--r--usr/src/cmd/lp/lib/msgs/putmessage.c58
-rw-r--r--usr/src/cmd/lp/lib/msgs/read_fifo.c366
-rw-r--r--usr/src/cmd/lp/lib/msgs/streamio.c172
-rw-r--r--usr/src/cmd/lp/lib/msgs/write_fifo.c91
-rw-r--r--usr/src/cmd/lp/lib/oam/Makefile107
-rw-r--r--usr/src/cmd/lp/lib/oam/agettxt.c61
-rw-r--r--usr/src/cmd/lp/lib/oam/buffers.c34
-rw-r--r--usr/src/cmd/lp/lib/oam/fmtmsg.c248
-rw-r--r--usr/src/cmd/lp/lib/oam/gen-defs63
-rw-r--r--usr/src/cmd/lp/lib/oam/gen-text46
-rw-r--r--usr/src/cmd/lp/lib/oam/llib-llpoam39
-rw-r--r--usr/src/cmd/lp/lib/oam/lp_lib_oam.xcl29
-rw-r--r--usr/src/cmd/lp/lib/oam/msg.source981
-rw-r--r--usr/src/cmd/lp/lib/papi/Makefile81
-rw-r--r--usr/src/cmd/lp/lib/papi/job.c1420
-rw-r--r--usr/src/cmd/lp/lib/papi/library.c98
-rw-r--r--usr/src/cmd/lp/lib/papi/lpsched-jobs.c535
-rw-r--r--usr/src/cmd/lp/lib/papi/lpsched-misc.c189
-rw-r--r--usr/src/cmd/lp/lib/papi/lpsched-msgs.c623
-rw-r--r--usr/src/cmd/lp/lib/papi/lpsched-printers.c496
-rw-r--r--usr/src/cmd/lp/lib/papi/lpsched-service.c47
-rw-r--r--usr/src/cmd/lp/lib/papi/mapfile273
-rw-r--r--usr/src/cmd/lp/lib/papi/papi_impl.h148
-rw-r--r--usr/src/cmd/lp/lib/papi/ppd.c164
-rw-r--r--usr/src/cmd/lp/lib/papi/printer.c516
-rw-r--r--usr/src/cmd/lp/lib/papi/service.c303
-rw-r--r--usr/src/cmd/lp/lib/printers/Makefile73
-rw-r--r--usr/src/cmd/lp/lib/printers/chkprinter.c91
-rw-r--r--usr/src/cmd/lp/lib/printers/default.c78
-rw-r--r--usr/src/cmd/lp/lib/printers/delprinter.c156
-rw-r--r--usr/src/cmd/lp/lib/printers/freeprinter.c89
-rw-r--r--usr/src/cmd/lp/lib/printers/getpentry.c170
-rw-r--r--usr/src/cmd/lp/lib/printers/getprinter.c404
-rw-r--r--usr/src/cmd/lp/lib/printers/llib-llpprt99
-rw-r--r--usr/src/cmd/lp/lib/printers/okprinter.c155
-rw-r--r--usr/src/cmd/lp/lib/printers/p_head.c71
-rw-r--r--usr/src/cmd/lp/lib/printers/printwheels.c249
-rw-r--r--usr/src/cmd/lp/lib/printers/putprinter.c794
-rw-r--r--usr/src/cmd/lp/lib/requests/Makefile68
-rw-r--r--usr/src/cmd/lp/lib/requests/anyrequests.c75
-rw-r--r--usr/src/cmd/lp/lib/requests/freerequest.c81
-rw-r--r--usr/src/cmd/lp/lib/requests/getrequest.c266
-rw-r--r--usr/src/cmd/lp/lib/requests/llib-llpreq59
-rw-r--r--usr/src/cmd/lp/lib/requests/putrequest.c225
-rw-r--r--usr/src/cmd/lp/lib/requests/r_head.c70
-rw-r--r--usr/src/cmd/lp/lib/secure/Makefile64
-rw-r--r--usr/src/cmd/lp/lib/secure/llib-llpsec52
-rw-r--r--usr/src/cmd/lp/lib/secure/secure.c269
-rw-r--r--usr/src/cmd/lp/lib/users/Makefile65
-rw-r--r--usr/src/cmd/lp/lib/users/llib-llpusr59
-rw-r--r--usr/src/cmd/lp/lib/users/loadpri.c254
-rw-r--r--usr/src/cmd/lp/lib/users/storepri.c81
-rw-r--r--usr/src/cmd/lp/lib/users/usermgmt.c148
-rw-r--r--usr/src/cmd/lp/model/Makefile104
-rw-r--r--usr/src/cmd/lp/model/Makefile.msg35
-rw-r--r--usr/src/cmd/lp/model/alert.proto81
-rw-r--r--usr/src/cmd/lp/model/drain.output.c100
-rw-r--r--usr/src/cmd/lp/model/lp.cat.c699
-rw-r--r--usr/src/cmd/lp/model/lp.set.c144
-rw-r--r--usr/src/cmd/lp/model/lp.tell.c501
-rw-r--r--usr/src/cmd/lp/model/lp.tsol_separator.c528
-rw-r--r--usr/src/cmd/lp/model/netpr/Makefile113
-rw-r--r--usr/src/cmd/lp/model/netpr/bsd_misc.c278
-rw-r--r--usr/src/cmd/lp/model/netpr/misc.c165
-rw-r--r--usr/src/cmd/lp/model/netpr/net.c377
-rw-r--r--usr/src/cmd/lp/model/netpr/netdebug.h51
-rw-r--r--usr/src/cmd/lp/model/netpr/netpr.c482
-rw-r--r--usr/src/cmd/lp/model/netpr/netpr.h174
-rw-r--r--usr/src/cmd/lp/model/netpr/tcp_misc.c208
-rw-r--r--usr/src/cmd/lp/model/netstandard644
-rw-r--r--usr/src/cmd/lp/model/standard1078
-rw-r--r--usr/src/cmd/lp/model/tsol_netstandard751
-rw-r--r--usr/src/cmd/lp/model/tsol_netstandard_foomatic788
-rw-r--r--usr/src/cmd/lp/model/tsol_standard1162
-rw-r--r--usr/src/cmd/lp/model/tsol_standard_foomatic1190
-rwxr-xr-xusr/src/cmd/lp/model/uri253
-rw-r--r--usr/src/cmd/lp/terminfo/40.ti68
-rw-r--r--usr/src/cmd/lp/terminfo/44x.ti57
-rw-r--r--usr/src/cmd/lp/terminfo/45x.ti42
-rw-r--r--usr/src/cmd/lp/terminfo/477.ti181
-rw-r--r--usr/src/cmd/lp/terminfo/47x.ti134
-rw-r--r--usr/src/cmd/lp/terminfo/495.ti78
-rw-r--r--usr/src/cmd/lp/terminfo/53x0.ti81
-rw-r--r--usr/src/cmd/lp/terminfo/57x.ti105
-rw-r--r--usr/src/cmd/lp/terminfo/58x.ti103
-rw-r--r--usr/src/cmd/lp/terminfo/593.ti73
-rw-r--r--usr/src/cmd/lp/terminfo/Makefile77
-rw-r--r--usr/src/cmd/lp/terminfo/PS.ti36
-rw-r--r--usr/src/cmd/lp/terminfo/citoh.ti127
-rw-r--r--usr/src/cmd/lp/terminfo/daisy.ti126
-rw-r--r--usr/src/cmd/lp/terminfo/dec.ti130
-rw-r--r--usr/src/cmd/lp/terminfo/epson.ti301
-rw-r--r--usr/src/cmd/lp/terminfo/hplaser.ti122
-rw-r--r--usr/src/cmd/lp/terminfo/ibm.ti353
-rw-r--r--usr/src/cmd/lp/terminfo/unknown.ti30
-rw-r--r--usr/src/cmd/print/Makefile106
-rw-r--r--usr/src/cmd/print/Makefile.sp105
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/Makefile110
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/accept.c117
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/cancel.c255
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/common.c678
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/common.h70
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/disable.c163
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/enable.c117
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/in.lpd.c786
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/lp.c334
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/lpc.c561
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/lpmove.c210
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/lpq.c134
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/lpr.c276
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/lprm.c101
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/lpstat.c1444
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/reject.c122
-rw-r--r--usr/src/cmd/print/bsd-sysv-commands/rfc1179.xml110
-rw-r--r--usr/src/cmd/print/conv_fix/Makefile69
-rw-r--r--usr/src/cmd/print/conv_fix/conv_fix.c149
-rw-r--r--usr/src/cmd/print/lpget/Makefile68
-rw-r--r--usr/src/cmd/print/lpget/lpget.c174
-rw-r--r--usr/src/cmd/print/lpset/Makefile69
-rw-r--r--usr/src/cmd/print/lpset/lpset.c544
-rw-r--r--usr/src/cmd/print/ppdmgr/Makefile53
-rw-r--r--usr/src/cmd/print/ppdmgr/ppd-cache-update40
-rw-r--r--usr/src/cmd/print/ppdmgr/ppd-cache-update.xml90
-rw-r--r--usr/src/cmd/print/printer-info/Makefile68
-rw-r--r--usr/src/cmd/print/printer-info/printer-info.c196
-rw-r--r--usr/src/cmd/print/printmgr/Makefile87
-rw-r--r--usr/src/cmd/print/printmgr/bin/Makefile51
-rw-r--r--usr/src/cmd/print/printmgr/bin/printmgr.sh38
-rw-r--r--usr/src/cmd/print/printmgr/com/Makefile46
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/Makefile46
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/Makefile46
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/Makefile46
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/BST.java327
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/BSTItem.java109
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/Constants.java75
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/Makefile144
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/help-l10n-comments.txt242
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helpTest.java196
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/extract43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/parseMain.java811
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/parsehelp.sh83
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/images/appicon.gifbin0 -> 422 bytes
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAboutBox.java117
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAccess.java518
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAddAccessFailedException.java43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAddPrinterFailedException.java40
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAuthOptions.java423
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmButton.java216
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmButtonScreen.java175
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmCacheMissingPPDException.java43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmCalls.java158
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDelete.java183
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDeleteFailedException.java43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDialog.java125
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDialogConstraints.java43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmFindFrame.java221
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmFrame.java133
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmGuiException.java55
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpContent.java52
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpController.java101
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpDetailPanel.java597
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpException.java38
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpFrame.java101
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpIndexPanel.java383
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpItem.java92
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpRepository.java294
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpSearchPanel.java451
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmIncompleteFormException.java43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmInstallPrinter.java2194
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmInstallScreen.java494
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLoad.java275
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLogDisplay.java244
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLogin.java423
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLoginFailedException.java43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmMessageDialog.java206
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmModifyPrinterFailedException.java40
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmMustBeRemoteServerException.java43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmNeedPPDCacheException.java44
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmNullSelectedPrinterException.java39
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmOKCancelDialog.java242
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmOther.java232
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmPrinterExistsException.java39
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmResources.java614
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmTextField.java86
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmTop.java1303
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmUserCancelledException.java43
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmUtility.java216
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pm_gen_copyright64
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddAccess.rawhlp97
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddAccessFailed.rawhlp62
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddPrinterFailed.rawhlp68
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/DeletePrinterFailed.rawhlp56
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/HelpOnHelp.rawhlp127
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallLocal.rawhlp171
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallLocalPPD.rawhlp177
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallNetwork.rawhlp176
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallNetworkPPD.rawhlp187
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp132
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LoginFailed.rawhlp59
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/MainWindow.rawhlp116
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/Modify.rawhlp167
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ModifyFailed.rawhlp62
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ModifyPPD.rawhlp176
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/NISAuthentication.rawhlp97
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/NameService.rawhlp155
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/Overview.rawhlp122
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrintManagerSettings.rawhlp111
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrinterPort.rawhlp67
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrinterType.rawhlp64
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/RemoteServer.rawhlp53
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ShowCommandConsole.rawhlp84
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToAddAccess.rawhlp141
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToConfirmActions.rawhlp66
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToDelete.rawhlp81
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToExit.rawhlp53
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToFindPrinter.rawhlp68
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToInstallLocal.rawhlp176
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToInstallNetwork.rawhlp181
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToModify.rawhlp119
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToSelectName.rawhlp83
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToShowCommand.rawhlp75
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToStart.rawhlp81
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Debug.java314
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterAdd.java552
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterDelete.java197
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterMod.java841
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterNS.c276
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterNS.java626
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterUtil.java557
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterView.java485
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Host.java351
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Makefile126
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/NS.c821
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/NameService.java140
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Printer.java497
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/PrinterDebug.java126
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/PrinterUtil.java206
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/SysCommand.java245
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Test.java369
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Valid.java395
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmAuthException.java45
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmAuthRhostException.java47
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmCmdFailedException.java45
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmException.java44
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmHostNotPingableException.java45
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmInternalErrorException.java47
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmMisc.java46
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmNSNotConfiguredException.java46
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmtest28
-rw-r--r--usr/src/cmd/print/printmgr/com/sun/admin/pm/server/tests/template27
-rw-r--r--usr/src/cmd/print/scripts/Makefile149
-rw-r--r--usr/src/cmd/print/scripts/Makefile.yp58
-rw-r--r--usr/src/cmd/print/scripts/conv_lp102
-rw-r--r--usr/src/cmd/print/scripts/conv_lpd213
-rw-r--r--usr/src/cmd/print/scripts/desktop-print-management34
-rw-r--r--usr/src/cmd/print/scripts/desktop-print-management-applet32
-rw-r--r--usr/src/cmd/print/scripts/desktop-print-management-applet.desktop37
-rw-r--r--usr/src/cmd/print/scripts/desktop-print-management-prefs33
-rw-r--r--usr/src/cmd/print/scripts/desktop-print-management-prefs.desktop56
-rw-r--r--usr/src/cmd/print/scripts/desktop-print-management.desktop47
-rw-r--r--usr/src/cmd/print/scripts/getmakes37
-rw-r--r--usr/src/cmd/print/scripts/getmodels45
-rw-r--r--usr/src/cmd/print/scripts/getppdfile88
-rw-r--r--usr/src/cmd/print/scripts/getppds104
-rw-r--r--usr/src/cmd/print/scripts/lpadmin403
-rw-r--r--usr/src/cmd/print/scripts/lpsystem33
-rw-r--r--usr/src/cmd/print/scripts/manufaliases32
-rw-r--r--usr/src/cmd/print/scripts/ppdfilename2mmp100
-rw-r--r--usr/src/cmd/print/scripts/ppdmgr1765
-rw-r--r--usr/src/cmd/print/scripts/printers.conf31
-rw-r--r--usr/src/cmd/print/selector/Makefile54
-rwxr-xr-xusr/src/cmd/print/selector/desktop-print-management-applet90
-rwxr-xr-xusr/src/cmd/print/selector/print-service298
-rw-r--r--usr/src/lib/print/Makefile94
-rw-r--r--usr/src/lib/print/libhttp-core/Makefile56
-rw-r--r--usr/src/lib/print/libhttp-core/Makefile.com63
-rw-r--r--usr/src/lib/print/libhttp-core/common/LICENSE.txt964
-rw-r--r--usr/src/lib/print/libhttp-core/common/LICENSE.txt.descrip1
-rw-r--r--usr/src/lib/print/libhttp-core/common/debug.h70
-rw-r--r--usr/src/lib/print/libhttp-core/common/http-addr.c371
-rw-r--r--usr/src/lib/print/libhttp-core/common/http-private.h115
-rw-r--r--usr/src/lib/print/libhttp-core/common/http-support.c379
-rw-r--r--usr/src/lib/print/libhttp-core/common/http.c2569
-rw-r--r--usr/src/lib/print/libhttp-core/common/http.h439
-rw-r--r--usr/src/lib/print/libhttp-core/common/mapfile71
-rw-r--r--usr/src/lib/print/libhttp-core/i386/Makefile30
-rw-r--r--usr/src/lib/print/libhttp-core/sparc/Makefile30
-rw-r--r--usr/src/lib/print/libipp-core/Makefile56
-rw-r--r--usr/src/lib/print/libipp-core/Makefile.com59
-rw-r--r--usr/src/lib/print/libipp-core/common/ipp.c136
-rw-r--r--usr/src/lib/print/libipp-core/common/ipp.h348
-rw-r--r--usr/src/lib/print/libipp-core/common/ipp_types.c303
-rw-r--r--usr/src/lib/print/libipp-core/common/mapfile60
-rw-r--r--usr/src/lib/print/libipp-core/common/read.c666
-rw-r--r--usr/src/lib/print/libipp-core/common/strings.c411
-rw-r--r--usr/src/lib/print/libipp-core/common/write.c415
-rw-r--r--usr/src/lib/print/libipp-core/i386/Makefile30
-rw-r--r--usr/src/lib/print/libipp-core/sparc/Makefile30
-rw-r--r--usr/src/lib/print/libipp-listener/Makefile56
-rw-r--r--usr/src/lib/print/libipp-listener/Makefile.com68
-rw-r--r--usr/src/lib/print/libipp-listener/common/cancel-job.c96
-rw-r--r--usr/src/lib/print/libipp-listener/common/common.c309
-rw-r--r--usr/src/lib/print/libipp-listener/common/create-job.c108
-rw-r--r--usr/src/lib/print/libipp-listener/common/cups-accept-jobs.c68
-rw-r--r--usr/src/lib/print/libipp-listener/common/cups-get-classes.c90
-rw-r--r--usr/src/lib/print/libipp-listener/common/cups-get-default.c81
-rw-r--r--usr/src/lib/print/libipp-listener/common/cups-get-printers.c91
-rw-r--r--usr/src/lib/print/libipp-listener/common/cups-move-job.c103
-rw-r--r--usr/src/lib/print/libipp-listener/common/cups-reject-jobs.c68
-rw-r--r--usr/src/lib/print/libipp-listener/common/disable-printer.c77
-rw-r--r--usr/src/lib/print/libipp-listener/common/enable-printer.c68
-rw-r--r--usr/src/lib/print/libipp-listener/common/get-job-attributes.c89
-rw-r--r--usr/src/lib/print/libipp-listener/common/get-jobs.c99
-rw-r--r--usr/src/lib/print/libipp-listener/common/get-printer-attributes.c92
-rw-r--r--usr/src/lib/print/libipp-listener/common/hold-job.c96
-rw-r--r--usr/src/lib/print/libipp-listener/common/ipp-listener.c520
-rw-r--r--usr/src/lib/print/libipp-listener/common/ipp-listener.h70
-rw-r--r--usr/src/lib/print/libipp-listener/common/mapfile52
-rw-r--r--usr/src/lib/print/libipp-listener/common/pause-printer.c68
-rw-r--r--usr/src/lib/print/libipp-listener/common/print-job.c184
-rw-r--r--usr/src/lib/print/libipp-listener/common/purge-jobs.c71
-rw-r--r--usr/src/lib/print/libipp-listener/common/release-job.c95
-rw-r--r--usr/src/lib/print/libipp-listener/common/restart-job.c106
-rw-r--r--usr/src/lib/print/libipp-listener/common/resume-printer.c68
-rw-r--r--usr/src/lib/print/libipp-listener/common/send-document.c143
-rw-r--r--usr/src/lib/print/libipp-listener/common/set-job-attributes.c90
-rw-r--r--usr/src/lib/print/libipp-listener/common/set-printer-attributes.c83
-rw-r--r--usr/src/lib/print/libipp-listener/common/validate-job.c107
-rw-r--r--usr/src/lib/print/libipp-listener/i386/Makefile30
-rw-r--r--usr/src/lib/print/libipp-listener/sparc/Makefile30
-rw-r--r--usr/src/lib/print/libpapi-common/Makefile57
-rw-r--r--usr/src/lib/print/libpapi-common/Makefile.com56
-rw-r--r--usr/src/lib/print/libpapi-common/common/attribute.c1119
-rw-r--r--usr/src/lib/print/libpapi-common/common/common.c135
-rw-r--r--usr/src/lib/print/libpapi-common/common/config-site.h60
-rw-r--r--usr/src/lib/print/libpapi-common/common/config.h159
-rw-r--r--usr/src/lib/print/libpapi-common/common/library.c105
-rw-r--r--usr/src/lib/print/libpapi-common/common/list.c177
-rw-r--r--usr/src/lib/print/libpapi-common/common/mapfile168
-rw-r--r--usr/src/lib/print/libpapi-common/common/misc.c224
-rw-r--r--usr/src/lib/print/libpapi-common/common/papi.h452
-rw-r--r--usr/src/lib/print/libpapi-common/common/status.c133
-rw-r--r--usr/src/lib/print/libpapi-common/common/uri.c300
-rw-r--r--usr/src/lib/print/libpapi-common/common/uri.h66
-rw-r--r--usr/src/lib/print/libpapi-common/i386/Makefile30
-rw-r--r--usr/src/lib/print/libpapi-common/sparc/Makefile30
-rw-r--r--usr/src/lib/print/libpapi-dynamic/Makefile56
-rw-r--r--usr/src/lib/print/libpapi-dynamic/Makefile.com57
-rw-r--r--usr/src/lib/print/libpapi-dynamic/common/job.c457
-rw-r--r--usr/src/lib/print/libpapi-dynamic/common/mapfile279
-rw-r--r--usr/src/lib/print/libpapi-dynamic/common/nss.c532
-rw-r--r--usr/src/lib/print/libpapi-dynamic/common/papi_impl.h97
-rw-r--r--usr/src/lib/print/libpapi-dynamic/common/printer.c513
-rw-r--r--usr/src/lib/print/libpapi-dynamic/common/psm.c95
-rw-r--r--usr/src/lib/print/libpapi-dynamic/common/service.c572
-rw-r--r--usr/src/lib/print/libpapi-dynamic/i386/Makefile30
-rw-r--r--usr/src/lib/print/libpapi-dynamic/sparc/Makefile30
-rw-r--r--usr/src/lib/print/libpapi-ipp/Makefile56
-rw-r--r--usr/src/lib/print/libpapi-ipp/Makefile.com71
-rw-r--r--usr/src/lib/print/libpapi-ipp/common/ipp-support.c631
-rw-r--r--usr/src/lib/print/libpapi-ipp/common/job.c666
-rw-r--r--usr/src/lib/print/libpapi-ipp/common/mapfile292
-rw-r--r--usr/src/lib/print/libpapi-ipp/common/papi_impl.h111
-rw-r--r--usr/src/lib/print/libpapi-ipp/common/printer.c430
-rw-r--r--usr/src/lib/print/libpapi-ipp/common/service.c394
-rw-r--r--usr/src/lib/print/libpapi-ipp/i386/Makefile30
-rw-r--r--usr/src/lib/print/libpapi-ipp/sparc/Makefile30
-rw-r--r--usr/src/lib/print/libpapi-lpd/Makefile56
-rw-r--r--usr/src/lib/print/libpapi-lpd/Makefile.com94
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/job.c312
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/library.c90
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/lpd-cancel.c121
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/lpd-job.c626
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/lpd-misc.c206
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/lpd-port.c823
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/lpd-query.c507
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/mapfile322
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/papi_impl.h111
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/printer.c220
-rw-r--r--usr/src/lib/print/libpapi-lpd/common/service.c299
-rw-r--r--usr/src/lib/print/libpapi-lpd/i386/Makefile31
-rw-r--r--usr/src/lib/print/libpapi-lpd/sparc/Makefile31
-rw-r--r--usr/src/lib/print/libprint/Makefile54
-rw-r--r--usr/src/lib/print/libprint/Makefile.com58
-rw-r--r--usr/src/lib/print/libprint/common/list.c189
-rw-r--r--usr/src/lib/print/libprint/common/list.h50
-rw-r--r--usr/src/lib/print/libprint/common/llib-lprint141
-rw-r--r--usr/src/lib/print/libprint/common/mapfile-vers86
-rw-r--r--usr/src/lib/print/libprint/common/ns.c187
-rw-r--r--usr/src/lib/print/libprint/common/ns.h202
-rw-r--r--usr/src/lib/print/libprint/common/ns_bsd_addr.c571
-rw-r--r--usr/src/lib/print/libprint/common/ns_cmn_kvp.c262
-rw-r--r--usr/src/lib/print/libprint/common/ns_cmn_printer.c157
-rw-r--r--usr/src/lib/print/libprint/common/nss_convert.c207
-rw-r--r--usr/src/lib/print/libprint/common/nss_ldap.c2477
-rw-r--r--usr/src/lib/print/libprint/common/nss_printer.c151
-rw-r--r--usr/src/lib/print/libprint/common/nss_write.c325
-rw-r--r--usr/src/lib/print/libprint/common/sunPrinter.at.conf.txt64
-rw-r--r--usr/src/lib/print/libprint/common/sunPrinter.oc.conf.txt116
-rw-r--r--usr/src/lib/print/libprint/i386/Makefile30
-rw-r--r--usr/src/lib/print/libprint/sparc/Makefile30
-rw-r--r--usr/src/lib/print/mod_ipp/Makefile95
-rw-r--r--usr/src/lib/print/mod_ipp/httpd-standalone-ipp.conf341
-rw-r--r--usr/src/lib/print/mod_ipp/index.html44
-rw-r--r--usr/src/lib/print/mod_ipp/ipp-listener.xml84
-rw-r--r--usr/src/lib/print/mod_ipp/mapfile52
-rw-r--r--usr/src/lib/print/mod_ipp/mod_ipp.c552
-rw-r--r--usr/src/pkg/manifests/SUNWippcore.mf29
-rw-r--r--usr/src/pkg/manifests/SUNWippl.mf29
-rw-r--r--usr/src/pkg/manifests/SUNWlp-cmds.mf28
-rw-r--r--usr/src/pkg/manifests/SUNWlpr-cmds.mf28
-rw-r--r--usr/src/pkg/manifests/SUNWps.mf1
-rw-r--r--usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf4
-rw-r--r--usr/src/pkg/manifests/library-print-open-printing-ipp.mf185
-rw-r--r--usr/src/pkg/manifests/library-print-open-printing-lpd.mf46
-rw-r--r--usr/src/pkg/manifests/library-print-open-printing.mf55
-rw-r--r--usr/src/pkg/manifests/print-lp-compatibility-sunos4.mf47
-rw-r--r--usr/src/pkg/manifests/print-lp-filter-postscript-lp-filter.mf63
-rw-r--r--usr/src/pkg/manifests/print-lp-ipp-ipp-listener.mf61
-rw-r--r--usr/src/pkg/manifests/print-lp-ipp-libipp.mf44
-rw-r--r--usr/src/pkg/manifests/print-lp-print-client-commands.mf84
-rw-r--r--usr/src/pkg/manifests/print-lp-print-manager-legacy.mf79
-rw-r--r--usr/src/pkg/manifests/print-lp.mf171
-rw-r--r--usr/src/pkg/manifests/system-trusted.mf14
-rw-r--r--usr/src/pkg/manifests/text-doctools.mf162
818 files changed, 159097 insertions, 0 deletions
diff --git a/usr/src/cmd/Makefile b/usr/src/cmd/Makefile
index 338b9fe056..5aa255deb0 100644
--- a/usr/src/cmd/Makefile
+++ b/usr/src/cmd/Makefile
@@ -820,6 +820,7 @@ _dc: $(DCSUBDIRS)
fs.d: fstyp
ksh: shcomp isaexec
mdb: terminfo
+print: lp
$(FIRST_SUBDIRS) $(BWOSDIRS) $(SUBDIRS) $(AUDITSUBDIRS): FRC
@if [ -f $@/Makefile ]; then \
diff --git a/usr/src/cmd/lp/Makefile b/usr/src/cmd/lp/Makefile
new file mode 100644
index 0000000000..e18469f38a
--- /dev/null
+++ b/usr/src/cmd/lp/Makefile
@@ -0,0 +1,125 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+#
+
+include ./Makefile.lp
+
+SUBDIRS = filter crontab lib cmd model
+
+MSGSUBDIRS = filter lib cmd model
+
+ROOTDIRS = \
+ $(ROOTLIBLP) \
+ $(ROOTLIBLP)/bin \
+ $(ROOTLIBLP)/model \
+ $(ROOTLIBLPLOCL) \
+ $(ROOTLIB)/print \
+ $(LPOWNSDIRS)
+LPOWNSDIRS = \
+ $(ROOTETCLP) \
+ $(ROOTETCLP)/classes \
+ $(ROOTETCLP)/forms \
+ $(ROOTETCLP)/interfaces \
+ $(ROOTETCLP)/printers \
+ $(ROOTETCLP)/pwheels \
+ $(ROOTETCLP)/ppd \
+ $(ROOTVAR)/lp \
+ $(ROOTVAR)/lp/logs \
+ $(ROOTVARSP)/lp \
+ $(ROOTVARSP)/lp/admins \
+ $(ROOTVARSP)/lp/requests \
+ $(ROOTVARSP)/lp/system
+
+SYMDIR1 = $(ROOTVARSP)/lp/admins/lp
+SYMDIR2 = $(ROOTVARSP)/lp/bin
+SYMDIR3 = $(ROOTVARSP)/lp/logs
+SYMDIR4 = $(ROOTETCLP)/logs
+SYMDIR5 = $(ROOTVARSP)/lp/model
+
+$(SYMDIR1) := SYMLNKDEST = ../../../../etc/lp
+$(SYMDIR2) := SYMLNKDEST = ../../../usr/lib/lp/bin
+$(SYMDIR3) := SYMLNKDEST = ../../lp/logs
+$(SYMDIR4) := SYMLNKDEST = ../../var/lp/logs
+$(SYMDIR5) := SYMLNKDEST = ../../../usr/lib/lp/model
+
+ROOTSYMLINKDIRS = $(SYMDIR1) $(SYMDIR2) $(SYMDIR3) $(SYMDIR4) $(SYMDIR5)
+
+$(ROOTVAR)/lp := DIRMODE = 775
+$(ROOTVAR)/lp/logs := DIRMODE = 775
+$(ROOTETCLP) := DIRMODE = 775
+$(ROOTETCLP)/classes := DIRMODE = 775
+$(ROOTETCLP)/forms := DIRMODE = 775
+$(ROOTETCLP)/interfaces := DIRMODE = 775
+$(ROOTETCLP)/printers := DIRMODE = 775
+$(ROOTETCLP)/pwheels := DIRMODE = 775
+$(ROOTETCLP)/ppd := DIRMODE = 775
+$(ROOTVARSP)/lp := DIRMODE = 775
+$(ROOTVARSP)/lp/admins := DIRMODE = 775
+$(ROOTVARSP)/lp/requests := DIRMODE = 775
+$(ROOTVARSP)/lp/system := DIRMODE = 775
+$(ROOTLIB)/print := DIRMODE = 0755
+
+POFILE= lp.po
+POFILES= lp_*.po
+
+.KEEP_STATE:
+
+all: $(TXTS) $(SUBDIRS)
+
+#
+# Each message catalog file is generated in each sub
+# directory and copied to the usr/src/cmd/lp/ directory.
+# Those message catalog files are consolidated into one
+# message catalog file. The consolidated one will be copied
+# into the $(ROOT)/catalog/SUNW_OST_OSCMD/ directory.
+#
+
+_msg: $(MSGDOMAINPOFILE)
+
+$(POFILE): $(MSGSUBDIRS) pofile_POFILES
+
+install: $(ROOTDIRS) $(ROOTSYMLINKDIRS) $(SUBDIRS)
+
+clean strip lint: $(SUBDIRS)
+
+clobber: $(SUBDIRS) local_clobber
+
+local_clobber:
+ $(RM) $(CLOBBERFILES)
+
+$(ROOTDIRS) :
+ $(INS.dir)
+
+$(ROOTSYMLINKDIRS) :
+ -$(RM) $@; $(SYMLINK) $(SYMLNKDEST) $@
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/cmd/lp/Makefile.lp b/usr/src/cmd/lp/Makefile.lp
new file mode 100644
index 0000000000..90814cf119
--- /dev/null
+++ b/usr/src/cmd/lp/Makefile.lp
@@ -0,0 +1,121 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# cmd/lp/Makefile.lp
+# Common makefile definitions (should be) used by all lp makefiles
+#
+
+include $(SRC)/cmd/Makefile.cmd
+
+LPROOT= $(SRC)/cmd/lp
+ROOTVAR= $(ROOT)/var
+ROOTVARSP= $(ROOT)/var/spool
+
+ROOTETCLP= $(ROOTETC)/lp
+ROOTLIBLP= $(ROOTLIB)/lp
+ROOTBINLP= $(ROOTBIN)/lp
+ROOTLIBLPPOST = $(ROOTLIBLP)/postscript
+ROOTLIBLPLOCL = $(ROOTLIBLP)/local
+
+ROOTUSRUCB= $(ROOT)/usr/ucb
+
+
+#
+# $(EMODES): Modes for executables
+# $(SMODES): Modes for setuid executables
+# $(DMODES): Modes for directories
+#
+EMODES = 0555
+SMODES = 04555
+DMODES = 0775
+
+
+INC = $(ROOT)/usr/include
+INCSYS = $(INC)/sys
+
+LPINC = $(SRC)/cmd/lp/include
+LPLIB = $(SRC)/cmd/lp/lib
+
+LIBACC = $(LPLIB)/access/liblpacc.a
+LIBCLS = $(LPLIB)/class/liblpcls.a
+LIBFLT = $(LPLIB)/filters/liblpflt.a
+LIBFRM = $(LPLIB)/forms/liblpfrm.a
+LIBLP = $(LPLIB)/lp/liblp.a
+LIBMSG = $(LPLIB)/msgs/liblpmsg.a
+LIBOAM = $(LPLIB)/oam/liblpoam.a
+LIBPRT = $(LPLIB)/printers/liblpprt.a
+LIBREQ = $(LPLIB)/requests/liblpreq.a
+LIBSEC = $(LPLIB)/secure/liblpsec.a
+LIBUSR = $(LPLIB)/users/liblpusr.a
+
+LINTACC = $(LPLIB)/access/llib-llpacc.ln
+LINTCLS = $(LPLIB)/class/llib-llpcls.ln
+LINTFLT = $(LPLIB)/filters/llib-llpflt.ln
+LINTFRM = $(LPLIB)/forms/llib-llpfrm.ln
+LINTLP = $(LPLIB)/lp/llib-llp.ln
+LINTMSG = $(LPLIB)/msgs/llib-llpmsg.ln
+LINTOAM = $(LPLIB)/oam/llib-llpoam.ln
+LINTPRT = $(LPLIB)/printers/llib-llpprt.ln
+LINTREQ = $(LPLIB)/requests/llib-llpreq.ln
+LINTSEC = $(LPLIB)/secure/llib-llpsec.ln
+LINTUSR = $(LPLIB)/users/llib-llpusr.ln
+
+CERRWARN += -_gcc=-Wno-sequence-point
+CERRWARN += -_gcc=-Wno-implicit-function-declaration
+CERRWARN += -_gcc=-Wno-parentheses
+CERRWARN += -_gcc=-Wno-uninitialized
+CERRWARN += -_gcc=-Wno-unused-variable
+CERRWARN += -_gcc=-Wno-unused-value
+CERRWARN += -_gcc=-Wno-unused-label
+CERRWARN += -_gcc=-Wno-unused-function
+CERRWARN += -_gcc=-Wno-clobbered
+CERRWARN += -_gcc=-Wno-empty-body
+CERRWARN += -_gcc=-Wno-extra
+CERRWARN += -_gcc=-Wno-address
+
+all:= TARGET= all
+install:= TARGET= install
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+lint:= TARGET= lint
+strip:= TARGET= strip
+catalog:= TARGET= catalog
+_msg:= TARGET= catalog
+
+ROOTLIBLPPROG= $(PROG:%=$(ROOTLIBLP)/%)
+ROOTBINLPPROG= $(PROG:%=$(ROOTBINLP)/%)
+ROOTETCLPPROG= $(PROG:%=$(ROOTETCLP)/%)
+ROOTUSRUCBPROG= $(PROG:%=$(ROOTUSRUCB)/%)
+ROOTLIBLPPOSTPROG= $(PROG:%=$(ROOTLIBLPPOST)/%)
+ROOTLIBLPLOCLPROG= $(PROG:%=$(ROOTLIBLPLOCL)/%)
+
+$(ROOTLIBLP)/% \
+$(ROOTBINLP)/% \
+$(ROOTETCLP)/% \
+$(ROOTUSRUCB)/% \
+$(ROOTLIBLPPOST)/% $(ROOTLIBLPLOCL)/%: %
+ $(INS.file)
diff --git a/usr/src/cmd/lp/Makefile.lp.msg b/usr/src/cmd/lp/Makefile.lp.msg
new file mode 100644
index 0000000000..07ca9b6dff
--- /dev/null
+++ b/usr/src/cmd/lp/Makefile.lp.msg
@@ -0,0 +1,33 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2002-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/Makefile.lp.msg
+
+$(POFILE): $(POFILES)
+ $(BUILDPO.pofiles)
+
+include $(SRC)/Makefile.msg.targ
diff --git a/usr/src/cmd/lp/cmd/Makefile b/usr/src/cmd/lp/cmd/Makefile
new file mode 100644
index 0000000000..54b6369a00
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/Makefile
@@ -0,0 +1,95 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.lp
+
+SUBDIRS = lptest lpadmin lpsched scripts
+
+LOCALPROG = lpshut
+
+SBINPROG = lpfilter lpforms lpusers
+
+LIBLINKS = $(SBINPROG)
+
+PROG = $(LOCALPROG) $(SBINPROG)
+
+OBJS= $(SBINPROG:=.o)
+
+SRCS= $(OBJS:.o=.c)
+
+POFILE= lp_cmd.po
+POFILES= $(SRCS:%.c=%.po) lpschedlpshut.po
+
+ROOTLIBLPLOCLPROG= $(LOCALPROG:%=$(ROOTLIBLPLOCL)/%)
+ROOTSBINPROG= $(SBINPROG:%=$(ROOTUSRSBIN)/%)
+ROOTSYMLINKS= $(LIBLINKS:%=$(ROOTLIB)/%)
+
+
+CPPFLAGS = -I$(LPINC) $(CPPFLAGS.master)
+LDFLAGS += $(MAPFILE.NGB:%=-M%)
+
+# conditional assignments
+#
+lpfilter:= LDLIBS += $(LIBFLT) $(LIBMSG) $(LIBACC) $(LIBOAM) $(LIBLP) \
+ -lgen -lsecdb
+lpforms:= LDLIBS += $(LIBFRM) $(LIBMSG) $(LIBREQ) $(LIBOAM) \
+ $(LIBACC) $(LIBLP) -lsecdb
+lpshut:= LDLIBS += $(LIBMSG) $(LIBOAM) $(LIBLP)
+lpusers:= LDLIBS += $(LIBMSG) $(LIBACC) $(LIBOAM) $(LIBUSR) $(LIBLP)
+
+.KEEP_STATE:
+
+all: $(PROG) $(SUBDIRS)
+
+install: $(PROG) $(ROOTLIBLPLOCLPROG) $(ROOTSBINPROG) \
+ $(ROOTSYMLINKS) $(SUBDIRS)
+
+catalog: $(SUBDIRS) $(POFILE)
+ $(CP) $(POFILE) ..
+
+clean: $(SUBDIRS)
+ $(RM) $(OBJS)
+
+clobber: $(SUBDIRS) local_clobber
+
+local_clobber:
+ $(RM) $(OBJS) $(PROG) $(CLOBBERFILES)
+
+strip: $(SUBDIRS)
+ $(STRIP) $(PROG)
+
+lint:
+ $(LINT.c) $(SRCS) $(LDLIBS)
+
+$(ROOTSYMLINKS):
+ $(RM) $@; $(SYMLINK) ../sbin/$(@F) $@
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+include ../Makefile.lp.msg
+
+FRC:
diff --git a/usr/src/cmd/lp/cmd/Makefile.msg b/usr/src/cmd/lp/cmd/Makefile.msg
new file mode 100644
index 0000000000..55da7c46d3
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/Makefile.msg
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/cmd/Makefile.msg
+
+POFILES = $(OBJS:%.o=%.po)
+
+include ../../Makefile.lp.msg
+
+catalog: $(POFILE)
+ $(CP) $(POFILE) ../..
diff --git a/usr/src/cmd/lp/cmd/lpadmin/Makefile b/usr/src/cmd/lp/cmd/lpadmin/Makefile
new file mode 100644
index 0000000000..ace6fc7acf
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/Makefile
@@ -0,0 +1,104 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/cmd/lpadmin/Makefile
+#
+
+include ../../Makefile.lp
+
+CPPFLAGS = -D_REENTRANT -I. -I$(LPINC) $(CPPFLAGS.master)
+
+SRCS= chkopts.c \
+ default.c \
+ do_align.c \
+ do_fault.c \
+ do_mount.c \
+ do_printer.c \
+ do_pwheel.c \
+ done.c \
+ fromclass.c \
+ ismodel.c \
+ lpadmin.c \
+ options.c \
+ output.c \
+ pick_opts.c \
+ rmdest.c \
+ send_message.c \
+ signals.c \
+ startup.c \
+ usage.c
+
+OBJS= $(SRCS:.c=.o)
+
+LPLIBS= $(LIBACC) \
+ $(LIBCLS) \
+ $(LIBMSG) \
+ $(LIBPRT) \
+ $(LIBFRM) \
+ $(LIBREQ) \
+ $(LIBOAM) \
+ $(LIBLP)
+
+SYSLIBS= -lcurses
+
+LDLIBS += -lsecdb $(LPLIBS) $(SYSLIBS) $(I18N)
+LDFLAGS += $(MAPFILE.NGB:%=-M%)
+
+PROG= lpadmin
+
+
+#ROOTSYMLINK= $(ROOTLIBPROG)
+
+POFILE= lp_cmd_lpadmin.po
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS) $(MAPFILE.NGB)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTLIBLPLOCLPROG) #$(ROOTSYMLINK)
+
+#$(ROOTSYMLINK):
+# $(RM) $@; $(SYMLINK) ../sbin/$(PROG) $@
+
+clean:
+ $(RM) $(OBJS)
+
+clobber: clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint:
+ $(LINT.c) $(SRCS) $(LDLIBS)
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/cmd/lpadmin/chkopts.c b/usr/src/cmd/lp/cmd/lpadmin/chkopts.c
new file mode 100644
index 0000000000..caf021c84f
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/chkopts.c
@@ -0,0 +1,1200 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdio.h"
+#include "string.h"
+#include "pwd.h"
+#include "sys/types.h"
+#include "errno.h"
+
+#include "lp.h"
+#include "printers.h"
+#include "form.h"
+#include "class.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+#define PPDZIP ".gz"
+
+
+extern PRINTER *printer_pointer;
+
+extern PWHEEL *pwheel_pointer;
+
+extern struct passwd *getpwnam();
+
+void chkopts2(),
+ chkopts3();
+static void chksys();
+
+FORM formbuf;
+
+char **f_allow,
+ **f_deny,
+ **u_allow,
+ **u_deny,
+ **p_add,
+ **p_remove;
+
+PRINTER *oldp = 0;
+
+PWHEEL *oldS = 0;
+
+short daisy = 0;
+
+static int root_can_write();
+
+static char *unpack_sdn();
+
+static char ** bad_list;
+
+#if defined(__STDC__)
+static unsigned long sum_chkprinter ( char ** , char * , char * , char * , char * , char * );
+static int isPPD(char *ppd_file);
+#else
+static unsigned long sum_chkprinter();
+static int isPPD();
+#endif
+
+/**
+ ** chkopts() -- CHECK LEGALITY OF COMMAND LINE OPTIONS
+ **/
+
+void chkopts ()
+{
+ short isfAuto = 0;
+
+ /*
+ * Check -d.
+ */
+ if (d) {
+ if (
+ a || c || f || P || j || m || M || t || p || r || u || x
+#if defined(DIRECT_ACCESS)
+ || C
+#endif
+#ifdef LP_USE_PAPI_ATTR
+ || n_opt
+#endif
+ || strlen(modifications)
+ ) {
+ LP_ERRMSG (ERROR, E_ADM_DALONE);
+ done (1);
+ }
+
+ if (
+ *d
+ && !STREQU(d, NAME_NONE)
+ && !isprinter(d)
+ && !isclass(d)
+ ) {
+ LP_ERRMSG1 (ERROR, E_ADM_NODEST, d);
+ done (1);
+ }
+ return;
+ }
+
+ /*
+ * Check -x.
+ */
+ if (x) {
+ if ( /* MR bl88-02718 */
+ A || a || c || f || P || j || m || M || t || p || r || u || d
+#if defined(DIRECT_ACCESS)
+ || C
+#endif
+#ifdef LP_USE_PAPI_ATTR
+ || n_opt
+#endif
+ || strlen(modifications)
+ ) {
+ LP_ERRMSG (ERROR, E_ADM_XALONE);
+ done (1);
+ }
+
+ if (
+ !STREQU(NAME_ALL, x)
+ && !STREQU(NAME_ANY, x)
+ && !isprinter(x)
+ && !isclass(x)
+ ) {
+ LP_ERRMSG1 (ERROR, E_ADM_NODEST, x);
+ done (1);
+ }
+ return;
+ }
+
+ /*
+ * Problems common to both -p and -S (-S alone).
+ */
+ if (A && STREQU(A, NAME_LIST) && (W != -1 || Q != -1)) {
+ LP_ERRMSG (ERROR, E_ADM_LISTWQ);
+ done (1);
+ }
+
+
+ /*
+ * Check -S.
+ */
+ if (!p && S) {
+ if (
+ M || t || a || f || P || c || r || e || i || m || H || h
+ || l || v || I || T || D || F || u || U || j || o
+#ifdef LP_USE_PAPI_ATTR
+ || n_opt
+#endif
+ ) {
+ LP_ERRMSG (ERROR, E_ADM_SALONE);
+ done (1);
+ }
+ if (!A && W == -1 && Q == -1) {
+ LP_ERRMSG (ERROR, E_ADM_NOAWQ);
+ done (1);
+ }
+ if (S[0] && S[1])
+ LP_ERRMSG (WARNING, E_ADM_ASINGLES);
+ if (!STREQU(NAME_ALL, *S) && !STREQU(NAME_ANY, *S))
+ chkopts3(1);
+ return;
+ }
+
+ /*
+ * At this point we must have a printer (-p option).
+ */
+ if (!p) {
+ LP_ERRMSG (ERROR, E_ADM_NOACT);
+ done (1);
+ }
+ if (STREQU(NAME_NONE, p)) {
+ LP_ERRMSG1 (ERROR, E_LP_NULLARG, "p");
+ done (1);
+ }
+
+
+ /*
+ * Mount but nothing to mount?
+ */
+ if (M && (!f && !S)) {
+ LP_ERRMSG (ERROR, E_ADM_MNTNONE);
+ done (1);
+ }
+
+ /*
+ * -Q isn't allowed with -p.
+ */
+ if (Q != -1) {
+ LP_ERRMSG (ERROR, E_ADM_PNOQ);
+ done (1);
+ }
+
+ /*
+ * Fault recovery.
+ */
+ if (
+ F
+ && !STREQU(F, NAME_WAIT)
+ && !STREQU(F, NAME_BEGINNING)
+ && (
+ !STREQU(F, NAME_CONTINUE)
+ || j
+ && STREQU(F, NAME_CONTINUE)
+ )
+ ) {
+#if defined(J_OPTION)
+ if (j)
+ LP_ERRMSG (ERROR, E_ADM_FBADJ);
+ else
+#endif
+ LP_ERRMSG (ERROR, E_ADM_FBAD);
+ done (1);
+ }
+
+#if defined(J_OPTION)
+ /*
+ * The -j option is used only with the -F option.
+ */
+ if (j) {
+ if (M || t || a || f || P || c || r || e || i || m || H || h ||
+#ifdef LP_USE_PAPI_ATTR
+ n_opt ||
+#endif
+ l || v || I || T || D || u || U || o) {
+ LP_ERRMSG (ERROR, E_ADM_JALONE);
+ done (1);
+ }
+ if (j && !F) {
+ LP_ERRMSG (ERROR, E_ADM_JNOF);
+ done (1);
+ }
+ return;
+ }
+#endif
+
+#if defined(DIRECT_ACCESS)
+ /*
+ * -C is only used to modify -u
+ */
+ if (C && !u) {
+ LP_ERRMSG (ERROR, E_ADM_CNOU);
+ done (1);
+ }
+#endif
+
+ /*
+ * The -a option needs the -M and -f options,
+ * Also, -ofilebreak is used only with -a.
+ */
+ if (a && (!M || !f)) {
+ LP_ERRMSG (ERROR, E_ADM_MALIGN);
+ done (1);
+ }
+ if (filebreak && !a)
+ LP_ERRMSG (WARNING, E_ADM_FILEBREAK);
+
+ /*
+ * The "-p all" case is restricted to certain options.
+ */
+ if (
+ (STREQU(NAME_ANY, p) || STREQU(NAME_ALL, p))
+ && (
+ a || h || l || M || t || D || e || f || P || H || s
+#ifdef LP_USE_PAPI_ATTR
+ || n_opt
+#endif
+ || i || I || m || S || T || u || U || v || banner != -1
+ || cpi || lpi || width || length || stty_opt
+ )
+ ) {
+ LP_ERRMSG (ERROR, E_ADM_ANYALLNONE);
+ done (1);
+
+ }
+
+ /*
+ * Allow giving -v or -U option as way of making
+ * remote printer into local printer.
+ * Note: "!s" here means the user has not given the -s;
+ * later it means the user gave -s local-system.
+ */
+ if (!s && (v || U))
+ s = Local_System;
+
+ /*
+ * Be careful about checking "s" before getting here.
+ * We want "s == 0" to mean this is a local printer; however,
+ * if the user wants to change a remote printer to a local
+ * printer, we have to have "s == Local_System" long enough
+ * to get into "chkopts2()" where a special check is made.
+ * After "chkopts2()", "s == 0" means local.
+ */
+ if (!STREQU(NAME_ALL, p) && !STREQU(NAME_ANY, p))
+ /*
+ * If old printer, make sure it exists. If new printer,
+ * check that the name is okay, and that enough is given.
+ * (This stuff has been moved to "chkopts2()".)
+ */
+ chkopts2(1);
+
+ if (!s) {
+
+ /*
+ * Only one of -i, -m, -e.
+ */
+ if ((i && e) || (m && e) || (i && m)) {
+ LP_ERRMSG (ERROR, E_ADM_INTCONF);
+ done (1);
+ }
+
+ /*
+ * Check -e arg.
+ */
+ if (e) {
+ if (!isprinter(e)) {
+ LP_ERRMSG1 (ERROR, E_ADM_NOPR, e);
+ done (1);
+ }
+ if (strcmp(e, p) == 0) {
+ LP_ERRMSG (ERROR, E_ADM_SAMEPE);
+ done (1);
+ }
+ }
+
+ /*
+ * Check -m arg.
+ */
+ if (m && !ismodel(m)) {
+ LP_ERRMSG1 (ERROR, E_ADM_NOMODEL, m);
+ done (1);
+ }
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * Check -n arg. The ppd file exists.
+ */
+ if ((n_opt != NULL) && !isPPD(n_opt)) {
+ LP_ERRMSG1 (ERROR, E_ADM_NOPPD, n_opt);
+ done (1);
+ }
+#endif
+
+ /*
+ * Need exactly one of -h or -l (but will default -h).
+ */
+ if (h && l) {
+ LP_ERRMSG2 (ERROR, E_ADM_CONFLICT, 'h', 'l');
+ done (1);
+ }
+ if (!h && !l)
+ h = 1;
+
+ /*
+ * Check -c and -r.
+ */
+ if (c && r && strcmp(c, r) == 0) {
+ LP_ERRMSG (ERROR, E_ADM_SAMECR);
+ done (1);
+ }
+
+
+ /*
+ * Are we creating a class with the same name as a printer?
+ */
+ if (c) {
+ if (STREQU(c, p)) {
+ LP_ERRMSG1 (ERROR, E_ADM_CLNPR, c);
+ done (1);
+ }
+ if (isprinter(c)) {
+ LP_ERRMSG1 (ERROR, E_ADM_CLPR, c);
+ done (1);
+ }
+ }
+
+ if (v && (is_printer_uri(v) < 0)) {
+ /*
+ * The device must be writeable by root.
+ */
+ if (v && root_can_write(v) == -1)
+ done (1);
+ }
+
+ /*
+ * Can't have both device and dial-out.
+ */
+ if (v && U) {
+ LP_ERRMSG (ERROR, E_ADM_BOTHUV);
+ done (1);
+ }
+
+ } else
+ if (
+ A || a || e || H || h || i || l || m || ( t && !M) || ( M && !t)
+ || o || U || v || Q != -1 || W != -1
+#ifdef LP_USE_PAPI_ATTR
+ || n_opt
+#endif
+ ) {
+ LP_ERRMSG (ERROR, E_ADM_NOTLOCAL);
+ done(1);
+ }
+
+
+ /*
+ * We need the printer type for some things, and the boolean
+ * "daisy" (from Terminfo) for other things.
+ */
+ if (!T && oldp)
+ T = oldp->printer_types;
+ if (T) {
+ short a_daisy;
+
+ char ** pt;
+
+
+ if (lenlist(T) > 1 && searchlist(NAME_UNKNOWN, T)) {
+ LP_ERRMSG (ERROR, E_ADM_MUNKNOWN);
+ done (1);
+ }
+
+ for (pt = T; *pt; pt++)
+ if (tidbit(*pt, (char *)0) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_BADTYPE, *pt);
+ done (1);
+ }
+
+ /*
+ * All the printer types had better agree on whether the
+ * printer takes print wheels!
+ */
+ daisy = a_daisy = -1;
+ for (pt = T; *pt; pt++) {
+ tidbit (*pt, "daisy", &daisy);
+ if (daisy == -1)
+ daisy = 0;
+ if (a_daisy == -1)
+ a_daisy = daisy;
+ else if (a_daisy != daisy) {
+ LP_ERRMSG (ERROR, E_ADM_MIXEDTYPES);
+ done (1);
+ }
+ }
+ }
+ if (cpi || lpi || length || width || S || f || filebreak)
+ if (!T) {
+ LP_ERRMSG (ERROR, E_ADM_TOPT);
+ done (1);
+
+ }
+
+ /*
+ * Check -o cpi=, -o lpi=, -o length=, -o width=
+ */
+ if (cpi || lpi || length || width) {
+ unsigned long rc;
+
+ if ((rc = sum_chkprinter(T, cpi, lpi, length, width, NULL)) == 0) {
+ if (bad_list)
+ LP_ERRMSG1 (
+ INFO,
+ E_ADM_NBADCAPS,
+ sprintlist(bad_list)
+ );
+
+ } else {
+ if ((rc & PCK_CPI) && cpi)
+ LP_ERRMSG1 (ERROR, E_ADM_BADCAP, "cpi=");
+
+ if ((rc & PCK_LPI) && lpi)
+ LP_ERRMSG1 (ERROR, E_ADM_BADCAP, "lpi=");
+
+ if ((rc & PCK_WIDTH) && width)
+ LP_ERRMSG1 (ERROR, E_ADM_BADCAP, "width=");
+
+ if ((rc & PCK_LENGTH) && length)
+ LP_ERRMSG1 (ERROR, E_ADM_BADCAP, "length=");
+
+ LP_ERRMSG (ERROR, E_ADM_BADCAPS);
+ done(1);
+ }
+ }
+
+ /*
+ * Check -I (old or new):
+ */
+ if (T && lenlist(T) > 1) {
+
+#define BADILIST(X) (lenlist(X) > 1 || X && *X && !STREQU(NAME_SIMPLE, *X))
+ if (
+ I && BADILIST(I)
+ || !I && oldp && BADILIST(oldp->input_types)
+ ) {
+ LP_ERRMSG (ERROR, E_ADM_ONLYSIMPLE);
+ done (1);
+ }
+ }
+
+ /*
+ * MOUNT:
+ * Only one print wheel can be mounted at a time.
+ */
+ if (M && S && S[0] && S[1])
+ LP_ERRMSG (WARNING, E_ADM_MSINGLES);
+
+ /*
+ * NO MOUNT:
+ * If the printer takes print wheels, the -S argument
+ * should be a simple list; otherwise, it must be a
+ * mapping list. (EXCEPT: In either case, "none" alone
+ * means delete the existing list.)
+ */
+ if (S && !M) {
+ register char **item,
+ *cp;
+
+ /*
+ * For us to be here, "daisy" must have been set.
+ * (-S requires knowing printer type (T), and knowing
+ * T caused call to "tidbit()" to set "daisy").
+ */
+ if (!STREQU(S[0], NAME_NONE) || S[1])
+ if (daisy) {
+ for (item = S; *item; item++) {
+ if (strchr(*item, '=')) {
+ LP_ERRMSG (ERROR, E_ADM_PWHEELS);
+ done (1);
+ }
+ if (!syn_name(*item)) {
+ LP_ERRMSG1 (ERROR, E_LP_NOTNAME, *item);
+ done (1);
+ }
+ }
+ } else {
+ register int die = 0;
+
+ for (item = S; *item; item++) {
+ if (!(cp = strchr(*item, '='))) {
+ LP_ERRMSG (ERROR, E_ADM_CHARSETS);
+ done (1);
+ }
+
+ *cp = 0;
+ if (!syn_name(*item)) {
+ LP_ERRMSG1 (ERROR, E_LP_NOTNAME, *item);
+ done (1);
+ }
+ if (PCK_CHARSET & sum_chkprinter(T, (char *)0, (char *)0, (char *)0, (char *)0, *item)) {
+ LP_ERRMSG1 (ERROR, E_ADM_BADSET, *item);
+ die = 1;
+ } else {
+ if (bad_list)
+ LP_ERRMSG2 (
+ INFO,
+ E_ADM_NBADSET,
+ *item,
+ sprintlist(bad_list)
+ );
+ }
+ *cp++ = '=';
+ if (!syn_name(cp)) {
+ LP_ERRMSG1 (ERROR, E_LP_NOTNAME, cp);
+ done (1);
+ }
+ }
+ if (die) {
+ LP_ERRMSG (ERROR, E_ADM_BADSETS);
+ done (1);
+ }
+ }
+ }
+
+ if (P) {
+ int createForm = 0;
+ char **plist;
+
+ if (getform(P, &formbuf, (FALERT *)0, (FILE **)0) != -1) {
+ if ((!formbuf.paper) || (!STREQU(formbuf.paper,P)) ) {
+ LP_ERRMSG (ERROR, E_ADM_ALSO_SEP_FORM);
+ done (1);
+ }
+ } else
+ createForm = 1;
+
+ if (*P == '~') { /* removing types of papers */
+ P++;
+ p_remove = getlist(P, LP_WS, LP_SEP);
+ p_add = NULL;
+ } else { /* adding types of papers */
+ p_add = getlist(P, LP_WS, LP_SEP);
+ p_remove = NULL;
+ if (createForm) {
+ char cmdBuf[200];
+
+ for (plist = p_add; *plist; plist++) {
+ snprintf(cmdBuf, sizeof (cmdBuf),
+ "lpforms -f %s -d\n", *plist);
+ system(cmdBuf);
+ }
+ }
+ }
+
+ if (!f && !M) { /* make paper allowed on printer too */
+ f = Malloc(strlen(P) + strlen(NAME_ALLOW) +
+ strlen(": "));
+ sprintf(f, "%s:%s", NAME_ALLOW, P);
+ isfAuto = 1;
+ }
+ }
+ /*
+ * NO MOUNT:
+ * The -f option restricts the forms that can be used with
+ * the printer.
+ * - construct the allow/deny lists
+ * - check each allowed form to see if it'll work
+ * on the printer
+ */
+ if (f && !M) {
+ register char *type = strtok(f, ":"),
+ *str = strtok((char *)0, ":"),
+ **pf;
+
+ register int die = 0;
+
+
+ if (STREQU(type, NAME_ALLOW) && str) {
+ if ((pf = f_allow = getlist(str, LP_WS, LP_SEP)) != NULL) {
+ while (*pf) {
+ if ((!isfAuto) &&
+ !STREQU(*pf, NAME_NONE)
+ && verify_form(*pf) < 0
+ )
+ die = 1;
+ pf++;
+ }
+ if (die) {
+ LP_ERRMSG (ERROR, E_ADM_FORMCAPS);
+ done (1);
+ }
+
+ } else
+ LP_ERRMSG1 (WARNING, E_ADM_MISSING, NAME_ALLOW);
+
+ } else if (STREQU(type, NAME_DENY) && str) {
+ if ((pf = f_deny = getlist(str, LP_WS, LP_SEP)) != NULL) {
+ if (!STREQU(*pf, NAME_ALL)) {
+ while (*pf) {
+ if ((!isfAuto) &&
+ !STREQU(*pf, NAME_NONE) &&
+ getform(*pf, &formbuf,
+ (FALERT *)0, (FILE **)0) < 0
+ ) {
+ LP_ERRMSG2(WARNING,
+ E_ADM_ICKFORM, *pf, p);
+ die = 1;
+ }
+ pf++;
+ }
+ }
+ if (die) {
+ done (1);
+ }
+
+ } else
+ LP_ERRMSG1 (WARNING, E_ADM_MISSING, NAME_DENY);
+
+ } else {
+ LP_ERRMSG (ERROR, E_ADM_FALLOWDENY);
+ done (1);
+ }
+ }
+
+ /*
+ * The -u option is setting use restrictions on printers.
+ * - construct the allow/deny lists
+ */
+ if (u) {
+ register char *type = strtok(u, ":"),
+ *str = strtok((char *)0, ":");
+
+ if (STREQU(type, NAME_ALLOW) && str) {
+ if (!(u_allow = getlist(str, LP_WS, LP_SEP)))
+ LP_ERRMSG1 (WARNING, E_ADM_MISSING, NAME_ALLOW);
+
+ } else if (STREQU(type, NAME_DENY) && str) {
+ if (!(u_deny = getlist(str, LP_WS, LP_SEP)))
+ LP_ERRMSG1 (WARNING, E_ADM_MISSING, NAME_DENY);
+
+ } else {
+ LP_ERRMSG (ERROR, E_LP_UALLOWDENY);
+ done (1);
+ }
+ }
+
+ return;
+}
+
+/**
+ ** root_can_write() - CHECK THAT "root" CAN SENSIBLY WRITE TO PATH
+ **/
+
+static int root_can_write (path)
+ char *path;
+{
+ static int lp_uid = -1;
+
+ struct passwd *ppw;
+
+ struct stat statbuf;
+
+
+ if (lstat(path, &statbuf) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_NOENT, v);
+ return (-1);
+ }
+ /*
+ * If the device is a symlink (and it is not a root owned symlink),
+ * verify that the owner matches the destination owner.
+ */
+ if (S_ISLNK(statbuf.st_mode) && statbuf.st_uid != 0) {
+ uid_t uid = statbuf.st_uid;
+
+ if (Stat(path, &statbuf) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_NOENT, v);
+ return (-1);
+ }
+
+ if (statbuf.st_uid != uid) {
+ LP_ERRMSG1 (ERROR, E_ADM_ISMISMATCH, v);
+ done(1);
+ }
+
+ LP_ERRMSG1(WARNING, E_ADM_ISNOTROOTOWNED, v);
+ }
+
+ if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
+ LP_ERRMSG1 (WARNING, E_ADM_ISDIR, v);
+ } else if ((statbuf.st_mode & S_IFMT) == S_IFBLK)
+ LP_ERRMSG1 (WARNING, E_ADM_ISBLK, v);
+
+ if (lp_uid == -1) {
+ if (!(ppw = getpwnam(LPUSER)))
+ ppw = getpwnam(ROOTUSER);
+ endpwent ();
+ if (ppw)
+ lp_uid = ppw->pw_uid;
+ else
+ lp_uid = 0;
+ }
+ if (!STREQU(v, "/dev/null"))
+ if ((statbuf.st_uid && statbuf.st_uid != lp_uid)
+ || (statbuf.st_mode & (S_IWGRP|S_IRGRP|S_IWOTH|S_IROTH)))
+ LP_ERRMSG1 (WARNING, E_ADM_DEVACCESS, v);
+
+ return (0);
+}
+
+/**
+ ** unpack_sdn() - TURN SCALED TYPE INTO char* TYPE
+ **/
+
+static char *unpack_sdn (sdn)
+ SCALED sdn;
+{
+ register char *cp;
+ extern char *malloc();
+
+ if (sdn.val <= 0 || 99999 < sdn.val)
+ cp = 0;
+
+ else if (sdn.val == N_COMPRESSED)
+ cp = strdup(NAME_COMPRESSED);
+
+ else if ((cp = malloc(sizeof("99999.999x"))))
+ (void) sprintf(cp, "%.3f%c", sdn.val, sdn.sc);
+
+ return (cp);
+}
+
+/**
+ ** verify_form() - SEE IF PRINTER CAN HANDLE FORM
+ **/
+
+int verify_form (form)
+ char *form;
+{
+ register char *cpi_f,
+ *lpi_f,
+ *width_f,
+ *length_f,
+ *chset;
+
+ register int rc = 0;
+ char **paperAllowed = NULL;
+ char **paperDenied = NULL;
+
+ register unsigned long checks;
+
+
+ if (STREQU(form, NAME_ANY))
+ form = NAME_ALL;
+
+ while (getform(form, &formbuf, (FALERT *)0, (FILE **)0) != -1) {
+ if (formbuf.paper) {
+ if (!paperAllowed) {
+ load_paperprinter_access(p, &paperAllowed,
+ &paperDenied);
+ freelist(paperDenied);
+ }
+ if (!allowed(formbuf.paper,paperAllowed,NULL)) {
+ LP_ERRMSG1 (INFO, E_ADM_BADCAP,
+ gettext("printer doesn't support paper type"));
+ rc = -1;
+ }
+ }
+ else {
+
+ cpi_f = unpack_sdn(formbuf.cpi);
+ lpi_f = unpack_sdn(formbuf.lpi);
+ width_f = unpack_sdn(formbuf.pwid);
+ length_f = unpack_sdn(formbuf.plen);
+
+ if (
+ formbuf.mandatory
+ && !daisy
+ && !search_cslist(
+ formbuf.chset,
+ (S && !M? S : (oldp? oldp->char_sets : (char **)0))
+ )
+ )
+ chset = formbuf.chset;
+ else
+ chset = 0;
+
+ if ((checks = sum_chkprinter(
+ T,
+ cpi_f,
+ lpi_f,
+ length_f,
+ width_f,
+ chset
+ ))) {
+ rc = -1;
+ if ((checks & PCK_CPI) && cpi_f)
+ LP_ERRMSG1 (INFO, E_ADM_BADCAP, "cpi");
+
+ if ((checks & PCK_LPI) && lpi_f)
+ LP_ERRMSG1 (INFO, E_ADM_BADCAP, "lpi");
+
+ if ((checks & PCK_WIDTH) && width_f)
+ LP_ERRMSG1 (INFO, E_ADM_BADCAP, "width");
+
+ if ((checks & PCK_LENGTH) && length_f)
+ LP_ERRMSG1 (INFO, E_ADM_BADCAP, "length");
+
+ if ((checks & PCK_CHARSET) && formbuf.chset) {
+ LP_ERRMSG1 (INFO, E_ADM_BADSET, formbuf.chset);
+ rc = -2;
+ }
+ LP_ERRMSG1 (INFO, E_ADM_FORMCAP, formbuf.name);
+ } else {
+ if (bad_list)
+ LP_ERRMSG2 (
+ INFO,
+ E_ADM_NBADMOUNT,
+ formbuf.name,
+ sprintlist(bad_list)
+ );
+ }
+ }
+
+ if (!STREQU(form, NAME_ALL)) {
+ if (paperAllowed)
+ freelist(paperAllowed);
+ return (rc);
+ }
+
+ }
+ if (paperAllowed)
+ freelist(paperAllowed);
+
+ if (!STREQU(form, NAME_ALL)) {
+ LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
+ done (1);
+ }
+
+ return (rc);
+}
+
+/*
+ Second phase of parsing for -p option.
+ In a seperate routine so we can call it from other
+ routines. This is used when any or all are used as
+ a printer name. main() loops over each printer, and
+ must call this function for each printer found.
+*/
+void
+chkopts2(called_from_chkopts)
+int called_from_chkopts;
+{
+ /*
+ Only do the getprinter() if we are not being called
+ from lpadmin.c. Otherwise we mess up our arena for
+ "all" processing.
+ */
+ if (!called_from_chkopts)
+ oldp = printer_pointer;
+ else if (!(oldp = getprinter(p)) && errno != ENOENT) {
+ LP_ERRMSG2 (ERROR, E_LP_GETPRINTER, p, PERROR);
+ done(1);
+ }
+
+ if (oldp) {
+ if (
+ !c && !d && !f && !P && !M && !t && !r && !u && !x && !A
+ && !strlen(modifications)
+ ) {
+ LP_ERRMSG (ERROR, E_ADM_PLONELY);
+ done (1);
+ }
+
+ /*
+ * For the case "-s local-system", we need to keep
+ * "s != 0" long enough to get here, where it keeps
+ * us from taking the old value. After this, we make
+ * "s == 0" to indicate this is a local printer.
+ */
+ if (s && s != Local_System)
+ chksys(s);
+ if (!s && oldp->remote && *(oldp->remote))
+ s = strdup(oldp->remote);
+ if (s == Local_System)
+ s = 0;
+
+ /*
+ * A remote printer converted to a local printer
+ * requires device or dial info.
+ */
+ if (!s && oldp->remote && !v && !U) {
+ LP_ERRMSG (ERROR, E_ADM_NOUV);
+ done (1);
+ }
+
+
+ } else {
+ if (getclass(p)) {
+ LP_ERRMSG1 (ERROR, E_ADM_PRCL, p);
+ done (1);
+ }
+
+ if (!syn_name(p)) {
+ LP_ERRMSG1 (ERROR, E_LP_NOTNAME, p);
+ done (1);
+ }
+
+ if (s == Local_System)
+ s = 0;
+ if (s)
+ chksys(s);
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * New printer - if no model and a PPD file is defined then
+ * use 'standard_foomatic' otherwise use
+ * the 'standard' model.
+ */
+ if (!(e || i || m) && !s) {
+ if (n_opt != NULL) {
+ m = STANDARD_FOOMATIC;
+ } else {
+ m = STANDARD;
+ }
+ }
+#else
+ /*
+ * New printer - if no model, use standard
+ */
+ if (!(e || i || m) && !s)
+ m = STANDARD;
+#endif
+
+ /*
+ * A new printer requires device or dial info.
+ */
+ if (!v && !U && !s) {
+ LP_ERRMSG (ERROR, E_ADM_NOUV);
+ done (1);
+ }
+
+ /*
+ * Can't quiet a new printer,
+ * can't list the alerting for a new printer.
+ */
+ if (
+ A
+ && (STREQU(A, NAME_QUIET) || STREQU(A, NAME_LIST))
+ ) {
+ LP_ERRMSG1 (ERROR, E_ADM_BADQUIETORLIST, p);
+ done (1);
+ }
+
+ /*
+ * New printer - if no input types given, assume "simple".
+ */
+ if (!I) {
+ I = getlist(NAME_SIMPLE, LP_WS, LP_SEP);
+ strcat (modifications, "I");
+ }
+ }
+}
+
+/*
+ Second phase of parsing for -S option.
+ In a seperate routine so we can call it from other
+ routines. This is used when any or all are used as
+ a print wheel name. main() loops over each print wheel,
+ and must call this function for each print wheel found.
+*/
+void
+chkopts3(called_from_chkopts)
+int called_from_chkopts;
+{
+ /*
+ Only do the getpwheel() if we are not being called
+ from lpadmin.c. Otherwise we mess up our arena for
+ "all" processing.
+ */
+ if (!called_from_chkopts)
+ oldS = pwheel_pointer;
+ else
+ oldS = getpwheel(*S);
+
+ if (!oldS) {
+ if (!syn_name(*S)) {
+ LP_ERRMSG1 (ERROR, E_LP_NOTNAME, *S);
+ done (1);
+ }
+
+ /*
+ * Can't quiet a new print wheel,
+ * can't list the alerting for a new print wheel.
+ */
+ if (
+ A
+ && (STREQU(A, NAME_QUIET) || STREQU(A, NAME_LIST))
+ ) {
+ LP_ERRMSG1 (ERROR, E_ADM_BADQUIETORLIST, *S);
+ done (1);
+ }
+ }
+}
+
+static void
+chksys(s)
+char *s;
+{
+ char *cp;
+
+ if (STREQU(s, NAME_ALL) || STREQU(s, NAME_ANY)) {
+ LP_ERRMSG (ERROR, E_ADM_ANYALLSYS);
+ done(1);
+ }
+
+ if ((cp = strchr(s, '!')) != NULL)
+ *cp = '\0';
+
+ if (cp)
+ *cp = '!';
+
+ return;
+}
+
+/**
+ ** sum_chkprinter() - CHECK TERMINFO STUFF FOR A LIST OF PRINTER TYPES
+ **/
+
+#include "lp.set.h"
+
+static unsigned long
+#if defined(__STDC__)
+sum_chkprinter (
+ char ** types,
+ char * cpi,
+ char * lpi,
+ char * len,
+ char * wid,
+ char * cs
+)
+#else
+sum_chkprinter (types, cpi, lpi, len, wid, cs)
+ char ** types;
+ char * cpi;
+ char * lpi;
+ char * len;
+ char * wid;
+ char * cs;
+#endif
+{
+ char ** pt;
+
+ unsigned long worst = 0;
+ unsigned long this = 0;
+
+
+ /*
+ * Check each printer type, to see if any won't work with
+ * the attributes requested. However, return ``success''
+ * if at least one type works. Keep a list of the failed
+ * types for the caller to report.
+ */
+ bad_list = 0;
+ for (pt = types; *pt; pt++) {
+ this = chkprinter(*pt, cpi, lpi, len, wid, cs);
+ if (this != 0)
+ addlist (&bad_list, *pt);
+ worst |= this;
+ }
+ if (lenlist(types) == lenlist(bad_list))
+ return (worst);
+ else
+ return (0);
+}
+
+/*
+ * Function: isPPD()
+ *
+ * Description: Check that the given PPD file exists. The argument given can
+ * either be a relative path or a full path to the file.
+ *
+ * Returns: 1 = PPD file found
+ * 0 = PPD file not found
+ */
+
+static int
+isPPD(char *ppd_file)
+{
+ int result = 0;
+ char *ppd = NULL;
+
+ if (ppd_file != NULL) {
+ if (*ppd_file == '/') {
+ ppd = strdup(ppd_file);
+ } else {
+ ppd = makepath(Lp_Model, "ppd", ppd_file, (char *)0);
+ }
+
+ /*
+ * now check the file exists
+ */
+ if ((ppd != NULL) && (Access(ppd, 04) != -1)) {
+ result = 1;
+ } else {
+ /*
+ * files does not exist so append .gz and check if
+ * that exist
+ */
+ ppd = Realloc(ppd, strlen(ppd)+ strlen(PPDZIP)+2);
+ if (ppd != NULL) {
+ ppd = strcat(ppd, PPDZIP);
+ if (Access(ppd, 04) != -1) {
+ result = 1;
+ }
+ }
+ }
+
+ if (ppd != NULL) {
+ free(ppd);
+ }
+ }
+ return (result);
+} /* isPPD() */
diff --git a/usr/src/cmd/lp/cmd/lpadmin/default.c b/usr/src/cmd/lp/cmd/lpadmin/default.c
new file mode 100644
index 0000000000..aba979373a
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/default.c
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+
+#include "stdio.h"
+#include "errno.h"
+#include "sys/types.h"
+
+#include "lp.h"
+#include "printers.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+
+/**
+ ** getdflt() - RETURN DEFAULT DESTINATION
+ **/
+
+char *getdflt ()
+{
+ char *name;
+
+ if ((name = getdefault()))
+ return (name);
+ else
+ return ("");
+}
+
+/**
+ ** newdflt() - ESTABLISH NEW DEFAULT DESTINATION
+ **/
+
+void newdflt (name)
+ char *name;
+{
+ BEGIN_CRITICAL
+ if (name && *name && !STREQU(name, NAME_NONE)) {
+ if (putdefault(name) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_WRDEFAULT, PERROR);
+ done (1);
+ }
+
+ } else {
+ if (deldefault() == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_WRDEFAULT, PERROR);
+ done (1);
+ }
+
+ }
+ END_CRITICAL
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/do_align.c b/usr/src/cmd/lp/cmd/lpadmin/do_align.c
new file mode 100644
index 0000000000..ed845761bf
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/do_align.c
@@ -0,0 +1,677 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libintl.h>
+
+#include "lp.h"
+#include "msgs.h"
+#include "printers.h"
+#include "requests.h"
+#include "form.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+
+extern void mount_unmount();
+
+extern short printer_status;
+
+extern char *cur_pwheel,
+ *disable_reason,
+ *reject_reason;
+
+extern FORM formbuf;
+
+static int again();
+
+static void disable(),
+ enable(),
+ accept(),
+ reject(),
+ cancel(),
+ sigpipe(),
+ sigother();
+
+static jmp_buf cleanup_env,
+ pipe_env;
+
+/**
+ ** do_align() - SET UP PRINTER TO PRINT ALIGNMENT PATTERNS
+ **/
+
+int do_align (printer, form, pwheel)
+ char *printer,
+ *form,
+ *pwheel;
+{
+ short status;
+
+ char *req_id = 0,
+ *file_prefix,
+ *rfile,
+ *fifo,
+ buffer[MSGMAX];
+
+ long printer_chk;
+
+ int try;
+
+ FILE *align_fp,
+ *fifo_fp;
+
+ REQUEST req;
+
+ void (*old_sighup)(),
+ (*old_sigint)(),
+ (*old_sigquit)(),
+ (*old_sigterm)();
+
+
+ /*
+ * Having reached this point means we've already fetched
+ * the form definition. Now get the alignment pattern.
+ */
+ if (getform(form, (FORM *)0, (FALERT *)0, &align_fp) == -1) {
+ LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
+ done (1);
+ }
+ if (!align_fp) {
+ LP_ERRMSG1 (WARNING, E_ADM_NOALIGN, form);
+ return (0);
+ }
+
+ /*
+ * Having reached this far also means we've already obtained
+ * the printer status from the Spooler. We'll be changing the
+ * status of the printer and queue and will have to restore
+ * the disable/reject reasons.
+ * NOTE: We can't restore the dates!
+ */
+
+
+ /*
+ * Construct a request to print a ``file'' for copy. The
+ * equivalent "lp" command (with a filename) would be:
+ *
+ * lp -p printer -H immediate -f form -T type -S charset -c -P 1-N
+ *
+ * "type", "charset", and "N" are derived from the form def'n.
+ * This command would make us next to print ONCE THE FORM IS
+ * MOUNTED.
+ *
+ * NOTE: Don't bother with the -S charset if it isn't mandatory,
+ * so we won't get a rejection. Also, we use either the print
+ * wheel given in the -S option or, lacking that, the currently
+ * mounted print wheel. (The former WILL be mounted.) This also
+ * avoids a rejection by the Spooler.
+ */
+ req.copies = 1;
+ req.destination = printer;
+/* req.file_list = 0; This is done later. */
+ req.form = form;
+ req.actions = ACT_IMMEDIATE | ACT_FAST;
+ req.alert = 0;
+ req.options = "nobanner";
+ req.priority = 20; /* it doesn't matter */
+ sprintf ((req.pages = "1-999999")+2, "%d", formbuf.np);
+ req.charset = NAME_ANY; /* Don't restrict the request */
+ req.modes = 0;
+ req.title = "Aligning Form";
+ req.input_type = formbuf.conttype;
+ req.user = getname();
+
+
+ /*
+ * The following code is sensitive to interrupts: We must
+ * catch interrupts so to restore the printer to its original
+ * state, but if we get interrupted while receiving a message
+ * from the Spooler, we can't issue additional messages because
+ * the old responses still in the response queue will confuse us.
+ * Thus while sending/receiving a message we ignore signals.
+ */
+ if (setjmp(cleanup_env) != 0)
+ done (1);
+ trap_signals (); /* make sure we've done this once */
+ old_sighup = signal(SIGHUP, sigother);
+ old_sigint = signal(SIGINT, sigother);
+ old_sigquit = signal(SIGQUIT, sigother);
+ old_sigterm = signal(SIGTERM, sigother);
+
+ /*
+ * We'll try the following twice, first with the page list
+ * set as above. If the request gets refused because there's
+ * no filter to convert the content, we'll try again without
+ * the page list. I don't think the number-of-pages-in-a-form
+ * feature is likely to be used much, so why hassle the
+ * administrator?
+#if defined(WARN_OF_TOO_MANY_LINES)
+ * However, do warn him or her.
+#endif
+ */
+
+ try = 0;
+Again: try++;
+
+ /*
+ * Have the Spooler allocate a request file and another file
+ * for our use. We'll delete the other file and recreate it
+ * as a FIFO. We can do this because "lpadmin" can only be run
+ * (successfully) by an administrator. This is the key to what
+ * we're doing! We are submitting a named pipe (FIFO) for
+ * printing, which gives us a connection to the printer
+ * through any filters needed!
+ */
+
+ BEGIN_CRITICAL
+ send_message (S_ALLOC_FILES, 2);
+ if (mrecv(buffer, MSGMAX) != R_ALLOC_FILES) {
+ LP_ERRMSG (ERROR, E_LP_MRECV);
+ done (1);
+ }
+ END_CRITICAL
+ (void)getmessage (buffer, R_ALLOC_FILES, &status, &file_prefix);
+
+ switch (status) {
+ case MOK:
+ break;
+
+ case MNOMEM:
+ LP_ERRMSG (ERROR, E_LP_MNOMEM);
+ done (1);
+ }
+
+ if (!(rfile = malloc((unsigned int)strlen(file_prefix) + 2 + 1))) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done (1);
+ }
+
+ sprintf (rfile, "%s-1", file_prefix);
+
+ if (!(fifo = makepath(Lp_Temp, rfile, (char *)0))) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done (1);
+ }
+ req.file_list = 0;
+ addlist (&req.file_list, fifo);
+
+ if (
+ Unlink(fifo) == -1
+ || Mknod(fifo, S_IFIFO | 0600, 0) == -1
+ ) {
+ LP_ERRMSG1 (ERROR, E_ADM_NFIFO, PERROR);
+ done (1);
+ }
+
+ /*
+ * In quick succession,
+ *
+ * - mount the form,
+ * - disable the printer,
+ * - make the Spooler accept requests (if need be),
+ * - submit the request,
+ * - make the Spooler reject requests (if need be).
+ *
+ * We want to minimize the window when another request can
+ * be submitted ahead of ours. Though this window is small,
+ * it is a flaw in our design. Disabling the printer will
+ * help, because it will stop any request that is printing
+ * (if the form is already mounted) and will prevent any other
+ * request from printing. (We disable the printer AFTER trying
+ * to mount the form, because we don't disable a printer for a
+ * regular mount, and we'd like to make this mount APPEAR to
+ * be as similar as possible.)
+ */
+
+ if (try == 1) {
+
+ mount_unmount (S_MOUNT, printer, NB(form), NB(pwheel));
+ /* This will die if the mount fails, leaving */
+ /* the Spooler to clean up our files. */
+
+ if (!(printer_status & PS_DISABLED))
+ disable (printer, CUZ_MOUNTING, 0);
+
+ if (printer_status & PS_REJECTED)
+ accept (printer);
+
+ if (setjmp(cleanup_env) != 0) {
+ if (printer_status & PS_DISABLED)
+ disable (printer, disable_reason, 1);
+ if (printer_status & PS_REJECTED)
+ reject (printer, reject_reason);
+ if (req_id && *req_id)
+ cancel (req_id);
+ done (1);
+ }
+ }
+
+ sprintf (rfile, "%s-0", file_prefix);
+ if (putrequest(rfile, &req) == -1) {
+ LP_ERRMSG1 (ERROR, E_LP_PUTREQUEST, PERROR);
+ goto Done;
+ }
+ BEGIN_CRITICAL
+ send_message (S_PRINT_REQUEST, rfile);
+ if (mrecv(buffer, MSGMAX) != R_PRINT_REQUEST) {
+ LP_ERRMSG (ERROR, E_LP_MRECV);
+ done (1);
+ }
+ END_CRITICAL
+ (void)getmessage (buffer, R_PRINT_REQUEST, &status, &req_id, &printer_chk);
+
+ switch (status) {
+
+ case MNOFILTER:
+ if (try == 1) {
+ req.pages = 0;
+ goto Again;
+ }
+ LP_ERRMSG (ERROR, E_ADM_NFILTER);
+ goto Done;
+
+ case MOK:
+#if defined(WARN_OF_TOO_MANY_LINES)
+ if (!req.pages)
+ LP_ERRMSG1 (WARNING, E_ADM_NPAGES, formbuf.np);
+#endif
+ break;
+
+ case MERRDEST:
+ accept (printer); /* someone snuck a reject in! */
+ goto Again;
+
+ case MNOMEM:
+ LP_ERRMSG (ERROR, E_LP_MNOMEM);
+ goto Done;
+
+ case MNODEST:
+ LP_ERRMSG1 (ERROR, E_LP_PGONE, printer);
+ goto Done;
+
+ case MNOOPEN: /* not quite, but close */
+ LP_ERRMSG (ERROR, E_ADM_ERRDEST);
+ goto Done;
+
+ case MDENYDEST:
+ if (printer_chk) {
+ char reason[1024],
+ *cp = reason;
+
+ if (printer_chk & PCK_TYPE)
+ cp += sprintf(cp, "printer type, ");
+ if (printer_chk & PCK_CHARSET)
+ cp += sprintf(cp, "character set, ");
+ if (printer_chk & PCK_CPI)
+ cp += sprintf(cp, "character pitch, ");
+ if (printer_chk & PCK_LPI)
+ cp += sprintf(cp, "line pitch, ");
+ if (printer_chk & PCK_WIDTH)
+ cp += sprintf(cp, "page width, ");
+ if (printer_chk & PCK_LENGTH)
+ cp += sprintf(cp, "page length, ");
+ if (printer_chk & PCK_BANNER)
+ cp += sprintf(cp, "nobanner, ");
+ cp[-2] = 0;
+ LP_ERRMSG1 (ERROR, E_LP_PTRCHK, reason);
+ goto Done;
+ }
+ /*fall through*/
+
+ case MUNKNOWN:
+ case MNOMEDIA:
+ case MDENYMEDIA:
+ case MNOMOUNT:
+ case MNOSPACE:
+ case MNOPERM:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, status);
+
+Done: if (!(printer_status & PS_DISABLED))
+ enable (printer);
+ if (printer_status & PS_REJECTED)
+ reject (printer, reject_reason);
+ done (1);
+ /*NOTREACHED*/
+ }
+
+ if (printer_status & PS_REJECTED)
+ reject (printer, reject_reason);
+
+ /*
+ * Enable printing, to start the interface program going.
+ * Because of our precautions above, our request SHOULD be
+ * the one that prints!
+ */
+ enable (printer);
+
+ /*
+ * Open the FIFO. One problem: This will hang until the
+ * interface program opens the other end!!
+ */
+ if (!(fifo_fp = fopen(fifo, "w"))) {
+ LP_ERRMSG1 (ERROR, E_ADM_NFIFO, PERROR);
+ done (1);
+ }
+
+ /*
+ * Loop, dumping the ENTIRE alignment pattern to the FIFO
+ * each time. SIGPIPE probably means the printer faulted.
+ */
+ if (setjmp(pipe_env) == 0) {
+ /*
+ * Don't send a form feed after the last copy, since
+ * the interface program does that. To implement this,
+ * we send the form feed BEFORE the alignment pattern;
+ * this way we can simply not send it the first time.
+ */
+ char * ff = 0;
+ char * ff_before = 0;
+
+ /*
+ * If we'll be inserting page breaks between alignment
+ * patterns, look up the control sequence for this.
+ *
+ * MORE: We currently don't have the smarts to figure out
+ * WHICH printer type the Spooler will pick; we would need
+ * to steal some of its code for that (see pickfilter.c)
+ * The best we do so far is use the alignment pattern's
+ * content type, if known.
+ */
+ if (filebreak) {
+ if (
+ formbuf.conttype
+ && searchlist_with_terminfo(
+ formbuf.conttype,
+ T /* having "filebreak" => OK */
+ )
+ )
+ tidbit (formbuf.conttype, "ff", &ff);
+ else
+ tidbit (*T, "ff", &ff);
+ }
+
+ signal (SIGPIPE, sigpipe);
+ do {
+ register int n;
+ char buf[BUFSIZ];
+
+ if (ff_before && *ff_before)
+ fputs (ff_before, fifo_fp);
+ ff_before = ff;
+
+ rewind (align_fp);
+ while ((n = fread(buf, 1, BUFSIZ, align_fp)) > 0)
+ fwrite (buf, 1, n, fifo_fp);
+
+ fflush (fifo_fp);
+
+ } while (again());
+ fclose (align_fp);
+ signal (SIGPIPE, SIG_DFL);
+
+ } else {
+ cancel (req_id);
+
+#define P(X) printf (X)
+
+P("We were interrupted while printing the alignment pattern;\n");
+P("check the printer. The form is mounted, so you will have to\n");
+P("unmount it if you need to print more alignment patterns later.\n");
+ }
+
+ /*
+ * Disable the printer, if needed, and close the FIFO.
+ * Use the wait version of the disable, so our request isn't
+ * stopped, and do it before closing the FIFO, so another request
+ * can't start printing if it isn't supposed to.
+ */
+ if (printer_status & PS_DISABLED)
+ disable (printer, disable_reason, 1);
+ fclose (fifo_fp);
+
+ signal (SIGHUP, old_sighup);
+ signal (SIGINT, old_sigint);
+ signal (SIGQUIT, old_sigquit);
+ signal (SIGTERM, old_sigterm);
+
+ return (1);
+}
+
+/**
+ ** accept() - MAKE PRINTER ACCEPT REQUESTS
+ **/
+
+static void accept (printer)
+ char *printer;
+{
+ int rc;
+
+ BEGIN_CRITICAL
+ send_message (S_ACCEPT_DEST, printer);
+ rc = output(R_ACCEPT_DEST);
+ END_CRITICAL
+
+ switch (rc) {
+ case MOK:
+ case MERRDEST: /* someone may have snuck in an accept */
+ break;
+
+ case MNODEST: /* make up your mind, Spooler! */
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ }
+ return;
+}
+
+/**
+ ** reject() - MAKE PRINTER REJECT REQUESTS
+ **/
+
+static void reject (printer, reason)
+ char *printer,
+ *reason;
+{
+ int rc;
+
+ BEGIN_CRITICAL
+ send_message (S_REJECT_DEST, printer, reason);
+ rc = output(R_REJECT_DEST);
+ END_CRITICAL
+
+ switch (rc) {
+
+ case MOK:
+ case MERRDEST: /* someone may have snuck in a reject */
+ break;
+
+ case MNODEST: /* make up your mind, Spooler! */
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ }
+ return;
+}
+
+/**
+ ** enable() - ENABLE THE PRINTER
+ **/
+
+static void enable (printer)
+ char *printer;
+{
+ int rc;
+
+ BEGIN_CRITICAL
+ send_message (S_ENABLE_DEST, printer);
+ rc = output(R_ENABLE_DEST);
+ END_CRITICAL
+
+ switch (rc) {
+ case MOK:
+ case MERRDEST: /* someone may have snuck in an enable */
+ break;
+
+ case MNODEST: /* make up your mind, Spooler! */
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ }
+ return;
+}
+
+/**
+ ** disable() - DISABLE THE PRINTER
+ **/
+
+static void disable (printer, reason, when)
+ char *printer,
+ *reason;
+ int when;
+{
+ int rc;
+
+ BEGIN_CRITICAL
+ send_message (S_DISABLE_DEST, printer, reason, when);
+ rc = output(R_DISABLE_DEST);
+ END_CRITICAL
+
+ switch (rc) {
+ case MOK:
+ case MERRDEST: /* someone may have snuck in a disable */
+ break;
+
+ case MNODEST: /* make up your mind, Spooler! */
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ }
+ return;
+}
+
+/**
+ ** cancel() - MAKE PRINTER ACCEPT REQUESTS
+ **/
+
+static void cancel (req_id)
+ char *req_id;
+{
+ int rc;
+
+ BEGIN_CRITICAL
+ send_message (S_CANCEL_REQUEST, req_id);
+ rc = output(R_CANCEL_REQUEST);
+ END_CRITICAL
+
+ switch (rc) {
+ case MOK:
+ case MUNKNOWN:
+ case M2LATE:
+ break;
+
+ case MNOPERM:
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ }
+ return;
+}
+
+/**
+ ** again()
+ **/
+
+static int again ()
+{
+ char answer[BUFSIZ];
+
+
+ for (;;) {
+
+ printf (
+ gettext("Press return to print an alignment pattern [q to quit]: ")
+ );
+
+ if (!fgets(answer, sizeof (answer), stdin))
+ return (0);
+
+ answer[strlen(answer) -1] = '\0';
+
+ if (
+ STREQU(answer, "q")
+ || STREQU(answer, "n")
+ || STREQU(answer, "no")
+ )
+ return (0);
+
+ else if (
+ !*answer
+ || STREQU(answer, "y")
+ || STREQU(answer, "yes")
+ )
+ return (1);
+
+ printf (gettext("Sorry?\n"));
+ }
+}
+
+/**
+ ** sigpipe()
+ ** sigother()
+ **/
+
+static void sigpipe ()
+{
+ signal (SIGPIPE, SIG_IGN);
+ longjmp (pipe_env, 1);
+ /*NOTREACHED*/
+}
+
+static void sigother (sig)
+ int sig;
+{
+ signal (sig, SIG_IGN);
+ longjmp (cleanup_env, 1);
+ /*NOTREACHED*/
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/do_fault.c b/usr/src/cmd/lp/cmd/lpadmin/do_fault.c
new file mode 100644
index 0000000000..9ef9795ef2
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/do_fault.c
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+#include "sys/types.h"
+
+#include "lp.h"
+#include "printers.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+
+/**
+ ** do_fault() - CHANGE FAULT RECOVERY FOR CURRENT JOB
+ **/
+
+void do_fault ()
+{
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/do_mount.c b/usr/src/cmd/lp/cmd/lpadmin/do_mount.c
new file mode 100644
index 0000000000..86bb067155
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/do_mount.c
@@ -0,0 +1,336 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+
+#include "stdio.h"
+#include "string.h"
+#include "sys/types.h"
+
+#include "lp.h"
+#include "msgs.h"
+#include "printers.h"
+#include "form.h"
+#include "access.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+extern FORM formbuf;
+
+void mount_unmount();
+
+short printer_status;
+
+static char *cur_pwheel;
+char *disable_reason,
+ *reject_reason;
+
+static void inquire_printer_status();
+
+/**
+ ** do_mount() - MOUNT/UNMOUNT A FORM/PRINT-WHEEL
+ **/
+
+void do_mount (printer, form, pwheel)
+ char *printer,
+ *form,
+ *pwheel;
+{
+ /*
+ * Take care of unmounts, first.
+ */
+
+ if (form && STREQU(form, NAME_NONE))
+ form = "";
+ if (pwheel && (STREQU(pwheel, NAME_ANY) || STREQU(pwheel, NAME_NONE)))
+ pwheel = "";
+
+ if (form && !*form && a)
+ LP_ERRMSG (WARNING, E_ADM_UNALIGN);
+
+ if (form && !*form && pwheel && !*pwheel) {
+ mount_unmount (S_UNMOUNT, printer, NAME_NONE, NAME_ANY);
+ form = 0;
+ pwheel = 0;
+ } else if (form && !*form) {
+ mount_unmount (S_UNMOUNT, printer, NAME_NONE, "");
+ form = 0;
+ } else if (pwheel && !*pwheel) {
+ mount_unmount (S_UNMOUNT, printer, "", NAME_ANY);
+ pwheel = 0;
+ }
+
+ if (!form && !pwheel)
+ return;
+
+ /*
+ * See if the form will work on the printer. We do this even if
+ * the form has already been allowed, just in case the form has
+ * changed since then. Also, the check reads the form definition
+ * into a global that we can use for subsequent checks.
+ */
+ if (!s) { /* a local printer */
+
+ if (form && *form)
+ switch (verify_form(form)) {
+ case -1:
+ LP_ERRMSG (WARNING, E_ADM_BADMOUNT);
+ break;
+ case -2:
+ LP_ERRMSG1 (ERROR, E_ADM_MANDCHSET, formbuf.chset);
+ done (1);
+ }
+
+ /*
+ * Is the form allowed on the printer?
+ */
+ if (form && *form && !is_form_allowed_printer(form, printer))
+ LP_ERRMSG2 (WARNING, E_ADM_ICKFORM, form, printer);
+
+
+ /*
+ * Does the printer take print wheels?
+ * For us to be here, "daisy" must have been set.
+ * (-S requires knowing printer type (T), and knowing
+ * T caused call to "tidbit()" to set "daisy").
+ */
+ if (pwheel && *pwheel && !daisy) {
+ LP_ERRMSG (ERROR, E_ADM_NOPWHEEL);
+ done (1);
+ }
+
+ /*
+ * If the form requires a particular print wheel, make sure
+ * it is either mounted already, or is being mounted now.
+ */
+ if (form && *form) {
+ /*
+ * The printer status is also needed for "do_align()".
+ */
+ inquire_printer_status (printer);
+
+ /*
+ * The "!daisy" case was investigated in "verify_form()".
+ */
+ if (daisy && formbuf.mandatory && formbuf.chset)
+ if (!pwheel || !*pwheel) {
+ if (!STREQU(formbuf.chset, cur_pwheel))
+ LP_ERRMSG1 (
+ WARNING,
+ E_ADM_MANDPWHEEL1,
+ formbuf.chset
+ );
+ } else if (!STREQU(formbuf.chset, pwheel)) {
+ LP_ERRMSG1 (
+ WARNING,
+ E_ADM_MANDPWHEEL2,
+ formbuf.chset
+ );
+ }
+ }
+
+ /*
+ * Is the print wheel listed for this printer?
+ * The information that will tell us is either in the
+ * original info. we read in ("oldp->char_sets") if this
+ * is an existing printer, or--if this is a new printer--we
+ * don't have it (ambiguous -S options, mate!)
+ */
+ if (
+ pwheel
+ && *pwheel
+ && !(
+ oldp
+ && searchlist(pwheel, oldp->char_sets)
+ )
+ )
+ LP_ERRMSG2 (WARNING, E_ADM_ICKPWHEEL, pwheel, printer);
+
+ }
+
+ /*
+ * Do the mount with the printing of the alignment pattern,
+ * if required and possible. Otherwise, just mount the form
+ * (and print-wheel).
+ */
+ if (!a || !do_align(printer, form, pwheel))
+ mount_unmount (S_MOUNT, printer, NB(form), NB(pwheel));
+
+ return;
+}
+
+void mount_unmount (type, printer, form, pwheel)
+ int type;
+ char *printer,
+ *form,
+ *pwheel;
+{
+ int rc;
+
+ if (t) { /* tray specified */
+ type = (type == S_MOUNT ? S_MOUNT_TRAY : S_UNMOUNT_TRAY);
+ send_message(type, printer, form, pwheel, t);
+ } else
+ send_message(type, printer, form, pwheel);
+
+ rc = output(type + 1);
+
+ switch(rc) {
+
+ case MOK:
+ break;
+
+ case MNOMEDIA:
+ LP_ERRMSG (ERROR, E_ADM_NOMEDIA);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNODEST:
+ LP_ERRMSG1 (ERROR, E_ADM_NODEST, printer);
+ done (1);
+ /*NOTREACHED*/
+
+ case MBUSY:
+ LP_ERRMSG (ERROR, E_ADM_MNTLATER);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNOTRAY:
+ LP_ERRMSG (ERROR, E_ADM_BADTRAY);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ /*NOTREACHED*/
+
+ }
+ return;
+}
+
+void
+do_max_trays(char *printer)
+{
+ int rc;
+
+ if (t) /* tray specified */
+ send_message(S_MAX_TRAYS, printer, t);
+
+ rc = output(R_MAX_TRAYS);
+
+ switch(rc) {
+
+ case MOK:
+ break;
+
+ case MNOMEDIA:
+ LP_ERRMSG (ERROR, E_ADM_NOMEDIA);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNODEST:
+ LP_ERRMSG1 (ERROR, E_ADM_NODEST, printer);
+ done (1);
+ /*NOTREACHED*/
+
+ case MBUSY:
+ LP_ERRMSG (ERROR, E_ADM_MNTLATER);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNOTRAY:
+ LP_ERRMSG (ERROR, E_ADM_MAXTRAY);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ /*NOTREACHED*/
+
+ }
+ return;
+}
+
+/**
+ ** inquire_printer_status()
+ **/
+
+static void inquire_printer_status (printer)
+ char *printer;
+{
+ short status;
+
+ char *s_ignore,
+ buffer[MSGMAX];
+
+ long l_ignore;
+
+
+ send_message (S_INQUIRE_PRINTER_STATUS, printer);
+ if (mrecv(buffer, MSGMAX) != R_INQUIRE_PRINTER_STATUS) {
+ LP_ERRMSG (ERROR, E_LP_MRECV);
+ done (1);
+ }
+ (void)getmessage (
+ buffer,
+ R_INQUIRE_PRINTER_STATUS,
+ &status,
+ &s_ignore,
+ &s_ignore,
+ &cur_pwheel,
+ &disable_reason,
+ &reject_reason,
+ &printer_status,
+ &s_ignore,
+ &l_ignore,
+ &l_ignore
+ );
+
+ switch (status) {
+ case MOK:
+ disable_reason = strdup(disable_reason);
+ reject_reason = strdup(reject_reason);
+ cur_pwheel = strdup(cur_pwheel);
+ break;
+
+ case MNODEST:
+ LP_ERRMSG1 (ERROR, E_LP_PGONE, printer);
+ done (1);
+ }
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/do_printer.c b/usr/src/cmd/lp/cmd/lpadmin/do_printer.c
new file mode 100644
index 0000000000..66ab3f2803
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/do_printer.c
@@ -0,0 +1,781 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/zone.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <sys/tsol/label_macro.h>
+#include <bsm/devices.h>
+#include "lp.h"
+#include "class.h"
+#if defined PS_FAULTED
+#undef PS_FAULTED
+#endif
+#include "printers.h"
+#include "msgs.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+extern void fromallclasses();
+
+#if !defined(PATH_MAX)
+# define PATH_MAX 1024
+#endif
+#if PATH_MAX < 1024
+# undef PATH_MAX
+# define PATH_MAX 1024
+#endif
+
+extern char *label;
+
+static void configure_printer();
+static char *fullpath();
+char *nameit();
+static void pack_white(char *ptr);
+
+/**
+ ** do_printer() - CREATE OR CHANGE PRINTER
+ **/
+
+void do_printer ()
+{
+ int rc;
+
+ /*
+ * Set or change the printer configuration.
+ */
+ if (strlen(modifications))
+ configure_printer (modifications);
+
+ /*
+ * Allow/deny forms.
+ */
+ BEGIN_CRITICAL
+ if (!oldp)
+ if (allow_form_printer(getlist(NAME_NONE, "", ","), p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+
+ if (f_allow || f_deny) {
+ if (f_allow && allow_form_printer(f_allow, p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+
+ if (f_deny && deny_form_printer(f_deny, p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+ }
+ END_CRITICAL
+
+ /* Add/remove types of paper */
+
+ BEGIN_CRITICAL
+ if (!oldp)
+ if (add_paper_to_printer(getlist(NAME_NONE, "", ","),p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+
+
+ if (p_add && add_paper_to_printer(p_add, p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+
+ if (p_remove && remove_paper_from_printer(p_remove, p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+ END_CRITICAL
+
+ /*
+ * Allow/deny users.
+ */
+ BEGIN_CRITICAL
+ if (!oldp)
+ if (allow_user_printer(getlist(NAME_ALL, "", ","), p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+
+ if (u_allow || u_deny) {
+ if (u_allow && allow_user_printer(u_allow, p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+
+ if (u_deny && deny_user_printer(u_deny, p) == -1) {
+ LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
+ done(1);
+ }
+ }
+ END_CRITICAL
+
+ /*
+ * Tell the Spooler about the printer
+ */
+ send_message(S_LOAD_PRINTER, p, "", "");
+ rc = output(R_LOAD_PRINTER);
+
+ switch (rc) {
+ case MOK:
+ break;
+
+ case MNODEST:
+ case MERRDEST:
+ LP_ERRMSG (ERROR, E_ADM_ERRDEST);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNOSPACE:
+ LP_ERRMSG (WARNING, E_ADM_NOPSPACE);
+ break;
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * Now that the Spooler knows about the printer,
+ * we can do the balance of the changes.
+ */
+
+ /*
+ * Mount or unmount form, print-wheel.
+ */
+ if (M)
+ do_mount(p, (f? f : (char *)0), (S? *S : (char *)0));
+ else if (t) do_max_trays(p);
+
+ /*
+ * Display the alert type.
+ */
+ if (A && STREQU(A, NAME_LIST)) {
+ if (label)
+ (void) printf(gettext("Printer %s: "), label);
+ printalert (stdout, &(oldp->fault_alert), 1);
+ }
+
+ /*
+ * -A quiet.
+ */
+ if (A && STREQU(A, NAME_QUIET)) {
+
+ send_message(S_QUIET_ALERT, p, (char *)QA_PRINTER, "");
+ rc = output(R_QUIET_ALERT);
+
+ switch(rc) {
+ case MOK:
+ break;
+
+ case MNODEST: /* not quite, but not a lie either */
+ case MERRDEST:
+ LP_ERRMSG1 (WARNING, E_LP_NOQUIET, p);
+ break;
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ /*NOTREACHED*/
+ }
+ }
+
+ /*
+ * Add printer p to class c
+ */
+ if (c) {
+ CLASS *pc,
+ clsbuf;
+
+ if (STREQU(c, NAME_ANY))
+ c = NAME_ALL;
+
+Loop: if (!(pc = getclass(c))) {
+ if (STREQU(c, NAME_ALL))
+ goto Done;
+
+ if (errno != ENOENT) {
+ LP_ERRMSG2 (
+ ERROR,
+ E_LP_GETCLASS,
+ c,
+ PERROR
+ );
+ done (1);
+ }
+
+ /*
+ * Create the class
+ */
+ clsbuf.name = strdup(c);
+ clsbuf.members = 0;
+ if (addlist(&clsbuf.members, p) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done (1);
+ }
+ pc = &clsbuf;
+
+ } else if (searchlist(p, pc->members))
+ LP_ERRMSG2 (WARNING, E_ADM_INCLASS, p, pc->name);
+
+ else if (addlist(&pc->members, p) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done (1);
+ }
+
+ BEGIN_CRITICAL
+ if (putclass(pc->name, pc) == -1) {
+ LP_ERRMSG2 (
+ ERROR,
+ E_LP_PUTCLASS,
+ pc->name,
+ PERROR
+ );
+ done(1);
+ }
+ END_CRITICAL
+
+ send_message (S_LOAD_CLASS, pc->name);
+ rc = output(R_LOAD_CLASS);
+
+ switch(rc) {
+ case MOK:
+ break;
+
+ case MNODEST:
+ case MERRDEST:
+ LP_ERRMSG (ERROR, E_ADM_ERRDEST);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNOSPACE:
+ LP_ERRMSG (WARNING, E_ADM_NOCSPACE);
+ break;
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ /*NOTREACHED*/
+ }
+
+ if (STREQU(c, NAME_ALL))
+ goto Loop;
+ }
+Done:
+ /*
+ * Remove printer p from class r
+ */
+ if (r) {
+ if (STREQU(r, NAME_ALL) || STREQU(r, NAME_ANY))
+ fromallclasses(p);
+ else
+ fromclass(p, r);
+ }
+
+ return;
+}
+
+/**
+ ** configure_printer() - SET OR CHANGE CONFIGURATION OF PRINTER
+ **/
+
+static void configure_printer (list)
+ char *list;
+{
+ register PRINTER *prbufp;
+
+ PRINTER printer_struct;
+
+ char type;
+ char * infile_opts = NULL;
+
+
+ if (oldp) {
+
+ prbufp = oldp;
+
+ if (!T)
+ T = prbufp->printer_types;
+
+ if (!i && !e && !m)
+ /*
+ * Don't copy the original interface program
+ * again, but do keep the name of the original.
+ */
+ ignprinter = BAD_INTERFACE;
+ else
+ ignprinter = 0;
+
+ /*
+ * If we are making this a remote printer,
+ * make sure that local-only attributes are
+ * cleared.
+ */
+ if (s) {
+ prbufp->banner = 0;
+ prbufp->cpi.val = 0;
+ prbufp->cpi.sc = 0;
+ prbufp->device = 0;
+ prbufp->dial_info = 0;
+ prbufp->fault_rec = 0;
+ prbufp->interface = 0;
+ prbufp->lpi.val = 0;
+ prbufp->lpi.sc = 0;
+ prbufp->plen.val = 0;
+ prbufp->plen.sc = 0;
+ prbufp->login = 0;
+ prbufp->speed = 0;
+ prbufp->stty = 0;
+ prbufp->pwid.val = 0;
+ prbufp->pwid.sc = 0;
+ prbufp->fault_alert.shcmd = strdup(NAME_NONE);
+ prbufp->fault_alert.Q = 0;
+ prbufp->fault_alert.W = 0;
+#if defined(CAN_DO_MODULES)
+ prbufp->modules = 0;
+#endif
+
+ /*
+ * If we are making this a local printer, make
+ * sure that some local-only attributes are set.
+ * (If the user has specified these as well, his/her
+ * values will overwrite what we set here.)
+ */
+ } else if (oldp->remote) {
+ prbufp->banner = BAN_ALWAYS;
+ prbufp->interface = makepath(Lp_Model, STANDARD, (char *)0);
+ prbufp->fault_alert.shcmd = nameit(NAME_MAIL);
+
+ /*
+ * Being here means "!s && oldp->remote" is true,
+ * i.e. this printer never had an interface pgm
+ * before. Thus we can safely clear the following.
+ * This is needed to let "putprinter()" copy the
+ * (default) interface program.
+ */
+ ignprinter = 0;
+ }
+
+ } else {
+ /*
+ * The following takes care of the lion's share
+ * of the initialization of a new printer structure.
+ * However, special initialization (e.g. non-zero,
+ * or substructure members) needs to be considered
+ * for EACH NEW MEMBER added to the structure.
+ */
+ (void)memset (&printer_struct, 0, sizeof(printer_struct));
+
+ prbufp = &printer_struct;
+ prbufp->banner = BAN_ALWAYS;
+ prbufp->cpi.val = 0;
+ prbufp->cpi.sc = 0;
+ if (!s)
+ prbufp->interface = makepath(Lp_Model, m, (char *)0);
+ prbufp->lpi.val = 0;
+ prbufp->lpi.sc = 0;
+ prbufp->plen.val = 0;
+ prbufp->plen.sc = 0;
+ prbufp->pwid.val = 0;
+ prbufp->pwid.sc = 0;
+ if (!s && !A)
+ prbufp->fault_alert.shcmd = nameit(NAME_MAIL);
+ prbufp->fault_alert.Q = 0;
+ prbufp->fault_alert.W = 0;
+ prbufp->options = NULL;
+ }
+
+ while ((type = *list++) != '\0') switch(type) {
+
+ case 'A':
+ if (!s) {
+ if (STREQU(A, NAME_MAIL) || STREQU(A, NAME_WRITE))
+ prbufp->fault_alert.shcmd = nameit(A);
+ else if (!STREQU(A, NAME_QUIET))
+ prbufp->fault_alert.shcmd = A;
+ }
+ break;
+
+ case 'b':
+ if (!s)
+ prbufp->banner = banner;
+ break;
+
+ case 'c':
+ if (!s)
+ prbufp->cpi = cpi_sdn;
+ break;
+
+ case 'D':
+ prbufp->description = D;
+ break;
+
+ case 'e':
+ if (!s) {
+ prbufp->interface = makepath(
+ Lp_A_Interfaces,
+ e,
+ (char *)0
+ );
+ }
+ break;
+
+ case 'F':
+ if (!s)
+ prbufp->fault_rec = F;
+ break;
+
+#if defined(CAN_DO_MODULES)
+ case 'H':
+ if (!s)
+ prbufp->modules = H;
+ break;
+#endif
+
+ case 'h':
+ if (!s)
+ prbufp->login = 0;
+ break;
+
+ case 'i':
+ if (!s)
+ prbufp->interface = fullpath(i);
+ break;
+
+ case 'I':
+ prbufp->input_types = I;
+ break;
+
+ case 'l':
+ if (!s)
+ prbufp->login = 1;
+ break;
+
+ case 'L':
+ if (!s)
+ prbufp->plen = length_sdn;
+ break;
+
+ case 'm':
+ if (!s)
+ prbufp->interface = makepath(Lp_Model, m, (char *)0);
+ break;
+
+ case 'M':
+ if (!s)
+ prbufp->lpi = lpi_sdn;
+ break;
+
+#ifdef LP_USE_PAPI_ATTR
+ case 'n':
+ {
+ if (n_opt != NULL)
+ {
+ if (*n_opt == '/')
+ {
+ prbufp->ppd = fullpath(n_opt);
+ }
+ else
+ {
+ prbufp->ppd =
+ makepath(Lp_Model, "ppd", n_opt, (char *)0);
+ }
+ ppdopt = 1;
+ }
+ break;
+ }
+#endif
+
+ case 'o':
+ /*
+ * The "undefined" key-value -o options
+ *
+ * Options requires special handling. It is a
+ * list whose members are to be handled
+ * individually.
+ *
+ * Need to: set new options, keep old options if not
+ * redefined, remove old options if defined as "key=".
+ *
+ *
+ * "p" is a global containing the printer name
+ */
+
+ if (!s) {
+
+ if ((infile_opts = getpentry(p, PR_OPTIONS)) == NULL)
+ prbufp->options = o_options;
+ else {
+ prbufp->options =
+ pick_opts(infile_opts, o_options);
+ }
+ }
+ break;
+
+ case 'R':
+ if (s) {
+ prbufp->remote = s;
+ prbufp->dial_info = 0;
+ prbufp->device = 0;
+ } else
+ prbufp->remote = 0;
+ break;
+
+ case 's':
+ if (!s) {
+ /*
+ * lpadmin always defers to stty
+ */
+ prbufp->speed = 0;
+ prbufp->stty = stty_opt;
+ }
+ break;
+
+ case 'S':
+ if (!M)
+ if (STREQU(*S, NAME_NONE))
+ prbufp->char_sets = 0;
+ else
+ prbufp->char_sets = S;
+ break;
+
+ case 'T':
+ prbufp->printer_types = T;
+ break;
+
+ case 'U':
+ if (!s) {
+ prbufp->dial_info = U;
+ prbufp->device = 0;
+ prbufp->remote = 0;
+ }
+ break;
+
+ case 'v':
+ if (!s) {
+ prbufp->device = v;
+ prbufp->dial_info = 0;
+ prbufp->remote = 0;
+ }
+ break;
+
+ case 'w':
+ if (!s)
+ prbufp->pwid = width_sdn;
+ break;
+
+ case 'W':
+ if (!s)
+ prbufp->fault_alert.W = W;
+ break;
+
+ }
+
+
+ BEGIN_CRITICAL
+ if (putprinter(p, prbufp) == -1) {
+ if (
+ errno == EINVAL
+ && (badprinter & BAD_INTERFACE)
+ )
+ LP_ERRMSG1 (
+ ERROR,
+ E_ADM_BADINTF,
+ prbufp->interface
+ );
+ else
+ LP_ERRMSG2 (
+ ERROR,
+ E_LP_PUTPRINTER,
+ p,
+ PERROR
+ );
+ done(1);
+ }
+
+ if ((getzoneid() == GLOBAL_ZONEID) && system_labeled &&
+ (prbufp->device != NULL))
+ update_dev_dbs(p, prbufp->device, "ADD");
+
+ END_CRITICAL
+
+ return;
+}
+
+/**
+ ** fullpath()
+ **/
+
+static char *fullpath (str)
+ char *str;
+{
+ register char *cur_dir,
+ *path;
+
+
+ while (*str && *str == ' ')
+ str++;
+ if (*str == '/')
+ return (str);
+
+ if (!(cur_dir = malloc(PATH_MAX + 1)))
+ return (str);
+
+ getcwd (cur_dir, PATH_MAX);
+ path = makepath(cur_dir, str, (char *)0);
+
+ /*
+ * Here we could be nice and strip out /./ and /../
+ * stuff, but it isn't necessary.
+ */
+
+ return (path);
+}
+
+/**
+ ** nameit() - ADD USER NAME TO COMMAND
+ **/
+
+char *nameit (cmd)
+ char *cmd;
+{
+ register char *nm = getname(),
+ *copy = malloc(
+ (unsigned) (strlen(cmd) + 1 +
+ strlen(nm) + 1)
+ );
+
+ (void) strcpy (copy, cmd);
+ (void) strcat (copy, " ");
+ (void) strcat (copy, nm);
+ return (copy);
+}
+
+/*
+ * update_dev_dbs - ADD/REMOVE ENTRIES FOR THE PRINTER IN DEVICE
+ * ALLOCATION FILES
+ *
+ * We intentionally ignore errors, since we don't want the printer
+ * installation to be viewed as failing just because we didn't add
+ * the device_allocate entry.
+ *
+ * Input:
+ * prtname - printer name
+ * devname - device associated w/ this printer
+ * func - [ADD|REMOVE] entries in /etc/security/device_allocate
+ * and /etc/security/device_maps
+ *
+ * Return:
+ * Always 'quiet' return. Failures are ignored.
+ */
+void
+update_dev_dbs(char *prtname, char *devname, char *func)
+{
+ int fd, status;
+ pid_t pid;
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ /* fork failed, just return quietly */
+ return;
+ case 0:
+ /* child */
+ /* redirect to /dev/null */
+ (void) close(1);
+ (void) close(2);
+ fd = open("/dev/null", O_WRONLY);
+ fd = dup(fd);
+
+ if (strcmp(func, "ADD") == 0) {
+ execl("/usr/sbin/add_allocatable", "add_allocatable",
+ "-n", prtname, "-t", "lp", "-l", devname,
+ "-o", "minlabel=admin_low:maxlabel=admin_high",
+ "-a", "*", "-c", "/bin/true", NULL);
+ } else {
+ if (strcmp(func, "REMOVE") == 0) {
+ execl("/usr/sbin/remove_allocatable",
+ "remove_allocatable", "-n", prtname, NULL);
+ }
+ }
+ _exit(1);
+ /* NOT REACHED */
+ default:
+ waitpid(pid, &status, 0);
+ return;
+ }
+}
+
+/*
+ * pack_white(ptr) trims off multiple occurances of white space from a NULL
+ * terminated string pointed to by "ptr".
+ */
+static void
+pack_white(char *ptr)
+{
+ char *tptr;
+ char *mptr;
+ int cnt;
+
+ if (ptr == NULL)
+ return;
+ cnt = strlen(ptr);
+ if (cnt == 0)
+ return;
+ mptr = (char *)calloc((unsigned)cnt+1, sizeof (char));
+ if (mptr == NULL)
+ return;
+ tptr = strtok(ptr, " \t");
+ while (tptr != NULL) {
+ (void) strcat(mptr, tptr);
+ (void) strcat(mptr, " ");
+ tptr = strtok(NULL, " \t");
+ }
+ cnt = strlen(mptr);
+ (void) strcpy(ptr, mptr);
+ free(mptr);
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/do_pwheel.c b/usr/src/cmd/lp/cmd/lpadmin/do_pwheel.c
new file mode 100644
index 0000000000..a53cb55d23
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/do_pwheel.c
@@ -0,0 +1,199 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1991 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.11 */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <libintl.h>
+
+#include "lp.h"
+#include "printers.h"
+#include "msgs.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+
+extern char *nameit(),
+ *label;
+
+static void configure_pwheel();
+
+/**
+ ** do_pwheel() - SET ALERT FOR NEED TO MOUNT PRINT WHEEL
+ **/
+
+void do_pwheel ()
+{
+ int rc;
+
+
+ if (A && STREQU(A, NAME_NONE)) {
+ BEGIN_CRITICAL
+ if (delpwheel(*S) == -1) {
+ LP_ERRMSG1 (WARNING, E_ADM_BADPWHEEL, *S);
+ return;
+ }
+ END_CRITICAL
+
+ } else if (strlen(modifications))
+ configure_pwheel (modifications);
+
+ if (A && STREQU(A, NAME_LIST)) {
+ if (label)
+ (void) printf(gettext("Print wheel %s: "), label);
+ printalert (stdout, &(oldS->alert), 0);
+ return;
+ }
+
+ if (A && STREQU(A, NAME_QUIET)) {
+
+ send_message(S_QUIET_ALERT, *S, (char *)QA_PRINTWHEEL, "");
+ rc = output(R_QUIET_ALERT);
+
+ switch(rc) {
+ case MOK:
+ break;
+
+ case MNODEST: /* not quite, but not a lie either */
+ case MERRDEST:
+ LP_ERRMSG1 (WARNING, E_LP_NOQUIET, *S);
+ break;
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ /*NOTREACHED*/
+ }
+
+ return;
+ }
+
+ if (A && STREQU(A, NAME_NONE)) {
+ send_message(S_UNLOAD_PRINTWHEEL, *S);
+ rc = output(R_UNLOAD_PRINTWHEEL);
+ } else {
+ send_message(S_LOAD_PRINTWHEEL, *S);
+ rc = output(R_LOAD_PRINTWHEEL);
+ }
+
+ switch(rc) {
+ case MOK:
+ break;
+
+ case MNODEST:
+ /*
+ * Should only occur if we're deleting a print wheel
+ * alert that doesn't exist.
+ */
+ break;
+
+ case MERRDEST:
+ LP_ERRMSG (ERROR, E_ADM_ERRDEST);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNOSPACE:
+ LP_ERRMSG (WARNING, E_ADM_NOPWSPACE);
+ break;
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ /*NOTREACHED*/
+ }
+ return;
+}
+
+/**
+ ** configure_pwheel() - SET OR CHANGE CONFIGURATION OF A PRINT WHEEL
+ **/
+
+static void configure_pwheel (list)
+ char *list;
+{
+ register PWHEEL *ppw;
+
+ PWHEEL pwheel_buf;
+
+ char type;
+
+
+ if (oldS)
+ ppw = oldS;
+ else {
+ ppw = &pwheel_buf;
+ ppw->alert.shcmd = 0;
+ ppw->alert.Q = 0;
+ ppw->alert.W = 0;
+ }
+
+ while ((type = *list++) != '\0') switch(type) {
+
+ case 'A':
+ if (STREQU(A, NAME_MAIL) || STREQU(A, NAME_WRITE))
+ ppw->alert.shcmd = nameit(A);
+ else
+ ppw->alert.shcmd = A;
+
+ break;
+
+ case 'Q':
+ ppw->alert.Q = Q;
+ break;
+
+ case 'W':
+ ppw->alert.W = W;
+ break;
+
+ }
+
+ BEGIN_CRITICAL
+ if (putpwheel(*S, ppw) == -1) {
+ LP_ERRMSG2 (
+ ERROR,
+ E_ADM_PUTPWHEEL,
+ *S,
+ PERROR
+ );
+ done(1);
+ }
+ END_CRITICAL
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/done.c b/usr/src/cmd/lp/cmd/lpadmin/done.c
new file mode 100644
index 0000000000..51121528d0
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/done.c
@@ -0,0 +1,44 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+
+extern void exit();
+
+#include "lp.h"
+#include "msgs.h"
+
+#include "lpadmin.h"
+
+/**
+ ** done() - CLEAN UP AND EXIT
+ **/
+
+void done (rc)
+ int rc;
+{
+ (void)mclose ();
+ exit (rc);
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/fromclass.c b/usr/src/cmd/lp/cmd/lpadmin/fromclass.c
new file mode 100644
index 0000000000..ab0cb36698
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/fromclass.c
@@ -0,0 +1,149 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+
+#include "stdio.h"
+#include "errno.h"
+
+#include "lp.h"
+#include "class.h"
+#include "msgs.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+
+static void _fromclass();
+
+/**
+ ** fromclass() - REMOVE PRINTER FROM A CLASS
+ **/
+
+void fromclass (printer, class)
+ char *printer,
+ *class;
+{
+ CLASS *pc;
+
+ if (!(pc = getclass(class))) {
+ LP_ERRMSG1 (ERROR, E_LP_NOCLASS, class);
+ done (1);
+ }
+
+ if (!searchlist(printer, pc->members)) {
+ LP_ERRMSG2 (ERROR, E_ADM_NOTMEM, printer, class);
+ done (1);
+ }
+
+ _fromclass (printer, class, pc);
+
+ return;
+}
+
+/**
+ ** fromallclasses() - DELETE A PRINTER FROM ALL CLASSES
+ **/
+
+void fromallclasses (printer)
+ char *printer;
+{
+ register CLASS *pc;
+
+
+ while ((pc = getclass(NAME_ALL)))
+ if (searchlist(printer, pc->members))
+ _fromclass (printer, pc->name, pc);
+
+ if (errno != ENOENT) {
+ LP_ERRMSG1 (ERROR, E_ADM_GETCLASSES, PERROR);
+ done (1);
+ }
+
+ return;
+}
+
+/**
+ ** _fromclass() - REALLY DELETE PRINTER FROM CLASS
+ **/
+
+static void _fromclass (printer, class, pc)
+ char *printer,
+ *class;
+ CLASS *pc;
+{
+ int rc;
+
+
+ if (dellist(&pc->members, printer) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done(1);
+ }
+
+ if (!pc->members)
+ rmdest (1, class);
+
+ else {
+ BEGIN_CRITICAL
+ if (putclass(class, pc) == -1) {
+ LP_ERRMSG2 (
+ ERROR,
+ E_LP_PUTCLASS,
+ class,
+ PERROR
+ );
+ done(1);
+ }
+ END_CRITICAL
+
+ send_message(S_LOAD_CLASS, class, "", "");
+ rc = output(R_LOAD_CLASS);
+
+ switch(rc) {
+ case MOK:
+ break;
+
+ case MNODEST:
+ case MERRDEST:
+ LP_ERRMSG (ERROR, E_ADM_ERRDEST);
+ done (1);
+ /*NOTREACHED*/
+
+ case MNOSPACE:
+ LP_ERRMSG (WARNING, E_ADM_NOCSPACE);
+ break;
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ /*NOTREACHED*/
+ }
+
+ }
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/ismodel.c b/usr/src/cmd/lp/cmd/lpadmin/ismodel.c
new file mode 100644
index 0000000000..3503747aac
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/ismodel.c
@@ -0,0 +1,40 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+
+#include "lp.h"
+#include "lpadmin.h"
+
+extern int Access();
+
+int ismodel (name)
+ char *name;
+{
+ if (!name || !*name)
+ return (0);
+
+ return (Access(makepath(Lp_Model, name, (char *)0), 04) != -1);
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c
new file mode 100644
index 0000000000..83560a6bf4
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.c
@@ -0,0 +1,231 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdio.h"
+#include "ctype.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "sys/utsname.h"
+#include "string.h"
+
+#include "lp.h"
+#include "msgs.h"
+#include "access.h"
+#include "class.h"
+#include "printers.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+#include <locale.h>
+
+extern void chkopts(),
+ chkopts2(),
+ chkopts3(),
+ exit();
+
+int system_labeled = 0;
+
+int scheduler_active = 0;
+
+char *label = 0;
+
+PRINTER *printer_pointer = 0;
+
+static CLASS *class_pointer = 0;
+
+PWHEEL *pwheel_pointer = 0;
+char *Local_System = 0;
+
+/**
+ ** main()
+ **/
+
+int
+main(int argc, char *argv[])
+{
+ struct utsname un;
+
+ (void) setlocale (LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ if (!is_user_admin()) {
+ LP_ERRMSG (ERROR, E_LP_NOTADM);
+ done (1);
+ /*NOTREACHED*/
+ }
+
+ system_labeled = is_system_labeled();
+
+ uname(&un);
+ Local_System = strdup(un.nodename);
+
+ options (argc, argv); /* process command line options */
+
+ chkopts (); /* check for legality of options */
+
+ startup (); /* open path to Spooler */
+
+ if (d)
+ newdflt (d); /* -d */
+
+ else if (x) {
+
+ /* allow "any" or "all" to do all destinations */
+ if (STREQU(NAME_ALL, x) || STREQU(NAME_ANY, x)) {
+
+ /*
+ * Just deleting all the printers should get
+ * rid of all the classes, too, but removing
+ * the classes first should make things go a bit
+ * faster.
+ */
+
+ while ((class_pointer = getclass(NAME_ALL)))
+ rmdest (1, class_pointer->name);
+
+ if (errno != ENOENT) {
+ LP_ERRMSG1 (
+ ERROR,
+ E_ADM_GETCLASSES,
+ PERROR
+ );
+ done (1);
+ /*NOTREACHED*/
+ }
+
+ while ((printer_pointer = getprinter(NAME_ALL)))
+ rmdest (0, printer_pointer->name);
+
+ if (errno != ENOENT) {
+ LP_ERRMSG1 (
+ ERROR,
+ E_ADM_GETPRINTERS,
+ PERROR
+ );
+ done (1);
+ /*NOTREACHED*/
+ }
+
+ } else
+ rmdest (isclass(x), x);
+
+ } else if (!p && S) {
+ if (STREQU(*S, NAME_ALL) || STREQU(*S, NAME_ANY)) {
+ while ((pwheel_pointer = getpwheel(NAME_ALL))) {
+ *S = pwheel_pointer->name;
+ chkopts3 (0);
+ label = *S;
+ do_pwheel ();
+ }
+ } else {
+ label = 0;
+ do_pwheel ();
+ }
+
+#if defined(J_OPTION)
+ } else if (j) {
+ do_fault (); /* -j */
+#endif
+
+ } else {
+ /* allow "any" or "all" to do all printers */
+ if (STREQU(NAME_ALL, p) || STREQU(NAME_ANY, p)) {
+ int called=0;
+ while ((printer_pointer = getprinter(NAME_ALL)) != NULL) {
+ /*
+ * "chkopts2()" will clobber "s".
+ */
+ char * save_s = s;
+
+ called++;
+ p = printer_pointer->name;
+ chkopts2 (0);
+
+ if (s)
+ if (
+ A || a || e || F || H
+ || h || i || l || m || M
+ || o || U || v
+ || Q != -1 || W != -1
+ )
+ LP_ERRMSG1 (
+ WARNING,
+ E_ADM_SIGNORE,
+ p
+ );
+ label = p;
+ do_printer ();
+
+ s = save_s;
+ }
+ if (called == 0 )
+ LP_ERRMSG (ERROR, E_ADM_PLONELY);
+
+ if (errno != ENOENT) {
+ LP_ERRMSG2 (
+ ERROR,
+ E_LP_GETPRINTER,
+ NAME_ALL,
+ PERROR
+ );
+ done (1);
+ /*NOTREACHED*/
+ }
+ } else {
+ label = 0;
+ do_printer (); /* -p etc. */
+ }
+ }
+ done (0);
+ /*NOTREACHED*/
+ return (0);
+}
+
+/**
+ ** putp() - FAKE ROUTINES TO AVOID REAL ONES
+ **/
+
+int putp ()
+{
+ return (0);
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h
new file mode 100644
index 0000000000..3e58a3b087
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/lpadmin.h
@@ -0,0 +1,139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#define BEGIN_CRITICAL { ignore_signals(); {
+#define END_CRITICAL } trap_signals(); }
+
+extern void ignore_signals(),
+ trap_signals();
+
+extern int a,
+ banner,
+#if defined(DIRECT_ACCESS)
+ C,
+#endif
+ filebreak,
+ h,
+ j,
+ l,
+ M,
+ t,
+ o,
+ Q,
+ W,
+ scheduler_active;
+
+extern char *A,
+ *c,
+ *cpi,
+ *d,
+ *D,
+ *e,
+ *f,
+ **f_allow,
+ **f_deny,
+ **p_add,
+ **p_remove,
+ *P,
+ *F,
+ **H,
+ *i,
+ **I,
+ *length,
+ *lpi,
+ *m,
+ modifications[128],
+#ifdef LP_USE_PAPI_ATTR
+ *n_opt,
+#endif
+ *p,
+ *r,
+ *s,
+ *stty_opt,
+ **o_options,
+ **S,
+ **T,
+ *u,
+ **u_allow,
+ **u_deny,
+ *U,
+ *v,
+ *width,
+ *x;
+
+#if defined(LPUSER)
+extern SCALED cpi_sdn,
+ length_sdn,
+ lpi_sdn,
+ width_sdn;
+#endif
+
+#if defined(PR_MAX)
+extern PRINTER *oldp;
+
+extern PWHEEL *oldS;
+#endif
+
+extern short daisy;
+
+extern char *Local_System;
+
+extern char *getdflt();
+
+extern int ismodel(),
+ output(),
+ verify_form(),
+ do_align();
+
+extern void do_fault(),
+ do_mount(),
+ do_printer(),
+ do_pwheel(),
+ done(),
+ fromclass(),
+ newdflt(),
+ options(),
+ rmdest(),
+ startup(),
+ usage();
+
+/* Routines/variables needed for labeled systems */
+extern void update_dev_dbs(char *, char *, char *);
+extern int system_labeled;
+
+
+#if defined(__STDC__)
+void send_message( int , ... );
+extern char ** pick_opts(char *, char **);
+#else
+extern void send_message();
+extern char ** pick_opts();
+#endif
diff --git a/usr/src/cmd/lp/cmd/lpadmin/options.c b/usr/src/cmd/lp/cmd/lpadmin/options.c
new file mode 100644
index 0000000000..04928e5795
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/options.c
@@ -0,0 +1,775 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include "ctype.h"
+#include "stdio.h"
+#include "string.h"
+#include "stdlib.h"
+#include <libintl.h>
+
+#include "lp.h"
+#include "printers.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+#ifdef LP_USE_PAPI_ATTR
+#if defined(CAN_DO_MODULES)
+#define OPT_LIST "A:ac:d:D:e:f:F:H:hi:I:lm:Mn:o:p:Q:r:S:s:T:u:U:v:W:x:t:P:"
+#else
+#define OPT_LIST "A:ac:d:D:e:f:F:hi:I:lm:Mn:o:p:Q:r:S:s:T:u:U:v:W:x:t:P:"
+#endif
+
+#else
+#if defined(CAN_DO_MODULES)
+#define OPT_LIST "A:ac:d:D:e:f:F:H:hi:I:lm:Mo:p:Q:r:S:s:T:u:U:v:W:x:t:P:"
+#else
+#define OPT_LIST "A:ac:d:D:e:f:F:hi:I:lm:Mo:p:Q:r:S:s:T:u:U:v:W:x:t:P:"
+#endif
+#endif
+
+#define MALLOC(pointer) \
+ if (!(pointer = strdup(optarg))) { \
+ LP_ERRMSG (ERROR, E_LP_MALLOC); \
+ done (1); \
+ } else
+
+#define REALLOC(pointer) \
+ if (!(pointer = realloc(pointer, (unsigned) (strlen(pointer) + 1 + strlen(optarg) + 1)))) { \
+ LP_ERRMSG (ERROR, E_LP_MALLOC); \
+ done (1); \
+ } else if (strcat(pointer, " ")) \
+ (void)strcat (pointer, optarg); \
+ else
+
+extern char *optarg;
+
+extern int optind,
+ opterr,
+ optopt;
+
+extern double strtod();
+
+extern long strtol();
+
+int a = 0, /* alignment needed for mount */
+ banner = -1, /* allow/don't-allow nobanner */
+#if defined(DIRECT_ACCESS)
+ C = 0, /* direct a.o.t. normal access */
+#endif
+ filebreak = 0,
+ h = 0, /* hardwired terminal */
+ j = 0, /* do -F just for current job */
+ l = 0, /* login terminal */
+ M = 0, /* do mount */
+ t = 0, /* tray number*/
+ o = 0, /* some -o options given */
+ Q = -1, /* queue threshold for alert */
+ W = -1; /* alert interval */
+
+char *A = 0, /* alert type */
+ *c = 0, /* class name */
+ *cpi = 0, /* string value of -o cpi= */
+ *d = 0, /* default destination */
+ *D = 0, /* description */
+ *e = 0, /* copy existing interface */
+ *f = 0, /* forms list - allow/deny */
+ *P = 0, /* paper list */
+ *F = 0, /* fault recovery */
+ **H = 0, /* list of modules to push */
+ *i = 0, /* interface pathname */
+ **I = 0, /* content-type-list */
+ *length = 0, /* string value of -o length= */
+ *lpi = 0, /* string value of -o lpi= */
+ *m = 0, /* model name */
+ modifications[128], /* list of mods to make */
+#ifdef LP_USE_PAPI_ATTR
+ *n_opt = NULL, /* PPD file name */
+#endif
+ *p = 0, /* printer name */
+ *r = 0, /* class to remove printer from */
+ *s = 0, /* system printer is on */
+ *stty_opt= 0, /* string value of -o stty= */
+ **o_options = 0,/* undefined lpadmin -o options */
+ **S = 0, /* -set/print-wheel list */
+ **T = 0, /* terminfo names */
+ *u = 0, /* user allow/deny list */
+ *U = 0, /* dialer_info */
+ *v = 0, /* device pathname */
+ *width = 0, /* string value of -o width= */
+ *x = 0; /* destination to be deleted */
+
+SCALED cpi_sdn = { 0, 0 },
+ length_sdn = { 0, 0 },
+ lpi_sdn = { 0, 0 },
+ width_sdn = { 0, 0 };
+
+static char *modp = modifications;
+
+static void oparse();
+
+static char * empty_list[] = { 0 };
+
+/**
+ ** options() - PARSE COMMAND LINE ARGUMENTS INTO OPTIONS
+ **/
+
+void options (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int optsw,
+ ac,
+ Aflag = 0;
+
+ char *cp,
+ *rest,
+ **av;
+ char stroptsw[] = "-X";
+
+#if defined(__STDC__)
+ typedef char * const * stupid; /* dumb-ass ANSI C */
+#else
+ typedef char ** stupid;
+#endif
+
+
+ /*
+ * Add a fake value to the end of the "argv" list, to
+ * catch the case that a valued-option comes last.
+ */
+ av = malloc((argc + 2) * sizeof(char *));
+ for (ac = 0; ac < argc; ac++)
+ av[ac] = argv[ac];
+ av[ac++] = "--";
+
+ opterr = 0;
+ while ((optsw = getopt(ac, (stupid)av, OPT_LIST)) != EOF) {
+
+ switch (optsw) {
+
+ /*
+ * These options MAY take a value. Check the value;
+ * if it begins with a '-', assume it's really the next
+ * option.
+ */
+ case 'd':
+ case 'p': /* MR bl87-27863 */
+ case 'I':
+#if defined(CAN_DO_MODULES)
+ case 'H':
+#endif
+ if (*optarg == '-') {
+ /*
+ * This will work if we were given
+ *
+ * -x -foo
+ *
+ * but would fail if we were given
+ *
+ * -x-foo
+ */
+ optind--;
+ switch (optsw) {
+ case 'd':
+#if defined(CAN_DO_MODULES)
+ case 'H':
+#endif
+ optarg = NAME_NONE;
+ break;
+ case 'p':
+ optarg = NAME_ALL;
+ break;
+ case 'I':
+ optarg = 0;
+ break;
+ }
+ }
+ break;
+
+ /*
+ * These options MUST have a value. Check the value;
+ * if it begins with a dash or is null, complain.
+ */
+ case 'Q':
+ case 'W':
+ case 't':
+ /*
+ * These options take numeric values, which might
+ * be negative. Negative values are handled later,
+ * but here we just screen them.
+ */
+ (void)strtol(optarg, &rest, 10);
+ if (!rest || !*rest)
+ break;
+ /*FALLTHROUGH*/
+ case 'A':
+ case 'c':
+ case 'e':
+ case 'f':
+ case 'P':
+ case 'F':
+ case 'i':
+ case 'm':
+#ifdef LP_USE_PAPI_ATTR
+ case 'n':
+#endif
+ case 'o':
+/* case 'p': */ /* MR bl87-27863 */
+ case 'r':
+ case 'S':
+ case 's':
+ case 'T':
+ case 'u':
+ case 'U':
+ case 'v':
+ case 'x':
+ /*
+ * These options also must have non-null args.
+ */
+ if (!*optarg) {
+ stroptsw[1] = optsw;
+ LP_ERRMSG1 (ERROR, E_LP_NULLARG, stroptsw);
+ done (1);
+ }
+ if (*optarg == '-') {
+ stroptsw[1] = optsw;
+ LP_ERRMSG1 (ERROR, E_LP_OPTARG, stroptsw);
+ done (1);
+ }
+ if (optsw == 'A')
+ Aflag++;
+ break;
+ case 'D':
+ /*
+ * These options can have a null arg.
+ */
+ if (*optarg == '-') {
+ stroptsw[1] = optsw;
+ LP_ERRMSG1 (ERROR, E_LP_OPTARG, stroptsw);
+ done (1);
+ }
+ break;
+ }
+
+ switch (optsw) {
+
+ case 'a': /* alignment pattern needed for mount */
+ a = 1;
+ break;
+
+ case 'A': /* alert type */
+ if (A)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'A');
+ MALLOC(A);
+ Aflag++;
+ if (!STREQU(A, NAME_QUIET) && !STREQU(A, NAME_LIST))
+ *modp++ = 'A';
+ break;
+
+ case 'c': /* class to insert printer p */
+ if (c)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'c');
+ MALLOC(c);
+ break;
+
+#if defined(DIRECT_ACCESS)
+ case 'C':
+ C = 1;
+ break;
+#endif
+
+ case 'd': /* system default destination */
+ if (d)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'd');
+ MALLOC(d);
+ break;
+
+ case 'D': /* description */
+ if (D)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'D');
+ MALLOC(D);
+ *modp++ = 'D';
+ break;
+
+ case 'e': /* existing printer interface */
+ if (e)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'e');
+ MALLOC(e);
+ *modp++ = 'e';
+ break;
+
+ case 'f': /* set up forms allow/deny */
+ if (f)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'f');
+ MALLOC(f);
+ break;
+
+ case 'P': /* set up forms allow/deny */
+ if (P)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'P');
+ MALLOC(P);
+ break;
+
+ case 'F': /* fault recovery */
+ if (F)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'F');
+ MALLOC(F);
+ *modp++ = 'F';
+ break;
+
+#if defined(CAN_DO_MODULES)
+ case 'H':
+ if (H)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'H');
+ if (!optarg || !*optarg || STREQU(NAME_NONE, optarg))
+ H = empty_list;
+ if (!(H = getlist(optarg, LP_WS, LP_SEP))) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done(1);
+ }
+ *modp++ = 'H';
+ break;
+#endif
+
+ case 'h': /* hardwired terminal */
+ h = 1;
+ *modp++ = 'h';
+ break;
+
+ case 'i': /* interface pathname */
+ if (i)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'i');
+ MALLOC(i);
+ *modp++ = 'i';
+ break;
+
+ case 'I': /* content-type-list */
+ if (I)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'I');
+ if (!optarg || !*optarg || STREQU(NAME_NONE, optarg))
+ I = empty_list;
+ else if (!(I = getlist(optarg, LP_WS, LP_SEP))) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done (1);
+ }
+ *modp++ = 'I';
+ break;
+
+#if defined(J_OPTION)
+ case 'j': /* fault recovery just for current job */
+ j = 1;
+(void) printf (gettext("Sorry, the -j option is currently broken\n"));
+ break;
+#endif
+
+ case 'l': /* login terminal */
+ l = 1;
+ *modp++ = 'l';
+ break;
+
+ case 'm': /* model interface */
+ if (m)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'm');
+ MALLOC(m);
+ *modp++ = 'm';
+ break;
+
+#ifdef LP_USE_PAPI_ATTR
+ case 'n': /* PPD file */
+ if (n_opt)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'n');
+ MALLOC(n_opt);
+ *modp++ = 'n';
+ break;
+#endif
+
+ case 'M': /* a mount request */
+ M = 1;
+ break;
+
+ case 'o': /* several different options */
+ oparse (optarg);
+ o = 1;
+ break;
+
+ case 'p': /* printer name */
+ if (p)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'p');
+ MALLOC(p);
+ break;
+
+ case 'Q':
+ if (Q != -1)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'Q');
+ if (STREQU(NAME_ANY, optarg))
+ Q = 1;
+ else {
+ Q = strtol(optarg, &rest, 10);
+ if (Q < 0) {
+ LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'Q');
+ done (1);
+ }
+ if (rest && *rest) {
+ LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'Q');
+ done (1);
+ }
+ if (Q == 0) {
+ LP_ERRMSG1 (ERROR, E_ADM_ZEROARG, 'Q');
+ done (1);
+ }
+ }
+ *modp++ = 'Q';
+ break;
+
+ case 'r': /* class to remove p from */
+ if (r)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'r');
+ MALLOC(r);
+ break;
+
+ case 'S': /* char_set/print-wheels */
+ if (S)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'S');
+ if (!(S = getlist(optarg, LP_WS, LP_SEP))) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done (1);
+ }
+ *modp++ = 'S';
+ break;
+
+ case 's':
+ if (s)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 's');
+
+ if ((cp = strchr(optarg, '!')))
+ *cp = '\0';
+
+ if ((STREQU(optarg, NAME_NONE)) ||
+ (STREQU(optarg, "localhost")))
+
+ s = Local_System;
+ else if (STREQU(optarg, Local_System)) {
+ if (cp) {
+ LP_ERRMSG (ERROR, E_ADM_NAMEONLOCAL);
+ done(1);
+ } else
+ s = Local_System;
+ } else {
+ if (cp)
+ *cp = '!';
+
+ MALLOC(s);
+ }
+
+ /* 's' already used for stty 'R' for remote? */
+ *modp++ = 'R';
+ break;
+
+ case 't': /* tray number*/
+ if (t != 0) LP_ERRMSG1 (WARNING, E_LP_2MANY, 't');
+ t = strtol(optarg, &rest, 10);
+ if (t <= 0) {
+ LP_ERRMSG1 (ERROR, E_LP_NEGARG, 't');
+ done (1);
+ }
+ if (rest && *rest) {
+ LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 't');
+ done (1);
+ }
+ break;
+
+ case 'T': /* terminfo names for p */
+ if (T)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'T');
+ if (!(T = getlist(optarg, LP_WS, LP_SEP))) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done (1);
+ }
+ *modp++ = 'T';
+ break;
+
+ case 'u': /* user allow/deny list */
+ if (u)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'u');
+ MALLOC(u);
+ break;
+
+ case 'U': /* dialer_info */
+ if (U)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'U');
+ MALLOC(U);
+ *modp++ = 'U';
+ break;
+
+ case 'v': /* device pathname */
+ if (v)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'v');
+ MALLOC(v);
+ *modp++ = 'v';
+ break;
+
+ case 'W': /* alert interval */
+ if (W != -1)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'W');
+ if (STREQU(NAME_ONCE, optarg))
+ W = 0;
+ else {
+ W = strtol(optarg, &rest, 10);
+ if (W < 0) {
+ LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'W');
+ done (1);
+ }
+ if (rest && *rest) {
+ LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'W');
+ done (1);
+ }
+ }
+ *modp++ = 'W';
+ break;
+
+ case 'x': /* destination to be deleted */
+ if (x)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'x');
+ MALLOC(x);
+ break;
+
+ default:
+ if (optopt == '?') {
+ usage ();
+ done (0);
+
+ } else {
+ stroptsw[1] = optsw;
+
+ if (strchr(OPT_LIST, optopt))
+ LP_ERRMSG1 (ERROR, E_LP_OPTARG,
+ stroptsw);
+ else
+ LP_ERRMSG1 (ERROR, E_LP_OPTION,
+ stroptsw);
+ done (1);
+ }
+ }
+ }
+
+ if (optind < argc)
+ LP_ERRMSG1 (WARNING, E_LP_EXTRA, argv[optind]);
+
+ if ((v) && (!Aflag)) {
+ if (!(A = strdup("write"))) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ done (1);
+ }
+ *modp++ = 'A';
+ }
+
+ return;
+}
+
+/**
+ ** oparse() - PARSE -o OPTION
+ **/
+
+static void oparse (optarg)
+ char *optarg;
+{
+ register char **list = dashos(optarg);
+
+
+ if (!list)
+ return;
+
+ for ( ; (optarg = *list); list++)
+
+ if (STREQU(optarg, "banner")) {
+ if (banner != -1)
+ LP_ERRMSG1 (
+ WARNING,
+ E_ADM_2MANY,
+ "banner/nobanner"
+ );
+ banner = BAN_ALWAYS;
+ *modp++ = 'b';
+
+ } else if (STREQU(optarg, "nobanner")) {
+ if (banner != -1)
+ LP_ERRMSG1 (
+ WARNING,
+ E_ADM_2MANY,
+ "banner/nobanner"
+ );
+ banner = BAN_OPTIONAL;
+ *modp++ = 'b';
+
+ /* handle banner=(always|optional|never) */
+ } else if (STRNEQU(optarg, "banner=", 7)) {
+ char *ptr;
+
+ ptr = (optarg += 7);
+ if (banner != -1)
+ LP_ERRMSG1 ( WARNING, E_ADM_2MANY,
+ "banner/nobanner/banner=(always|optional|never)"
+ );
+
+ /* like "banner", always print a banner */
+ if (strcasecmp(ptr, "always") == 0)
+ banner = BAN_ALWAYS;
+ /* like "nobanner", print a banner unless requested */
+ if (strcasecmp(ptr, "optional") == 0)
+ banner = BAN_OPTIONAL;
+ /* never print a banner */
+ if (strcasecmp(ptr, "never") == 0)
+ banner = BAN_NEVER;
+ *modp++ = 'b';
+
+ } else if (STRNEQU(optarg, "length=", 7)) {
+ if (length)
+ LP_ERRMSG1 (
+ WARNING,
+ E_ADM_2MANY,
+ "length="
+ );
+ length = (optarg += 7);
+
+ if (!*optarg) {
+ length_sdn.val = 0;
+ length_sdn.sc = 0;
+
+ } else {
+ length_sdn = _getsdn(optarg, &optarg, 0);
+ if (errno == EINVAL) {
+ LP_ERRMSG (ERROR, E_LP_BADSCALE);
+ done (1);
+ }
+ }
+ *modp++ = 'L';
+
+ } else if (STRNEQU(optarg, "width=", 6)) {
+ if (width)
+ LP_ERRMSG1 (
+ WARNING,
+ E_ADM_2MANY,
+ "width="
+ );
+ width = (optarg += 6);
+
+ if (!*optarg) {
+ width_sdn.val = 0;
+ width_sdn.sc = 0;
+
+ } else {
+ width_sdn = _getsdn(optarg, &optarg, 0);
+ if (errno == EINVAL) {
+ LP_ERRMSG (ERROR, E_LP_BADSCALE);
+ done (1);
+ }
+ }
+ *modp++ = 'w';
+
+ } else if (STRNEQU(optarg, "cpi=", 4)) {
+ if (cpi)
+ LP_ERRMSG1 (WARNING, E_ADM_2MANY, "cpi=");
+
+ cpi = (optarg += 4);
+
+ if (!*optarg) {
+ cpi_sdn.val = 0;
+ cpi_sdn.sc = 0;
+
+ } else {
+ cpi_sdn = _getsdn(optarg, &optarg, 1);
+ if (errno == EINVAL) {
+ LP_ERRMSG (ERROR, E_LP_BADSCALE);
+ done (1);
+ }
+ }
+ *modp++ = 'c';
+
+ } else if (STRNEQU(optarg, "lpi=", 4)) {
+ if (lpi)
+ LP_ERRMSG1 (WARNING, E_ADM_2MANY, "lpi=");
+ lpi = (optarg += 4);
+
+ if (!*optarg) {
+ lpi_sdn.val = 0;
+ lpi_sdn.sc = 0;
+
+ } else {
+ lpi_sdn = _getsdn(optarg, &optarg, 0);
+ if (errno == EINVAL) {
+ LP_ERRMSG (ERROR, E_LP_BADSCALE);
+ done (1);
+ }
+ }
+ *modp++ = 'M';
+
+ } else if (STRNEQU(optarg, "stty=", 5)) {
+
+ optarg += 5;
+ if (!*optarg)
+ stty_opt = 0;
+
+ else {
+ if (strchr(LP_QUOTES, *optarg)) {
+ register int len
+ = strlen(optarg);
+
+ if (optarg[len - 1] == *optarg)
+ optarg[len - 1] = 0;
+ optarg++;
+ }
+ if (stty_opt)
+ REALLOC (stty_opt);
+ else
+ MALLOC (stty_opt);
+ }
+ *modp++ = 's';
+
+ } else if (STREQU(optarg, "filebreak")) {
+ filebreak = 1;
+
+ } else if (STREQU(optarg, "nofilebreak")) {
+ filebreak = 0;
+
+ /* added support for using -o to pass any key=value pair */
+ } else if (*optarg) {
+
+ if ((addlist(&o_options, optarg)) != 0) {
+ fprintf(stderr, gettext("System Error %d\n"), errno);
+ }
+
+ *modp++ = 'o';
+ optarg++;
+ }
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/output.c b/usr/src/cmd/lp/cmd/lpadmin/output.c
new file mode 100644
index 0000000000..269c6712a9
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/output.c
@@ -0,0 +1,146 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+
+#include "stdio.h"
+#include "string.h"
+#include "sys/types.h"
+
+#include "lp.h"
+#include "printers.h"
+#include "msgs.h"
+#include "requests.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+
+/**
+ ** output() - (MISNOMER) HANDLE MESSAGES BACK FROM SPOOLER
+ **/
+
+int output (type)
+ int type;
+{
+ char buffer[MSGMAX];
+
+ int rc;
+
+ short status;
+ char *dummy;
+
+
+ if (!scheduler_active)
+ switch (type) {
+
+ case R_MOUNT_TRAY:
+ case R_UNMOUNT_TRAY:
+ case R_MOUNT:
+ case R_UNMOUNT:
+ case R_MAX_TRAYS:
+ case R_QUIET_ALERT:
+ case R_INQUIRE_PRINTER_STATUS:
+ case R_ALLOC_FILES:
+ case R_PRINT_REQUEST:
+ case R_REJECT_DEST:
+ case R_ACCEPT_DEST:
+ case R_DISABLE_DEST:
+ case R_ENABLE_DEST:
+ case R_CANCEL_REQUEST:
+ default:
+ LP_ERRMSG (ERROR, E_LP_NEEDSCHED);
+ done (1);
+
+ case R_UNLOAD_PRINTER:
+ case R_UNLOAD_CLASS:
+ case R_UNLOAD_PRINTWHEEL:
+ if (anyrequests()) {
+ LP_ERRMSG (ERROR, E_LP_HAVEREQS);
+ done (1);
+ }
+ /* fall through */
+
+ case R_LOAD_PRINTER:
+ case R_LOAD_CLASS:
+ case R_LOAD_PRINTWHEEL:
+ return (MOK);
+
+ }
+
+ status = MOKMORE;
+ while (status == MOKMORE) {
+
+ if ((rc = mrecv(buffer, MSGMAX)) != type) {
+ LP_ERRMSG (ERROR, E_LP_MRECV);
+ done (1);
+ }
+
+ switch(type) {
+
+ case R_MOUNT_TRAY:
+ case R_UNMOUNT_TRAY:
+ case R_MOUNT:
+ case R_UNMOUNT:
+ case R_MAX_TRAYS:
+ case R_LOAD_PRINTER:
+ case R_UNLOAD_PRINTER:
+ case R_LOAD_CLASS:
+ case R_UNLOAD_CLASS:
+ case R_LOAD_PRINTWHEEL:
+ case R_UNLOAD_PRINTWHEEL:
+ case R_QUIET_ALERT:
+ case R_REJECT_DEST:
+ case R_ACCEPT_DEST:
+ case R_ENABLE_DEST:
+ case R_CANCEL_REQUEST:
+ rc = getmessage(buffer, type, &status);
+ goto CheckRC;
+
+ case R_DISABLE_DEST:
+ rc = getmessage(buffer, type, &status, &dummy);
+CheckRC: if (rc != type) {
+ LP_ERRMSG1 (ERROR, E_LP_BADREPLY, rc);
+ done (1);
+ }
+ break;
+
+ case R_INQUIRE_PRINTER_STATUS:
+ case R_ALLOC_FILES:
+ case R_PRINT_REQUEST:
+ return (0); /* handled by caller */
+ }
+
+ }
+
+ return (status);
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/pick_opts.c b/usr/src/cmd/lp/cmd/lpadmin/pick_opts.c
new file mode 100644
index 0000000000..a4c56dbd70
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/pick_opts.c
@@ -0,0 +1,107 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <libintl.h>
+
+#include "lp.h"
+#include "class.h"
+#include "printers.h"
+#include "msgs.h"
+
+char **
+pick_opts(char * infile_opts, char ** new_opts)
+{
+ char * flasts = NULL;
+ char * old_opt;
+ char ** final_opts = NULL;
+ int key_len;
+ int keyfound = 0;
+ char ** head;
+
+ if (infile_opts == NULL || new_opts == NULL) {
+ (void) printf("lpadmin error: Cannot process -o options");
+ return (NULL);
+ }
+
+ head = new_opts;
+ for (; *new_opts != NULL; new_opts++) {
+ if (strlen(*new_opts) > (strcspn(*new_opts, "=") + 1)) {
+ if ((addlist(&final_opts, *new_opts)) != 0) {
+ fprintf(stderr,
+ gettext("lpadmin: System Error %d\n"),
+ errno);
+
+ return (NULL);
+ }
+ }
+ }
+ /*
+ * For each currently set option, ie, those already in the file,
+ * compare to new list from lpadmin (new_opts).
+ */
+ for (old_opt = strtok_r(infile_opts, LP_SEP, &flasts);
+ old_opt != NULL; old_opt = strtok_r(NULL, LP_SEP, &flasts)) {
+
+ keyfound = 0;
+
+ for (new_opts = head; *new_opts != NULL; new_opts++) {
+
+ key_len = strcspn(*new_opts, "=");
+ /*
+ * if the keys match, and the the key from the
+ * lpadmin -o has a value, take the new value from
+ * lpadmin
+ */
+ if ((strncmp(old_opt, *new_opts, key_len + 1)) == 0) {
+ keyfound++;
+ }
+ }
+ if (keyfound == 0) {
+ if ((addlist(&final_opts, old_opt)) != 0) {
+ fprintf(stderr,
+ gettext("lpadmin: System Error %d\n"),
+ errno);
+
+ return (NULL);
+ }
+ }
+
+ }
+
+ return (final_opts);
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/rmdest.c b/usr/src/cmd/lp/cmd/lpadmin/rmdest.c
new file mode 100644
index 0000000000..35ff27d364
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/rmdest.c
@@ -0,0 +1,127 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "stdio.h"
+#include "ctype.h"
+#include "errno.h"
+#include "sys/types.h"
+
+#include "lp.h"
+#include "msgs.h"
+#include "access.h"
+#include "class.h"
+#include "printers.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+extern void fromallclasses();
+
+/**
+ ** rmdest() - REMOVE DESTINATION
+ **/
+
+void rmdest (aclass, dest)
+ int aclass;
+ char *dest;
+{
+ int rc,
+ type;
+
+
+ if (!aclass)
+ type = S_UNLOAD_PRINTER;
+ else
+ type = S_UNLOAD_CLASS;
+
+
+ send_message(type, dest, "", "");
+ rc = output(type + 1);
+
+ switch (rc) {
+ case MOK:
+ case MNODEST:
+ BEGIN_CRITICAL
+ if (
+ aclass && delclass(dest) == -1
+ || !aclass && delprinter(dest) == -1
+ ) {
+ if (rc == MNODEST && errno == ENOENT)
+ LP_ERRMSG1 (
+ ERROR,
+ E_ADM_NODEST,
+ dest
+ );
+
+ else
+ LP_ERRMSG2 (
+ ERROR,
+(rc == MNODEST? (aclass? E_LP_DELCLASS : E_LP_DELPRINTER) : E_ADM_DELSTRANGE),
+ dest,
+ PERROR
+ );
+
+ done(1);
+ }
+ END_CRITICAL
+
+ /*
+ * S_UNLOAD_PRINTER tells the Spooler to remove
+ * the printer from all classes (in its internal
+ * tables, of course). So it's okay for us to do
+ * the same with the disk copies.
+ */
+ if (!aclass)
+ fromallclasses (dest);
+
+ if (STREQU(getdflt(), dest))
+ newdflt (NAME_NONE);
+
+ if (system_labeled) {
+ update_dev_dbs(dest, NULL, "REMOVE");
+ }
+ break;
+
+ case MBUSY:
+ LP_ERRMSG1 (ERROR, E_ADM_DESTBUSY, dest);
+ done (1);
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
+ done (1);
+ break;
+
+ }
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/send_message.c b/usr/src/cmd/lp/cmd/lpadmin/send_message.c
new file mode 100644
index 0000000000..b7cf7f366e
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/send_message.c
@@ -0,0 +1,88 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+
+#include "stdio.h"
+
+#if defined(__STDC__)
+#include "stdarg.h"
+#else
+#include "varargs.h"
+#endif
+
+#include "msgs.h"
+
+#define WHO_AM_I I_AM_LPADMIN
+#include "oam.h"
+
+#include "lpadmin.h"
+
+
+/**
+ ** send_message() - HANDLE MESSAGE SENDING TO SPOOLER
+ **/
+
+/*VARARGS1*/
+
+void
+#if defined(__STDC__)
+send_message (
+ int type,
+ ...
+)
+#else
+send_message (type, va_alist)
+ int type;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ int n;
+
+ char msgbuf[MSGMAX];
+
+
+ if (!scheduler_active)
+ return;
+
+#if defined(__STDC__)
+ va_start (ap, type);
+#else
+ va_start (ap);
+#endif
+
+ (void)_putmessage (msgbuf, type, ap);
+
+ va_end (ap);
+
+ if (msend(msgbuf) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MSEND);
+ done(1);
+ }
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/signals.c b/usr/src/cmd/lp/cmd/lpadmin/signals.c
new file mode 100644
index 0000000000..4cebf21564
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/signals.c
@@ -0,0 +1,119 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+
+#include "signal.h"
+
+#include "lpadmin.h"
+
+static int trapping = -1; /* -1 means first time */
+
+static
+#ifdef SIGPOLL
+ void
+#else
+ int
+#endif
+ (*old_sighup)(),
+ (*old_sigint)(),
+ (*old_sigquit)(),
+ (*old_sigterm)();
+
+/**
+ ** catch() - CLEAN UP AFTER SIGNAL
+ **/
+
+static void
+catch (sig)
+{
+ (void)signal (SIGHUP, SIG_IGN);
+ (void)signal (SIGINT, SIG_IGN);
+ (void)signal (SIGQUIT, SIG_IGN);
+ (void)signal (SIGTERM, SIG_IGN);
+ done (1);
+}
+
+/**
+ ** trap_signals() - SET SIGNALS TO BE CAUGHT FOR CLEAN EXIT
+ **/
+
+void trap_signals ()
+{
+ switch (trapping) {
+
+ case -1: /* first time */
+
+#define SETSIG(SIG) \
+ if (signal(SIG, SIG_IGN) != SIG_IGN) \
+ signal (SIG, catch);
+
+ SETSIG (SIGHUP);
+ SETSIG (SIGINT);
+ SETSIG (SIGQUIT);
+ SETSIG (SIGTERM);
+ break;
+
+ case 0: /* currently ignoring */
+ signal (SIGHUP, old_sighup);
+ signal (SIGINT, old_sigint);
+ signal (SIGQUIT, old_sigquit);
+ signal (SIGTERM, old_sigterm);
+ trapping = 1;
+ break;
+
+ case 1: /* already trapping */
+ break;
+
+ }
+ return;
+}
+
+/**
+ ** ignore_signals() - SET SIGNALS TO BE IGNORED FOR CRITICAL SECTIONS
+ **/
+
+void ignore_signals ()
+{
+ switch (trapping) {
+
+ case -1: /* first time */
+ trap_signals ();
+ /*fall through*/
+
+ case 1: /* currently trapping */
+ old_sighup = signal(SIGHUP, SIG_IGN);
+ old_sigint = signal(SIGINT, SIG_IGN);
+ old_sigquit = signal(SIGQUIT, SIG_IGN);
+ old_sigterm = signal(SIGTERM, SIG_IGN);
+ trapping = 0;
+ break;
+
+ case 0: /* already ignoring */
+ break;
+
+ }
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/startup.c b/usr/src/cmd/lp/cmd/lpadmin/startup.c
new file mode 100644
index 0000000000..2c2fb76974
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/startup.c
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+
+#include "stdio.h"
+
+#include "lp.h"
+#include "msgs.h"
+
+#include "lpadmin.h"
+
+
+/**
+ ** startup() - OPEN CHANNEL TO SPOOLER
+ **/
+
+void startup ()
+{
+ trap_signals ();
+
+ if (mopen() == -1)
+ scheduler_active = 0;
+ else
+ scheduler_active = 1;
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpadmin/usage.c b/usr/src/cmd/lp/cmd/lpadmin/usage.c
new file mode 100644
index 0000000000..dc0f0bdbdf
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpadmin/usage.c
@@ -0,0 +1,139 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+
+#include "lp.h"
+#include "printers.h"
+#include <locale.h>
+
+/**
+ ** usage() - PRINT COMMAND USAGE
+ **/
+
+void usage ()
+{
+#if defined(CAN_DO_MODULES)
+ (void) printf (gettext(
+"usage:\n"
+"\n"
+" (add printer)\n\n"
+" lpadmin -p printer {-v device | -U dial-info | -s system[!printer]} [options]\n"
+" [-s system[!printer]] (remote system/printer name)\n"
+" [-v device] (printer port name)\n"
+" [-U dial-info] (phone # or sys. name)\n"
+" [-T type-list] (printer types)\n"
+" [-c class | -r class] (add to/del from class)\n"
+" [-A mail|write|quiet|showfault|cmd [-W interval]]\n"
+" (alert definition)\n"
+" [-A none] (no alerts)\n"
+" [-A list] (examine alert)\n"
+" [-D comment] (printer description)\n"
+" [-e printer | -i interface | -m model] (interface program)\n"
+" [-l | -h] (is/isn't login tty)\n"
+" [-f allow:forms-list | deny:forms-list] (forms allowed)\n"
+" [-u allow:user-list | deny:user-list] (who's allowed to use)\n"
+" [-S char-set-maps | print-wheels] (list of avail. fonts)\n"
+" [-I content-type-list] (file types accepted\n"
+" [-F beginning|continue|wait] (fault recovery)\n"
+" [-o stty='stty-options'] (port characteristics)\n"
+" [-o cpi=scaled-number] (character pitch)\n"
+" [-o lpi=scaled-number] (line pitch)\n"
+" [-o width=scaled-number] (page width)\n"
+" [-o length=scaled-number] (page length)\n"
+" [-o nobanner] (allow no banner)\n\n"
+" [-P paper-list] (add paper type)\n"
+" [-P ~paper-list] (remove paper type)\n"
+" [-t number-of-trays] (number of paper trays)\n"
+" [-H module,...|keep|default|none] (STREAMS modules to push)\n\n"
+" (delete printer or class)\n"
+" lpadmin -x printer-or-class\n\n"
+" (define default destination)\n"
+" lpadmin -d printer-or-class\n\n"
+" (mount form, printwheel)\n"
+" lpadmin -p printer -M {options}\n"
+" [-f form [-a [-o filebreak]] [-t tray-number]]\n"
+" (mount (align) form (on tray))\n"
+" [-S print-wheel] (mount print wheel)\n\n"
+" (define print-wheel mount alert)\n"
+" lpadmin -S print-wheel {options}\n"
+" [-A mail|write|quiet|cmd [-W interval] [-Q queue-size]]\n"
+" [-A none] (no alerts)\n"
+" [-A list] (examine alert)\n "));
+#else
+ (void) printf (gettext(
+"usage:\n"
+"\n"
+" (add printer)\n\n"
+" lpadmin -p printer {-v device | -U dial-info | -s system[!printer]} [options]\n"
+" [-s system[!printer]] (remote system/printer name)\n"
+" [-v device] (printer port name)\n"
+" [-U dial-info] (phone # or sys. name)\n"
+" [-T type-list] (printer types)\n"
+" [-c class | -r class] (add to/del from class)\n"
+" [-A mail|write|quiet|showfault|cmd [-W interval]]\n"
+" (alert definition)\n"
+" [-A none] (no alerts)\n"
+" [-A list] (examine alert)\n"
+" [-D comment] (printer description)\n"
+" [-e printer | -i interface | -m model] (interface program)\n"
+" [-l | -h] (is/isn't login tty)\n"
+" [-f allow:forms-list | deny:forms-list] (forms allowed)\n"
+" [-u allow:user-list | deny:user-list] (who's allowed to use)\n"
+" [-S char-set-maps | print-wheels] (list of avail. fonts)\n"
+" [-I content-type-list] (file types accepted\n"
+" [-F beginning|continue|wait] (fault recovery)\n"
+" [-o stty='stty-options'] (port characteristics)\n"
+" [-o cpi=scaled-number] (character pitch)\n"
+" [-o lpi=scaled-number] (line pitch)\n"
+" [-o width=scaled-number] (page width)\n"
+" [-o length=scaled-number] (page length)\n"
+" [-o nobanner] (allow no banner)\n\n"
+" [-P paper-list] (add paper type)\n"
+" [-P ~paper-list] (remove paper type)\n"
+" [-t number-of-trays] (number of paper trays)\n"
+" (delete printer or class)\n"
+" lpadmin -x printer-or-class\n\n"
+" (define default destination)\n"
+" lpadmin -d printer-or-class\n\n"
+" (mount form, printwheel)\n"
+" lpadmin -p printer -M {options}\n"
+" [-f form [-a [-o filebreak]] [-t tray-number]]\n"
+" (mount (align) form (on tray))\n"
+" [-S print-wheel] (mount print wheel)\n\n"
+" (define print-wheel mount alert)\n"
+" lpadmin -S print-wheel {options}\n"
+" [-A mail|write|quiet|cmd [-W interval] [-Q queue-size]]\n"
+" [-A none] (no alerts)\n"
+" [-A list] (examine alert)\n "));
+#endif
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpfilter.c b/usr/src/cmd/lp/cmd/lpfilter.c
new file mode 100644
index 0000000000..257523ff86
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpfilter.c
@@ -0,0 +1,916 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <locale.h>
+
+#include "lp.h"
+#include "access.h"
+#include "filters.h"
+#include "msgs.h"
+
+#define WHO_AM_I I_AM_LPFILTER
+#include "oam.h"
+
+#define OPT_LIST "f:F:ixl"
+
+int add_filter(),
+ reload_filter(),
+ delete_filter(),
+ list_filter();
+
+static void alert_spooler(),
+ same_complaints();
+
+static char *opt();
+
+/*
+ * Unfortunately, the LP requirements show the listing of a filter
+ * to be in a different order than the stored filter table. We can't
+ * change the stored version because it's the same as UNISON uses.
+ * So, we can't reuse the "FL_..." #defines found in "filters.h".
+ * But the following have similar use.
+ */
+#define FL_MAX_P FL_MAX
+# define FL_IGN_P 8
+# define FL_PTYPS_P 2
+# define FL_PRTRS_P 3
+# define FL_ITYPS_P 0
+# define FL_NAME_P 7
+# define FL_OTYPS_P 1
+# define FL_TYPE_P 4
+# define FL_CMD_P 5
+# define FL_TMPS_P 6
+
+#define TABLE 0
+#define TABLE_I 1
+
+static struct headings {
+ char *v;
+ short len;
+} headings[FL_MAX_P] = {
+
+#define ENTRY(X) X, sizeof(X)-1
+ ENTRY("Input types:"),
+ ENTRY("Output types:"),
+ ENTRY("Printer types:"),
+ ENTRY("Printers:"),
+ ENTRY("Filter type:"),
+ ENTRY("Command:"),
+ ENTRY("Options:"),
+ ENTRY(""),
+ ENTRY("")
+#undef ENTRY
+
+};
+
+/**
+ ** usage()
+ **/
+
+void usage ()
+{
+ (void) printf (gettext(
+"usage:\n"
+"\n"
+" (add or change filter)\n"
+" lpfilter -f filter-name {-F path-name | -}\n"
+"\n"
+" (restore delivered filter)\n"
+" lpfilter -f filter-name -i\n"
+"\n"
+" (list a filter)\n"
+" lpfilter -f filter-name -l\n"
+"\n"
+" (list all filters)\n"
+" lpfilter -f \"all\" -l\n"
+"\n"
+" (delete filter)\n"
+" lpfilter -f filter-name -x\n"));
+
+ return;
+}
+
+/**
+ ** main()
+ **/
+
+int main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind,
+ opterr,
+ optopt,
+ getopt();
+
+ extern char *optarg;
+
+ int c,
+ (*action)(),
+ (*newaction)();
+
+ FILE *input;
+
+ char *filter,
+ *p;
+ char stroptsw[] = "-X";
+
+
+ (void) setlocale (LC_ALL, "");
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ if (!is_user_admin()) {
+ LP_ERRMSG (ERROR, E_LP_NOTADM);
+ exit (1);
+ }
+
+ action = 0;
+ input = 0;
+ filter = 0;
+
+ opterr = 0;
+
+ while ((c = getopt(argc, argv, OPT_LIST)) != -1) switch (c) {
+
+ case 'f':
+ if (filter)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'f');
+ filter = optarg;
+ if (
+ STREQU(NAME_ANY, filter)
+ || STREQU(NAME_NONE, filter)
+ ) {
+ LP_ERRMSG (ERROR, E_LP_ANYNONE);
+ exit (1);
+ } else if (!syn_name(filter)) {
+ LP_ERRMSG1 (ERROR, E_LP_NOTNAME, filter);
+ exit (1);
+ } else if (!*filter)
+ filter = NAME_ALL;
+ break;
+
+ case 'F':
+ if (input)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'F');
+ if (!(input = fopen(optarg, "r"))) {
+ LP_ERRMSG1 (ERROR, E_FL_OPEN, optarg);
+ exit (1);
+ }
+ newaction = add_filter;
+ goto Check;
+
+ case 'i':
+ newaction = reload_filter;
+ goto Check;
+
+ case 'x':
+ newaction = delete_filter;
+ goto Check;
+
+ case 'l':
+ newaction = list_filter;
+Check: if (action && newaction != action) {
+ LP_ERRMSG2 (
+ ERROR,
+ E_LP_AMBIG,
+ opt(action),
+ opt(newaction)
+ );
+ exit (1);
+ }
+ action = newaction;
+ break;
+
+ default:
+ if (optopt == '?') {
+ usage ();
+ exit (0);
+ }
+ stroptsw[1] = optopt;
+ if (strchr(OPT_LIST, optopt))
+ LP_ERRMSG1 (ERROR, E_LP_OPTARG, stroptsw);
+ else
+ LP_ERRMSG1 (ERROR, E_LP_OPTION, stroptsw);
+ exit (1);
+
+ }
+
+ if (optind < argc && STREQU(argv[optind], "-"))
+ if (action) {
+ LP_ERRMSG2 (ERROR, E_LP_AMBIG, opt(action), "-");
+ exit (1);
+ } else {
+ action = add_filter;
+ optind++;
+ }
+
+ if (!filter) {
+ LP_ERRMSG (ERROR, E_FL_NOFILT);
+ exit (1);
+ }
+
+ if (!action) {
+ LP_ERRMSG (ERROR, E_FL_NOACT);
+ exit (1);
+ }
+
+ if (optind < argc)
+ LP_ERRMSG1 (WARNING, E_FL_IGNORE, argv[optind]);
+
+ return ((*action)(filter, input));
+}
+
+/**
+ ** add_filter()
+ **/
+
+int add_filter (filter, input)
+ char *filter;
+ FILE *input;
+{
+ register FILTER *pf,
+ *store,
+ *ps;
+
+ register int fld;
+
+ register char *p;
+
+ char buf[3 * BUFSIZ],
+ *file;
+
+ int line,
+ bad_headings,
+ real_fields[FL_MAX],
+ at_least_one,
+ ret;
+
+ FILTER flbuf;
+
+
+ /*
+ * First we read in the input and parse it into a filter,
+ * storing it in the filter buffer "flbuf". Keep track of
+ * which fields have been given, to avoid overwriting unchanged
+ * fields later.
+ */
+
+ if (!input)
+ input = stdin;
+
+ for (fld = 0; fld < FL_MAX; fld++)
+ real_fields[fld] = 0;
+ flbuf.templates = 0;
+
+ line = bad_headings = 0;
+ while (fgets(buf, sizeof(buf), input) != NULL) {
+
+ buf[strlen(buf) - 1] = 0;
+
+ line++;
+
+ p = buf + strspn(buf, " \t");
+ if (!*p || *p == '#')
+ continue;
+
+ for (fld = 0; fld < FL_MAX; fld++)
+ if (
+ headings[fld].v
+ && headings[fld].len
+ && CS_STRNEQU(
+ p,
+ headings[fld].v,
+ headings[fld].len
+ )
+ ) {
+ real_fields[fld] = 1;
+ p += headings[fld].len + 1;
+ break;
+ }
+
+ if (fld >= FL_MAX) {
+
+ if (bad_headings++ >= 5) {
+ LP_ERRMSG (ERROR, E_FL_GARBAGE);
+ return (1);
+ }
+ LP_ERRMSG1 (WARNING, E_FL_HEADING, line);
+
+ } else switch (fld) {
+
+ case FL_IGN_P:
+ case FL_NAME_P:
+ break;
+ case FL_CMD_P:
+ flbuf.command = strdup(strip(p));
+ break;
+ case FL_TYPE_P:
+ flbuf.type = s_to_filtertype(strip(p));
+ break;
+ case FL_PTYPS_P:
+ flbuf.printer_types = getlist(p, LP_WS, LP_SEP);
+ break;
+ case FL_ITYPS_P:
+ flbuf.input_types = getlist(p, LP_WS, LP_SEP);
+ break;
+ case FL_OTYPS_P:
+ flbuf.output_types = getlist(p, LP_WS, LP_SEP);
+ break;
+ case FL_PRTRS_P:
+ flbuf.printers = getlist(p, LP_WS, LP_SEP);
+ break;
+ case FL_TMPS_P:
+ if (flbuf.templates) {
+ char **temp;
+
+ temp = getlist(p, "", LP_SEP);
+ mergelist (&(flbuf.templates), temp);
+ freelist (temp);
+ } else
+ flbuf.templates = getlist(p, "", LP_SEP);
+ break;
+
+ }
+
+ }
+ if (ferror(input)) {
+ LP_ERRMSG (ERROR, E_FL_READ);
+ return (1);
+ }
+
+ /*
+ * We have the input stored, now get the current copy of the
+ * filter(s). If no filter exists, we create it.
+ */
+
+ if (STREQU(NAME_ALL, filter)) {
+
+ /*
+ * Adding ``all'' means changing all filters to reflect
+ * the information in the input. We'll preload the
+ * filters so that we know how many there are.
+ */
+ if (
+ !(file = getfilterfile(FILTERTABLE))
+ || loadfilters(file) == -1
+ ) {
+ switch (errno) {
+ case ENOENT:
+ LP_ERRMSG (ERROR, E_FL_NOTALL);
+ break;
+ default:
+ same_complaints (FILTERTABLE, TABLE);
+ break;
+ }
+ return (1);
+ }
+
+ store = (FILTER *)malloc((nfilters + 1) * sizeof(FILTER));
+ if (!store) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ return (1);
+ }
+
+ for (ps = store; (pf = getfilter(filter)); )
+ *ps++ = *pf;
+ ps->name = 0;
+
+ switch (errno) {
+ case ENOENT:
+ if (ps - store != nfilters) {
+ LP_ERRMSG1 (
+ ERROR,
+ E_FL_STRANGE,
+ getfilterfile(FILTERTABLE)
+ );
+ return (1);
+ }
+ break;
+ default:
+ same_complaints (FILTERTABLE, TABLE);
+ return (1);
+ }
+
+ } else {
+
+ store = (FILTER *)malloc(2 * sizeof(FILTER));
+ if (!store) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ return (1);
+ }
+
+ if ((pf = getfilter(filter))) {
+ store[0] = *pf;
+ } else
+ switch (errno) {
+ case ENOENT:
+ /*
+ * We must be adding a new filter, so
+ * set up default values. Check that
+ * we'll have something reasonable to add.
+ */
+ pf = store;
+ pf->name = strdup(filter);
+ pf->command = 0;
+ pf->type = fl_slow;
+ pf->printer_types = 0;
+ pf->printers = 0;
+ pf->input_types = 0;
+ pf->output_types = 0;
+ pf->templates = 0;
+ if (!flbuf.command) {
+ LP_ERRMSG (ERROR, E_FL_NOCMD);
+ return (1);
+ }
+ break;
+ default:
+ same_complaints (FILTERTABLE, TABLE);
+ return (1);
+ }
+
+ store[1].name = 0;
+
+ }
+
+ at_least_one = ret = 0;
+ for (ps = store; ps->name; ps++) {
+
+ for (fld = 0; fld < FL_MAX; fld++)
+ if (real_fields[fld]) switch(fld) {
+ case FL_IGN_P:
+ case FL_NAME_P:
+ break;
+ case FL_CMD_P:
+ ps->command = flbuf.command;
+ break;
+ case FL_TYPE_P:
+ ps->type = flbuf.type;
+ break;
+ case FL_PTYPS_P:
+ ps->printer_types = flbuf.printer_types;
+ break;
+ case FL_ITYPS_P:
+ ps->input_types = flbuf.input_types;
+ break;
+ case FL_OTYPS_P:
+ ps->output_types = flbuf.output_types;
+ break;
+ case FL_PRTRS_P:
+ ps->printers = flbuf.printers;
+ break;
+ case FL_TMPS_P:
+ ps->templates = flbuf.templates;
+ break;
+ }
+
+ if (putfilter(ps->name, ps) == -1) {
+ if (errno == EBADF) switch (lp_errno) {
+ case LP_ETEMPLATE:
+ LP_ERRMSG (ERROR, E_FL_BADTEMPLATE);
+ break;
+ case LP_EKEYWORD:
+ LP_ERRMSG (ERROR, E_FL_BADKEY);
+ break;
+ case LP_EPATTERN:
+ LP_ERRMSG (ERROR, E_FL_BADPATT);
+ break;
+ case LP_EREGEX:
+ {
+ char * why;
+
+ extern int regerrno;
+
+
+ switch (regerrno) {
+ case 11:
+ why = "range endpoint too large";
+ break;
+ case 16:
+ why = "bad number";
+ break;
+ case 25:
+ why = "\"\\digit\" out of range";
+ break;
+ case 36:
+ why = "illegal or missing delimiter";
+ break;
+ case 41:
+ why = "no remembered search string";
+ break;
+ case 42:
+ why = "\\(...\\) imbalance";
+ break;
+ case 43:
+ why = "too many \\(";
+ break;
+ case 44:
+ why = "more than 2 numbers given in \\{...\\}";
+ break;
+ case 45:
+ why = "} expected after \\";
+ break;
+ case 46:
+ why = "first number exceeds second in \\{...\\}";
+ break;
+ case 49:
+ why = "[...] imbalance";
+ break;
+ case 50:
+ why = "regular expression overflow";
+ break;
+ }
+ LP_ERRMSG1 (ERROR, E_FL_BADREGEX, why);
+ break;
+ }
+ case LP_ERESULT:
+ LP_ERRMSG (ERROR, E_FL_BADRESULT);
+ break;
+ case LP_ENOMEM:
+ errno = ENOMEM;
+ same_complaints (FILTERTABLE, TABLE);
+ break;
+ } else
+ same_complaints (FILTERTABLE, TABLE);
+ ret = 1;
+ break;
+ } else
+ at_least_one = 1;
+
+ }
+
+ if (at_least_one)
+ (void)alert_spooler ();
+
+ return (ret);
+}
+
+/**
+ ** reload_filter()
+ **/
+
+int reload_filter (filter)
+ char *filter;
+{
+ register FILTER *pf,
+ *store,
+ *ps;
+
+ char *factory_file;
+
+ int ret,
+ at_least_one;
+
+ /*
+ * ``Manually'' load the archived filters, so that a call
+ * to "getfilter()" will read from them instead of the regular
+ * table.
+ */
+ if (
+ !(factory_file = getfilterfile(FILTERTABLE_I))
+ || loadfilters(factory_file) == -1
+ ) {
+ switch (errno) {
+ case ENOENT:
+ LP_ERRMSG (ERROR, E_FL_NOFACTY);
+ break;
+ default:
+ same_complaints (FILTERTABLE_I, TABLE_I);
+ break;
+ }
+ return (1);
+ }
+
+ if (STREQU(NAME_ALL, filter)) {
+
+ store = (FILTER *)malloc((nfilters + 1) * sizeof(FILTER));
+ if (!store) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ return (1);
+ }
+
+ for (ps = store; (pf = getfilter(filter)); )
+ *ps++ = *pf;
+ ps->name = 0;
+
+ switch (errno) {
+ case ENOENT:
+ if (ps - store != nfilters) {
+ LP_ERRMSG1 (
+ ERROR,
+ E_FL_STRANGE,
+ getfilterfile(FILTERTABLE_I)
+ );
+ return (1);
+ }
+ break;
+ default:
+ same_complaints (FILTERTABLE_I, TABLE_I);
+ return (1);
+ }
+
+ } else {
+
+ store = (FILTER *)malloc(2 * sizeof(FILTER));
+ if (!store) {
+ LP_ERRMSG (ERROR, E_LP_MALLOC);
+ return (1);
+ }
+
+ if (!(pf = getfilter(filter))) switch (errno) {
+ case ENOENT:
+ LP_ERRMSG (ERROR, E_FL_FACTYNM);
+ return (1);
+ default:
+ same_complaints (FILTERTABLE_I, TABLE_I);
+ return (1);
+ }
+
+ store[0] = *pf;
+ store[1].name = 0;
+
+ }
+
+ /*
+ * Having stored the archived filter(s) in our own area, clear
+ * the currently loaded table so that the subsequent calls to
+ * "putfilter()" will read in the regular table.
+ */
+ trash_filters ();
+
+ at_least_one = ret = 0;
+ for (ps = store; ps->name; ps++)
+ if (putfilter(ps->name, ps) == -1) {
+ same_complaints (FILTERTABLE, TABLE);
+ ret = 1;
+ break;
+ } else
+ at_least_one = 1;
+
+ if (at_least_one)
+ (void)alert_spooler ();
+
+ return (ret);
+}
+
+/**
+ ** delete_filter()
+ **/
+
+int delete_filter (filter)
+ char *filter;
+{
+ if (delfilter(filter) == -1) switch (errno) {
+ case ENOENT:
+ LP_ERRMSG1 (ERROR, E_FL_UNKFILT, filter);
+ return (1);
+ default:
+ same_complaints (FILTERTABLE, TABLE);
+ return (1);
+ }
+
+ (void)alert_spooler ();
+
+ return (0);
+}
+
+/**
+ ** list_filter()
+ **/
+
+static void _list_filter();
+
+int list_filter (filter)
+ char *filter;
+{
+ register FILTER *pf;
+
+ char *nl;
+
+ if (STREQU(NAME_ALL, filter)) {
+
+ nl = "";
+ while ((pf = getfilter(filter))) {
+ printf (gettext("%s(Filter \"%s\")\n"), nl, pf->name);
+ _list_filter (pf);
+ nl = "\n";
+ }
+
+ switch (errno) {
+ case ENOENT:
+ return (0);
+ default:
+ same_complaints (FILTERTABLE, TABLE);
+ return (1);
+ }
+
+ } else {
+
+ if ((pf = getfilter(filter))) {
+ _list_filter (pf);
+ return (0);
+ }
+
+ switch (errno) {
+ case ENOENT:
+ LP_ERRMSG1 (ERROR, E_FL_UNKFILT, filter);
+ return (1);
+ default:
+ same_complaints (FILTERTABLE, TABLE);
+ return (1);
+ }
+
+ }
+}
+
+static void _list_filter (pf)
+ register FILTER *pf;
+{
+ register char **pp,
+ *sep;
+
+ register int fld;
+
+ char * head;
+
+
+ for (fld = 0; fld < FL_MAX_P; fld++) switch (fld) {
+ case FL_IGN_P:
+ case FL_NAME_P:
+ break;
+ case FL_CMD_P:
+ printf (
+ "%s %s\n",
+ headings[fld].v,
+ (pf->command? pf->command : "")
+ );
+ break;
+ case FL_TYPE_P:
+ printf (
+ "%s %s\n",
+ headings[fld].v,
+ (pf->type == fl_fast? FL_FAST : FL_SLOW)
+ );
+ break;
+ case FL_PTYPS_P:
+ pp = pf->printer_types;
+ goto Lists;
+ case FL_ITYPS_P:
+ pp = pf->input_types;
+ goto Lists;
+ case FL_OTYPS_P:
+ pp = pf->output_types;
+ goto Lists;
+ case FL_PRTRS_P:
+ pp = pf->printers;
+Lists: printlist_qsep = 1;
+ printlist_setup ("", "", LP_SEP, "");
+ printf ("%s ", headings[fld].v);
+ printlist (stdout, pp);
+ printf ("\n");
+ break;
+ case FL_TMPS_P:
+ head = makestr(headings[fld].v, " ", (char *)0);
+ printlist_qsep = 1;
+ printlist_setup (head, "", "\n", "\n");
+ printlist (stdout, pf->templates);
+ break;
+ }
+
+ return;
+}
+
+/**
+ ** opt() - GENERATE OPTION FROM FUNCTION NAME
+ **/
+
+static char *opt (fnc)
+ int (*fnc)();
+{
+ if (fnc == add_filter)
+ return ("-F");
+ else if (fnc == reload_filter)
+ return ("-i");
+ else if (fnc == list_filter)
+ return ("-l");
+ else if (fnc == delete_filter)
+ return ("-x");
+ else
+ return ("-?");
+}
+
+/**
+ ** alert_spooler() - TELL SPOOLER TO LOAD FILTER TABLE
+ **/
+
+static void alert_spooler ()
+{
+ char msgbuf[MSGMAX];
+
+ int mtype;
+
+ short status;
+
+ /*
+ * If the attempt to open a message queue to the
+ * Spooler fails, assume it isn't running and just
+ * return--don't say anything, `cause the user may
+ * know. Any other failure deserves an error message.
+ */
+
+ if (mopen() == -1)
+ return;
+
+ (void)putmessage (msgbuf, S_LOAD_FILTER_TABLE);
+
+ if (msend(msgbuf) == -1)
+ goto Error;
+ if (mrecv(msgbuf, MSGMAX) == -1)
+ goto Error;
+
+ mtype = getmessage(msgbuf, R_LOAD_FILTER_TABLE, &status);
+ if (mtype != R_LOAD_FILTER_TABLE) {
+ LP_ERRMSG1 (ERROR, E_LP_BADREPLY, mtype);
+ (void)mclose ();
+ exit (1);
+ }
+
+ if (status == MOK)
+ goto NoError;
+
+Error: LP_ERRMSG (ERROR, E_FL_NOSPLOAD);
+
+NoError:(void)mclose ();
+ return;
+
+}
+
+/**
+ ** same_complaints() - PRINT COMMON ERROR MESSAGES
+ **/
+
+static void same_complaints (table, type)
+ char *table;
+ int type;
+{
+ switch (errno) {
+ case EACCES:
+ if (type == TABLE)
+ LP_ERRMSG1 (
+ ERROR,
+ E_FL_ACCESS,
+ getfilterfile(table)
+ );
+ else
+ LP_ERRMSG1 (
+ ERROR,
+ E_FL_ACCESSI,
+ getfilterfile(table)
+ );
+ break;
+ case EAGAIN:
+ case EDEADLK:
+ LP_ERRMSG1 (ERROR, E_LP_AGAIN, getfilterfile(table));
+ break;
+ default:
+ LP_ERRMSG2 (
+ ERROR,
+ E_FL_UNKNOWN,
+ getfilterfile(table),
+ strerror(errno)
+ );
+ break;
+ }
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpforms.c b/usr/src/cmd/lp/cmd/lpforms.c
new file mode 100644
index 0000000000..a421304ad8
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpforms.c
@@ -0,0 +1,1438 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include <locale.h>
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "access.h"
+#include "form.h"
+#include "msgs.h"
+
+#define WHO_AM_I I_AM_LPFORMS
+#include "oam.h"
+
+#define OPT_LIST "f:F:xlLA:u:W:Q:P:d"
+
+#define TMPDIR "/usr/tmp"
+
+typedef int (*Action)();
+
+#if defined(__STDC__)
+
+static int add_form ( char * , FILE * , FALERT * , char * );
+static int add_alert ( char * , FILE * , FALERT * , char * );
+static int delete_form ( char * );
+static int list_form ( char * );
+static int list_alert ( char * );
+static int list_both ( char * );
+static int any_alert ( char * , FILE * , FALERT * );
+static int quiet_alert ( char * );
+static int notify_spooler ( int , int , char * );
+static int onerror ( int , int , int );
+
+static Action set_action ( int (*)() , char * );
+
+#else
+
+static int add_form();
+static int add_alert();
+static int delete_form();
+static int list_form();
+static int list_alert();
+static int list_both();
+static int any_alert();
+static int quiet_alert();
+static int notify_spooler();
+static int onerror();
+
+static Action set_action();
+
+#endif
+
+/**
+ ** usage()
+ **/
+
+void usage ()
+{
+ (void) printf (gettext(
+"usage:\n"
+"\n"
+" (add or change form)\n"
+" lpforms -f form-name [options]\n"
+" [-F path-name | - | -P paper [-d] | -d ] (form definition)\n"
+" -F path-name (initialize from file)\n"
+" - (initialize from stdin)\n"
+" -P paper [-d] (initialize with paper (as default))\n"
+" -d (create form with paper of same name)\n"
+" [-u allow:user-list | deny:user-list] (who's allowed to use)\n"
+" [-A mail | write | shell-command] (alert definition)\n"
+" [-Q threshold] (# needed for alert)\n"
+" [-W interval] (minutes between alerts)\n"
+"\n"
+" (list form)\n"
+" lpforms -f form-name -l\n"
+" lpforms -f form-name -L (verbose for -P forms)\n"
+"\n"
+" (delete form)\n"
+" lpforms -f form-name -x\n"
+"\n"
+" (define alert for forms with no alert yet)\n"
+" lpforms -f any -A {mail | write | shell-command}\n"
+"\n"
+" (define alert for all forms)\n"
+" lpforms -f all -A {mail | write | shell-command}\n"
+"\n"
+" (examine alerting)\n"
+" lpforms -f form-name -A list\n"
+"\n"
+" (stop alerting)\n"
+" lpforms -f form-name -A quiet (temporarily)\n"
+" lpforms -f form-name -A none (for good)"
+"\n"
+));
+
+ return;
+}
+
+static char *P = NULL;
+static int d = 0;
+static int L = 0;
+/**
+ ** main()
+ **/
+
+int
+main(int argc, char *argv[])
+{
+ extern int optind;
+ extern int opterr;
+ extern int optopt;
+
+ extern char * optarg;
+
+ int c;
+ int cnt = 0;
+
+ char * form = 0;
+ char * u = 0;
+ char * cp;
+ char * rest;
+ char stroptsw[] = "-X";
+
+ Action action = 0;
+
+ FILE *input = 0;
+
+ FORM fbuf;
+
+ FALERT alert = { (char *)0, -1, -1 };
+
+ struct stat statbuf;
+
+
+ (void) setlocale (LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ if (!is_user_admin()) {
+ LP_ERRMSG (ERROR, E_LP_NOTADM);
+ exit (1);
+ }
+
+ opterr = 0;
+
+ while ((c = getopt(argc, argv, OPT_LIST)) != -1) {
+
+ /*
+ * These options take values; "getopt()" passes values
+ * that begin with a dash without checking if they're
+ * options. If a value is missing, we want to complain
+ * about it.
+ */
+ switch (c) {
+ case 'W':
+ case 'Q':
+ /*
+ * These options take numeric values, which might
+ * be negative. Negative values are handled later,
+ * but here we just screen them.
+ */
+ (void)strtol (optarg, &rest, 10);
+ if (!rest || (!*rest && rest != optarg))
+ break;
+ /*FALLTHROUGH*/
+ case 'f':
+ case 'F':
+ case 'A':
+ case 'u':
+ if (!*optarg) {
+ stroptsw[1] = c;
+ LP_ERRMSG1 (ERROR, E_LP_NULLARG, stroptsw);
+ exit (1);
+ }
+ if (*optarg == '-') {
+ stroptsw[1] = c;
+ LP_ERRMSG1 (ERROR, E_LP_OPTARG, stroptsw);
+ exit (1);
+ }
+ break;
+ }
+
+ switch (c) {
+
+ case 'f':
+ if (form)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'f');
+ form = optarg;
+ if (!syn_name(form)) {
+ LP_ERRMSG1 (ERROR, E_LP_NOTNAME, form);
+ exit (1);
+ } else if (!*form)
+ form = NAME_ALL;
+ break;
+
+ case 'F':
+ if (input)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'F');
+ if (!(input = fopen(optarg, "r"))) {
+ LP_ERRMSG1 (ERROR, E_FOR_OPEN, optarg);
+ exit (1);
+ }
+ action = set_action(add_form, "-F");
+ break;
+
+ case 'A':
+ if (STREQU(NAME_LIST, optarg))
+ action = set_action(list_alert, "\"-A list\"");
+
+ else if (STREQU(NAME_QUIET, optarg))
+ action = set_action(quiet_alert, "\"-A quiet\"");
+
+ else {
+ if (STREQU(MAIL, optarg) || STREQU(WRITE, optarg))
+ alert.shcmd = makestr(optarg, " ", getname(), (char *)0);
+ else
+ alert.shcmd = strdup(optarg);
+ action = set_action(add_alert, "-A");
+ }
+ break;
+
+ case 'Q':
+ if (alert.Q != -1)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'Q');
+ if (STREQU(NAME_ANY, optarg))
+ alert.Q = 1;
+ else {
+ alert.Q = strtol(optarg, &rest, 10);
+ if (alert.Q < 0) {
+ LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'Q');
+ exit (1);
+ }
+ if (rest && *rest) {
+ LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'Q');
+ exit (1);
+ }
+ if (alert.Q == 0) {
+ LP_ERRMSG1 (ERROR, E_LP_ZEROARG, 'Q');
+ exit (1);
+ }
+ }
+ action = set_action(add_alert, "-Q");
+ break;
+
+ case 'W':
+ if (alert.W != -1)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'W');
+ if (STREQU(NAME_ONCE, optarg))
+ alert.W = 0;
+ else {
+ alert.W = strtol(optarg, &rest, 10);
+ if (alert.W < 0) {
+ LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'W');
+ exit (1);
+ }
+ if (rest && *rest) {
+ LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'W');
+ exit (1);
+ }
+ }
+ action = set_action(add_alert, "-W");
+ break;
+
+ case 'u':
+ if (u)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'u');
+ u = strdup(optarg);
+ action = set_action(add_form, "-u");
+ break;
+
+ case 'x':
+ action = set_action(delete_form, "-x");
+ break;
+
+ case 'L':
+ L = 1;
+ action = set_action(list_form, "-L");
+ break;
+ case 'l':
+ action = set_action(list_form, "-l");
+ break;
+
+ case 'd':
+ d = 1;
+ action = set_action(add_form, "-d");
+ break;
+
+ case 'P':
+ if (P)
+ LP_ERRMSG1 (WARNING, E_LP_2MANY, 'P');
+ action = set_action(add_form, "-P");
+ P = strdup(optarg);
+ break;
+
+ default:
+ if (optopt == '?') {
+ usage ();
+ exit (0);
+ }
+ stroptsw[1] = optopt;
+ if (strchr(OPT_LIST, optopt))
+ LP_ERRMSG1 (ERROR, E_LP_OPTARG, stroptsw);
+ else
+ LP_ERRMSG1 (ERROR, E_LP_OPTION, stroptsw);
+ exit (1);
+
+ }
+ }
+
+ if (!form) {
+ LP_ERRMSG (ERROR, E_FOR_FORMNAME);
+ exit (1);
+ }
+
+ if (STREQU(NAME_ANY, form))
+ action = set_action(any_alert, "\"-f any\"");
+
+ if (optind < argc && STREQU(argv[optind], "-")) {
+ action = set_action(add_form, "-");
+ input = stdin;
+ optind++;
+ }
+ if (optind < argc)
+ LP_ERRMSG1 (WARNING, E_FOR_EXTRAARG, argv[optind]);
+
+ if (!action) {
+ LP_ERRMSG (ERROR, E_FOR_NOACT);
+ exit (1);
+ }
+
+ if (action == any_alert && STREQU(alert.shcmd, NAME_NONE)) {
+ LP_ERRMSG (WARNING, E_FOR_ANYDEL);
+ exit (0);
+ }
+
+ /*
+ * We must have a shell command for the alert if:
+ *
+ * (1) we're adding a new form and the -W or -Q options
+ * have been given, or
+ *
+ * (2) the -f any option was given.
+ */
+ if (
+ (
+ action == add_form
+ && !alert.shcmd
+ && (alert.Q != -1 || alert.W != -1)
+ && !STREQU(NAME_ALL, form)
+ && getform(form, &fbuf, (FALERT *)0, (FILE **)0) != 0
+ )
+ || action == any_alert && !alert.shcmd
+ ) {
+ LP_ERRMSG (ERROR, E_FOR_NOSHCMDERR);
+ return (1);
+ }
+
+ if (P && (! STREQU(P,form))) {
+ while (P && (cnt++ < 2)) {
+ /*
+ * two times should do it unless user has edited
+ * files directly
+ */
+ if (getform(P, &fbuf, (FALERT *)0, (FILE **)0) != -1) {
+ if (!fbuf.paper) {
+ LP_ERRMSG3(ERROR, E_FOR_ALSO_SEP_FORM,
+ form, P, P);
+ return (1);
+ } else if (!STREQU(fbuf.paper, P))
+ P = Strdup(fbuf.paper);
+ else
+ break; /* we found a good paper */
+ } else {
+ int result;
+ int saveD;
+
+ saveD = d;
+ d = 1;
+ result = ((*action)(P, NULL, &alert, u));
+ d = saveD;
+ return (result ? result :
+ ((*action)(form, input, &alert, u)));
+ }
+ }
+ }
+
+ if (d && !P)
+ P = Strdup(form);
+
+ return ((*action)(form, input, &alert, u));
+}
+
+/**
+ ** add_alert()
+ ** add_form()
+ **/
+
+/*
+ * "add_alert()" exists just to simplify the checking of mixed
+ * options in "set_action()".
+ */
+
+static int
+#if defined(__STDC__)
+add_alert (
+ char * form,
+ FILE * input,
+ FALERT * p_new_alert,
+ char * u
+)
+#else
+add_alert (form, input, new_alert, u)
+ char * form;
+ FILE * input;
+ FALERT * p_new_alert;
+ char * u;
+#endif
+{
+ return (add_form(form, input, p_new_alert, u));
+}
+
+static int
+#if defined(__STDC__)
+add_form (
+ char * form,
+ FILE * input,
+ FALERT * p_new_alert,
+ char * u
+)
+#else
+add_form (form, input, new_alert, u)
+ char * form;
+ FILE * input;
+ FALERT * p_new_alert;
+ char * u;
+#endif
+{
+ int fld;
+ int which_set[FO_MAX];
+ int new_form = 0;
+ int nform;
+ int return_code;
+
+ char * all_list[] = { NAME_ALL, 0 };
+ char ** u_allow = 0;
+ char ** u_deny = 0;
+
+ FILE * align_fp = 0;
+
+ FORM fbuf;
+ FORM new_fbuf;
+
+ FALERT alert;
+
+
+ /*
+ * Read the input configuration (if any) and parse it into a form,
+ * storing it in the form buffer "fbuf". Keep track of
+ * which fields have been given, to avoid overwriting unchanged
+ * fields later.
+ */
+ if (input) {
+ for (fld = 0; fld < FO_MAX; fld++)
+ which_set[fld] = 0;
+
+ if (rdform(form, &new_fbuf, fileno(input), onerror,
+ which_set) == -1) {
+ LP_ERRMSG2 (ERROR, E_FOR_UNKNOWN, "(input)", PERROR);
+ return (1);
+ }
+ for (fld = 0; fld < FO_MAX; fld++)
+ if (which_set[fld])
+ break;
+ if (fld >= FO_MAX)
+ LP_ERRMSG (WARNING, E_FOR_EMPTYFILE);
+
+ /*
+ * Read the alignment pattern (if any) into a temporary
+ * file so that it can be used for (potentially) many
+ * forms.
+ */
+ if (which_set[FO_ALIGN]) {
+
+ size_t n;
+
+ char buf[BUFSIZ];
+
+
+
+ if ((align_fp = tmpfile()) == NULL) {
+ LP_ERRMSG (ERROR, E_FOR_CTMPFILE);
+ exit (1);
+ }
+
+ while ((n = fread(buf, 1, BUFSIZ, input)))
+ fwrite (buf, 1, n, align_fp);
+ }
+ }
+
+ /*
+ * Parse the user allow/deny list (if any).
+ */
+ if (u) {
+
+ char * cp;
+ char * type;
+
+
+ type = strtok(u, ":");
+ cp = strtok((char *)0, ":");
+
+ if (STREQU(type, NAME_ALLOW) && cp) {
+ if (!(u_allow = getlist(cp, LP_WS, LP_SEP)))
+ LP_ERRMSG1 (
+ WARNING,
+ E_LP_MISSING,
+ NAME_ALLOW
+ );
+
+ } else if (STREQU(type, NAME_DENY) && cp) {
+ if (!(u_deny = getlist(cp, LP_WS, LP_SEP)))
+ LP_ERRMSG1 (
+ WARNING,
+ E_LP_MISSING,
+ NAME_DENY
+ );
+
+ } else {
+ LP_ERRMSG (ERROR, E_LP_UALLOWDENY);
+ exit (1);
+ }
+ }
+
+ /*
+ * The following loop gets either a particular form or
+ * all forms (one at a time). The value of "return_code"
+ * controls the loop and is also the value to use in the
+ * "return()" at the end.
+ */
+ nform = 0;
+ return_code = -1;
+ while (return_code == -1) {
+
+ /*
+ * If we are adding/changing a single form, set
+ * the loop control to get us out.
+ */
+ if (!STREQU(NAME_ALL, form))
+ return_code = 0;
+
+ nform++;
+
+ if (P) {
+ memset ((char *)&fbuf, 0, sizeof(FORM));
+ fbuf.name = strdup(form);
+ fbuf.plen.val = DPLEN;
+ fbuf.plen.sc = 0;
+ fbuf.pwid.val = DPWIDTH;
+ fbuf.pwid.sc = 0;
+ fbuf.lpi.val = DLPITCH;
+ fbuf.lpi.sc = 0;
+ fbuf.cpi.val = DCPITCH;
+ fbuf.cpi.sc = 0;
+ fbuf.np = DNP;
+ fbuf.chset = strdup(DCHSET);
+ fbuf.mandatory = 0;
+ fbuf.rcolor = strdup(DRCOLOR);
+ fbuf.conttype = strdup(DCONTYP);
+ fbuf.paper = P;
+ fbuf.isDefault = d;
+ alert.shcmd = 0;
+ alert.W = alert.Q = -1;
+ new_form = 1;
+
+ } else if (getform(form, &fbuf, &alert, (FILE **)0) == -1)
+ switch (errno) {
+
+ case ENOENT:
+ /*
+ * This is a problem only if it occurs
+ * immediately on trying to get ``all''.
+ */
+ if (STREQU(NAME_ALL, form)) {
+ if (nform > 1)
+ return_code = 0;
+ else {
+ LP_ERRMSG (ERROR, E_FOR_NOFORMS);
+ return_code = 1;
+ }
+ continue;
+ }
+
+ /*
+ * We're adding a new form,
+ * so set up default values.
+ */
+ memset ((char *)&fbuf, 0, sizeof(FORM));
+ fbuf.name = strdup(form);
+ fbuf.plen.val = DPLEN;
+ fbuf.plen.sc = 0;
+ fbuf.pwid.val = DPWIDTH;
+ fbuf.pwid.sc = 0;
+ fbuf.lpi.val = DLPITCH;
+ fbuf.lpi.sc = 0;
+ fbuf.cpi.val = DCPITCH;
+ fbuf.cpi.sc = 0;
+ fbuf.np = DNP;
+ fbuf.chset = strdup(DCHSET);
+ fbuf.mandatory = 0;
+ fbuf.rcolor = strdup(DRCOLOR);
+ fbuf.conttype = strdup(DCONTYP);
+ alert.shcmd = 0;
+ alert.W = alert.Q = -1;
+
+ new_form = 1;
+ break;
+
+ default:
+ /*
+ * Don't know if we'll have a good name
+ * in the "all" case on getting here, so
+ * punt on naming the form in the error
+ * message.
+ */
+ LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
+ return_code = 1;
+ continue;
+ }
+
+ /*
+ * Copy just those items that were given in the input.
+ */
+ if (!input && new_form && !P) {
+ LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
+ return (1);
+ }
+ if (input)
+ for (fld = 0; fld < FO_MAX; fld++)
+ if (which_set[fld]) switch(fld) {
+
+ case FO_PLEN:
+ fbuf.plen = new_fbuf.plen;
+ break;
+
+ case FO_PWID:
+ fbuf.pwid = new_fbuf.pwid;
+ break;
+
+ case FO_CPI:
+ fbuf.cpi = new_fbuf.cpi;
+ break;
+
+ case FO_LPI:
+ fbuf.lpi = new_fbuf.lpi;
+ break;
+
+ case FO_NP:
+ fbuf.np = new_fbuf.np;
+ break;
+
+ case FO_CHSET:
+ fbuf.chset = new_fbuf.chset;
+ fbuf.mandatory = new_fbuf.mandatory;
+ break;
+
+ case FO_RCOLOR:
+ fbuf.rcolor = new_fbuf.rcolor;
+ break;
+
+ case FO_CMT:
+ fbuf.comment = new_fbuf.comment;
+ break;
+
+ case FO_ALIGN:
+ fbuf.conttype = new_fbuf.conttype;
+ rewind (align_fp);
+ break;
+
+ case FO_PAPER:
+ fbuf.paper = new_fbuf.paper;
+ fbuf.isDefault = new_fbuf.isDefault;
+ break;
+
+ }
+
+ /*
+ * Set just those alert elements that were given.
+ * However, complain about those form(s) that don't have
+ * a shell command yet, and none was given, yet -W or -Q
+ * were given.
+ */
+ if (
+ !alert.shcmd && !p_new_alert->shcmd
+ && (p_new_alert->W != -1 || p_new_alert->Q != -1)
+ )
+ LP_ERRMSG1 (WARNING, E_FOR_NOSHCMDWARN, fbuf.name);
+ else {
+ if (p_new_alert->shcmd)
+ alert.shcmd = p_new_alert->shcmd;
+ if (p_new_alert->Q != -1)
+ alert.Q = p_new_alert->Q;
+ if (p_new_alert->W != -1)
+ alert.W = p_new_alert->W;
+ }
+
+ /*
+ * Create/update the form.
+ */
+#define P_FBUF (new_form || input? &fbuf : (FORM *)0)
+ if (putform(fbuf.name, P_FBUF, &alert, &align_fp) == -1) {
+ LP_ERRMSG2 (ERROR, E_LP_PUTFORM, fbuf.name, PERROR);
+ return_code = 1;
+ continue;
+ }
+
+ /*
+ * Allow/deny users.
+ */
+ if (new_form && allow_user_form(all_list, fbuf.name) == -1) {
+ LP_ERRMSG1 (ERROR, E_LP_ACCESSINFO, PERROR);
+ return_code = 1;
+ continue;
+ }
+ if (u_allow && allow_user_form(u_allow, fbuf.name) == -1) {
+ LP_ERRMSG1 (ERROR, E_LP_ACCESSINFO, PERROR);
+ return_code = 1;
+ continue;
+ }
+ if (u_deny && deny_user_form(u_deny, fbuf.name) == -1) {
+ LP_ERRMSG1 (ERROR, E_LP_ACCESSINFO, PERROR);
+ return_code = 1;
+ continue;
+ }
+
+ notify_spooler (S_LOAD_FORM, R_LOAD_FORM, fbuf.name);
+
+ }
+
+ if (align_fp)
+ close_lpfile (align_fp);
+
+ return (return_code);
+}
+
+/**
+ ** list_form()
+ ** list_alert()
+ ** list_both()
+ **/
+
+#if defined(__STDC__)
+
+static int list ( char * , void (*)() );
+static void _list_form ( FORM * , FALERT * , FILE * );
+static void _list_alert ( FORM * , FALERT * );
+static void _list_both ( FORM * , FALERT * , FILE * );
+
+#else
+
+static int list();
+static void _list_form();
+static void _list_alert();
+static void _list_both();
+
+#endif
+
+static int
+#if defined(__STDC__)
+list_form (
+ char *form
+)
+#else
+list_form (form)
+ char *form;
+#endif
+{
+ return (list(form, _list_form));
+}
+
+static int
+#if defined(__STDC__)
+list_alert (
+ char *form
+)
+#else
+list_alert (form)
+ char *form;
+#endif
+{
+ return (list(form, _list_alert));
+}
+
+static int
+#if defined(__STDC__)
+list_both (
+ char *form
+)
+#else
+list_both (form)
+ char *form;
+#endif
+{
+ return (list(form, _list_both));
+}
+
+static int
+#if defined(__STDC__)
+list (
+ char *form,
+ void (*subaction)()
+)
+#else
+list (form, subaction)
+ char *form;
+ void (*subaction)();
+#endif
+{
+ FORM fbuf;
+
+ FALERT alert;
+
+ FILE * align_fp;
+
+ char *nl;
+
+
+ if (STREQU(NAME_ALL, form)) {
+
+ nl = "";
+ while (getform(form, &fbuf, &alert, &align_fp) == 0) {
+ printf (gettext("%sForm name: %s\n"), nl, fbuf.name);
+ (*subaction) (&fbuf, &alert, align_fp);
+ nl = "\n";
+ }
+
+ switch (errno) {
+ case ENOENT:
+ return (0);
+ default:
+ /*
+ * Don't know if we'll have a good name
+ * in the "all" case on getting here, so
+ * punt on naming the form in the error
+ * message.
+ */
+ LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
+ return (1);
+ }
+
+ } else {
+
+ if (getform(form, &fbuf, &alert, &align_fp) == 0) {
+ (*subaction) (&fbuf, &alert, align_fp);
+ return (0);
+ }
+
+ switch (errno) {
+ case ENOENT:
+ LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
+ return (1);
+ default:
+ LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
+ return (1);
+ }
+
+ }
+}
+
+/**
+ ** _list_form()
+ **/
+
+static void
+#if defined(__STDC__)
+_list_form (
+ FORM * pf,
+ FALERT * palert,
+ FILE * align_fp
+)
+#else
+_list_form (pf, palert, align_fp)
+ FORM * pf;
+ FALERT * palert;
+ FILE * align_fp;
+#endif
+{
+ size_t n;
+
+ char buf[BUFSIZ];
+
+ int which_set[FO_MAX];
+ int fld,whichVal;
+
+
+ whichVal = (pf->paper && (L == 0) ? 0 : 1);
+ for (fld = 0; fld < FO_MAX; fld++)
+ which_set[fld] = whichVal;
+ if (!align_fp)
+ which_set[FO_ALIGN] = 0;
+ if (pf->paper)
+ which_set[FO_PAPER] = 1;
+ wrform (pf->name, pf, 1, onerror, which_set);
+ if (align_fp)
+ while ((n = fread(buf, 1, BUFSIZ, align_fp)))
+ write (1, buf, n);
+}
+
+/**
+ ** _list_alert()
+ **/
+
+static void
+#if defined(__STDC__)
+_list_alert (
+ FORM * ignore,
+ FALERT * palert
+)
+#else
+_list_alert (ignore, palert)
+ FORM * ignore;
+ FALERT * palert;
+#endif
+{
+ printalert (stdout, palert, 0);
+}
+
+/**
+ ** _list_both()
+ **/
+
+static void
+#if defined(__STDC__)
+_list_both (
+ FORM * pf,
+ FALERT * palert,
+ FILE * align_fp
+)
+#else
+_list_both (pf, palert, align_fp)
+ FORM * pf;
+ FALERT * palert;
+ FILE * align_fp;
+#endif
+{
+ _list_alert (pf, palert);
+ _list_form (pf, palert, align_fp);
+}
+
+/**
+ ** any_alert()
+ **/
+
+static int
+#if defined(__STDC__)
+any_alert (
+ char * form,
+ FILE * ignore,
+ FALERT * p_new_alert
+)
+#else
+any_alert (form, ignore, p_new_alert)
+ char * form;
+ FILE * ignore;
+ FALERT * p_new_alert;
+#endif
+{
+ FORM fbuf;
+
+ FALERT alert;
+
+
+ while (getform(NAME_ALL, &fbuf, &alert, (FILE **)0) == 0)
+ if (!alert.shcmd)
+ if (putform(fbuf.name, (FORM *)0, p_new_alert, (FILE **)0) == -1) {
+ LP_ERRMSG2 (ERROR, E_LP_PUTFORM, fbuf.name, PERROR);
+ return (1);
+ }
+
+ return (0);
+}
+
+/**
+ ** delete_form()
+ ** quiet_alert()
+ **/
+
+#if defined(__STDC__)
+
+static int dq ( char * , int (*)() );
+static int _delete_form ( char * );
+static int _quiet_alert ( char * );
+
+#else
+
+static int dq();
+static int _delete_form();
+static int _quiet_alert();
+
+#endif
+
+static int
+#if defined(__STDC__)
+delete_form (
+ char *form
+)
+#else
+delete_form (form)
+ char *form;
+#endif
+{
+ return (dq(form, _delete_form));
+}
+
+static int
+#if defined(__STDC__)
+quiet_alert (
+ char * form
+)
+#else
+quiet_alert (form)
+ char * form;
+#endif
+{
+ return (dq(form, _quiet_alert));
+}
+
+static int
+#if defined(__STDC__)
+dq (
+ char *form,
+ int (*subaction)()
+)
+#else
+dq (form, subaction)
+ char *form;
+ int (*subaction)();
+#endif
+{
+ FORM fbuf;
+
+
+ if (STREQU(NAME_ANY, form) || STREQU(NAME_NONE, form)) {
+ LP_ERRMSG (ERROR, E_FOR_ANYNONE);
+ exit (1);
+ }
+
+ if (STREQU(NAME_ALL, form)) {
+
+ while (getform(form, &fbuf, (FALERT *)0, (FILE **)0) == 0)
+ if ((*subaction)(fbuf.name) == 1)
+ return (1);
+
+ switch (errno) {
+ case ENOENT:
+ return (0);
+ default:
+ /*
+ * Don't know if we'll have a good name
+ * in the "all" case on getting here, so
+ * punt on naming the form in the error
+ * message.
+ */
+ LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
+ return (1);
+ }
+
+ } else {
+
+ if (getform(form, &fbuf, (FALERT *)0, (FILE **)0) == 0)
+ return ((*subaction)(fbuf.name));
+
+ switch (errno) {
+ case ENOENT:
+ LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
+ return (1);
+ default:
+ LP_ERRMSG2 (ERROR, E_LP_GETFORM, form, PERROR);
+ return (1);
+ }
+ }
+}
+
+static int
+#if defined(__STDC__)
+_delete_form (
+ char *form
+)
+#else
+_delete_form (form)
+ char *form;
+#endif
+{
+ switch (notify_spooler(S_UNLOAD_FORM, R_UNLOAD_FORM, form)) {
+
+ case -1:
+ if (anyrequests()) {
+ LP_ERRMSG (ERROR, E_FOR_MOPENREQX);
+ return (1);
+ }
+ /*FALLTHROUGH*/
+
+ case MNODEST:
+ if (delform(form) == -1) {
+ if (errno == ENOENT) {
+ LP_ERRMSG1 (ERROR, E_LP_NOFORM, form);
+ return (1);
+ } else {
+ LP_ERRMSG2 (
+ ERROR,
+ E_FOR_UNKNOWN,
+ form,
+ PERROR
+ );
+ return (1);
+ }
+ }
+ break;
+
+ case MOK:
+ if (delform(form) == -1) {
+ LP_ERRMSG (ERROR, E_FOR_DELSTRANGE);
+ return (1);
+ }
+ break;
+ }
+ return (0);
+}
+
+static int
+#if defined(__STDC__)
+_quiet_alert (
+ char * form
+)
+#else
+_quiet_alert (form)
+ char * form;
+#endif
+{
+ char *msgbuf;
+
+ int mtype;
+
+ int size;
+
+ short status;
+
+ /*
+ * If the attempt to open a message queue to the
+ * Spooler fails, assume it isn't running and just
+ * return--don't say anything, `cause the user may
+ * know. Any other failure deserves an error message.
+ */
+
+ if (mopen() == -1)
+ return (0);
+
+ size = putmessage (NULL, S_QUIET_ALERT, form, QA_FORM);
+ msgbuf = malloc(size);
+ putmessage (msgbuf, S_QUIET_ALERT, form, QA_FORM);
+
+ if (msend(msgbuf) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MSEND);
+ mclose ();
+ return (1);
+ }
+
+ if (mrecv(msgbuf, size) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MRECV);
+ mclose ();
+ return (1);
+ }
+
+ mtype = getmessage(msgbuf, R_QUIET_ALERT, &status);
+ free (msgbuf);
+ mclose ();
+ if (mtype != R_QUIET_ALERT) {
+ LP_ERRMSG (ERROR, E_LP_BADREPLY);
+ return (1);
+ }
+
+ switch (status) {
+
+ case MOK:
+ break;
+
+ case MNODEST: /* not quite, but not a lie either */
+ case MERRDEST:
+ LP_ERRMSG1 (WARNING, E_LP_NOQUIET, form);
+ break;
+
+ case MNOPERM: /* taken care of up front */
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, status);
+ return (1);
+ /*NOTREACHED*/
+ }
+
+ return (0);
+}
+
+/**
+ ** set_action() - CHECK FOR AMBIGUOUS ACTIONS
+ **/
+
+static Action
+#if defined(__STDC__)
+set_action (
+ Action action,
+ char * option
+)
+#else
+set_action (action, option)
+ Action action;
+ char * option;
+#endif
+{
+ static Action prev_action = 0;
+
+ static char * prev_option;
+
+
+ if (
+ action == list_form && prev_action == list_alert
+ || action == list_alert && prev_action == list_form
+ )
+ action = list_both;
+
+ else if (
+ action == add_form && prev_action == add_alert
+ || action == add_alert && prev_action == add_form
+ )
+ action = add_form;
+
+ else if (
+ action == any_alert && prev_action == add_alert
+ || action == add_alert && prev_action == any_alert
+ )
+ action = any_alert;
+
+ else if (prev_action && prev_action != action) {
+ LP_ERRMSG2 (ERROR, E_LP_AMBIG, option, prev_option);
+ exit (1);
+ }
+
+OK: prev_action = action;
+ prev_option = option;
+ return (action);
+}
+
+/**
+ ** notify_spooler() - NOTIFY SPOOLER OF ACTION ON FORMS DB
+ **/
+
+static int
+#if defined(__STDC__)
+notify_spooler (
+ int sendmsg,
+ int replymsg,
+ char * form
+)
+#else
+notify_spooler (sendmsg, replymsg, form)
+ int sendmsg;
+ int replymsg;
+ char * form;
+#endif
+{
+ char * msgbuf;
+
+ int mtype;
+ int size;
+
+ short status;
+
+ /*
+ * If the attempt to open a message queue to the
+ * Spooler fails, assume it isn't running and just
+ * return--don't say anything, `cause the user may
+ * know. Any other failure deserves an error message.
+ */
+
+ if (mopen() == -1)
+ return (-1);
+
+ size = putmessage((char *)0, sendmsg, form);
+ msgbuf = malloc(size);
+ putmessage (msgbuf, sendmsg, form);
+
+ if (msend(msgbuf) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MSEND);
+ mclose ();
+ exit (1);
+ }
+ if (mrecv(msgbuf, size) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MRECV);
+ mclose ();
+ exit (1);
+ }
+ mclose ();
+
+ mtype = getmessage(msgbuf, replymsg, &status);
+ free (msgbuf);
+ if (mtype != replymsg) {
+ LP_ERRMSG (ERROR, E_LP_BADREPLY);
+ exit (1);
+ }
+
+ if (status == MOK)
+ return (MOK);
+
+ if (sendmsg == S_LOAD_FORM)
+ switch (status) {
+ case MNOSPACE:
+ LP_ERRMSG (ERROR, E_FOR_NOSPACE);
+ break;
+ case MNOPERM:
+ LP_ERRMSG (ERROR, E_LP_NOTADM);
+ break;
+
+ /*
+ * The following two error conditions should have
+ * already been trapped, so treat them as bad status
+ * should they occur.
+ */
+ case MNODEST:
+ case MERRDEST:
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, status);
+ break;
+ }
+
+ if (sendmsg == S_UNLOAD_FORM)
+ switch (status) {
+ case MBUSY:
+ LP_ERRMSG1 (ERROR, E_FOR_FORMBUSY, form);
+ break;
+ case MNODEST:
+ return (MNODEST);
+ case MNOPERM:
+ LP_ERRMSG (ERROR, E_LP_NOTADM);
+ break;
+ default:
+ LP_ERRMSG (ERROR, E_LP_BADSTATUS);
+ break;
+ }
+
+ exit (1);
+}
+
+/**
+ ** onerror()
+ **/
+
+static int
+#if defined(__STDC__)
+onerror (
+ int Errno,
+ int lp_errno,
+ int linenum
+)
+#else
+onerror (Errno, lp_errno, linenum)
+ int Errno;
+ int lp_errno;
+ int linenum;
+#endif
+{
+ static int nerrors = 0;
+
+
+ if (Errno == EBADF) {
+ switch (lp_errno) {
+ case LP_EBADSDN:
+ LP_ERRMSG1 (WARNING, E_FOR_BADSCALE, linenum);
+ break;
+ case LP_EBADINT:
+ LP_ERRMSG1 (WARNING, E_FOR_BADINT, linenum);
+ break;
+ case LP_EBADNAME:
+ LP_ERRMSG1 (WARNING, E_FOR_NOTNAME, linenum);
+ break;
+ case LP_EBADARG:
+ LP_ERRMSG1 (WARNING, E_FOR_BADCHSETQUALIFIER, linenum);
+ break;
+ case LP_ETRAILIN:
+ LP_ERRMSG1 (WARNING, E_FOR_TRAILIN, linenum);
+ break;
+ case LP_EBADCTYPE:
+ LP_ERRMSG1 (WARNING, E_FOR_NOTCTYPE, linenum);
+ break;
+ case LP_EBADHDR:
+ LP_ERRMSG1 (WARNING, E_FOR_BADHDR, linenum);
+ break;
+ }
+ if (nerrors++ >= 5) {
+ LP_ERRMSG (ERROR, E_LP_GARBAGE);
+ return (-1);
+ }
+ return (0);
+ } else {
+ LP_ERRMSG2 (ERROR, E_FOR_UNKNOWN, "(stdin)", PERROR);
+ return (-1);
+ }
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/Makefile b/usr/src/cmd/lp/cmd/lpsched/Makefile
new file mode 100644
index 0000000000..c5c645ffe8
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/Makefile
@@ -0,0 +1,139 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/cmd/lpsched/lpsched/Makefile
+#
+
+PROG= lpsched
+
+include ../../Makefile.lp
+
+MANIFEST= server.xml
+SVCMETHOD= print-svc
+
+ROOTMANIFESTDIR= $(ROOTSVCAPPLICATIONPRINT)
+
+PURIFYOPTS = -logfile=/tmp/errs.%p
+PURIFY = purify $(PURIFYOPTS)
+
+
+# Doing -DDEBUG allows some nice log files to be generated
+# with the -d option.
+
+CPPFLAGS = -I. -I$(LPINC) $(CPPFLAGS.master)
+
+HDRS= \
+ nodes.h \
+ dispatch.h \
+ validate.h \
+ lpsched.h
+
+SRCS= \
+ alerts.c \
+ cancel.c \
+ daisyforms.c \
+ disena.c \
+ disp1.c \
+ disp2.c \
+ disp3.c \
+ disp4.c \
+ disp5.c \
+ disptab.c \
+ dowait.c \
+ exec.c \
+ faults.c \
+ files.c \
+ flt.c \
+ fncs.c \
+ getkey.c \
+ init.c \
+ log.c \
+ lpfsck.c \
+ lpsched.c \
+ msgs.c \
+ notify.c \
+ pickfilter.c \
+ ports.c \
+ requeue.c \
+ rstatus.c \
+ schedule.c \
+ status.c \
+ terminate.c \
+ validate.c
+
+OBJS= $(SRCS:.c=.o)
+
+
+LPLIBS = \
+ $(LIBMSG) \
+ $(LIBFRM) \
+ $(LIBREQ) \
+ $(LIBPRT) \
+ $(LIBCLS) \
+ $(LIBACC) \
+ $(LIBFLT) \
+ $(LIBUSR) \
+ $(LIBOAM) \
+ $(LIBLP) \
+ $(LIBSEC)
+
+SYSLIBS= -lcurses -lgen -lcurses -lnsl -ltsol -lsecdb -lbsm
+
+LDLIBS += $(LPLIBS) $(SYSLIBS)
+
+POFILE= lp_cmd_lpsched.po
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS) $(LPLIBS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(PROG).pure: $(OBJS) $(LPLIBS)
+ $(PURIFY) $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(ROOTLIBLPLOCLPROG) $(ROOTMANIFEST) $(ROOTSVCMETHOD)
+
+
+check: $(CHKMANIFEST)
+
+
+clean:
+ $(RM) $(OBJS)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint: lint_SRCS
+
+include ../Makefile.msg
+
+FRC:
+
+include ../../../Makefile.targ
diff --git a/usr/src/cmd/lp/cmd/lpsched/alerts.c b/usr/src/cmd/lp/cmd/lpsched/alerts.c
new file mode 100644
index 0000000000..7e9b5c5824
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/alerts.c
@@ -0,0 +1,349 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "lpsched.h"
+#include "stdarg.h"
+
+static char *Fa_msg[] =
+{
+ "Subject: Mount form %s\n\nThe form %s needs to be mounted\non the printer(s):\n",
+ " %-14s (%d requests)\n",
+ "Total print requests queued for this form: %d\n",
+ "Use the %s ribbon.\n",
+ "Use any ribbon.\n",
+ "Use the %s print wheel, if appropriate.\n",
+ "Use any print wheel, if appropriate.\n",
+};
+
+static char *Fa_New_msg[] =
+{
+ "The form `%s' needs to be mounted\non the printer(s):\n",
+ "The form `%s' (paper size: `%s') needs\nto be mounted on the printer(s):\n",
+};
+
+static char *Pa_msg[] =
+{
+ "Subject: Mount print-wheel %s\n\nThe print-wheel %s needs to be mounted\non the printer(s):\n",
+ " %-14s (%d request(s))\n",
+ "Total print requests queued for this print-wheel: %d\n",
+};
+
+static char *Pf_msg[] =
+{
+ "Subject: Problem with printer %s\n\nThe printer %s has stopped printing for the reason given below.\n",
+ "Fix the problem and bring the printer back on line\nto resume printing.\n",
+ "Fix the problem and bring the printer back on line, and issue\nan enable command when you want to resume or restart printing.\n",
+ "Fix the problem and bring the printer back on line.\nPrinting has stopped, but will be restarted in a few minutes;\nissue an enable command if you want to restart sooner.\nUnless someone issues a change request\n\n\tlp -i %s -P ...\n\nto change the page list to print, the current request will be reprinted from\nthe beginning.\n",
+ "\nThe reason(s) it stopped (multiple reasons indicate repeated attempts):\n\n"
+};
+
+static void pformat(),
+ pwformat(),
+ fformat();
+
+static int f_count(),
+ p_count();
+
+/*VARARGS1*/
+void
+alert (int type, ...)
+{
+ va_list args;
+
+ va_start (args, type);
+
+ switch (type) {
+ case A_PRINTER: {
+ PSTATUS *pr = va_arg(args, PSTATUS *);
+ RSTATUS *rp = va_arg(args, RSTATUS *);
+ char *text = va_arg(args, char *);
+ pformat(pr->alert->msgfile, text, pr, rp);
+ if (!pr->alert->active)
+ {
+ if (exec(EX_ALERT, pr) == 0)
+ pr->alert->active = 1;
+ else
+ {
+ if (errno == EBUSY)
+ pr->alert->exec->flags |= EXF_RESTART;
+ else
+ Unlink(pr->alert->msgfile);
+ }
+ }
+ break;
+ }
+ case A_PWHEEL: {
+ PWSTATUS *pp = va_arg(args, PWSTATUS *);
+ pwformat(pp->alert->msgfile, pp);
+ if (!pp->alert->active) {
+ if (exec(EX_PALERT, pp) == 0)
+ pp->alert->active = 1;
+ else {
+ if (errno == EBUSY)
+ pp->alert->exec->flags |= EXF_RESTART;
+ else
+ Unlink(pp->alert->msgfile);
+ }
+ }
+ break;
+ }
+ case A_FORM: {
+ int isFormMessage;
+ char *formPath;
+ FSTATUS *fp = va_arg(args, FSTATUS *);
+
+ isFormMessage = (STREQU(fp->form->alert.shcmd, "showfault"));
+ if (isFormMessage)
+ formPath = makepath(Lp_A_Forms, fp->form->name,
+ FORMMESSAGEFILE, (char * )NULL);
+ else
+ formPath = fp->alert->msgfile;
+
+ fformat(formPath, fp,isFormMessage);
+
+ if (isFormMessage) {
+ Free(formPath);
+ schedule (EV_FORM_MESSAGE, fp);
+ } else if (!fp->alert->active) {
+ if (exec(EX_FALERT, fp) == 0)
+ fp->alert->active = 1;
+ else {
+ if (errno == EBUSY)
+ fp->alert->exec->flags |= EXF_RESTART;
+ else
+ Unlink(fp->alert->msgfile);
+ }
+ }
+ break;
+ }
+ }
+ va_end(args);
+}
+
+static void
+pformat(char *file, char *text, PSTATUS *pr, RSTATUS *rp)
+{
+ int fd;
+
+ if (Access(pr->alert->msgfile, 0) == 0) {
+ if ((fd = open_locked(file, "a", MODE_READ)) < 0)
+ return;
+ if (text)
+ fdprintf(fd, text);
+ close(fd);
+ } else {
+ if ((fd = open_locked(file, "w", MODE_READ)) < 0)
+ return;
+ fdprintf(fd, Pf_msg[0], NB(pr->printer->name), NB(pr->printer->name));
+ if (STREQU(pr->printer->fault_rec, NAME_WAIT))
+ fdprintf(fd, Pf_msg[2]);
+ else {
+ if (pr->exec->pid > 0)
+ fdprintf(fd, Pf_msg[1]);
+ else if (rp)
+ fdprintf(fd, Pf_msg[3], rp->secure->req_id);
+ }
+ fdprintf(fd, Pf_msg[4]);
+ if (text) {
+ while (*text == '\n' || *text == '\r')
+ text++;
+ fdprintf(fd, "%s", text);
+ }
+ close(fd);
+ }
+}
+
+static void
+pwformat(char *file, PWSTATUS *pp)
+{
+ int fd, i;
+
+ if ((fd = open_locked(file, "w", MODE_READ)) < 0)
+ return;
+ fdprintf(fd, Pa_msg[0], NB(pp->pwheel->name), NB(pp->pwheel->name));
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
+ PSTATUS *p = PStatus[i];
+
+ if (p->printer->daisy && !SAME(p->pwheel_name, pp->pwheel->name) &&
+ searchlist(pp->pwheel->name, p->printer->char_sets)) {
+ int n = p_count(pp, p->printer->name);
+
+ if (n)
+ fdprintf(fd, Pa_msg[1], p->printer->name, n);
+ }
+ }
+ fdprintf(fd, Pa_msg[2], pp->requests);
+ close(fd);
+ pp->requests_last = pp->requests;
+}
+
+static void
+fformat(char *file, FSTATUS *fp, int isFormMessage)
+{
+ int fd, i;
+ int numLines=0;
+
+ if ((fd = open_locked(file, "w", MODE_READ)) < 0)
+ return;
+
+ if (isFormMessage)
+ if (fp->form->paper)
+ fdprintf(fd, Fa_New_msg[1], NB(fp->form->name),
+ fp->form->paper);
+ else
+ fdprintf(fd, Fa_New_msg[0], NB(fp->form->name));
+ else
+ fdprintf(fd, Fa_msg[0], NB(fp->form->name), NB(fp->form->name));
+
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
+ PSTATUS *p = PStatus[i];
+
+ if ((! isFormMountedOnPrinter(p,fp)) &&
+ allowed(fp->form->name, p->forms_allowed,
+ p->forms_denied)) {
+
+ int n = f_count(fp, p->printer->name);
+
+ if (n) {
+ fdprintf(fd, Fa_msg[1], p->printer->name, n);
+ numLines++;
+ }
+ }
+ }
+
+ if (numLines != 1) fdprintf(fd, Fa_msg[2], fp->requests);
+ if (!isFormMessage) {
+ if (fp->form->rcolor && !STREQU(fp->form->rcolor, NAME_ANY))
+ fdprintf(fd, Fa_msg[3], NB(fp->form->rcolor));
+ else
+ fdprintf(fd, Fa_msg[4]);
+
+ if (fp->form->chset && !STREQU(fp->form->chset, NAME_ANY))
+ fdprintf(fd, Fa_msg[5], NB(fp->form->chset));
+ else
+ fdprintf(fd, Fa_msg[6]);
+ }
+
+ close(fd);
+ fp->requests_last = fp->requests;
+}
+
+
+/* VARARGS1 */
+void
+cancel_alert(int type, ...)
+{
+ ALERT *ap;
+ va_list args;
+
+ va_start (args, type);
+
+ switch (type)
+ {
+ case A_PRINTER:
+ ap = va_arg(args, PSTATUS *)->alert;
+ break;
+
+ case A_PWHEEL:
+ ap = va_arg(args, PWSTATUS *)->alert;
+ break;
+
+ case A_FORM:
+ ap = va_arg(args, FSTATUS *)->alert;
+ break;
+
+ default:
+ return;
+ }
+ va_end(args);
+
+ ap->active = 0;
+ terminate(ap->exec);
+ Unlink(ap->msgfile);
+ return;
+}
+
+static int
+dest_equivalent_printer(char *dest, char *printer)
+{
+ CSTATUS * pc;
+
+ return (
+ STREQU(dest, printer)
+ || STREQU(dest, NAME_ANY)
+ || (
+ ((pc = search_cstatus(dest)) != NULL)
+ && searchlist(printer, pc->class->members)
+ )
+ );
+}
+
+static int
+f_count(FSTATUS *fp, char *name)
+{
+ int count = 0;
+ RSTATUS *rp;
+
+ for (rp = Request_List; rp != NULL; rp = rp->next)
+ if ((rp->form == fp ) &&
+ (dest_equivalent_printer(rp->request->destination, name)))
+ count++;
+
+ if (
+ NewRequest
+ && NewRequest->form == fp
+ && dest_equivalent_printer(NewRequest->request->destination, name)
+ )
+ count++;
+
+ return(count);
+}
+
+static int
+p_count(PWSTATUS *pp, char *name)
+{
+ int count = 0;
+ RSTATUS *rp;
+
+ for (rp = Request_List; rp != NULL; rp = rp->next)
+ if ((rp->pwheel == pp) &&
+ (dest_equivalent_printer(rp->request->destination, name)))
+ count++;
+
+ if (
+ NewRequest
+ && NewRequest->pwheel == pp
+ && dest_equivalent_printer(NewRequest->request->destination, name)
+ )
+ count++;
+
+ return(count);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/cancel.c b/usr/src/cmd/lp/cmd/lpsched/cancel.c
new file mode 100644
index 0000000000..9b1fc200a7
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/cancel.c
@@ -0,0 +1,62 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "lpsched.h"
+
+
+/**
+ ** cancel() - CANCEL A REQUEST
+ **/
+
+int
+cancel (RSTATUS *prs, int spool)
+{
+ if (prs->request->outcome & RS_DONE)
+ return (0);
+
+ prs->request->outcome |= RS_CANCELLED;
+
+ if (spool || (prs->request->actions & ACT_NOTIFY))
+ prs->request->outcome |= RS_NOTIFY;
+
+ if (prs->request->outcome & RS_PRINTING) {
+ terminate(prs->printer->exec);
+ }
+ else if (prs->request->outcome & RS_FILTERING) {
+ terminate (prs->exec);
+ }
+ else if (prs->request->outcome | RS_NOTIFY) {
+ notify (prs, "canceled by remote system\n", 0, 0, 0);
+ }
+ check_request (prs);
+
+ return (1);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/daisyforms.c b/usr/src/cmd/lp/cmd/lpsched/daisyforms.c
new file mode 100644
index 0000000000..52304d9603
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/daisyforms.c
@@ -0,0 +1,470 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "lpsched.h"
+#include <syslog.h>
+
+static int max_requests_needing_form_mounted ( FSTATUS * );
+static int max_requests_needing_pwheel_mounted ( char * );
+
+/**
+ ** queue_form() - ADD A REQUEST TO A FORM QUEUE
+ **/
+
+void
+queue_form(RSTATUS *prs, FSTATUS *pfs)
+{
+ if ((prs->form = pfs) != NULL) {
+ prs->form->requests++;
+ if (prs->printer)
+ check_form_alert (prs->form, (_FORM *)0);
+ }
+ return;
+}
+
+/**
+ ** unqueue_form() - REMOVE A REQUEST FROM A FORM QUEUE
+ **/
+
+void
+unqueue_form(RSTATUS *prs)
+{
+ FSTATUS * pfs = prs->form;
+
+ prs->form = 0;
+ if (pfs) {
+ pfs->requests--;
+ if (prs->printer)
+ check_form_alert (pfs, (_FORM *)0);
+ }
+ return;
+}
+
+/**
+ ** queue_pwheel() - ADD A REQUEST TO A PRINT WHEEL QUEUE
+ **/
+
+void
+queue_pwheel(RSTATUS *prs, char *name)
+{
+ if (name) {
+ prs->pwheel_name = Strdup(name);
+ /*
+ * Don't bother queueing the request for
+ * a print wheel if this request is destined for
+ * only this printer and the printer doesn't take
+ * print wheels.
+ */
+ if (
+ !one_printer_with_charsets(prs)
+ && (prs->pwheel = search_pwstatus(name))
+ ) {
+ prs->pwheel->requests++;
+ check_pwheel_alert (prs->pwheel, (PWHEEL *)0);
+ }
+ }
+ return;
+}
+
+/**
+ ** unqueue_pwheel() - REMOVE A REQUEST FROM A PRINT WHEEL QUEUE
+ **/
+
+void
+unqueue_pwheel(RSTATUS *prs)
+{
+ PWSTATUS * ppws = prs->pwheel;
+
+ prs->pwheel = 0;
+ unload_str (&(prs->pwheel_name));
+ if (ppws) {
+ ppws->requests--;
+ check_pwheel_alert (ppws, (PWHEEL *)0);
+ }
+ return;
+}
+
+/**
+ ** check_form_alert() - CHECK CHANGES TO MOUNT FORM ALERT
+ **/
+
+void
+check_form_alert(FSTATUS *pfs, _FORM *pf)
+{
+ short trigger,
+ fire_off_alert = 0;
+
+ int requests_waiting;
+
+
+ /*
+ * Call this routine whenever a requests has been queued
+ * or dequeued for a form, and whenever the form changes.
+ * If a pointer to a new _FORM is passed, the FSTATUS
+ * structure is updated with the changes. Use a second
+ * argument of 0 if no change.
+ *
+ * WARNING: It is valid to call this routine when adding
+ * a NEW form (not just changing it). Thus the members of
+ * the structure "pfs->form" may not be set.
+ * In this case, though, "pf" MUST be set, and there can
+ * be NO alert active.
+ */
+
+ syslog(LOG_DEBUG, "check_form_alert:\n");
+ if (pfs)
+ syslog(LOG_DEBUG, "check_form_alert: pfs->name <%s>\n",
+ (pfs->form->name != NULL) ? pfs->form->name : "null");
+ if (pf)
+ syslog(LOG_DEBUG, "check_form_alert: pf->name <%s>\n",
+ (pf->name != NULL) ? pf->name : "null");
+
+
+ if (pf) {
+ if ((trigger = pf->alert.Q) <= 0)
+ trigger = 1;
+ } else
+ trigger = pfs->trigger;
+
+ if (Starting)
+ goto Return;
+
+#define OALERT pfs->form->alert
+#define NALERT pf->alert
+
+ requests_waiting = max_requests_needing_form_mounted(pfs);
+
+ /*
+ * Cancel an active alert if the number of requests queued
+ * has dropped below the threshold (or the threshold has been
+ * raised), or if the alert command or period has changed.
+ * In the latter case we'll reactive the alert later.
+ */
+ if (pfs->alert->active)
+ if (!requests_waiting || requests_waiting < trigger)
+ cancel_alert (A_FORM, pfs);
+
+ else if (
+ pf
+ && (
+ !SAME(NALERT.shcmd, OALERT.shcmd)
+ || NALERT.W != OALERT.W
+ || NALERT.Q != OALERT.Q
+ )
+ )
+ cancel_alert (A_FORM, pfs);
+
+ /*
+ * If we still have the condition for an alert, we'll fire
+ * one off. It is possible the alert is still running, but
+ * that's okay. First, we may want to change the alert message;
+ * second, the "alert()" routine doesn't execute an alert
+ * if it is already running.
+ */
+ if (trigger > 0 && requests_waiting >= trigger)
+ if ((pf && NALERT.shcmd) || OALERT.shcmd)
+ fire_off_alert = 1;
+
+#undef OALERT
+#undef NALERT
+
+Return: if (pf) {
+
+ pfs->form = pf;
+
+ pfs->trigger = trigger;
+ }
+
+ /*
+ * Have to do this after updating the changes.
+ */
+ if (fire_off_alert)
+ alert (A_FORM, pfs);
+
+ return;
+}
+
+/**
+ ** check_pwheel_alert() - CHECK CHANGES TO MOUNT PRINTWHEEL ALERT
+ **/
+
+void
+check_pwheel_alert(PWSTATUS *ppws, PWHEEL *ppw)
+{
+ short trigger,
+ fire_off_alert = 0;
+ int requests_waiting;
+
+
+ /*
+ * Call this routine whenever a request has been queued
+ * or dequeued for a print-wheel, and whenever the print-wheel
+ * changes. If a pointer to a new PWHEEL is passed, the
+ * PWSTATUS structure is updated with the changes. Use a
+ * second argument of 0 if no change.
+ *
+ * WARNING: It is valid to call this routine when adding
+ * a NEW print wheel (not just changing it). Thus the members
+ * of the structure "ppws->pwheel" may not be set.
+ * In this case, though, "ppw" MUST be set, and there can
+ * be NO alert active.
+ */
+
+ if (ppw) {
+ if ((trigger = ppw->alert.Q) <= 0)
+ trigger = 1;
+ } else
+ trigger = ppws->trigger;
+
+ if (Starting)
+ goto Return;
+
+#define OALERT ppws->pwheel->alert
+#define NALERT ppw->alert
+
+ requests_waiting = max_requests_needing_pwheel_mounted(ppws->pwheel->name);
+
+ /*
+ * Cancel an active alert if the number of requests queued
+ * has dropped below the threshold (or the threshold has been
+ * raised), or if the alert command or period has changed.
+ * In the latter case we'll reactive the alert later.
+ */
+ if (ppws->alert->active)
+ if (!requests_waiting || requests_waiting < trigger)
+ cancel_alert (A_PWHEEL, ppws);
+
+ else if (
+ ppw
+ && (
+ !SAME(NALERT.shcmd, OALERT.shcmd)
+ || NALERT.W != OALERT.W
+ || NALERT.Q != OALERT.Q
+ )
+ )
+ cancel_alert (A_PWHEEL, ppws);
+
+ /*
+ * If we still have the condition for an alert, we'll fire
+ * one off. It is possible the alert is still running, but
+ * that's okay. First, we may want to change the alert message;
+ * second, the "alert()" routine doesn't execute an alert
+ * if it is already running.
+ */
+ if (trigger > 0 && requests_waiting >= trigger)
+ if ((ppw && NALERT.shcmd) || OALERT.shcmd)
+ fire_off_alert = 1;
+
+#undef OALERT
+#undef NALERT
+
+Return: if (ppw) {
+
+ ppws->pwheel = ppw;
+ ppws->trigger = trigger;
+ }
+
+ /*
+ * Have to do this after updating the changes.
+ */
+ if (fire_off_alert)
+ alert (A_PWHEEL, ppws);
+
+ return;
+}
+
+static int
+trayWithForm(PSTATUS *pps, FSTATUS *pfs, int startingTray, int checkAvail)
+{
+ int i;
+ PFSTATUS *ppfs;
+
+ ppfs = pps->forms;
+ if (startingTray < 0)
+ startingTray = 0;
+
+ if (ppfs) {
+ for (i = startingTray; i < pps->numForms; i++)
+ if ((!checkAvail || ppfs[i].isAvailable) &&
+ (ppfs[i].form == pfs))
+ return(i);
+ }
+ else if (!pfs)
+ /* no form request matches no form mounted */
+ return(0);
+
+ return(-1);
+}
+
+char *
+allTraysWithForm(PSTATUS *pps, FSTATUS *pfs)
+{
+
+ int tray = 0;
+ char *ptr, *p;
+ char trayList[MAX_INPUT];
+ int n;
+
+ ptr = trayList;
+ if (pfs && pfs->form && pfs->form->paper)
+ p = pfs->form->paper;
+ else
+ p = "";
+
+ n = sizeof (trayList);
+ snprintf(ptr, n, "LP_TRAY_ARG=%s:", p);
+
+ ptr += strlen(ptr);
+ n -= strlen(ptr);
+
+ while ((tray = trayWithForm(pps, pfs, tray, 1)) > 0) {
+ tray++;
+ snprintf(ptr, n, "%d,", tray);
+ ptr += strlen(ptr);
+ n -= strlen(ptr);
+ }
+ if (*(ptr-1) == ',')
+ *(ptr-1) = 0;
+
+ putenv(trayList);
+ return(NULL);
+}
+
+int
+isFormUsableOnPrinter(PSTATUS *pps, FSTATUS *pfs)
+{
+ return (trayWithForm(pps,pfs,0,1) >= 0 );
+}
+int
+isFormMountedOnPrinter(PSTATUS *pps, FSTATUS *pfs)
+{
+ return (trayWithForm(pps,pfs,0,0) >= 0 );
+}
+
+/**
+ ** max_requests_needing_form_mounted()
+ ** max_requests_needing_pwheel_mounted()
+ **/
+
+static int
+max_requests_needing_form_mounted(FSTATUS *pfs)
+{
+ PSTATUS * pps;
+ RSTATUS * prs;
+ int max = 0;
+ int i;
+
+ /*
+ * For each printer that doesn't have this form mounted,
+ * count the number of requests needing this form and
+ * assigned to the printer. Find the maximum across all such
+ * printers. Sorry, the code actually has a different loop
+ * (it steps through the requests) but the description of what
+ * happens below is easier to understand as given. (Looping
+ * through the printers would result in #printers x #requests
+ * steps, whereas this entails #requests steps.)
+ */
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ PStatus[i]->nrequests = 0;
+
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if ((prs->form == pfs) && ((pps = prs->printer) != NULL) &&
+ (!isFormMountedOnPrinter(pps,pfs)) &&
+ (++pps->nrequests >= max))
+ max = pps->nrequests;
+
+ if (NewRequest)
+ if (((pps = NewRequest->printer) != NULL) &&
+ (!isFormMountedOnPrinter(pps,pfs)))
+ if (++pps->nrequests >= max)
+ max = pps->nrequests;
+ return (max);
+}
+
+static int
+max_requests_needing_pwheel_mounted(char *pwheel_name)
+{
+ PSTATUS * pps;
+ RSTATUS * prs;
+ int max = 0;
+ int i;
+
+
+ /*
+ * For each printer that doesn't have this print-wheel mounted,
+ * count the number of requests needing this print-wheel and
+ * assigned to the printer. Find the maximum across all such
+ * printers. Sorry, the code actually has a different loop
+ * (it steps through the requests) but the description of what
+ * happens below is easier to understand as given. (Looping
+ * through the printers would result in #printers x #requests
+ * steps, whereas this entails #requests steps.)
+ */
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ PStatus[i]->nrequests = 0;
+
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if ((prs->pwheel_name != NULL) &&
+ (STREQU(prs->pwheel_name, pwheel_name)) &&
+ ((pps = prs->printer) != NULL) && pps->printer->daisy &&
+ (!SAME(pps->pwheel_name, pwheel_name)))
+ if (++pps->nrequests >= max)
+ max = pps->nrequests;
+
+ if (NewRequest)
+ if (
+ ((pps = NewRequest->printer) != NULL)
+ && pps->printer->daisy
+ && !SAME(pps->pwheel_name, pwheel_name)
+ )
+ if (++pps->nrequests >= max)
+ max = pps->nrequests;
+ return (max);
+}
+
+/**
+ ** one_printer_with_charsets()
+ **/
+
+int
+one_printer_with_charsets(RSTATUS *prs)
+{
+ /*
+ * This little function answers the question: Is a request
+ * that needs a character set destined for a particular
+ * printer that has selectable character sets instead of
+ * mountable print wheels?
+ */
+ return (
+ STREQU(prs->request->destination, prs->printer->printer->name)
+ && !prs->printer->printer->daisy
+ );
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/disena.c b/usr/src/cmd/lp/cmd/lpsched/disena.c
new file mode 100644
index 0000000000..559e59e17e
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/disena.c
@@ -0,0 +1,129 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9.1.4 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "lpsched.h"
+#include <time.h>
+
+/**
+ ** disable() - DISABLE PRINTER
+ **/
+
+int
+disable(PSTATUS *pps, char *reason, int when)
+{
+ if (pps->status & PS_DISABLED)
+ return (-1);
+
+ else {
+ pps->status |= PS_DISABLED;
+ time (&pps->dis_date);
+ load_str (&pps->dis_reason, reason);
+
+ dump_pstatus ();
+
+ if (pps->status & PS_BUSY)
+ switch (when) {
+
+ case DISABLE_STOP:
+ /*
+ * Stop current job, requeue.
+ */
+ if (pps->request)
+ pps->request->request->outcome |= RS_STOPPED;
+ terminate (pps->exec);
+ break;
+
+ case DISABLE_FINISH:
+ /*
+ * Let current job finish.
+ */
+ break;
+
+ case DISABLE_CANCEL:
+ /*
+ * Cancel current job outright.
+ */
+ if (pps->request)
+ cancel (pps->request, 1);
+ break;
+
+ }
+
+ /*
+ * Need we check to see if requests assigned to
+ * this printer should be assigned elsewhere?
+ * No, if the "validate()" routine is properly
+ * assigning requests. If another printer is available
+ * for printing requests (that would otherwise be)
+ * assigned to this printer, at least one of those
+ * requests will be assigned to that other printer,
+ * and should be currently printing. Once it is done
+ * printing, the queue will be examined for the next
+ * request, and the one(s) assigned this printer will
+ * be picked up.
+ */
+/* (void)queue_repel (pps, 0, (qchk_fnc_type)0); */
+
+ return (0);
+ }
+}
+
+/**
+ ** enable() - ENABLE PRINTER
+ **/
+
+int
+enable (register PSTATUS *pps)
+{
+ /*
+ * ``Enabling a printer'' includes clearing a fault and
+ * clearing the do-it-later flag to allow the printer
+ * to start up again.
+ */
+ if (!(pps->status & (PS_FAULTED|PS_DISABLED|PS_LATER)))
+ return (-1);
+
+ else {
+ pps->status &= ~(PS_FAULTED|PS_DISABLED|PS_LATER);
+ (void) time (&pps->dis_date);
+
+ dump_pstatus ();
+
+ if (pps->alert->active)
+ cancel_alert (A_PRINTER, pps);
+
+ /*
+ * Attract the FIRST request that is waiting to
+ * print to this printer. In this regard we're acting
+ * like the printer just finished printing a request
+ * and is looking for another.
+ */
+ queue_attract (pps, qchk_waiting, 1);
+ return (0);
+ }
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/disp1.c b/usr/src/cmd/lp/cmd/lpsched/disp1.c
new file mode 100644
index 0000000000..d8e667550d
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/disp1.c
@@ -0,0 +1,1177 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include "dispatch.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+static char *reqpath(char *, char **);
+static int mv_file(RSTATUS *, char *);
+
+
+RSTATUS *NewRequest;
+
+/*
+ * s_alloc_files()
+ */
+
+void
+s_alloc_files(char *m, MESG *md) /* funcdef */
+{
+ char *file_prefix;
+ ushort_t count;
+ mode_t old_msk;
+
+
+ /*
+ * Bugid 4140311
+ * Set umask to 0 before creating files.
+ */
+ old_msk = umask((mode_t)0);
+
+ getmessage(m, S_ALLOC_FILES, &count);
+ syslog(LOG_DEBUG, "s_alloc_files(%d)", count);
+
+ if ((file_prefix = _alloc_files(count, (char *)0, md->uid, md->gid))) {
+ mputm(md, R_ALLOC_FILES, MOK, file_prefix);
+ add_flt_act(md, FLT_FILES, file_prefix, count);
+ } else if (errno == EEXIST)
+ mputm(md, R_ALLOC_FILES, MERRDEST, "");
+ else
+ mputm(md, R_ALLOC_FILES, MNOMEM, "");
+
+ (void) umask(old_msk);
+
+}
+
+/*
+ * s_print_request()
+ */
+
+void
+s_print_request(char *m, MESG *md)
+{
+ extern char *Local_System;
+ char *file;
+ char *idno;
+ char *path;
+ char *req_file;
+ char *req_id = 0;
+ RSTATUS *rp;
+ REQUEST *r;
+ SECURE *s;
+ struct passwd *pw;
+ short err;
+ short status;
+ off_t size;
+ uid_t org_uid;
+ gid_t org_gid;
+#ifdef LP_USE_PAPI_ATTR
+ struct stat tmpBuf;
+ char tmpName[BUFSIZ];
+#endif
+
+
+ (void) getmessage(m, S_PRINT_REQUEST, &file);
+ syslog(LOG_DEBUG, "s_print_request(%s)", (file ? file : "NULL"));
+
+ /*
+ * "NewRequest" points to a request that's not yet in the
+ * request list but is to be considered with the rest of the
+ * requests (e.g. calculating # of requests awaiting a form).
+ */
+ if ((rp = NewRequest = new_rstatus(NULL, NULL)) == NULL)
+ status = MNOMEM;
+
+ else
+ {
+ req_file = reqpath(file, &idno);
+ path = makepath(Lp_Tmp, req_file, (char *)0);
+ (void) chownmod(path, Lp_Uid, Lp_Gid, 0644);
+ Free(path);
+
+ if (!(r = Getrequest(req_file)))
+ status = MNOOPEN;
+
+ else
+ {
+ rp->req_file = Strdup(req_file);
+
+ freerequest(rp->request);
+ rp->request = r;
+
+ rp->request->outcome = 0;
+ rp->secure->uid = md->uid;
+ rp->secure->gid = md->gid;
+ if (md->slabel != NULL)
+ rp->secure->slabel = Strdup(md->slabel);
+
+ pw = getpwuid(md->uid);
+ endpwent();
+ if (pw && pw->pw_name && *pw->pw_name)
+ rp->secure->user = Strdup(pw->pw_name);
+ else {
+ rp->secure->user = Strdup(BIGGEST_NUMBER_S);
+ (void) sprintf(rp->secure->user, "%u",
+ md->uid);
+ }
+
+ if ((rp->request->actions & ACT_SPECIAL) == ACT_HOLD)
+ rp->request->outcome |= RS_HELD;
+ if ((rp->request->actions & ACT_SPECIAL) == ACT_RESUME)
+ rp->request->outcome &= ~RS_HELD;
+ if ((rp->request->actions & ACT_SPECIAL) ==
+ ACT_IMMEDIATE) {
+ if (!md->admin) {
+ status = MNOPERM;
+ goto Return;
+ }
+ rp->request->outcome |= RS_IMMEDIATE;
+ }
+
+ size = chfiles(rp->request->file_list, Lp_Uid, Lp_Gid);
+
+ if (size < 0) {
+ /*
+ * at this point, chfiles() may have
+ * failed because the file may live on
+ * an NFS mounted filesystem, under
+ * a directory of mode 700. such a
+ * directory isn't accessible even by
+ * root, according to the NFS protocol
+ * (i.e. the Stat() in chfiles() failed).
+ * this most commonly happens via the
+ * automounter, and rlogin. thus we
+ * change our euid/egid to that of the
+ * user, and try again. if *this* fails,
+ * then the file must really be
+ * inaccessible.
+ */
+ org_uid = geteuid();
+ org_gid = getegid();
+
+ if (setegid(md->gid) != 0) {
+ status = MUNKNOWN;
+ goto Return;
+ }
+
+ if (seteuid(md->uid) != 0) {
+ setgid(org_gid);
+ status = MUNKNOWN;
+ goto Return;
+ }
+
+ size = chfiles(rp->request->file_list,
+ Lp_Uid, Lp_Gid);
+
+ if (seteuid(org_uid) != 0) {
+ /* should never happen */
+ note("s_print_request(): ");
+ note("seteuid back to uid=%d "
+ "failed!!\n", org_uid);
+ size = -1;
+ }
+
+ if (setegid(org_gid) != 0) {
+ /* should never happen */
+ note("s_print_request(): ");
+ note("setegid back to uid=%d "
+ "failed!!\n", org_uid);
+ size = -1;
+ }
+
+ if (size < 0) {
+ status = MUNKNOWN;
+ goto Return;
+ }
+ }
+ if (!(rp->request->outcome & RS_HELD) && size == 0) {
+ status = MNOPERM;
+ goto Return;
+ }
+ rp->secure->size = size;
+
+ (void) time(&rp->secure->date);
+ rp->secure->req_id = NULL;
+
+ if (!rp->request->title) {
+ if (strlen(*rp->request->file_list) <
+ (size_t)24)
+ rp->request->title =
+ Strdup(*rp->request->file_list);
+ else {
+ char *r;
+ if (r = strrchr(
+ *rp->request->file_list, '/'))
+ r++;
+ else
+ r = *rp->request->file_list;
+
+ rp->request->title = malloc(25);
+ sprintf(rp->request->title,
+ "%-.24s", r);
+ }
+ }
+
+ if ((err = validate_request(rp, &req_id, 0)) != MOK)
+ status = err;
+ else {
+ /*
+ * "req_id" will be supplied if this is from a
+ * remote system.
+ */
+ if (rp->secure->req_id == NULL) {
+ req_id = makestr(req_id, "-",
+ idno, (char *)0);
+ rp->secure->req_id = req_id;
+ } else
+ req_id = rp->secure->req_id;
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * Check if the PAPI job attribute file
+ * exists, if it does change the
+ * permissions and ownership of the file.
+ * This file is created when print jobs
+ * are submitted via the PAPI interface,
+ * the file pathname of this file is
+ * passed to the slow-filters and printer
+ * interface script as an environment
+ * variable when they are executed
+ */
+ snprintf(tmpName, sizeof (tmpName),
+ "%s-%s", idno, LP_PAPIATTRNAME);
+ path = makepath(Lp_Temp, tmpName, (char *)0);
+
+ if (stat(path, &tmpBuf) == 0) {
+ syslog(LOG_DEBUG,
+ "s_print_request: "\
+ "attribute file ='%s'", path);
+
+ /*
+ * IPP job attribute file exists
+ * for this job so change
+ * permissions and ownership of
+ * the file
+ */
+ (void) chownmod(path, Lp_Uid,
+ Lp_Gid, 0644);
+ Free(path);
+ }
+ else
+ {
+ syslog(LOG_DEBUG,
+ "s_print_request: "\
+ "no attribute file");
+ }
+#endif
+
+ /*
+ * fix for bugid 1103890.
+ * use Putsecure instead.
+ */
+ if ((Putsecure(req_file, rp->secure) == -1) ||
+ (putrequest(req_file, rp->request) == -1))
+ status = MNOMEM;
+ else
+ {
+ status = MOK;
+
+ insertr(rp);
+ NewRequest = 0;
+
+ if (rp->slow)
+ schedule(EV_SLOWF, rp);
+ else
+ schedule(EV_INTERF,
+ rp->printer);
+
+ del_flt_act(md, FLT_FILES);
+ }
+ }
+ }
+ }
+
+Return:
+ NewRequest = 0;
+ Free(req_file);
+ Free(idno);
+ if (status != MOK && rp) {
+ rmfiles(rp, 0);
+ free_rstatus(rp);
+ }
+ mputm(md, R_PRINT_REQUEST, status, NB(req_id), chkprinter_result);
+}
+
+/*
+ * s_start_change_request()
+ */
+
+void
+s_start_change_request(char *m, MESG *md)
+{
+ char *req_id;
+ char *req_file = "";
+ short status;
+ RSTATUS *rp;
+ char *path;
+ char tmpName[BUFSIZ];
+ struct stat tmpBuf;
+
+ (void) getmessage(m, S_START_CHANGE_REQUEST, &req_id);
+ syslog(LOG_DEBUG, "s_start_change_request(%s)",
+ (req_id ? req_id : "NULL"));
+
+ if (!(rp = request_by_id(req_id)))
+ status = MUNKNOWN;
+ else if ((md->admin == 0) && (is_system_labeled()) &&
+ (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
+ (!STREQU(md->slabel, rp->secure->slabel)))
+ status = MUNKNOWN;
+ else if (rp->request->outcome & RS_DONE)
+ status = M2LATE;
+ else if (!md->admin && md->uid != rp->secure->uid)
+ status = MNOPERM;
+ else if (rp->request->outcome & RS_CHANGING)
+ status = MNOOPEN;
+ else if (rp->request->outcome & RS_NOTIFYING)
+ status = MBUSY;
+ else {
+ status = MOK;
+
+ if (rp->request->outcome & RS_FILTERING &&
+ !(rp->request->outcome & RS_STOPPED)) {
+ rp->request->outcome |= (RS_REFILTER|RS_STOPPED);
+ terminate(rp->exec);
+ }
+
+ if (rp->request->outcome & RS_PRINTING &&
+ !(rp->request->outcome & RS_STOPPED)) {
+ rp->request->outcome |= RS_STOPPED;
+ terminate(rp->printer->exec);
+ }
+
+ rp->request->outcome |= RS_CHANGING;
+
+ /*
+ * Change the ownership of the request file to be "md->uid".
+ * Either this is identical to "rp->secure->uid", or it is
+ * "Lp_Uid" or it is root. The idea is that the
+ * person at the other end needs access, and that may not
+ * be who queued the request.
+ */
+
+ path = makepath(Lp_Tmp, rp->req_file, (char *)0);
+ (void) Chown(path, md->uid, rp->secure->gid);
+ Free(path);
+
+#ifdef LP_USE_PAPI_ATTR
+
+ /*
+ * Check if the PAPI job attribute file exists, if it does
+ * change the ownership of the file to be "md->uid".
+ * Either this is identical to "rp->secure->uid", or it is
+ * "Lp_Uid" or it is root. The idea is that the
+ * person at the other end needs access, and that may not
+ * be who queued the request.
+ */
+
+ snprintf(tmpName, sizeof (tmpName),
+ "%s-%s", strtok(strdup(rp->req_file), "-"),
+ LP_PAPIATTRNAME);
+
+ path = makepath(Lp_Tmp, tmpName, (char *)0);
+
+ if (stat(path, &tmpBuf) == 0) {
+ syslog(LOG_DEBUG,
+ "s_start_change_request: attribute file ='%s'",
+ path);
+
+ /*
+ * IPP job attribute file exists for this job so
+ * change permissions and ownership of the file
+ */
+ (void) Chown(path, md->uid, rp->secure->gid);
+ Free(path);
+ }
+ else
+ {
+ syslog(LOG_DEBUG,
+ "s_start_change_request: no attribute file");
+ }
+#endif
+
+ add_flt_act(md, FLT_CHANGE, rp);
+ req_file = rp->req_file;
+
+ }
+
+ mputm(md, R_START_CHANGE_REQUEST, status, req_file);
+}
+
+/*
+ * s_end_change_request()
+ */
+
+void
+s_end_change_request(char *m, MESG *md)
+{
+ char *req_id;
+ RSTATUS *rp;
+ off_t size;
+ off_t osize;
+ short err;
+ short status;
+ REQUEST *r = 0;
+ REQUEST oldr;
+ int call_schedule = 0;
+ int move_ok = 0;
+ char *path;
+ char tmpName[BUFSIZ];
+ struct stat tmpBuf;
+
+ (void) getmessage(m, S_END_CHANGE_REQUEST, &req_id);
+ syslog(LOG_DEBUG, "s_end_change_request(%s)",
+ (req_id ? req_id : "NULL"));
+
+ if (!(rp = request_by_id(req_id)))
+ status = MUNKNOWN;
+ else if ((md->admin == 0) && (is_system_labeled()) &&
+ (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
+ (!STREQU(md->slabel, rp->secure->slabel)))
+ status = MUNKNOWN;
+ else if (!(rp->request->outcome & RS_CHANGING))
+ status = MNOSTART;
+ else {
+ path = makepath(Lp_Tmp, rp->req_file, (char *)0);
+ (void) chownmod(path, Lp_Uid, Lp_Gid, 0644);
+ Free(path);
+
+#ifdef LP_USE_PAPI_ATTR
+
+ /*
+ * Check if the PAPI job attribute file exists,
+ * if it does change the permission and the ownership
+ * of the file to be "Lp_Uid".
+ */
+
+ snprintf(tmpName, sizeof (tmpName),
+ "%s-%s", strtok(strdup(rp->req_file), "-"),
+ LP_PAPIATTRNAME);
+
+ path = makepath(Lp_Tmp, tmpName, (char *)0);
+
+ if (stat(path, &tmpBuf) == 0) {
+ syslog(LOG_DEBUG,
+ "s_end_change_request: attribute file ='%s'",
+ path);
+
+ /*
+ * IPP job attribute file exists for this job so
+ * change permissions and ownership of the file
+ */
+ (void) chownmod(path, Lp_Uid, Lp_Gid, 0644);
+ Free(path);
+ }
+ else
+ {
+ syslog(LOG_DEBUG,
+ "s_end_change_request: no attribute file");
+ }
+#endif
+ rp->request->outcome &= ~(RS_CHANGING);
+ del_flt_act(md, FLT_CHANGE);
+ /*
+ * The RS_CHANGING bit may have been the only thing
+ * preventing this request from filtering or printing,
+ * so regardless of what happens below,
+ * we must check to see if the request can proceed.
+ */
+ call_schedule = 1;
+
+ if (!(r = Getrequest(rp->req_file)))
+ status = MNOOPEN;
+ else {
+ oldr = *(rp->request);
+ *(rp->request) = *r;
+
+ move_ok =
+ STREQU(oldr.destination, r->destination);
+
+ /*
+ * Preserve the current request status!
+ */
+ rp->request->outcome = oldr.outcome;
+
+ /*
+ * Here's an example of the dangers one meets
+ * when public flags are used for private
+ * purposes. ".actions" (indeed, anything in the
+ * REQUEST structure) is set by the person
+ * changing the job. However, lpsched uses
+ * ".actions" as place to indicate that a job
+ * came from a remote system and we must send
+ * back job completion--this is a strictly
+ * private flag that we must preserve.
+ */
+ rp->request->actions |=
+ (oldr.actions & ACT_NOTIFY);
+
+ if ((rp->request->actions & ACT_SPECIAL) ==
+ ACT_HOLD) {
+ rp->request->outcome |= RS_HELD;
+ /*
+ * To be here means either the user owns
+ * the request or he or she is the
+ * administrator. Since we don't want to
+ * set the RS_ADMINHELD flag if the user
+ * is the administrator, the following
+ * compare will work.
+ */
+ if (md->uid != rp->secure->uid)
+ rp->request->outcome |=
+ RS_ADMINHELD;
+ }
+
+ if ((rp->request->actions & ACT_SPECIAL) ==
+ ACT_RESUME) {
+ if ((rp->request->outcome & RS_ADMINHELD) &&
+ !md->admin) {
+ status = MNOPERM;
+ goto Return;
+ }
+ rp->request->outcome &=
+ ~(RS_ADMINHELD|RS_HELD);
+ }
+
+ if ((rp->request->actions & ACT_SPECIAL)
+ == ACT_IMMEDIATE) {
+ if (!md->admin) {
+ status = MNOPERM;
+ goto Return;
+ }
+ rp->request->outcome |= RS_IMMEDIATE;
+ }
+
+ size = chfiles(rp->request->file_list, Lp_Uid,
+ Lp_Gid);
+ if (size < 0) {
+ status = MUNKNOWN;
+ goto Return;
+ }
+ if (!(rp->request->outcome & RS_HELD) &&
+ size == 0) {
+ status = MNOPERM;
+ goto Return;
+ }
+
+ osize = rp->secure->size;
+ rp->secure->size = size;
+
+ if (move_ok == 0) {
+ char *dest = strdup(r->destination);
+ if ((status = mv_file(rp, dest)) == MOK)
+ rp->secure->size = osize;
+ free(dest);
+ } else if ((err = validate_request(rp, (char **)0,
+ move_ok)) != MOK) {
+ status = err;
+ rp->secure->size = osize;
+ } else {
+ status = MOK;
+
+ if ((rp->request->outcome & RS_IMMEDIATE) ||
+ (rp->request->priority != oldr.priority)) {
+ remover(rp);
+ insertr(rp);
+ }
+
+ freerequest(&oldr);
+ (void) putrequest(rp->req_file, rp->request);
+ /*
+ * fix for bugid 1103890.
+ * use Putsecure instead.
+ */
+ (void) Putsecure(rp->req_file, rp->secure);
+ }
+ }
+ }
+
+Return:
+ if (status != MOK && rp) {
+ if (r) {
+ freerequest(r);
+ *(rp->request) = oldr;
+ }
+ if (status != MNOSTART)
+ (void) putrequest(rp->req_file, rp->request);
+ }
+
+ if (call_schedule)
+ maybe_schedule(rp);
+
+ mputm(md, R_END_CHANGE_REQUEST, status, chkprinter_result);
+}
+
+/*
+ * _cancel()
+ * user may be (host!user)
+ */
+
+static char *
+_cancel(MESG *md, char *dest, char *user, char *req_id)
+{
+ static RSTATUS *rp;
+ static char *s_dest;
+ static char *s_user;
+ static char *s_req_id;
+ static int current;
+ RSTATUS *crp;
+ char *creq_id;
+
+ syslog(LOG_DEBUG, "_cancel(%s, %s, %s)", (dest ? dest : "NULL"),
+ (user ? user : "NULL"), (req_id ? req_id : "NULL"));
+
+ if (dest || user || req_id) {
+ s_dest = dest;
+ if (STREQU(user, "!"))
+ s_user = strdup("all!all");
+ else
+ s_user = user;
+ s_req_id = req_id;
+ rp = Request_List;
+ current = 0;
+ if (STREQU(s_req_id, CURRENT_REQ)) {
+ current = 1;
+ s_req_id = NULL;
+ }
+ }
+
+ while (rp != NULL) {
+ crp = rp;
+ rp = rp->next;
+
+ if (*s_dest && !STREQU(s_dest, crp->request->destination))
+ continue;
+
+ if (current && !(crp->request->outcome & RS_PRINTING))
+ continue;
+
+ if (s_req_id && *s_req_id &&
+ !STREQU(s_req_id, crp->secure->req_id))
+ continue;
+
+ if (*s_user && !bangequ(s_user, crp->secure->user))
+ continue;
+
+ if (!md->admin && md->uid != crp->secure->uid) {
+ errno = MNOPERM;
+ return (Strdup(crp->secure->req_id));
+ }
+
+ /*
+ * For Trusted Extensions, we need to check the
+ * sensitivity label of the
+ * connection and job before we try to cancel it.
+ */
+ if ((md->admin == 0) && (is_system_labeled()) &&
+ (md->slabel != NULL) && (crp->secure->slabel != NULL) &&
+ (!STREQU(md->slabel, crp->secure->slabel)))
+ continue;
+
+ crp->reason = MOK;
+ creq_id = Strdup(crp->secure->req_id);
+
+ syslog(LOG_DEBUG, "cancel reqid (%s) uid: %d, secureuid: %d",
+ creq_id, md->uid, crp->secure->uid);
+
+ if (cancel(crp, (md->uid != crp->secure->uid)))
+ errno = MOK;
+ else
+ errno = M2LATE;
+ return (creq_id);
+ }
+
+ errno = MUNKNOWN;
+ return (NULL);
+}
+
+/*
+ * s_cancel_request()
+ */
+
+void
+s_cancel_request(char *m, MESG *md)
+{
+ char *req_id, *rid;
+ short status;
+
+ (void) getmessage(m, S_CANCEL_REQUEST, &req_id);
+ syslog(LOG_DEBUG, "s_cancel_request(%s)", (req_id ? req_id : "NULL"));
+
+ if ((rid = _cancel(md, "", "", req_id)) != NULL)
+ Free(rid);
+ status = (short)errno;
+
+ mputm(md, R_CANCEL_REQUEST, status);
+}
+
+/*
+ * s_cancel()
+ */
+
+void
+s_cancel(char *m, MESG *md)
+{
+ char *req_id;
+ char *user;
+ char *destination;
+ char *rid;
+ char *nrid;
+ int nerrno;
+ int oerrno;
+
+ (void) getmessage(m, S_CANCEL, &destination, &user, &req_id);
+ syslog(LOG_DEBUG, "s_cancel(%s, %s, %s)",
+ (destination ? destination : "NULL"), (user ? user : "NULL"),
+ (req_id ? req_id : "NULL"));
+
+ if (STREQU(destination, NAME_ALL))
+ destination = "";
+ if (STREQU(req_id, NAME_ALL))
+ req_id = "";
+
+ if (rid = _cancel(md, destination, user, req_id)) {
+ oerrno = errno;
+
+ while ((nrid = _cancel(md, NULL, NULL, NULL)) != NULL) {
+ nerrno = errno;
+ mputm(md, R_CANCEL, MOKMORE, oerrno, rid);
+ Free(rid);
+ rid = nrid;
+ oerrno = nerrno;
+ }
+ mputm(md, R_CANCEL, MOK, oerrno, rid);
+ Free(rid);
+ return;
+ }
+
+ mputm(md, R_CANCEL, MOK, MUNKNOWN, "");
+}
+
+/*
+ * s_inquire_request_rank()
+ */
+
+void
+s_inquire_request_rank(char *m, MESG *md)
+{
+ char *form;
+ char *dest;
+ char *pwheel;
+ char *user;
+ char *req_id;
+ RSTATUS *rp;
+ RSTATUS *found = NULL;
+ int found_rank = 0;
+ short prop;
+ char files[BUFSIZ];
+ int i;
+
+ (void) getmessage(m, S_INQUIRE_REQUEST_RANK, &prop, &form, &dest,
+ &req_id, &user, &pwheel);
+ syslog(LOG_DEBUG, "s_inquire_request_rank(%d, %s, %s, %s, %s, %s)",
+ prop, (form ? form : "NULL"), (dest ? dest : "NULL"),
+ (req_id ? req_id : "NULL"), (user ? user : "NULL"),
+ (pwheel ? pwheel : "NULL"));
+
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ PStatus[i]->nrequests = 0;
+
+ for (rp = Request_List; rp != NULL; rp = rp->next) {
+ if (rp->printer && !(rp->request->outcome & RS_DONE))
+ rp->printer->nrequests++;
+
+ if (*form && !SAME(form, rp->request->form))
+ continue;
+
+ if (*dest && !STREQU(dest, rp->request->destination)) {
+ if (!rp->printer)
+ continue;
+ if (!STREQU(dest, rp->printer->printer->name))
+ continue;
+ }
+
+ if (*req_id && !STREQU(req_id, rp->secure->req_id))
+ continue;
+
+ if (*user && !bangequ(user, rp->secure->user))
+ continue;
+
+ if (*pwheel && !SAME(pwheel, rp->pwheel_name))
+ continue;
+ /*
+ * For Trusted Extensions, we need to check the sensitivity
+ * label of the connection and job before we return it to the
+ * client.
+ */
+ if ((md->admin <= 0) && (is_system_labeled()) &&
+ (md->slabel != NULL) && (rp->secure->slabel != NULL) &&
+ (!STREQU(md->slabel, rp->secure->slabel)))
+ continue;
+
+ if (found) {
+ GetRequestFiles(found->request, files, sizeof (files));
+ mputm(md, R_INQUIRE_REQUEST_RANK,
+ MOKMORE,
+ found->secure->req_id,
+ found->request->user,
+ /* bgolden 091996, bug 1257405 */
+ found->secure->slabel,
+ found->secure->size,
+ found->secure->date,
+ found->request->outcome,
+ found->printer->printer->name,
+ (found->form? found->form->form->name : ""),
+ NB(found->pwheel_name),
+ found_rank,
+ files);
+ }
+ found = rp;
+ found_rank = found->printer->nrequests;
+ }
+
+ if (found) {
+ GetRequestFiles(found->request, files, sizeof (files));
+ mputm(md, R_INQUIRE_REQUEST_RANK,
+ MOK,
+ found->secure->req_id,
+ found->request->user, /* bgolden 091996, bug 1257405 */
+ found->secure->slabel,
+ found->secure->size,
+ found->secure->date,
+ found->request->outcome,
+ found->printer->printer->name,
+ (found->form? found->form->form->name : ""),
+ NB(found->pwheel_name),
+ found_rank,
+ files);
+ } else
+ mputm(md, R_INQUIRE_REQUEST_RANK, MNOINFO, "", "", "", 0L, 0L,
+ 0, "", "", "", 0, "");
+}
+
+static int
+mv_file(RSTATUS *rp, char *dest)
+{
+ int stat;
+ char *olddest;
+ EXEC *oldexec;
+ SECURE * securep;
+ RSTATUS * prs;
+ char *reqno;
+
+ oldexec = rp->printer->exec;
+ olddest = rp->request->destination;
+ rp->request->destination = Strdup(dest);
+ if ((stat = validate_request(rp, (char **)0, 1)) == MOK) {
+ Free(olddest);
+
+ if (rp->request->outcome & RS_FILTERED) {
+ int cnt = 0;
+ char *reqno;
+ char **listp;
+ char tmp_nam[MAXPATHLEN];
+
+ reqno = getreqno(rp->secure->req_id);
+ for (listp = rp->request->file_list; *listp; listp++) {
+ cnt++;
+ snprintf(tmp_nam, sizeof (tmp_nam),
+ "%s/F%s-%d", Lp_Temp, reqno, cnt);
+ unlink(tmp_nam);
+
+ }
+ rp->request->outcome &= ~RS_FILTERED;
+ }
+
+ /* update /var/spool/lp/tmp/<host>/nnn-0 */
+ if (putrequest(rp->req_file, rp->request) < 0) {
+ note("putrequest failed\n");
+ return (MNOMEM);
+ }
+
+ /* update /var/spool/lp/requests/<host>/nnn-0 */
+ if ((securep = Getsecure(rp->req_file))) {
+ reqno = strdup(getreqno(securep->req_id));
+ (void) free(securep->req_id);
+ if ((securep->req_id = calloc(strlen(dest) + 1 +
+ strlen(reqno) +1, sizeof (char))) == NULL)
+ return (MNOMEM);
+ (void) sprintf(securep->req_id, "%s-%s", dest, reqno);
+ /* remove the old request file; save new one */
+ (void) rmsecure(rp->secure->req_id);
+ if (Putsecure(rp->req_file, securep) < 0) {
+ /* Putsecure includes note/errmessage */
+ return (MNOMEM);
+ }
+ } else {
+ note("Getsecure failed\n");
+ return (MNOMEM);
+ }
+
+ /* update internal jobs list: Request_list */
+ if (prs = request_by_id(rp->secure->req_id)) {
+ free(prs->secure->req_id);
+ prs->secure->req_id = strdup(securep->req_id);
+
+ /*
+ * We calloc'd securep->reqid earlier, now we free it
+ * here because we no longer call 'freesecure' from
+ * Putsecure() if we use a static structure
+ */
+
+ free(securep->req_id);
+ } else {
+ note("request_by_id failed\n");
+ return (MUNKNOWN);
+ }
+
+ /*
+ * If the request was being filtered or was printing,
+ * it would have been stopped in "validate_request()",
+ * but only if it has to be refiltered. Thus, the
+ * filtering has been stopped if it has to be stopped,
+ * but the printing may still be going.
+ */
+ if (rp->request->outcome & RS_PRINTING &&
+ !(rp->request->outcome & RS_STOPPED)) {
+ rp->request->outcome |= RS_STOPPED;
+ terminate(oldexec);
+ }
+
+ maybe_schedule(rp);
+ return (MOK);
+ }
+
+ Free(rp->request->destination);
+ rp->request->destination = olddest;
+ return (stat);
+}
+
+/*
+ * s_move_request()
+ */
+
+void
+s_move_request(char *m, MESG *md)
+{
+ RSTATUS *rp;
+ short err;
+ char *req_id;
+ char *dest;
+
+ (void) getmessage(m, S_MOVE_REQUEST, &req_id, &dest);
+ syslog(LOG_DEBUG, "s_move_request(%s, %s)", (req_id ? req_id : "NULL"),
+ (dest ? dest : "NULL"));
+
+
+ if (!(search_pstatus(dest)) && !(search_cstatus(dest))) {
+ mputm(md, R_MOVE_REQUEST, MNODEST, 0L);
+ return;
+ }
+
+ if ((rp = request_by_id(req_id))) {
+ if (STREQU(rp->request->destination, dest)) {
+ mputm(md, R_MOVE_REQUEST, MOK, 0L);
+ return;
+ }
+ if (rp->request->outcome & (RS_DONE|RS_NOTIFYING)) {
+ mputm(md, R_MOVE_REQUEST, M2LATE, 0L);
+ return;
+ }
+ if (rp->request->outcome & RS_CHANGING) {
+ mputm(md, R_MOVE_REQUEST, MBUSY, 0L);
+ return;
+ }
+ if ((err = mv_file(rp, dest)) == MOK) {
+ mputm(md, R_MOVE_REQUEST, MOK, 0L);
+ return;
+ }
+ mputm(md, R_MOVE_REQUEST, err, chkprinter_result);
+ return;
+ }
+ mputm(md, R_MOVE_REQUEST, MUNKNOWN, 0L);
+}
+
+/*
+ * s_move_dest()
+ */
+
+void
+s_move_dest(char *m, MESG *md)
+{
+ char *dest;
+ char *fromdest;
+ RSTATUS *rp;
+ char *found = (char *)0;
+ short num_ok = 0;
+
+ (void) getmessage(m, S_MOVE_DEST, &fromdest, &dest);
+ syslog(LOG_DEBUG, "s_move_dest(%s, %s)", (fromdest ? fromdest : "NULL"),
+ (dest ? dest : "NULL"));
+
+ if (!search_pstatus(fromdest) && !search_cstatus(fromdest)) {
+ mputm(md, R_MOVE_DEST, MNODEST, fromdest, 0);
+ return;
+ }
+
+ if (!(search_pstatus(dest)) && !(search_cstatus(dest))) {
+ mputm(md, R_MOVE_DEST, MNODEST, dest, 0);
+ return;
+ }
+
+ if (STREQU(dest, fromdest)) {
+ mputm(md, R_MOVE_DEST, MOK, "", 0);
+ return;
+ }
+
+ for (rp = Request_List; rp != NULL; rp = rp->next) {
+ if ((STREQU(rp->request->destination, fromdest)) &&
+ (!(rp->request->outcome &
+ (RS_DONE|RS_CHANGING|RS_NOTIFYING)))) {
+ if (mv_file(rp, dest) == MOK) {
+ num_ok++;
+ continue;
+ }
+ }
+
+ if (found)
+ mputm(md, R_MOVE_DEST, MMORERR, found, 0);
+
+ found = rp->secure->req_id;
+ }
+
+ if (found)
+ mputm(md, R_MOVE_DEST, MERRDEST, found, num_ok);
+ else
+ mputm(md, R_MOVE_DEST, MOK, "", num_ok);
+}
+
+/*
+ * reqpath
+ */
+
+static char *
+reqpath(char *file, char **idnumber)
+{
+ char *path;
+ char *cp;
+ char *cp2;
+
+ /*
+ * /var/spool/lp/tmp/machine/123-0
+ * /var/spool/lp/temp/123-0
+ * /usr/spool/lp/temp/123-0
+ * /usr/spool/lp/tmp/machine/123-0
+ * 123-0
+ * machine/123-0
+ *
+ * /var/spool/lp/tmp/machine/123-0 + 123
+ */
+ if (*file == '/') {
+ /*CONSTCOND*/
+ if (STRNEQU(file, Lp_Spooldir, strlen(Lp_Spooldir)))
+ cp = file + strlen(Lp_Spooldir) + 1;
+ else {
+ if (STRNEQU(file, "/usr/spool/lp", 13))
+ cp = file + strlen("/usr/spool/lp") + 1;
+ else {
+ *idnumber = NULL;
+ return (NULL);
+ }
+ }
+
+ if (STRNEQU(cp, "temp", 4)) {
+ cp += 5;
+ path = makepath(Local_System, cp, NULL);
+ }
+ else
+ path = Strdup(cp);
+ }
+ else
+ {
+ if (strchr(file, '/'))
+ path = makepath(file, NULL);
+ else
+ path = makepath(Local_System, file, NULL);
+ }
+
+ cp = strrchr(path, '/');
+ cp++;
+ if ((cp2 = strrchr(cp, '-')) == NULL)
+ *idnumber = Strdup(cp);
+ else
+ {
+ *cp2 = '\0';
+ *idnumber = Strdup(cp);
+ *cp2 = '-';
+ }
+
+ return (path);
+}
+
+/*
+ * The client is sending a peer connection to retrieve label information
+ * from. This is used in the event that the client is an intermediary for
+ * the actual requestor in a Trusted environment.
+ */
+void
+s_pass_peer_connection(char *m, MESG *md)
+{
+ short status = MTRANSMITERR;
+ char *dest;
+ struct strrecvfd recv_fd;
+
+ (void) getmessage(m, S_PASS_PEER_CONNECTION);
+ syslog(LOG_DEBUG, "s_pass_peer_connection()");
+
+ memset(&recv_fd, NULL, sizeof (recv_fd));
+ if (ioctl(md->readfd, I_RECVFD, &recv_fd) == 0) {
+ int fd = recv_fd.fd;
+
+ if (get_peer_label(fd, &md->slabel) == 0) {
+ if (md->admin == 1)
+ md->admin = -1; /* turn off query privilege */
+ status = MOK;
+ }
+
+ close(fd);
+ }
+
+ mputm(md, R_PASS_PEER_CONNECTION, status);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/disp2.c b/usr/src/cmd/lp/cmd/lpsched/disp2.c
new file mode 100644
index 0000000000..459367f2dc
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/disp2.c
@@ -0,0 +1,613 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "dispatch.h"
+#include <syslog.h>
+#include <time.h>
+
+char *showForms(PSTATUS *);
+
+/*
+ * untidbit_all() - CALL untidbit() FOR A LIST OF TYPES
+ */
+
+static void
+untidbit_all (char **printer_types)
+{
+ char ** pl;
+
+ for (pl = printer_types; *pl; pl++)
+ untidbit (*pl);
+ return;
+}
+
+/*
+ * s_load_printer()
+ */
+
+void
+s_load_printer(char *m, MESG *md)
+{
+ char *printer;
+ ushort status;
+ register PRINTER *pp;
+ register PSTATUS *pps;
+ char **paperDenied;
+
+ (void) getmessage(m, S_LOAD_PRINTER, &printer);
+ syslog(LOG_DEBUG, "s_load_printer(%s)", (printer ? printer : "NULL"));
+
+ if (!*printer)
+ /* no printer */
+ status = MNODEST;
+ else if (!(pp = Getprinter(printer))) {
+ /* Strange or missing printer? */
+ switch (errno) {
+ case EBADF:
+ status = MERRDEST;
+ break;
+ case ENOENT:
+ default:
+ status = MNODEST;
+ break;
+ }
+ } else if ((pps = search_pstatus(printer))) {
+ /* Printer we know about already? */
+ PRINTER *op = pps->printer;
+
+ pps->printer = pp;
+
+ /*
+ * Ensure that an old Terminfo type that's no longer
+ * needed gets freed, and that an existing type gets
+ * reloaded (in case it has been changed).
+ */
+ untidbit_all (op->printer_types);
+ untidbit_all (pp->printer_types);
+
+ /*
+ * Does an alert get affected?
+ * - Different command?
+ * - Different wait interval?
+ */
+ if (pps->alert->active)
+ if (!SAME(pp->fault_alert.shcmd,
+ op->fault_alert.shcmd) ||
+ pp->fault_alert.W != op->fault_alert.W) {
+ /*
+ * We can't use "cancel_alert()" here
+ * because it will remove the message.
+ * We'll do half of the cancel, then
+ * check if we need to run the new alert,
+ * and remove the message if not.
+ */
+ pps->alert->active = 0;
+ terminate (pps->alert->exec);
+ if (pp->fault_alert.shcmd)
+ alert(A_PRINTER, pps, (RSTATUS *)0,
+ (char *)0);
+ else
+ Unlink (pps->alert->msgfile);
+ }
+ freeprinter (op);
+
+ unload_list (&pps->users_allowed);
+ unload_list (&pps->users_denied);
+ unload_list (&pps->forms_allowed);
+ unload_list (&pps->forms_denied);
+ load_userprinter_access(pp->name, &pps->users_allowed,
+ &pps->users_denied);
+ load_formprinter_access(pp->name, &pps->forms_allowed,
+ &pps->forms_denied);
+
+ unload_list (&pps->paper_allowed);
+ load_paperprinter_access(pp->name, &pps->paper_allowed,
+ &paperDenied);
+ freelist(paperDenied);
+
+ load_sdn (&pps->cpi, pp->cpi);
+ load_sdn (&pps->lpi, pp->lpi);
+ load_sdn (&pps->plen, pp->plen);
+ load_sdn (&pps->pwid, pp->pwid);
+
+ pps->last_dial_rc = 0;
+ pps->nretry = 0;
+
+ /*
+ * Evaluate all requests queued for this printer,
+ * to make sure they are still eligible. They will
+ * get moved to another printer, get (re)filtered,
+ * or get canceled.
+ */
+ (void) queue_repel(pps, 0, (qchk_fnc_type)0);
+
+ status = MOK;
+ } else if (pp->remote) {
+ /* don't really load a remote printer */
+ status = MOK;
+ } else if ((pps = new_pstatus(pp))) {
+ pps->status = PS_DISABLED | PS_REJECTED;
+ load_str (&pps->dis_reason, CUZ_NEW_PRINTER);
+ load_str (&pps->rej_reason, CUZ_NEW_DEST);
+ load_str (&pps->fault_reason, CUZ_PRINTING_OK);
+ time (&pps->dis_date);
+ time (&pps->rej_date);
+
+ dump_pstatus ();
+
+ status = MOK;
+ } else {
+ freeprinter (pp);
+ status = MNOSPACE;
+ }
+
+
+ mputm (md, R_LOAD_PRINTER, status);
+ return;
+}
+
+/*
+ * s_unload_printer()
+ */
+
+static void
+_unload_printer(PSTATUS *pps)
+{
+ int i;
+
+ if (pps->alert->active)
+ cancel_alert (A_PRINTER, pps);
+
+ /*
+ * Remove this printer from the classes it may be in.
+ * This is likely to be redundant, i.e. upon deleting
+ * a printer the caller is SUPPOSED TO check all the
+ * classes; any that contain the printer will be changed
+ * and we should receive a S_LOAD_CLASS message for each
+ * to reload the class.
+ *
+ * HOWEVER, this leaves a (small) window where someone
+ * can sneak a request in destined for the CLASS. If
+ * we have deleted the printer but still have it in the
+ * class, we may have trouble!
+ */
+ for (i = 0; CStatus != NULL && CStatus[i] != NULL; i++)
+ (void) dellist(&(CStatus[i]->class->members),
+ pps->printer->name);
+
+ free_pstatus(pps);
+ /*
+ * this is removed from the PStatus table by the caller
+ * list_remove((void ***)&PStatus, (void *)pps);
+ */
+
+ return;
+}
+
+void
+s_unload_printer(char *m, MESG *md)
+{
+ char *printer;
+ ushort status;
+ register PSTATUS *pps;
+
+ (void) getmessage(m, S_UNLOAD_PRINTER, &printer);
+
+ syslog(LOG_DEBUG, "s_unload_printer(%s)",
+ (printer ? printer : "NULL"));
+
+ if (!*printer || STREQU(printer, NAME_ALL))
+ /* Unload ALL printers */
+ if (!Request_List)
+ /* If we have ANY requests queued, we can't do it. */
+ status = MBUSY;
+
+ else {
+ int i;
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ _unload_printer (PStatus[i]);
+ free(PStatus);
+ PStatus = NULL;
+ status = MOK;
+ }
+
+ else if (!(pps = search_pstatus(printer)))
+ /* Have we seen this printer before */
+ status = MNODEST;
+ else {
+ /*
+ * Note: This routine WILL MOVE requests to another
+ * printer. It will not stop until it has gone through
+ * the entire list of requests, so all requests that
+ * can be moved will be moved. If any couldn't move,
+ * however, we don't unload the printer.
+ */
+ if (queue_repel(pps, 1, (qchk_fnc_type)0))
+ status = MOK;
+ else
+ status = MBUSY;
+
+ if (status == MOK) {
+ _unload_printer (pps);
+ list_remove((void ***)&PStatus, (void *)pps);
+ }
+ }
+
+ if (status == MOK)
+ dump_pstatus ();
+
+ mputm (md, R_UNLOAD_PRINTER, status);
+ return;
+}
+
+/*
+ * combineReasons()
+ */
+
+static char *
+combineReasons(PSTATUS *pps, char *freeReason)
+{
+ char *reason = NULL;
+
+ if (pps->status & PS_FAULTED) {
+ if ((pps->status & (PS_DISABLED | PS_LATER)) &&
+ (!STREQU(pps->dis_reason, CUZ_STOPPED)) &&
+ (addstring(&reason, "Fault reason: ") == 0) &&
+ (addstring(&reason, pps->fault_reason) == 0) &&
+ (addstring(&reason, "\n\tDisable reason: ") == 0) &&
+ (addstring(&reason, pps->dis_reason) == 0))
+ *freeReason = 1;
+
+ else {
+ if (reason)
+ /* memory allocation failed part way through */
+ Free(reason);
+
+ reason = pps->fault_reason;
+ *freeReason = 0;
+ }
+ } else {
+ reason = pps->dis_reason;
+ *freeReason = 0;
+ }
+ return (reason);
+}
+
+static void
+local_printer_status(MESG *md, PSTATUS *pps, short status)
+{
+ char *reason = NULL;
+ char freeReason = 0;
+ char *formList = NULL;
+
+ reason = combineReasons(pps, &freeReason);
+ formList = showForms(pps);
+
+ send(md, R_INQUIRE_PRINTER_STATUS, status, pps->printer->name,
+ (formList ? formList : ""),
+ (pps->pwheel_name ? pps->pwheel_name : ""),
+ reason, pps->rej_reason, pps->status,
+ (pps->request ? pps->request->secure->req_id : ""),
+ pps->dis_date, pps->rej_date);
+
+ if (formList)
+ Free(formList);
+
+ if (freeReason)
+ Free(reason);
+}
+
+/*
+ * s_inquire_printer_status()
+ */
+
+void
+s_inquire_printer_status(char *m, MESG *md)
+{
+ char *printer;
+ register PSTATUS *pps;
+
+ (void) getmessage(m, S_INQUIRE_PRINTER_STATUS, &printer);
+ syslog(LOG_DEBUG, "s_inquire_printer_status(%s)", printer);
+
+ if (!*printer || STREQU(printer, NAME_ALL)) {
+ /* inquire about all printers */
+ int i;
+
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
+ pps = PStatus[i];
+ if (PStatus[i + 1] != NULL)
+ local_printer_status(md, pps, MOKMORE);
+ }
+ } else
+ /* inquire about a specific printer */
+ pps = search_pstatus(printer);
+
+ if (pps)
+ local_printer_status(md, pps, MOK);
+ else {
+ mputm(md, R_INQUIRE_PRINTER_STATUS, MNODEST, "", "", "", "",
+ "", 0, "", 0L, 0L);
+ }
+}
+
+
+/*
+ * s_load_class()
+ */
+
+void
+s_load_class(char *m, MESG *md)
+{
+ char *class;
+ ushort status;
+ register CLASS *pc;
+ register CSTATUS *pcs;
+
+ (void) getmessage(m, S_LOAD_CLASS, &class);
+ syslog(LOG_DEBUG, "s_load_class(%s)", (class ? class : "NULL"));
+
+ if (!*class)
+ /* no class defined */
+ status = MNODEST;
+ else if (!(pc = Getclass(class))) {
+ /* Strange or missing class */
+ switch (errno) {
+ case EBADF:
+ status = MERRDEST;
+ break;
+ case ENOENT:
+ default:
+ status = MNODEST;
+ break;
+ }
+
+ } else if ((pcs = search_cstatus(class))) {
+ /* Class we already know about */
+ register RSTATUS *prs;
+
+ freeclass (pcs->class);
+ pcs->class = pc;
+
+ /*
+ * Here we go through the list of requests
+ * to see who gets affected.
+ */
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if (STREQU(prs->request->destination, class)) {
+ /*
+ * If not still eligible for this class...
+ */
+ switch (validate_request(prs, (char **)0, 1)) {
+ case MOK:
+ case MERRDEST: /* rejecting (shouldn't happen) */
+ break;
+ case MDENYDEST:
+ case MNOMOUNT:
+ case MNOMEDIA:
+ case MNOFILTER:
+ default:
+ /*
+ * ...then too bad!
+ */
+ cancel (prs, 1);
+ break;
+ }
+ }
+
+ status = MOK;
+ } else if ((pcs = new_cstatus(pc))) {
+ /* Room for new class? */
+ pcs->status = CS_REJECTED;
+ load_str (&pcs->rej_reason, CUZ_NEW_DEST);
+ time (&pcs->rej_date);
+
+ dump_cstatus ();
+
+ status = MOK;
+ } else {
+ freeclass (pc);
+ status = MNOSPACE;
+ }
+
+
+ mputm (md, R_LOAD_CLASS, status);
+ return;
+}
+
+/*
+ * s_unload_class()
+ */
+
+static void
+_unload_class(CSTATUS *pcs)
+{
+ freeclass (pcs->class);
+ if (pcs->rej_reason != NULL)
+ Free (pcs->rej_reason);
+ Free(pcs);
+
+ return;
+}
+
+void
+s_unload_class(char *m, MESG *md)
+{
+ char *class;
+ ushort status;
+ RSTATUS *prs;
+ register CSTATUS *pcs;
+
+ (void) getmessage(m, S_UNLOAD_CLASS, &class);
+ syslog(LOG_DEBUG, "s_unload_class(%s)", (class ? class : "NULL"));
+
+ /*
+ * Unload ALL classes?
+ */
+ if (!*class || STREQU(class, NAME_ALL)) {
+ int i;
+ /*
+ * If we have a request queued for a member of ANY
+ * class, we can't do it.
+ */
+ status = MOK;
+ for (i = 0; ((CStatus[i] != NULL) && (status == MOK)); i++) {
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if (STREQU(prs->request->destination,
+ CStatus[i]->class->name)) {
+ status = MBUSY;
+ break;
+ }
+ }
+
+ if (status == MOK) {
+ for (i = 0; CStatus != NULL && CStatus[i] != NULL; i++)
+ _unload_class (CStatus[i]);
+ free(CStatus);
+ CStatus = NULL;
+ }
+
+ /*
+ * Have we seen this class before?
+ */
+ } else if (!(pcs = search_cstatus(class)))
+ status = MNODEST;
+
+ /*
+ * Is there even one request queued for this class?
+ * If not, we can safely remove it.
+ */
+ else {
+ status = MOK;
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if (STREQU(prs->request->destination, class)) {
+ status = MBUSY;
+ break;
+ }
+
+ if (status == MOK) {
+ _unload_class (pcs);
+ list_remove((void ***)&CStatus, (void *)pcs);
+ }
+ }
+
+ if (status == MOK)
+ dump_cstatus ();
+
+ mputm (md, R_UNLOAD_CLASS, status);
+ return;
+}
+
+/*
+ * s_inquire_class()
+ */
+
+void
+s_inquire_class(char *m, MESG *md)
+{
+ char *class;
+ register CSTATUS *pcs;
+
+ (void) getmessage(m, S_INQUIRE_CLASS, &class);
+ syslog(LOG_DEBUG, "s_inquire_class(%s)", (class ? class : "NULL"));
+
+
+
+ if (!*class || STREQU(class, NAME_ALL)) {
+ /* inquire about ALL classes */
+ int i;
+
+ for (i = 0; CStatus != NULL && CStatus[i] != NULL; i++) {
+ pcs = CStatus[i];
+ if (CStatus[i + 1] != NULL)
+ send(md, R_INQUIRE_CLASS, MOKMORE,
+ pcs->class->name, pcs->status,
+ pcs->rej_reason, pcs->rej_date);
+ }
+ } else
+ /* inquire about a single class */
+ pcs = search_cstatus(class);
+
+ if (pcs)
+ send(md, R_INQUIRE_CLASS, MOK, pcs->class->name, pcs->status,
+ pcs->rej_reason, pcs->rej_date);
+ else
+ mputm (md, R_INQUIRE_CLASS, MNODEST, "", 0, "", 0L);
+
+ return;
+}
+
+/*
+ * s_paper_allowed()
+ */
+
+void
+s_paper_allowed(char *m, MESG *md)
+{
+ char *printer;
+ char *paperList = NULL;
+ register PSTATUS *pps, *ppsnext;
+
+ (void) getmessage(m, S_PAPER_ALLOWED, &printer);
+ syslog(LOG_DEBUG, "s_paper_allowed(%s)", (printer ? printer : "NULL"));
+
+
+ if (!*printer || STREQU(printer, NAME_ALL)) {
+ /* inquire about ALL printers */
+ int i;
+
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
+ pps = PStatus[i];
+ if (PStatus[i + 1] != NULL) {
+ paperList = sprintlist(pps->paper_allowed);
+ send(md, R_PAPER_ALLOWED, MOKMORE,
+ pps->printer->name,
+ (paperList ? paperList : ""));
+ if (paperList)
+ Free(paperList);
+ }
+ }
+ } else
+ /* inquire about a specific printer */
+ pps = search_pstatus(printer);
+
+ if (pps) {
+ paperList = sprintlist(pps->paper_allowed);
+ send(md, R_PAPER_ALLOWED, MOK, pps->printer->name,
+ (paperList ? paperList : ""));
+ if (paperList)
+ Free(paperList);
+
+ } else {
+ mputm(md, R_PAPER_ALLOWED, MNODEST, "", "");
+ }
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/disp3.c b/usr/src/cmd/lp/cmd/lpsched/disp3.c
new file mode 100644
index 0000000000..4d363e7915
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/disp3.c
@@ -0,0 +1,804 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#include "dispatch.h"
+#include <syslog.h>
+
+/**
+ ** remount_form() - MOUNT A FORM WHERE ANOTHER WAS MOUNTED
+ **/
+
+void
+remount_form(register PSTATUS *pps, FSTATUS *pfs, short trayNum)
+{
+ trayNum--; /* make zero based */
+ if (pps->forms && (pps->forms[trayNum].form == pfs)) {
+ pps->forms[trayNum].isAvailable = (pfs ? 1 : 0);
+ /* force it */
+ return; /* nothing to do */
+ } else if ((!pps->forms) && (!pfs)) {
+ return; /* nothing to do */
+ }
+
+ /*
+ * Unmount the old form.
+ */
+ if (pps->forms && pps->forms[trayNum].form) {
+ register FSTATUS *Opfs = pps->forms[trayNum].form;
+
+ pps->forms[trayNum].form = 0;
+ pps->forms[trayNum].isAvailable = 1;
+ Opfs->mounted--;
+
+ /*
+ * Unmounting the form may make some print requests
+ * no longer printable, because they were accepted
+ * only because the form was already mounted.
+ * Unmounting the form will also force some requests
+ * to another printer (where the form is mounted)
+ * so they can print.
+ */
+ form_in_question = Opfs;
+ (void)queue_repel (pps, 0, qchk_form);
+
+ /*
+ * Maybe an alert is due.
+ */
+ check_form_alert (Opfs, (_FORM *)0);
+ }
+
+ /*
+ * Mount the new form?
+ */
+ if (pfs) {
+ syslog(LOG_DEBUG, "remount_form add %x(%s) to tray %d\n",
+ pfs, (pfs ? pfs->form->name : "NULL"), trayNum);
+
+ if (pps && !pps->forms) {
+ pps->forms = (PFSTATUS *)calloc((trayNum +1),
+ sizeof(PFSTATUS));
+ pps->numForms = trayNum + 1;
+ }
+
+ if (pps && pps->forms && (pps->numForms > trayNum)) {
+ pps->forms[trayNum].form = pfs;
+ pps->forms[trayNum].isAvailable = 1;
+ pfs->mounted++;
+ } else {
+ return; /* nothing to do, can't mount form,
+ so no need to pretend we did */
+ }
+
+
+ /*
+ * Attract all the requests needing this newly mounted
+ * form. This may cause some unnecessary shuffling, but
+ * we have to ensure requests aren't assigned to a printer
+ * without the form mounted, so that the alert check is
+ * correct.
+ */
+ if (pfs->requests) {
+ form_in_question = pfs;
+ queue_attract (pps, qchk_form, 0);
+
+ /*
+ * Maybe an alert can be shut off.
+ */
+ check_form_alert (pfs, (_FORM *)0);
+ }
+
+ } else {
+ /*
+ * Attract first request that doesn't need a form mounted.
+ * We only need to get one request printing, because it
+ * completing will cause the next request to be attracted.
+ */
+ form_in_question = 0;
+ queue_attract (pps, qchk_form, 1);
+ }
+
+ dump_pstatus ();
+
+ return;
+}
+
+/**
+ ** remount_pwheel() - MOUNT A PRINT-WHEEL WHERE ANOTHER WAS MOUNTED
+ **/
+
+static void
+remount_pwheel(register PSTATUS *pps, char *pwheel_name)
+{
+ PWSTATUS *ppws;
+
+ if (SAME(pps->pwheel_name, pwheel_name))
+ return; /* nothing to do */
+
+ /*
+ * Unmount the old print wheel
+ */
+ if (pps->pwheel_name) {
+ register PWSTATUS *Oppws = pps->pwheel;
+
+ pps->pwheel = 0;
+ if (Oppws)
+ Oppws->mounted--;
+
+ /*
+ * Unmounting the print wheel may make some print
+ * requests no longer printable, because they were
+ * accepted only because the print wheel was already
+ * mounted. Unmounting the print wheel will also force
+ * some requests to another printer (where the print wheel
+ * is mounted) so they can print.
+ */
+ pwheel_in_question = pps->pwheel_name;
+ (void)queue_repel (pps, 0, qchk_pwheel);
+
+ unload_str (&pps->pwheel_name);
+
+ /*
+ * Maybe an alert is due.
+ */
+ if (Oppws)
+ check_pwheel_alert (Oppws, (PWHEEL *)0);
+ }
+
+ /*
+ * Mount the new print wheel?
+ */
+ if (pwheel_name) {
+ load_str (&pps->pwheel_name, pwheel_name);
+ if (ppws = search_pwstatus(pwheel_name)) {
+ pps->pwheel = ppws;
+ ppws->mounted++;
+
+ /*
+ * Attract all requests needing this newly
+ * mounted print wheel. This may cause some
+ * unnecessary shuffling, but we have to ensure
+ * requests aren't assigned to a printer without
+ * the print-wheel mounted, so that the alert
+ * check is correct.
+ */
+ if (ppws->requests) {
+ pwheel_in_question = pwheel_name;
+ queue_attract (pps, qchk_pwheel, 0);
+
+ /*
+ * Maybe an alert can be shut off.
+ */
+ check_pwheel_alert (ppws, (PWHEEL *)0);
+ }
+
+ } else {
+ /*
+ * Attract the first request that needs this newly
+ * mounted print wheel. If no alert has been
+ * defined for the print wheel, we don't know how
+ * many requests are queued waiting for it, so we
+ * have to do this unconditionally.
+ */
+ pwheel_in_question = pwheel_name;
+ queue_attract (pps, qchk_pwheel, 1);
+ }
+
+ } else {
+ /*
+ * Attract the first request that doesn't need a
+ * print wheel mounted.
+ * We only need to get one request printing, because it
+ * completing will cause the next request to be attracted.
+ */
+ pwheel_in_question = 0;
+ queue_attract (pps, qchk_pwheel, 1);
+ }
+
+ dump_pstatus ();
+
+ return;
+}
+
+#define MAX_TRAYS 100
+
+/**
+ ** s_max_trays()
+ **/
+
+void
+s_max_trays(char *m, MESG *md)
+{
+ char *printer;
+ ushort status;
+ short numTrays;
+ register PSTATUS *pps;
+ register PFSTATUS *ppfs;
+
+ (void) getmessage(m, S_MAX_TRAYS, &printer, &numTrays);
+ syslog(LOG_DEBUG, "s_max_trays(%s, %d)", (printer ? printer : "NULL"),
+ numTrays);
+
+ /* Have we seen this printer before? */
+ if (!*printer || !(pps = search_pstatus(printer)))
+ status = MNODEST;
+
+ /* How about the tray? */
+ else if ((numTrays <=0) || (numTrays > MAX_TRAYS))
+ status = MNOTRAY;
+
+ /* If the printer is currently printing, we can't disturb it. */
+ else if (pps->request)
+ status = MBUSY;
+
+ else if (pps->forms) {
+ if (!(ppfs = Realloc(pps->forms,numTrays * sizeof(PFSTATUS))))
+ status = MNOMEM;
+ else {
+ int i;
+
+ for (i = pps->numForms; i < numTrays; i++) {
+ ppfs[i].form = NULL;
+ ppfs[i].isAvailable = 1;
+ }
+ pps->forms = ppfs;
+ pps->numForms = numTrays;
+ status = MOK;
+ }
+ } else if (!(ppfs = Calloc(numTrays,sizeof(PFSTATUS)))) {
+ status = MNOMEM;
+ } else {
+ pps->forms = ppfs;
+ pps->numForms = numTrays;
+ status = MOK;
+ }
+ dump_pstatus();
+ mputm(md, R_MAX_TRAYS, status);
+}
+
+/**
+ ** s_mount()
+ **/
+
+void
+s_mount(char *m, MESG *md)
+{
+ char *printer, *form, *pwheel_name;
+ ushort status;
+ register PSTATUS *pps;
+ register FSTATUS *pfs;
+
+ (void) getmessage(m, S_MOUNT, &printer, &form, &pwheel_name);
+ syslog(LOG_DEBUG, "s_mount(%s, %s, %s)", (printer ? printer : "NULL"),
+ (form ? form : "NULL"), (pwheel_name ? pwheel_name : "NULL"));
+
+ if (!*form && !*pwheel_name)
+ status = MNOMEDIA;
+
+ /* Have we seen this printer before? */
+ else if (!*printer || !(pps = search_pstatus(printer)))
+ status = MNODEST;
+
+ /* How about the form? */
+ else if (*form && !(pfs = search_fstatus(form)))
+ status = MNOMEDIA;
+
+ /* If the printer is currently printing, we can't disturb it. */
+ else if (pps->request)
+ status = MBUSY;
+
+ else {
+ /*
+ * Mount them.
+ */
+ if (*form)
+ remount_form (pps, pfs,1);
+ if (*pwheel_name)
+ remount_pwheel(pps, pwheel_name);
+
+ status = MOK;
+ }
+
+ mputm(md, R_MOUNT, status);
+}
+
+/*
+ * s_mount_tray()
+ */
+
+void
+s_mount_tray(char *m, MESG *md)
+{
+ char *printer, *form, *pwheel_name;
+ ushort status;
+ short trayNum;
+ register PSTATUS *pps;
+ register FSTATUS *pfs;
+
+ (void) getmessage(m, S_MOUNT_TRAY, &printer, &form, &pwheel_name,
+ &trayNum);
+ syslog(LOG_DEBUG, "s_mount_tray(%s, %s, %s, %d)",
+ (printer ? printer : "NULL"), (form ? form : "NULL"),
+ (pwheel_name ? pwheel_name : "NULL"), trayNum);
+
+ if (!*form && !*pwheel_name)
+ status = MNOMEDIA;
+
+ /* Have we seen this printer before? */
+ else if (!*printer || !(pps = search_pstatus(printer)))
+ status = MNODEST;
+
+ /* How about the form? */
+ else if (*form && !(pfs = search_fstatus(form)))
+ status = MNOMEDIA;
+
+ /* How about the tray? */
+ else if ((trayNum <=0) || (trayNum > pps->numForms))
+ status = MNOTRAY;
+
+ /* If the printer is currently printing, we can't disturb it. */
+ else if (pps->request)
+ status = MBUSY;
+
+ else {
+ /*
+ * Mount them.
+ */
+ if (*form)
+ remount_form(pps, pfs,trayNum);
+ if (*pwheel_name)
+ remount_pwheel(pps, pwheel_name);
+
+ status = MOK;
+ }
+
+ mputm (md, R_MOUNT_TRAY, status);
+}
+
+/**
+ ** s_unmount()
+ **/
+
+void
+s_unmount(char *m, MESG *md)
+{
+ char *printer,
+ *form,
+ *pwheel_name;
+ ushort status;
+ register PSTATUS *pps;
+
+ (void)getmessage (m, S_UNMOUNT, &printer, &form, &pwheel_name);
+ syslog(LOG_DEBUG, "s_unmount(%s, %s, %s)",
+ (printer ? printer : "NULL"), (form ? form : "NULL"),
+ (pwheel_name ? pwheel_name : "NULL"));
+
+ if (!*form && !*pwheel_name)
+ status = MNOMEDIA;
+
+ /*
+ * Have we seen this printer before?
+ */
+ else if (!*printer || !(pps = search_pstatus(printer)))
+ status = MNODEST;
+
+
+ /*
+ * If the printer is currently printing a request,
+ * we can't unmount the current form/pwheel.
+ */
+ else if (pps->request)
+ status = MBUSY;
+
+ else {
+ /*
+ * Unmount them.
+ */
+ if (*form)
+ remount_form (pps, (FSTATUS *)0,1);
+ if (*pwheel_name)
+ remount_pwheel (pps, (char *)0);
+
+ status = MOK;
+ }
+
+ mputm (md, R_UNMOUNT, status);
+ return;
+}
+/**
+ ** s_unmount_tray()
+ **/
+
+void
+s_unmount_tray(char *m, MESG *md)
+{
+ char *printer,
+ *form,
+ *pwheel_name;
+
+ ushort status;
+ short trayNum;
+
+ register PSTATUS *pps;
+
+ (void)getmessage (m, S_UNMOUNT_TRAY, &printer, &form, &pwheel_name,
+ &trayNum);
+ syslog(LOG_DEBUG, "s_unmount_tray(%s, %s, %s, %d)",
+ (printer ? printer : "NULL"), (form ? form : "NULL"),
+ (pwheel_name ? pwheel_name : "NULL"), trayNum);
+
+
+ if (!*form && !*pwheel_name)
+ status = MNOMEDIA;
+
+ else if (!*printer || !(pps = search_pstatus(printer)))
+ /* haven't seen this printer before */
+ status = MNODEST;
+ else if ((trayNum <=0) || (trayNum > pps->numForms))
+ /* haven't seen the tray before */
+ status = MNOTRAY;
+ else if (pps->request)
+ /* is the printer busy */
+ status = MBUSY;
+ else {
+ /* Unmount them. */
+ if (*form)
+ remount_form (pps, (FSTATUS *)0,trayNum);
+ if (*pwheel_name)
+ remount_pwheel (pps, (char *)0);
+
+ status = MOK;
+ }
+
+ mputm (md, R_UNMOUNT_TRAY, status);
+ return;
+}
+
+/**
+ ** s_load_form()
+ **/
+
+void
+s_load_form(char *m, MESG *md)
+{
+ char *form;
+ ushort status;
+ register _FORM *pf;
+ register FSTATUS *pfs;
+
+ (void)getmessage (m, S_LOAD_FORM, &form);
+ syslog(LOG_DEBUG, "s_load_form(%s)", (form ? form : "NULL"));
+
+ if (!*form)
+ /* no form specified */
+ status = MNODEST;
+ else if (!(pf = Getform(form))) {
+ /* strange or missing form */
+ switch (errno) {
+ case EBADF:
+ status = MERRDEST;
+ break;
+ case ENOENT:
+ default:
+ status = MNODEST;
+ break;
+ }
+
+ } else if ((pfs = search_fstatus(form))) {
+ /* Have we seen this form before? */
+ unload_list (&pfs->users_allowed);
+ unload_list (&pfs->users_denied);
+ load_userform_access (
+ pf->name,
+ &pfs->users_allowed,
+ &pfs->users_denied
+ );
+
+ load_sdn (&pfs->cpi, pf->cpi);
+ load_sdn (&pfs->lpi, pf->lpi);
+ load_sdn (&pfs->plen, pf->plen);
+ load_sdn (&pfs->pwid, pf->pwid);
+
+
+ /*
+ * These have to be done in the order shown,
+ * and after the assignments above, so that all
+ * the new information is in place for the
+ * checks. An unfortunate side effect is that
+ * it is possible for the alert to shut off
+ * and then come on again, if (1) enough requests
+ * are canceled to drop the level below the old
+ * alert threshold, but (2) the new alert threshold
+ * is even lower. The final alert will be correct,
+ * though.
+ */
+
+ form_in_question = pfs;
+ queue_check (qchk_form);
+
+ check_form_alert (pfs, pf);
+
+
+ status = MOK;
+
+ /*
+ * Room for a new form?
+ */
+ } else if ((pfs = new_fstatus(pf))) {
+ /*
+ * No alert is possible for a new form, of course,
+ * but this routine does a bit more than just check
+ * the alert.
+ */
+ check_form_alert (pfs, pf);
+ status = MOK;
+ } else {
+ free_form (pf);
+ status = MNOSPACE;
+ }
+
+ mputm (md, R_LOAD_FORM, status);
+ return;
+}
+
+/**
+ ** s_unload_form()
+ **/
+
+static void
+_unload_form(register FSTATUS *pfs)
+{
+ int i;
+ short numForms;
+ PFSTATUS *ppfs;
+
+ /*
+ * Unmount this form everywhere and get rid of it.
+ */
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ if (((ppfs = PStatus[i]->forms) != NULL) &&
+ ((numForms = PStatus[i]->numForms) > 0)) {
+ int j;
+ for ( j = 0 ; j < numForms ; j++ )
+ if (ppfs[j].form == pfs) ppfs[j].form= NULL;
+ }
+
+ return;
+}
+
+void
+s_unload_form(char *m, MESG *md)
+{
+ char *form;
+ ushort status;
+ RSTATUS *prs;
+ register FSTATUS *pfs;
+
+ (void)getmessage (m, S_UNLOAD_FORM, &form);
+ syslog(LOG_DEBUG, "s_unload_form(%s)", (form ? form : "NULL"));
+
+ if (!*form || STREQU(form, NAME_ALL)) {
+ int i;
+ /* If we have a request queued for ANY form, we can't do it. */
+ status = MOK;
+ for (i = 0; FStatus != NULL && FStatus[i] != NULL &&
+ status == MOK; i++) {
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if (prs->form == FStatus[i]) {
+ status = MBUSY;
+ break;
+ }
+ }
+
+ if (status == MOK) {
+ for (i = 0; FStatus != NULL && FStatus[i] != NULL; i++)
+ _unload_form (FStatus[i]);
+ free(FStatus);
+ FStatus = NULL;
+ }
+
+ } else if (!*form || !(pfs = search_fstatus(form)))
+ /* Have we seen this form before? */
+ status = MNODEST;
+ else {
+ /* Is there even one request waiting for this form? */
+ status = MOK;
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if (prs->form == pfs) {
+ status = MBUSY;
+ break;
+ }
+
+ if (status == MOK) {
+ _unload_form (pfs);
+ list_remove((void ***)&FStatus, (void *)pfs);
+ }
+ }
+
+ mputm (md, R_UNLOAD_FORM, status);
+ return;
+}
+
+/**
+ ** s_load_printwheel()
+ **/
+
+void
+s_load_printwheel(char *m, MESG *md)
+{
+ char *pwheel_name;
+ ushort status;
+ register PWHEEL *ppw;
+ register PWSTATUS *ppws;
+
+ (void)getmessage (m, S_LOAD_PRINTWHEEL, &pwheel_name);
+ syslog(LOG_DEBUG, "s_load_printwheel(%s)",
+ (pwheel_name ? pwheel_name : "NULL"));
+
+ if (!*pwheel_name)
+ /* no printwheel specified */
+ status = MNODEST;
+ else if (!(ppw = Getpwheel(pwheel_name))) {
+ /* Strange or missing print wheel? */
+ switch (errno) {
+ case EBADF:
+ status = MERRDEST;
+ break;
+ case ENOENT:
+ default:
+ status = MNODEST;
+ break;
+ }
+ } else if ((ppws = search_pwstatus(pwheel_name))) {
+ /* Print wheel we already know about? */
+ check_pwheel_alert (ppws, ppw);
+ status = MOK;
+ } else if ((ppws = new_pwstatus(ppw))) {
+ /* Room for a new print wheel? */
+ register RSTATUS *prs;
+
+ /*
+ * Because of the quirky nature of the print wheel
+ * structures, i.e. no structure unless an alert has
+ * been defined, we have to run through the requests
+ * and see which ones are waiting for this print wheel,
+ * so we can assign alerts and count pending requests.
+ */
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if ((prs->pwheel_name == pwheel_name) &&
+ (!one_printer_with_charsets(prs))) {
+ prs->pwheel = ppws;
+ ppws->requests++;
+ }
+ check_pwheel_alert (ppws, ppw);
+
+ status = MOK;
+ } else {
+ freepwheel (ppw);
+ status = MNOSPACE;
+ }
+
+ mputm (md, R_LOAD_PRINTWHEEL, status);
+ return;
+}
+
+/**
+ ** s_unload_printwheel()
+ **/
+
+static void
+_unload_pwheel(register PWSTATUS *ppws)
+{
+ register PSTATUS *pps;
+ register RSTATUS *prs;
+ int i;
+
+
+ /*
+ * ``Unmount'' the alert part of this print wheel everywhere.
+ * THIS IS NOT A COMPLETE UNMOUNT, JUST THE ALERT STRUCTURE
+ * IS REMOVED.
+ */
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ if (PStatus[i]->pwheel == ppws)
+ PStatus[i]->pwheel = 0;
+
+ /*
+ * Remove the alert part from all requests.
+ */
+ for (prs = Request_List; prs; prs = prs->next)
+ if (prs->pwheel == ppws)
+ prs->pwheel = 0;
+
+ /*
+ * Cancel any alert pending. Here we're different from the
+ * similar code for unloading a form, because, to be able to
+ * unload a form we first require NO requests pending. If no
+ * requests are pending there should be no alert to cancel.
+ * Print wheels, on the other hand, only exist as names and
+ * alerts. We can always unload a ``print wheel'' because
+ * all we're really unloading is an alert. Thus, there can
+ * be requests queued for the print wheel (the name), and
+ * thus there can be an alert running.
+ */
+ if (ppws->alert->active)
+ cancel_alert (A_PWHEEL, ppws);
+
+ free_pwstatus(ppws);
+
+ return;
+}
+
+void
+s_unload_printwheel(char *m, MESG *md)
+{
+ char *pwheel_name;
+
+ ushort status;
+
+ register PWSTATUS *ppws;
+
+
+ /*
+ * We don't care if any requests are waiting for the print
+ * wheel(s)--what we're removing here is (are) just the alert(s)!
+ */
+
+ (void)getmessage (m, S_UNLOAD_PRINTWHEEL, &pwheel_name);
+ syslog(LOG_DEBUG, "s_unload_printwheel(%s)",
+ (pwheel_name ? pwheel_name : "NULL"));
+
+
+ /*
+ * Remove all print wheel alerts?
+ */
+ if (!*pwheel_name || STREQU(pwheel_name, NAME_ALL)) {
+ int i;
+
+ for (i = 0; PWStatus != NULL && PWStatus[i] != NULL; i++)
+ _unload_pwheel (PWStatus[i]);
+ free(PWStatus);
+ PWStatus = NULL;
+ status = MOK;
+
+ /*
+ * Have we seen this print wheel before?
+ */
+ } else if (!(ppws = search_pwstatus(pwheel_name)))
+ status = MNODEST;
+
+ else {
+ _unload_pwheel (ppws);
+ list_remove((void ***)&PWStatus, (void *)ppws);
+ status = MOK;
+
+ }
+
+ mputm (md, R_UNLOAD_PRINTWHEEL, status);
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/disp4.c b/usr/src/cmd/lp/cmd/lpsched/disp4.c
new file mode 100644
index 0000000000..bb61d0cddc
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/disp4.c
@@ -0,0 +1,529 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "time.h"
+#include "dispatch.h"
+#include <syslog.h>
+
+
+/**
+ ** s_accept_dest()
+ **/
+
+void
+s_accept_dest(char *m, MESG *md)
+{
+ char *destination;
+ ushort status;
+ register PSTATUS *pps;
+ register CSTATUS *pcs;
+
+ getmessage (m, S_ACCEPT_DEST, &destination);
+ syslog(LOG_DEBUG, "s_accept_dest(%s)",
+ (destination ? destination : "NULL"));
+
+ /*
+ * Have we seen this destination as a printer?
+ */
+ if ((pps = search_pstatus(destination)))
+ if ((pps->status & PS_REJECTED) == 0)
+ status = MERRDEST;
+ else {
+ pps->status &= ~PS_REJECTED;
+ (void) time (&pps->rej_date);
+ dump_pstatus ();
+ status = MOK;
+ }
+
+ /*
+ * Have we seen this destination as a class?
+ */
+ else if ((pcs = search_cstatus(destination)))
+ if ((pcs->status & CS_REJECTED) == 0)
+ status = MERRDEST;
+ else {
+ pcs->status &= ~CS_REJECTED;
+ (void) time (&pcs->rej_date);
+ dump_cstatus ();
+ status = MOK;
+ }
+
+ else
+ status = MNODEST;
+
+ mputm (md, R_ACCEPT_DEST, status);
+ return;
+}
+
+/**
+ ** s_reject_dest()
+ **/
+
+void
+s_reject_dest(char *m, MESG *md)
+{
+ char *destination,
+ *reason;
+ ushort status;
+ register PSTATUS *pps;
+ register CSTATUS *pcs;
+
+
+ getmessage (m, S_REJECT_DEST, &destination, &reason);
+ syslog(LOG_DEBUG, "s_reject_dest(%s, %s)",
+ (destination ? destination : "NULL"),
+ (reason ? reason : "NULL"));
+
+ /*
+ * Have we seen this destination as a printer?
+ */
+ if ((pps = search_pstatus(destination)))
+ if (pps->status & PS_REJECTED)
+ status = MERRDEST;
+ else {
+ pps->status |= PS_REJECTED;
+ (void) time (&pps->rej_date);
+ load_str (&pps->rej_reason, reason);
+ dump_pstatus ();
+ status = MOK;
+ }
+
+ /*
+ * Have we seen this destination as a class?
+ */
+ else if ((pcs = search_cstatus(destination)))
+ if (pcs->status & CS_REJECTED)
+ status = MERRDEST;
+ else {
+ pcs->status |= CS_REJECTED;
+ (void) time (&pcs->rej_date);
+ load_str (&pcs->rej_reason, reason);
+ dump_cstatus ();
+ status = MOK;
+ }
+
+ else
+ status = MNODEST;
+
+ mputm (md, R_REJECT_DEST, status);
+ return;
+}
+
+/**
+ ** s_enable_dest()
+ **/
+
+void
+s_enable_dest(char *m, MESG *md)
+{
+ char *printer;
+ ushort status;
+ register PSTATUS *pps;
+
+
+ getmessage (m, S_ENABLE_DEST, &printer);
+ syslog(LOG_DEBUG, "s_enable_dest(%s)", (printer ? printer : "NULL"));
+
+ /*
+ * Have we seen this printer before?
+ */
+ if ((pps = search_pstatus(printer)))
+ if (enable(pps) == -1)
+ status = MERRDEST;
+ else
+ status = MOK;
+ else
+ status = MNODEST;
+
+ mputm (md, R_ENABLE_DEST, status);
+ return;
+}
+
+/**
+ ** s_disable_dest()
+ **/
+
+void
+s_disable_dest(char *m, MESG *md)
+{
+ char *destination,
+ *reason,
+ *req_id = 0;
+ ushort when,
+ status;
+ register PSTATUS *pps;
+
+ getmessage (m, S_DISABLE_DEST, &destination, &reason, &when);
+ syslog(LOG_DEBUG, "s_disable_dest(%s, %s, %d)",
+ (destination ? destination : "NULL"),
+ (reason ? reason : "NULL"), when);
+
+
+ /*
+ * Have we seen this printer before?
+ */
+ if ((pps = search_pstatus(destination))) {
+
+ /*
+ * If we are to cancel a currently printing request,
+ * we will send back the request's ID.
+ * Save a copy of the ID before calling "disable()",
+ * in case the disabling loses it (e.g. the request
+ * might get attached to another printer). (Actually,
+ * the current implementation won't DETACH the request
+ * from this printer until the child process responds,
+ * but a future implementation might.)
+ */
+ if (pps->request && when == 2)
+ req_id = Strdup(pps->request->secure->req_id);
+
+ if (disable(pps, reason, (int)when) == -1) {
+ if (req_id) {
+ Free (req_id);
+ req_id = 0;
+ }
+ status = MERRDEST;
+ } else
+ status = MOK;
+
+ } else
+ status = MNODEST;
+
+ mputm (md, R_DISABLE_DEST, status, NB(req_id));
+ if (req_id)
+ Free (req_id);
+
+ return;
+}
+
+/**
+ ** s_load_filter_table()
+ **/
+
+void
+s_load_filter_table(char *m, MESG *md)
+{
+ ushort status;
+
+ syslog(LOG_DEBUG, "s_load_filter_table()");
+
+ trash_filters ();
+ if (Loadfilters((char *)0) == -1)
+ status = MNOOPEN;
+ else {
+ /*
+ * This is what makes changing filters expensive!
+ */
+ queue_check (qchk_filter);
+
+ status = MOK;
+ }
+
+ mputm (md, R_LOAD_FILTER_TABLE, status);
+ return;
+}
+
+/**
+ ** s_unload_filter_table()
+ **/
+
+void
+s_unload_filter_table(char *m, MESG *md)
+{
+ syslog(LOG_DEBUG, "s_unload_filter_table()");
+
+ trash_filters ();
+
+ /*
+ * This is what makes changing filters expensive!
+ */
+ queue_check (qchk_filter);
+
+ mputm (md, R_UNLOAD_FILTER_TABLE, MOK);
+ return;
+}
+
+/**
+ ** s_load_user_file()
+ **/
+
+void
+s_load_user_file(char *m, MESG *md)
+{
+ /*
+ * The first call to "getuser()" will load the whole file.
+ */
+ syslog(LOG_DEBUG, "s_load_user_file()");
+
+ trashusers ();
+
+ mputm (md, R_LOAD_USER_FILE, MOK);
+ return;
+}
+
+/**
+ ** s_unload_user_file()
+ **/
+
+void
+s_unload_user_file(char *m, MESG *md)
+{
+ syslog(LOG_DEBUG, "s_unload_user_file()");
+
+ trashusers (); /* THIS WON'T DO TRUE UNLOAD, SORRY! */
+
+ mputm (md, R_UNLOAD_USER_FILE, MOK);
+ return;
+}
+/**
+ ** s_shutdown()
+ **/
+
+void
+s_shutdown(char *m, MESG *md)
+{
+ ushort immediate;
+
+ (void)getmessage (m, S_SHUTDOWN, &immediate);
+ syslog(LOG_DEBUG, "s_shutdown(%d)", immediate);
+
+ switch (md->type) {
+ case MD_STREAM:
+ case MD_SYS_FIFO:
+ case MD_USR_FIFO:
+ mputm (md, R_SHUTDOWN, MOK);
+ lpshut (immediate);
+ /*NOTREACHED*/
+ default:
+ syslog(LOG_DEBUG,
+ "Received S_SHUTDOWN on a type %d connection\n",
+ md->type);
+ }
+
+ return;
+}
+
+/**
+ ** s_quiet_alert()
+ **/
+
+void
+s_quiet_alert(char *m, MESG *md)
+{
+ char *name;
+ ushort type,
+ status;
+ register FSTATUS *pfs;
+ register PSTATUS *pps;
+ register PWSTATUS *ppws;
+
+
+ /*
+ * We quiet an alert by cancelling it with "cancel_alert()"
+ * and then resetting the active flag. This effectively just
+ * terminates the process running the alert but tricks the
+ * rest of the Spooler into thinking it is still active.
+ * The alert will be reactivated only AFTER "cancel_alert()"
+ * has been called (to clear the active flag) and then "alert()"
+ * is called again. Thus:
+ *
+ * For printer faults the alert will be reactivated when:
+ * - a fault is found after the current fault has been
+ * cleared (i.e. after successful print or after manually
+ * enabled).
+ *
+ * For forms/print-wheels the alert will be reactivated when:
+ * - the form/print-wheel becomes mounted and then unmounted
+ * again, with too many requests still pending;
+ * - the number of requests falls below the threshold and
+ * then rises above it again.
+ */
+
+ (void)getmessage (m, S_QUIET_ALERT, &name, &type);
+ syslog(LOG_DEBUG, "s_quiet_alert(%s, %d)", (name ? name : "NULL"),
+ type);
+
+ if (!*name)
+ status = MNODEST;
+
+ else switch (type) {
+ case QA_FORM:
+ if (!(pfs = search_fstatus(name)))
+ status = MNODEST;
+
+ else if (!pfs->alert->active)
+ status = MERRDEST;
+
+ else {
+ cancel_alert (A_FORM, pfs);
+ pfs->alert->active = 1;
+ status = MOK;
+ }
+ break;
+
+ case QA_PRINTER:
+ if (!(pps = search_pstatus(name)))
+ status = MNODEST;
+
+ else if (!pps->alert->active)
+ status = MERRDEST;
+
+ else {
+ cancel_alert (A_PRINTER, pps);
+ pps->alert->active = 1;
+ status = MOK;
+ }
+ break;
+
+ case QA_PRINTWHEEL:
+ if (!(ppws = search_pwstatus(name)))
+ status = MNODEST;
+
+ else if (!ppws->alert->active)
+ status = MERRDEST;
+
+ else {
+ cancel_alert (A_PWHEEL, ppws);
+ ppws->alert->active = 1;
+ status = MOK;
+ }
+ break;
+ }
+
+ mputm (md, R_QUIET_ALERT, status);
+ return;
+}
+
+/**
+ ** s_send_fault()
+ **/
+
+void
+s_send_fault(char *m, MESG *md)
+{
+ long key;
+ char *printerOrForm, *alert_text;
+ ushort status;
+ register PSTATUS *pps;
+
+ getmessage (m, S_SEND_FAULT, &printerOrForm, &key, &alert_text);
+ syslog(LOG_DEBUG, "s_send_fault(%s, %x, %s)",
+ (printerOrForm ? printerOrForm : "NULL"), key,
+ (alert_text ? alert_text : "NULL"));
+
+ if (!(pps = search_pstatus(printerOrForm)) || (!pps->exec) ||
+ pps->exec->key != key || !pps->request) {
+ status = MERRDEST;
+ } else {
+ printer_fault(pps, pps->request, alert_text, 0);
+ status = MOK;
+ }
+
+ mputm (md, R_SEND_FAULT, status);
+}
+
+/*
+ * s_clear_fault()
+ */
+void
+s_clear_fault(char *m, MESG *md)
+{
+ long key;
+ char *printerOrForm, *alert_text;
+ ushort status;
+ register PSTATUS *pps;
+
+ getmessage(m, S_CLEAR_FAULT, &printerOrForm, &key, &alert_text);
+ syslog(LOG_DEBUG, "s_clear_fault(%s, %x, %s)",
+ (printerOrForm ? printerOrForm : "NULL"), key,
+ (alert_text ? alert_text : "NULL"));
+
+
+ if (! (pps = search_pstatus(printerOrForm)) || ((key > 0) &&
+ ((!pps->exec) || pps->exec->key != key || !pps->request ))) {
+ status = MERRDEST;
+ } else {
+ clear_printer_fault(pps, alert_text);
+ status = MOK;
+ }
+
+ mputm (md, R_CLEAR_FAULT, status);
+}
+
+
+/*
+ * s_paper_changed()
+ */
+void
+s_paper_changed(char *m, MESG *md)
+{
+ short trayNum, mode, pagesPrinted;
+ char *printer, *paper;
+ ushort status;
+ short chgd = 0;
+ register PSTATUS *pps;
+ register FSTATUS *pfs,*pfsWas;
+
+ getmessage(m, S_PAPER_CHANGED, &printer, &trayNum, &paper, &mode,
+ &pagesPrinted);
+ syslog(LOG_DEBUG, "s_paper_changed(%s, %d, %s, %d, %d)",
+ (printer ? printer : "NULL"), trayNum, (paper ? paper : "NULL"),
+ mode, pagesPrinted);
+
+ if (!(pps = search_pstatus(printer)))
+ status = MNODEST;
+ else if ((trayNum <=0) || (trayNum > pps->numForms))
+ status = MNOTRAY;
+ else {
+ status = MOK;
+ if (*paper && (pfsWas = pps->forms[trayNum-1].form) &&
+ (!STREQU(pfsWas->form->paper,paper))) {
+ pfs = search_fptable(paper);
+ if (pfs) {
+ remount_form(pps, pfs, trayNum);
+ chgd = 1;
+ } else
+ status = MNOMEDIA;
+ }
+ if ( status == MOK ) {
+ pps->forms[trayNum].isAvailable = mode;
+ if ((chgd || !mode) && (!pagesPrinted) && pps->exec) {
+ if (pps->request)
+ pps->request->request->outcome |=
+ RS_STOPPED;
+ terminate(pps->exec);
+ schedule(EV_LATER, 1, EV_INTERF, pps);
+ }
+ }
+ }
+ mputm(md, R_PAPER_CHANGED, status);
+}
+
diff --git a/usr/src/cmd/lp/cmd/lpsched/disp5.c b/usr/src/cmd/lp/cmd/lpsched/disp5.c
new file mode 100644
index 0000000000..bd3a3dd92c
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/disp5.c
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "dispatch.h"
+#include <syslog.h>
+
+extern int Net_fd;
+
+extern MESG * Net_md;
+
+/**
+ ** s_child_done()
+ **/
+
+void
+s_child_done(char *m, MESG *md)
+{
+ long key;
+ short status;
+ short err;
+ int i;
+
+
+ getmessage (m, S_CHILD_DONE, &key, &status, &err);
+ syslog(LOG_DEBUG, "s_child_done(%d, %d, %d)", key, status, err);
+
+ for (i = 0; Exec_Table[i] != NULL; i++)
+ if ((Exec_Table[i]->key == key) && (Exec_Table[i]->md == md)) {
+ EXEC *ep = Exec_Table[i];
+
+ syslog(LOG_DEBUG,
+ "s_child_done(%d, 0x%8.8x): clearing 0x%8.8x",
+ key, md, ep);
+ /*
+ * Remove the message descriptor from the listen
+ * table, then forget about it; we don't want to
+ * accidently match this exec-slot to a future,
+ * unrelated child.
+ */
+ DROP_MD (ep->md);
+
+ ep->pid = -99;
+ ep->status = status;
+ ep->Errno = err;
+ DoneChildren++;
+ }
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/dispatch.h b/usr/src/cmd/lp/cmd/lpsched/dispatch.h
new file mode 100644
index 0000000000..ddb109e100
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/dispatch.h
@@ -0,0 +1,107 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4.1.2 */
+
+# include <time.h>
+
+# include "lpsched.h"
+
+void s_accept_dest ( char * , MESG * );
+void s_alloc_files ( char * , MESG * );
+void s_cancel ( char * , MESG * );
+void s_cancel_request ( char * , MESG * );
+void s_complete_job ( char * , MESG * );
+void s_disable_dest ( char * , MESG * );
+void s_enable_dest ( char * , MESG * );
+void s_end_change_request ( char * , MESG * );
+void s_inquire_class ( char * , MESG * );
+void s_inquire_printer_status ( char * , MESG * );
+void s_inquire_request_rank ( char * , MESG * );
+void s_load_class ( char * , MESG * );
+void s_load_filter_table ( char * , MESG * );
+void s_load_form ( char * , MESG * );
+void s_load_printer ( char * , MESG * );
+void s_load_printwheel ( char * , MESG * );
+void s_load_system ( char * , MESG * );
+void s_load_user_file ( char * , MESG * );
+void s_mount ( char * , MESG * );
+void s_move_dest ( char * , MESG * );
+void s_move_request ( char * , MESG * );
+void s_print_request ( char * , MESG * );
+void s_quiet_alert ( char * , MESG * );
+void s_reject_dest ( char * , MESG * );
+void s_send_fault ( char * , MESG * );
+void s_clear_fault ( char * , MESG * );
+void s_shutdown ( char * , MESG * );
+void s_start_change_request ( char * , MESG * );
+void s_unload_class ( char * , MESG * );
+void s_unload_filter_table ( char * , MESG * );
+void s_unload_form ( char * , MESG * );
+void s_unload_printer ( char * , MESG * );
+void s_unload_printwheel ( char * , MESG * );
+void s_unload_system ( char * , MESG * );
+void s_unload_user_file ( char * , MESG * );
+void s_unmount ( char * , MESG * );
+void r_new_child ( char * , MESG * );
+void r_send_job ( char * , MESG * );
+void s_job_completed ( char * , MESG * );
+void s_child_done ( char * , MESG * );
+void s_get_fault_message ( char * , MESG * );
+void s_max_trays ( char * , MESG *);
+void s_mount_tray ( char *, MESG * );
+void s_unmount_tray ( char *, MESG *);
+void s_paper_changed ( char *, MESG *);
+void s_paper_allowed ( char *, MESG *);
+void s_pass_peer_connection ( char * , MESG * );
+
+/**
+ ** dispatch_table[]
+ **/
+
+/*
+ * The dispatch table is used to decide if we should handle
+ * a message and which function should be used to handle it.
+ *
+ * D_ADMIN is set for messages that should be handled
+ * only if it came from an administrator. These entries should
+ * have a corresponding entry for the R_... message case, that
+ * provides a routine for sending back a MNOPERM message to those
+ * that aren't administrators. This is needed because the response
+ * message varies in size with the message type.
+ */
+
+typedef struct DISPATCH {
+ void (*fncp)();
+ ushort flags;
+} DISPATCH;
+
+#define D_ADMIN 0x01 /* Only "lp" or "root" can use msg. */
+#define D_BADMSG 0x02 /* We should never get this message */
+#define D_SYSTEM 0x04 /* Only siblings may use this message */
diff --git a/usr/src/cmd/lp/cmd/lpsched/disptab.c b/usr/src/cmd/lp/cmd/lpsched/disptab.c
new file mode 100644
index 0000000000..f828a4bbd6
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/disptab.c
@@ -0,0 +1,349 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include "dispatch.h"
+#include <syslog.h>
+
+static void r_H(),
+ r_HS();
+
+static DISPATCH dispatch_table[] = {
+/* R_BAD_MESSAGE */ 0, D_BADMSG,
+/* S_NEW_QUEUE */ 0, D_BADMSG,
+/* R_NEW_QUEUE */ 0, D_BADMSG,
+/* S_ALLOC_FILES */ s_alloc_files, 0,
+/* R_ALLOC_FILES */ 0, D_BADMSG,
+/* S_PRINT_REQUEST */ s_print_request, 0,
+/* R_PRINT_REQUEST */ 0, D_BADMSG,
+/* S_START_CHANGE_REQUEST */ s_start_change_request, 0,
+/* R_START_CHANGE_REQUEST */ 0, D_BADMSG,
+/* S_END_CHANGE_REQUEST */ s_end_change_request, 0,
+/* R_END_CHANGE_REQUEST */ 0, D_BADMSG,
+/* S_CANCEL_REQUEST */ s_cancel_request, 0,
+/* R_CANCEL_REQUEST */ 0, D_BADMSG,
+/* S_INQUIRE_REQUEST */ 0, D_BADMSG,
+/* R_INQUIRE_REQUEST */ 0, D_BADMSG,
+/* S_LOAD_PRINTER */ s_load_printer, D_ADMIN,
+/* R_LOAD_PRINTER */ r_H, D_BADMSG,
+/* S_UNLOAD_PRINTER */ s_unload_printer, D_ADMIN,
+/* R_UNLOAD_PRINTER */ r_H, D_BADMSG,
+/* S_INQUIRE_PRINTER_STATUS */ s_inquire_printer_status, 0,
+/* R_INQUIRE_PRINTER_STATUS */ 0, D_BADMSG,
+/* S_LOAD_CLASS */ s_load_class, D_ADMIN,
+/* R_LOAD_CLASS */ r_H, D_BADMSG,
+/* S_UNLOAD_CLASS */ s_unload_class, D_ADMIN,
+/* R_UNLOAD_CLASS */ r_H, D_BADMSG,
+/* S_INQUIRE_CLASS */ s_inquire_class, 0,
+/* R_INQUIRE_CLASS */ 0, D_BADMSG,
+/* S_MOUNT */ s_mount, D_ADMIN,
+/* R_MOUNT */ r_H, D_BADMSG,
+/* S_UNMOUNT */ s_unmount, D_ADMIN,
+/* R_UNMOUNT */ r_H, D_BADMSG,
+/* S_MOVE_REQUEST */ s_move_request, D_ADMIN,
+/* R_MOVE_REQUEST */ r_H, D_BADMSG,
+/* S_MOVE_DEST */ s_move_dest, D_ADMIN,
+/* R_MOVE_DEST */ r_HS, D_BADMSG,
+/* S_ACCEPT_DEST */ s_accept_dest, D_ADMIN,
+/* R_ACCEPT_DEST */ r_H, D_BADMSG,
+/* S_REJECT_DEST */ s_reject_dest, D_ADMIN,
+/* R_REJECT_DEST */ r_H, D_BADMSG,
+/* S_ENABLE_DEST */ s_enable_dest, D_ADMIN,
+/* R_ENABLE_DEST */ r_H, D_BADMSG,
+/* S_DISABLE_DEST */ s_disable_dest, D_ADMIN,
+/* R_DISABLE_DEST */ r_HS, D_BADMSG,
+/* S_LOAD_FILTER_TABLE */ s_load_filter_table, D_ADMIN,
+/* R_LOAD_FILTER_TABLE */ r_H, D_BADMSG,
+/* S_UNLOAD_FILTER_TABLE */ s_unload_filter_table, D_ADMIN,
+/* R_UNLOAD_FILTER_TABLE */ r_H, D_BADMSG,
+/* S_LOAD_PRINTWHEEL */ s_load_printwheel, D_ADMIN,
+/* R_LOAD_PRINTWHEEL */ r_H, D_BADMSG,
+/* S_UNLOAD_PRINTWHEEL */ s_unload_printwheel, D_ADMIN,
+/* R_UNLOAD_PRINTWHEEL */ r_H, D_BADMSG,
+/* S_LOAD_USER_FILE */ s_load_user_file, D_ADMIN,
+/* R_LOAD_USER_FILE */ r_H, D_BADMSG,
+/* S_UNLOAD_USER_FILE */ s_unload_user_file, D_ADMIN,
+/* R_UNLOAD_USER_FILE */ r_H, D_BADMSG,
+/* S_LOAD_FORM */ s_load_form, D_ADMIN,
+/* R_LOAD_FORM */ r_H, D_BADMSG,
+/* S_UNLOAD_FORM */ s_unload_form, D_ADMIN,
+/* R_UNLOAD_FORM */ r_H, D_BADMSG,
+/* S_GETSTATUS */ 0, D_ADMIN,
+/* R_GETSTATUS */ 0, D_BADMSG,
+/* S_QUIET_ALERT */ s_quiet_alert, D_ADMIN,
+/* R_QUIET_ALERT */ r_H, D_BADMSG,
+/* S_SEND_FAULT */ s_send_fault, 0,
+/* R_SEND_FAULT */ 0, D_BADMSG,
+/* S_SHUTDOWN */ s_shutdown, D_ADMIN,
+/* R_SHUTDOWN */ r_H, D_BADMSG,
+/* S_GOODBYE */ 0, D_BADMSG,
+/* S_CHILD_DONE */ s_child_done, 0,
+/* I_GET_TYPE */ 0, D_BADMSG,
+/* I_QUEUE_CHK */ 0, D_BADMSG,
+/* R_CONNECT */ 0, D_BADMSG,
+/* S_GET_STATUS */ 0, D_BADMSG,
+/* R_GET_STATUS */ 0, D_BADMSG,
+/* S_INQUIRE_REQUEST_RANK */ s_inquire_request_rank, 0,
+/* R_INQUIRE_REQUEST_RANK */ 0, D_BADMSG,
+/* S_CANCEL */ s_cancel, 0,
+/* R_CANCEL */ 0, D_BADMSG,
+/* S_NEW_CHILD */ 0, D_BADMSG,
+/* R_NEW_CHILD */ 0, D_BADMSG,
+/* S_SEND_JOB */ 0, D_BADMSG,
+/* R_SEND_JOB */ 0, D_BADMSG,
+/* S_JOB_COMPLETED */ 0, D_BADMSG,
+/* R_JOB_COMPLETED */ 0, D_BADMSG,
+/* S_INQUIRE_REMOTE_PRINTER */ 0, D_BADMSG,
+/* R_INQUIRE_REMOTE_PRINTER */ 0, D_BADMSG,
+/* S_LOAD_SYSTEM */ 0, D_BADMSG,
+/* R_LOAD_SYSTEM */ 0, D_BADMSG,
+/* S_UNLOAD_SYSTEM */ 0, D_BADMSG,
+/* R_UNLOAD_SYSTEM */ 0, D_BADMSG,
+/* S_CLEAR_FAULT */ s_clear_fault, 0,
+/* R_CLEAR_FAULT */ 0, D_BADMSG,
+/* S_MOUNT_TRAY */ s_mount_tray, D_ADMIN,
+/* R_MOUNT_TRAY */ r_H, D_BADMSG,
+/* S_UNMOUNT_TRAY */ s_unmount_tray, D_ADMIN,
+/* R_UNMOUNT_TRAY */ r_H, D_BADMSG,
+/* S_MAX_TRAYS */ s_max_trays, D_ADMIN,
+/* R_MAX_TRAYS */ r_H, D_BADMSG,
+/* S_PAPER_CHANGED */ s_paper_changed, 0,
+/* R_PAPER_CHANGED */ 0, D_BADMSG,
+/* S_PAPER_ALLOWED */ s_paper_allowed, 0,
+/* R_PAPER_ALLOWED */ 0, D_BADMSG,
+/* S_PASS_PEER_CONNECTION */ s_pass_peer_connection, 0,
+/* R_PASS_PEER_CONNECTION */ 0, D_BADMSG,
+};
+
+static char *dispatch_names[] = {
+"R_BAD_MESSAGE",
+"S_NEW_QUEUE",
+"R_NEW_QUEUE",
+"S_ALLOC_FILES",
+"R_ALLOC_FILES",
+"S_PRINT_REQUEST",
+"R_PRINT_REQUEST",
+"S_START_CHANGE_REQUEST",
+"R_START_CHANGE_REQUEST",
+"S_END_CHANGE_REQUEST",
+"R_END_CHANGE_REQUEST",
+"S_CANCEL_REQUEST",
+"R_CANCEL_REQUEST",
+"S_INQUIRE_REQUEST",
+"R_INQUIRE_REQUEST",
+"S_LOAD_PRINTER",
+"R_LOAD_PRINTER",
+"S_UNLOAD_PRINTER",
+"R_UNLOAD_PRINTER",
+"S_INQUIRE_PRINTER_STATUS",
+"R_INQUIRE_PRINTER_STATUS",
+"S_LOAD_CLASS",
+"R_LOAD_CLASS",
+"S_UNLOAD_CLASS",
+"R_UNLOAD_CLASS",
+"S_INQUIRE_CLASS",
+"R_INQUIRE_CLASS",
+"S_MOUNT",
+"R_MOUNT",
+"S_UNMOUNT",
+"R_UNMOUNT",
+"S_MOVE_REQUEST",
+"R_MOVE_REQUEST",
+"S_MOVE_DEST",
+"R_MOVE_DEST",
+"S_ACCEPT_DEST",
+"R_ACCEPT_DEST",
+"S_REJECT_DEST",
+"R_REJECT_DEST",
+"S_ENABLE_DEST",
+"R_ENABLE_DEST",
+"S_DISABLE_DEST",
+"R_DISABLE_DEST",
+"S_LOAD_FILTER_TABLE",
+"R_LOAD_FILTER_TABLE",
+"S_UNLOAD_FILTER_TABLE",
+"R_UNLOAD_FILTER_TABLE",
+"S_LOAD_PRINTWHEEL",
+"R_LOAD_PRINTWHEEL",
+"S_UNLOAD_PRINTWHEEL",
+"R_UNLOAD_PRINTWHEEL",
+"S_LOAD_USER_FILE",
+"R_LOAD_USER_FILE",
+"S_UNLOAD_USER_FILE",
+"R_UNLOAD_USER_FILE",
+"S_LOAD_FORM",
+"R_LOAD_FORM",
+"S_UNLOAD_FORM",
+"R_UNLOAD_FORM",
+"S_GETSTATUS",
+"R_GETSTATUS",
+"S_QUIET_ALERT",
+"R_QUIET_ALERT",
+"S_SEND_FAULT",
+"R_SEND_FAULT",
+"S_SHUTDOWN",
+"R_SHUTDOWN",
+"S_GOODBYE",
+"S_CHILD_DONE",
+"I_GET_TYPE",
+"I_QUEUE_CHK",
+"R_CONNECT",
+"S_GET_STATUS",
+"R_GET_STATUS",
+"S_INQUIRE_REQUEST_RANK",
+"R_INQUIRE_REQUEST_RANK",
+"S_CANCEL",
+"R_CANCEL",
+"S_NEW_CHILD",
+"R_NEW_CHILD",
+"S_SEND_JOB",
+"R_SEND_JOB",
+"S_JOB_COMPLETED",
+"R_JOB_COMPLETED",
+"S_INQUIRE_REMOTE_PRINTER",
+"R_INQUIRE_REMOTE_PRINTER",
+"S_LOAD_SYSTEM",
+"R_LOAD_SYSTEM",
+"S_UNLOAD_SYSTEM",
+"R_UNLOAD_SYSTEM",
+"S_CLEAR_FAULT",
+"R_CLEAR_FAULT",
+"S_MOUNT_TRAY",
+"R_MOUNT_TRAY",
+"S_UNMOUNT_TRAY",
+"R_UNMOUNT_TRAY",
+"S_MAX_TRAYS",
+"R_MAX_TRAYS",
+"S_PAPER_CHANGED",
+"R_PAPER_CHANGED",
+"S_PAPER_ALLOWED",
+"R_PAPER_ALLOWED",
+"S_PASS_PEER_CONNECTION",
+"R_PASS_PEER_CONNECTION",
+};
+
+/* see include/msgs.h */
+static char *status_names[] = {
+"MOK",
+"MOKMORE",
+"MOKREMOTE",
+"MMORERR",
+"MNODEST",
+"MERRDEST",
+"MDENYDEST",
+"MNOMEDIA",
+"MDENYMEDIA",
+"MNOFILTER",
+"MNOINFO",
+"MNOMEM",
+"MNOMOUNT",
+"MNOOPEN",
+"MNOPERM",
+"MNOSTART",
+"MUNKNOWN",
+"M2LATE",
+"MNOSPACE",
+"MBUSY",
+"MTRANSMITERR",
+"MNOMORE",
+"MGONEREMOTE",
+"MNOTRAY"
+};
+
+#define LAST_STATUS 23
+
+/*
+ * dispatchName() - ROUTINE TO GIVE ASCII DISPATCH NAME
+ */
+
+char *
+dispatchName(int type)
+{
+ if (type <= 0 || type > LAST_MESSAGE)
+ type = 0;
+ return (dispatch_names[type]);
+}
+
+char *
+statusName(int status)
+{
+ if (status < 0 || status > LAST_STATUS)
+ return ("unknown");
+ return (status_names[status]);
+}
+
+/*
+ * dispatch() - DISPATCH A ROUTINE TO HANDLE A MESSAGE
+ */
+
+void
+dispatch(int type, char *m, MESG *md)
+{
+ register DISPATCH *pd = &dispatch_table[type];
+
+ syslog(LOG_DEBUG, "dispatch(%s, %s, 0x%8.8x)",
+ dispatchName(type), m, md);
+
+ if (type <= 0 || type >= LAST_MESSAGE || pd->fncp == NULL)
+ mputm(md, R_BAD_MESSAGE);
+
+ else if (!pd->fncp || pd->flags & D_BADMSG)
+ mputm(md, R_BAD_MESSAGE);
+
+ else if (pd->flags & D_ADMIN && !md->admin)
+ if ((++pd)->fncp)
+ (*pd->fncp) (md, type+1);
+ else
+ mputm(md, R_BAD_MESSAGE);
+
+ else if (pd->flags & D_SYSTEM && md->type != MD_CHILD &&
+ md->type != MD_BOUND)
+ if ((++pd)->fncp)
+ (*pd->fncp) (md, type+1);
+ else
+ mputm(md, R_BAD_MESSAGE);
+
+ else
+ (*pd->fncp) (m, md);
+}
+
+/*
+ * r_H() - SEND MNOPERM RESPONSE MESSAGE
+ * r_HS() - SEND MNOPERM RESPONSE MESSAGE
+ */
+
+static void
+r_H(MESG *md, int type)
+{
+ mputm(md, type, MNOPERM);
+}
+
+static void
+r_HS(MESG *md, int type)
+{
+ mputm(md, type, MNOPERM, "");
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/dowait.c b/usr/src/cmd/lp/cmd/lpsched/dowait.c
new file mode 100644
index 0000000000..aadd4d34d3
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/dowait.c
@@ -0,0 +1,590 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "lpsched.h"
+#include "ctype.h"
+#include "sys/stat.h"
+#include <syslog.h>
+
+/*
+ * Macro to test if we should notify the user.
+ */
+#define SHOULD_NOTIFY(PRS) \
+ ( \
+ (PRS)->request->actions & (ACT_MAIL|ACT_WRITE|ACT_NOTIFY)\
+ || (PRS)->request->alert \
+ )
+
+static char * geterrbuf ( RSTATUS * );
+
+/**
+ ** dowait() - CLEAN UP CHILD THAT HAS FINISHED, RESCHEDULE ANOTHER TASK
+ **/
+
+void
+dowait (void)
+{
+ int exited,
+ killed,
+ canned,
+ i;
+ EXEC *ep;
+ char *errbuf = NULL;
+ register RSTATUS *prs;
+ register PSTATUS *pps;
+ register ALERT *pas;
+
+ syslog(LOG_DEBUG, "dowait(%d)", DoneChildren);
+ while (DoneChildren > 0) {
+ DoneChildren--;
+
+ for (i = 0; (ep = Exec_Table[i]) != NULL; i++)
+ if (ep->pid == -99)
+ break;
+
+ syslog(LOG_DEBUG, "dowait(): 0x%8.8x", ep);
+
+ if (Exec_Table[i] == NULL) /* nothing to cleanup */
+ continue;
+
+ syslog(LOG_DEBUG, "dowait(): cleaning up 0x%8.8x", ep);
+
+ ep->pid = 0;
+ ep->key = 0; /* avoid subsequent sneaks */
+ if (ep->md)
+ DROP_MD(ep->md);
+
+ killed = KILLED(ep->status);
+ exited = EXITED(ep->status);
+
+ syslog(LOG_DEBUG, "dowait(): type %d, killed %d, exited %d",
+ ep->type, killed, exited);
+
+ switch (ep->type) {
+
+ case EX_INTERF:
+ /*
+ * WARNING: It could be that when we get here
+ *
+ * pps->request->printer != pps
+ *
+ * because the request has been assigned to
+ * another printer.
+ */
+ pps = ep->ex.printer;
+ prs = pps->request;
+ pps->request = 0;
+ pps->status &= ~PS_BUSY;
+
+ /*
+ * If the interface program exited cleanly
+ * or with just a user error, the printer
+ * is assumed to be working.
+ */
+ if (0 <= exited && exited < EXEC_EXIT_USER) {
+ pps->status &= ~PS_FAULTED;
+ if (pps->alert->active)
+ cancel_alert (A_PRINTER, pps);
+ }
+
+ /*
+ * If the interface program was killed with
+ * SIGTERM, it may have been because we canceled
+ * the request, disabled the printer, or for some
+ * other reason stopped the request.
+ * If so, clear the "killed" flag because that's
+ * not the condition of importance here.
+ */
+ canned = 0;
+ if (killed == SIGTERM) {
+ if (prs->request->outcome & RS_CANCELLED)
+ canned = 1;
+
+ if (
+ canned
+ || pps->status & (PS_DISABLED|PS_FAULTED)
+ || prs->request->outcome & RS_STOPPED
+ || Shutdown
+ )
+ killed = 0;
+ }
+
+ /*
+ * If there was standard error output from the
+ * interface program, or if the interface program
+ * exited with a (user) exit code, or if it got
+ * a strange signal, the user should be notified.
+ */
+ errbuf = geterrbuf(prs);
+ if (
+ errbuf
+ || (0 < exited && exited <= EXEC_EXIT_USER)
+ || killed
+ ) {
+ if (exited != EXIT_RETRY) {
+ prs->request->outcome |= RS_FAILED;
+ }
+ prs->request->outcome |= RS_NOTIFY;
+ notify (prs, errbuf, killed, exited, 0);
+ if (errbuf)
+ Free (errbuf);
+
+ /*
+ * If the request was canceled, call "notify()"
+ * in case we're to notify the user.
+ */
+ } else if (canned) {
+ if (SHOULD_NOTIFY(prs))
+ prs->request->outcome |= RS_NOTIFY;
+ notify (prs, (char *)0, 0, 0, 0);
+
+ /*
+ * If the request finished successfully, call
+ * "notify()" in case we're to notify the user.
+ */
+ } else if (exited == 0) {
+ prs->request->outcome |= RS_PRINTED;
+
+ if (SHOULD_NOTIFY(prs))
+ prs->request->outcome |= RS_NOTIFY;
+ notify (prs, (char *)0, 0, 0, 0);
+ }
+
+ /*
+ * If the interface program exits with an
+ * exit code higher than EXEC_EXIT_USER, it's
+ * a special case.
+ */
+
+ switch (exited) {
+
+ case EXEC_EXIT_FAULT:
+ printer_fault (pps, prs, 0, 0);
+ break;
+
+ case EXEC_EXIT_HUP:
+ printer_fault (pps, prs, HANGUP_FAULT, 0);
+ break;
+
+ case EXEC_EXIT_INTR:
+ printer_fault (pps, prs, INTERRUPT_FAULT, 0);
+ break;
+
+ case EXEC_EXIT_PIPE:
+ printer_fault (pps, prs, PIPE_FAULT, 0);
+ break;
+
+ case EXEC_EXIT_EXIT:
+ note (
+ "Bad exit from interface program for printer %s: %d\n",
+ pps->printer->name,
+ ep->Errno
+ );
+ printer_fault (pps, prs, EXIT_FAULT, 0);
+ break;
+
+ case EXEC_EXIT_NPORT:
+ printer_fault (pps, prs, OPEN_FAULT, ep->Errno);
+ break;
+
+ case EXEC_EXIT_TMOUT:
+ printer_fault (pps, prs, TIMEOUT_FAULT, 0);
+ break;
+
+ case EXEC_EXIT_NOPEN:
+ errno = ep->Errno;
+ note (
+ "Failed to open a print service file (%s).\n",
+ PERROR
+ );
+ break;
+
+ case EXEC_EXIT_NEXEC:
+ errno = ep->Errno;
+ note (
+ "Failed to exec child process (%s).\n",
+ PERROR
+ );
+ break;
+
+ case EXEC_EXIT_NOMEM:
+ mallocfail ();
+ break;
+
+ case EXEC_EXIT_NFORK:
+ errno = ep->Errno;
+ note (
+ "Failed to fork child process (%s).\n",
+ PERROR
+ );
+ break;
+
+ case EXEC_EXIT_NPUSH:
+ printer_fault (pps, prs, PUSH_FAULT, ep->Errno);
+ break;
+
+ default:
+ if ((exited & EXEC_EXIT_NMASK) == EXEC_EXIT_NDIAL)
+ dial_problem (
+ pps,
+ prs,
+ exited & ~EXEC_EXIT_NMASK
+ );
+
+ else if (
+ exited < -1
+ || exited > EXEC_EXIT_USER
+ )
+ note (
+ "Bad exit from exec() for printer %s: %d\n",
+ pps->printer->name,
+ exited
+ );
+
+ break;
+ }
+
+ /*
+ * Being in the "dowait()" routine means the
+ * interface (and fast filter!) have stopped.
+ * If we have a fault and we're expected to try
+ * again later, make sure we try again later.
+ */
+ if (
+ (pps->status & PS_FAULTED)
+ && !STREQU(pps->printer->fault_rec, NAME_WAIT)
+ && !(pps->status & (PS_LATER|PS_DISABLED))
+ ) {
+ load_str (&pps->dis_reason, CUZ_STOPPED);
+ schedule (EV_LATER, WHEN_PRINTER, EV_ENABLE, pps);
+ }
+
+ prs->request->outcome &= ~(RS_PRINTING|RS_STOPPED);
+
+ /*
+ * If the printer to which this request was
+ * assigned is not able to handle requests now,
+ * push waiting requests off on to another
+ * printer.
+ */
+ if (prs->printer->status & (PS_FAULTED|PS_DISABLED|PS_LATER))
+ (void)queue_repel (prs->printer, 0, (qchk_fnc_type)0);
+
+ /*
+ * If the request is now assigned to a different
+ * printer, call "schedule()" to fire up an
+ * interface. If this request also happens to
+ * be dead, or in need of refiltering, it won't
+ * get scheduled.
+ */
+ if (
+ prs->printer != pps
+ )
+ schedule (EV_INTERF, prs->printer);
+
+ check_request (prs);
+
+ /*
+ * Attract the FIRST request that is waiting to
+ * print to this printer, unless the printer isn't
+ * ready to print another request. We do this
+ * even though requests may already be assigned
+ * to this printer, because a request NOT assigned
+ * might be ahead of them in the queue.
+ */
+ if (!(pps->status & (PS_FAULTED|PS_DISABLED|PS_LATER)))
+ queue_attract (pps, qchk_waiting, 1);
+
+ break;
+
+ case EX_SLOWF:
+ prs = ep->ex.request;
+ ep->ex.request = 0;
+ prs->exec = 0;
+ prs->request->outcome &= ~RS_FILTERING;
+
+ /*
+ * If the slow filter was killed with SIGTERM,
+ * it may have been because we canceled the
+ * request, stopped the filtering, or put a
+ * change hold on the request. If so, clear
+ * the "killed" flag because that's not the
+ * condition of importance.
+ */
+ canned = 0;
+ if (killed == SIGTERM){
+ if (prs->request->outcome & RS_CANCELLED)
+ canned = 1;
+
+ if (
+ canned
+ || prs->request->outcome & RS_STOPPED
+ || Shutdown
+ )
+ killed = 0;
+ }
+
+ /*
+ * If there was standard error output from the
+ * slow filter, or if the interface program exited
+ * with a non-zero exit code, the user should
+ * be notified.
+ */
+ errbuf = geterrbuf(prs);
+ if (prs->request->outcome
+ & (RS_REFILTER | RS_STOPPED)) {
+ if (errbuf) {
+ Free(errbuf);
+ errbuf = NULL;
+ }
+ }
+ if (
+ errbuf
+ || 0 < exited && exited <= EXEC_EXIT_USER
+ || killed
+ ) {
+ prs->request->outcome |= RS_FAILED;
+ prs->request->outcome |= RS_NOTIFY;
+ notify (prs, errbuf, killed, exited, 1);
+ if (errbuf)
+ Free (errbuf);
+
+
+ /*
+ * If the request was canceled, call "notify()"
+ * in case we're to notify the user.
+ */
+ } else if (canned) {
+ if (SHOULD_NOTIFY(prs))
+ prs->request->outcome |= RS_NOTIFY;
+ notify (prs, (char *)0, 0, 0, 1);
+
+ /*
+ * If the slow filter exited normally, mark
+ * the request as finished slow filtering.
+ */
+ } else if (exited == 0) {
+ prs->request->outcome |= RS_FILTERED;
+
+ } else if (exited == -1) {
+ /*EMPTY*/;
+
+ } else if (exited == EXEC_EXIT_NOPEN) {
+ errno = ep->Errno;
+ note (
+ "Failed to open a print service file (%s).\n",
+ PERROR
+ );
+
+ } else if (exited == EXEC_EXIT_NEXEC) {
+ errno = ep->Errno;
+ note (
+ "Failed to exec child process (%s).\n",
+ PERROR
+ );
+
+ } else if (exited == EXEC_EXIT_NOMEM) {
+ mallocfail ();
+
+ }
+
+ prs->request->outcome &= ~RS_STOPPED;
+
+ schedule (EV_INTERF, prs->printer);
+ if (
+ prs->request->outcome & RS_REFILTER
+ )
+ schedule (EV_SLOWF, prs);
+ else
+ schedule (EV_SLOWF, (RSTATUS *)0);
+
+ check_request (prs);
+ break;
+
+ case EX_NOTIFY:
+ prs = ep->ex.request;
+ ep->ex.request = 0;
+ prs->exec = 0;
+
+ prs->request->outcome &= ~RS_NOTIFYING;
+ if (!Shutdown || !killed)
+ prs->request->outcome &= ~RS_NOTIFY;
+
+ /*
+ * Now that this notification process slot
+ * has opened up, schedule the next notification
+ * (if any).
+ */
+ schedule (EV_NOTIFY, (RSTATUS *)0);
+
+ check_request (prs);
+ break;
+
+ case EX_ALERT:
+ pas = ep->ex.printer->alert;
+ goto CleanUpAlert;
+
+ case EX_FALERT:
+ pas = ep->ex.form->alert;
+ goto CleanUpAlert;
+
+ case EX_PALERT:
+ pas = ep->ex.pwheel->alert;
+ /*
+ * CAUTION: It may well be that we've removed
+ * the print wheel by the time we get here.
+ * Only the alert structure (and exec structure)
+ * can be considered okay.
+ */
+
+CleanUpAlert:
+ if (Shutdown)
+ break;
+
+ if (ep->flags & EXF_RESTART) {
+ ep->flags &= ~(EXF_RESTART);
+ if (exec(ep->type, ep->ex.form) == 0) {
+ pas->active = 1;
+ break;
+ }
+ }
+ (void)Unlink (pas->msgfile);
+ break;
+
+ }
+ }
+
+ return;
+}
+
+
+/**
+ ** geterrbuf() - READ NON-BLANK STANDARD ERROR OUTPUT
+ **/
+
+static char *
+geterrbuf(RSTATUS *prs)
+{
+ register char *cp;
+ int fd,
+ n;
+ char *buf = 0,
+ *file;
+ struct stat statbuf;
+
+ if (!prs) return(NULL);
+
+ file = makereqerr(prs);
+ if (
+ Stat(file, &statbuf) == 0
+ && statbuf.st_size
+ && (fd = Open(file, O_RDONLY)) != -1
+ ) {
+ /*
+ * Don't die if we can't allocate space for this
+ * file--the file may be huge!
+ */
+ lp_alloc_fail_handler = 0;
+ if ((buf = Malloc(statbuf.st_size + 1)))
+ if ((n = Read(fd, buf, statbuf.st_size)) > 0) {
+ buf[n] = 0;
+
+ /*
+ * NOTE: Ignore error output with no
+ * printable text. This hides problems we
+ * have with some shell scripts that
+ * occasionally cause spurious newlines
+ * when stopped via SIGTERM. Without this
+ * check for non-blank output, stopping
+ * a request sometimes causes a request
+ * failure.
+ */
+ for (cp = buf; *cp && isspace(*cp); cp++)
+ ;
+ if (!*cp) {
+ Free (buf);
+ buf = 0;
+ }
+ } else {
+ Free (buf);
+ buf = 0;
+ }
+ lp_alloc_fail_handler = mallocfail;
+ Close(fd);
+ }
+ if (file)
+ Free (file);
+
+ return (buf);
+}
+
+/**
+ ** check_request() - CLEAN UP AFTER REQUEST
+ **/
+
+void
+check_request(RSTATUS *prs)
+{
+ /*
+ * If the request is done, decrement the count of requests
+ * needing the form or print wheel. Update the disk copy of
+ * the request. If we're finished with the request, get rid of it.
+ */
+ if (prs->request->outcome & RS_DONE) {
+ unqueue_form (prs);
+ unqueue_pwheel (prs);
+ putrequest (prs->req_file, prs->request);
+ if (!(prs->request->outcome & (RS_ACTIVE | RS_NOTIFY))) {
+ rmfiles (prs, 1);
+ free_rstatus (prs);
+ }
+ }
+ return;
+}
+
+/**
+ ** check_children()
+ **/
+
+void
+check_children(void)
+{
+ register int i;
+
+ for (i = 0; Exec_Table[i] != NULL; i++)
+ if (Exec_Table[i]->pid > 0)
+ break;
+
+ if (Exec_Table[i] == NULL)
+ Shutdown = 2;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/exec.c b/usr/src/cmd/lp/cmd/lpsched/exec.c
new file mode 100644
index 0000000000..df88c57f21
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/exec.c
@@ -0,0 +1,1435 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include <pwd.h>
+#include <zone.h>
+#if defined PS_FAULTED
+#undef PS_FAULTED
+#endif /* PS_FAULTED */
+#include <dial.h>
+
+#include <stdlib.h>
+#include "limits.h"
+#include "stdarg.h"
+#include "wait.h"
+#include "dial.h"
+#include "lpsched.h"
+#include <syslog.h>
+#include "tsol/label.h"
+
+#define Done(EC,ERRNO) done(((EC) << 8),ERRNO)
+
+#define STRLCAT(dst, src, size) \
+ if (strlcat((dst), (src), (size)) >= (size)) { \
+ errno = EINVAL; \
+ return (-1); \
+ }
+
+static MESG * ChildMd;
+
+static int ChildPid;
+static int WaitedChildPid;
+static int do_undial;
+
+static char argbuf[ARG_MAX];
+
+static long key;
+
+static void sigtrap ( int );
+static void done ( int , int );
+static void cool_heels ( void );
+static void addenv (char ***envp, char * , char * );
+static void trap_fault_signals ( void );
+static void ignore_fault_signals ( void );
+static void child_mallocfail ( void );
+static void Fork2 ( void );
+
+static int Fork1 ( EXEC * );
+
+static void
+relock(void)
+{
+ struct flock l;
+
+ l.l_type = F_WRLCK;
+ l.l_whence = 1;
+ l.l_start = 0;
+ l.l_len = 0;
+ (void)Fcntl (lock_fd, F_SETLK, &l);
+ return;
+}
+
+static char *_exec_name(int type)
+{
+ static char *_names[] = {
+ "", "EX_INTERF", "EX_SLOWF", "EX_ALERT", "EX_FALERT", "EX_PALERT",
+ "EX_NOTIFY", "EX_FAULT_MESSAGE", "EX_FORM_MESSAGE", NULL };
+
+ if ((type < 0) || (type > EX_FORM_MESSAGE))
+ return ("BAD_EXEC_TYPE");
+ else
+ return (_names[type]);
+}
+
+/*
+ * This function replaces characters in a string that might be used
+ * to exploit a security hole. Replace command seperators (`, &, ;, |, ^),
+ * output redirection (>, |), variable expansion ($), and character
+ * escape (\).
+ *
+ * Bugid 4141687
+ * Add ( ) < * ? [
+ * Bugid 4139071
+ * Remove \
+ */
+void clean_string(char *ptr)
+{
+ char *cp;
+ wchar_t wc;
+ size_t len;
+
+ for (cp = ptr; *cp != NULL; ) {
+ if ((len = mbtowc(&wc, cp, MB_CUR_MAX)) == -1) {
+ cp++;
+ continue;
+ }
+
+ if (len == 1 &&
+ ((wc == L'`') || (wc == L'&') || (wc == L';') ||
+ (wc == L'|') || (wc == L'>') || (wc == L'^') ||
+ (wc == L'$') || (wc == L'(') || (wc == L')') ||
+ (wc == L'<') || (wc == L'*') || (wc == L'?') ||
+ (wc == L'[')))
+ *cp = '_';
+ cp += len;
+ }
+}
+
+enum trust {TRUSTED, UNTRUSTED};
+
+static char *arg_string(enum trust type, char *fmt, ...) __PRINTFLIKE(2);
+
+/* PRINTFLIKE2 */
+static char *
+arg_string(enum trust type, char *fmt, ...)
+{
+ char buf[BUFSIZ];
+ va_list args;
+
+ va_start(args, fmt);
+ (void) vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ /*
+ * If the string contains data from an untrusted origin (user supplied),
+ * clean it up in case one of our progeny is a shell script and isn't
+ * careful about checking its input.
+ */
+ if (type == UNTRUSTED)
+ clean_string(buf);
+
+ return (strdup(buf));
+}
+
+/* stolen from libc/gen/port/gen/execvp.c */
+static const char *
+execat(const char *s1, const char *s2, char *si)
+{
+ char *s;
+ int cnt = PATH_MAX + 1; /* number of characters in s2 */
+
+ s = si;
+ while (*s1 && *s1 != ':') {
+ if (cnt > 0) {
+ *s++ = *s1++;
+ cnt--;
+ } else
+ s1++;
+ }
+ if (si != s && cnt > 0) {
+ *s++ = '/';
+ cnt--;
+ }
+ while (*s2 && cnt > 0) {
+ *s++ = *s2++;
+ cnt--;
+ }
+ *s = '\0';
+ return (*s1 ? ++s1: 0);
+}
+
+/*
+ * Similiar to execvp(), execpt you can supply an environment and we always
+ * use /bin/sh for shell scripts. The PATH searched is the PATH in the
+ * current environment, not the environment in the argument list.
+ * This was pretty much stolen from libc/gen/port/execvp.c
+ */
+static int
+execvpe(char *name, char *const argv[], char *const envp[])
+{
+ char *path;
+ char fname[PATH_MAX+2];
+ char *newargs[256];
+ int i;
+ const char *cp;
+ unsigned etxtbsy = 1;
+ int eacces = 0;
+
+ if (*name == '\0') {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ if ((path = getenv("PATH")) == NULL)
+ path = "/usr/bin:/bin";
+
+ cp = strchr(name, '/')? (const char *)"": path;
+
+ do {
+ cp = execat(cp, name, fname);
+ retry:
+ /*
+ * 4025035 and 4038378
+ * if a filename begins with a "-" prepend "./" so that
+ * the shell can't interpret it as an option
+ */
+ if (*fname == '-') {
+ size_t size = strlen(fname) + 1;
+ if ((size + 2) > sizeof (fname)) {
+ errno = E2BIG;
+ return (-1);
+ }
+ (void) memmove(fname + 2, fname, size);
+ fname[0] = '.';
+ fname[1] = '/';
+ }
+ (void) execve(fname, argv, envp);
+ switch (errno) {
+ case ENOEXEC:
+ newargs[0] = "sh";
+ newargs[1] = fname;
+ for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) {
+ if (i >= 254) {
+ errno = E2BIG;
+ return (-1);
+ }
+ }
+ (void) execve("/bin/sh", newargs, envp);
+ return (-1);
+ case ETXTBSY:
+ if (++etxtbsy > 5)
+ return (-1);
+ (void) sleep(etxtbsy);
+ goto retry;
+ case EACCES:
+ ++eacces;
+ break;
+ case ENOMEM:
+ case E2BIG:
+ case EFAULT:
+ return (-1);
+ }
+ } while (cp);
+ if (eacces)
+ errno = EACCES;
+ return (-1);
+}
+
+static char time_buf[50];
+
+/**
+ ** exec() - FORK AND EXEC CHILD PROCESS
+ **/
+
+/*VARARGS1*/
+int
+exec(int type, ...)
+{
+ va_list args;
+
+ int i;
+ int procuid;
+ int procgid;
+ int ret;
+ int fr_flg;
+
+ char *cp;
+ char *infile;
+ char *outfile;
+ char *errfile;
+ char *sep;
+
+ char **listp;
+ char **file_list;
+ char *printerName;
+ char *printerNameToShow;
+ static char nameBuf[100];
+ char *clean_title;
+
+ PSTATUS *printer;
+
+ RSTATUS *request;
+
+ FSTATUS *form;
+
+ EXEC *ep;
+
+ PWSTATUS *pwheel;
+ time_t now;
+ struct passwd *pwp;
+#ifdef LP_USE_PAPI_ATTR
+ struct stat tmpBuf;
+ char tmpName[BUFSIZ];
+ char *path = NULL;
+#endif
+ char *av[ARG_MAX];
+ char **envp = NULL;
+ int ac = 0;
+ char *mail_zonename = NULL;
+ char *slabel = NULL;
+ int setid = 1;
+ char *ridno = NULL, *tmprid = NULL;
+
+ syslog(LOG_DEBUG, "exec(%s)", _exec_name(type));
+
+ memset(av, 0, sizeof (*av));
+
+ va_start (args, type);
+
+ switch (type) {
+
+ case EX_INTERF:
+ printer = va_arg(args, PSTATUS *);
+ request = printer->request;
+ ep = printer->exec;
+ break;
+
+ case EX_FAULT_MESSAGE:
+ printer = va_arg(args, PSTATUS *);
+ request = va_arg(args, RSTATUS *);
+ if (! ( printer->status & (PS_FORM_FAULT | PS_SHOW_FAULT))) {
+ return(0);
+ }
+ ep = printer->fault_exec;
+ printerName = (printer->printer && printer->printer->name
+ ? printer->printer->name : "??");
+ snprintf(nameBuf, sizeof (nameBuf),
+ "%s (on %s)\n", printerName, Local_System);
+
+ printerNameToShow = nameBuf;
+
+ (void) time(&now);
+ (void) strftime(time_buf, sizeof (time_buf),
+ NULL, localtime(&now));
+ break;
+
+ case EX_SLOWF:
+ request = va_arg(args, RSTATUS *);
+ ep = request->exec;
+ break;
+
+ case EX_NOTIFY:
+ request = va_arg(args, RSTATUS *);
+ if (request->request->actions & ACT_NOTIFY) {
+ errno = EINVAL;
+ return (-1);
+ }
+ ep = request->exec;
+ break;
+
+ case EX_ALERT:
+ printer = va_arg(args, PSTATUS *);
+ if (!(printer->printer->fault_alert.shcmd)) {
+ errno = EINVAL;
+ return(-1);
+ }
+ ep = printer->alert->exec;
+ break;
+
+ case EX_PALERT:
+ pwheel = va_arg(args, PWSTATUS *);
+ ep = pwheel->alert->exec;
+ break;
+
+ case EX_FORM_MESSAGE:
+ (void) time(&now);
+ (void) strftime(time_buf, sizeof (time_buf),
+ NULL, localtime(&now));
+
+ /*FALLTHRU*/
+ case EX_FALERT:
+ form = va_arg(args, FSTATUS *);
+ ep = form->alert->exec;
+ break;
+
+ default:
+ errno = EINVAL;
+ return(-1);
+
+ }
+ va_end (args);
+
+ if (!ep || (ep->pid > 0)) {
+ errno = EBUSY;
+ return(-1);
+ }
+
+ ep->flags = 0;
+
+ key = ep->key = getkey();
+
+ switch ((ep->pid = Fork1(ep))) {
+
+ case -1:
+ relock ();
+ return(-1);
+
+ case 0:
+ /*
+ * We want to be able to tell our parent how we died.
+ */
+ lp_alloc_fail_handler = child_mallocfail;
+ break;
+
+ default:
+ switch(type) {
+
+ case EX_INTERF:
+ request->request->outcome |= RS_PRINTING;
+ break;
+
+ case EX_NOTIFY:
+ request->request->outcome |= RS_NOTIFYING;
+ break;
+
+ case EX_SLOWF:
+ request->request->outcome |= RS_FILTERING;
+ request->request->outcome &= ~RS_REFILTER;
+ break;
+
+ }
+ return(0);
+
+ }
+
+ for (i = 0; i < NSIG; i++)
+ (void)signal (i, SIG_DFL);
+ (void)signal (SIGALRM, SIG_IGN);
+ (void)signal (SIGTERM, sigtrap);
+
+ closelog();
+ for (i = 0; i < OpenMax; i++)
+ if (i != ChildMd->writefd)
+ Close (i);
+ openlog("lpsched", LOG_PID|LOG_NDELAY|LOG_NOWAIT, LOG_LPR);
+
+ setpgrp();
+
+ /* Set a default path */
+ addenv (&envp, "PATH", "/usr/lib/lp/bin:/usr/bin:/bin:/usr/sbin:/sbin");
+ /* copy locale related variables */
+ addenv (&envp, "TZ", getenv("TZ"));
+ addenv (&envp, "LANG", getenv("LANG"));
+ addenv (&envp, "LC_ALL", getenv("LC_ALL"));
+ addenv (&envp, "LC_COLLATE", getenv("LC_COLLATE"));
+ addenv (&envp, "LC_CTYPE", getenv("LC_CTYPE"));
+ addenv (&envp, "LC_MESSAGES", getenv("LC_MESSAGES"));
+ addenv (&envp, "LC_MONETARY", getenv("LC_MONETARY"));
+ addenv (&envp, "LC_NUMERIC", getenv("LC_NUMERIC"));
+ addenv (&envp, "LC_TIME", getenv("LC_TIME"));
+
+ sprintf ((cp = BIGGEST_NUMBER_S), "%ld", key);
+ addenv (&envp, "SPOOLER_KEY", cp);
+
+#if defined(DEBUG)
+ addenv (&envp, "LPDEBUG", (debug? "1" : "0"));
+#endif
+
+ /*
+ * Open the standard input, standard output, and standard error.
+ */
+ switch (type) {
+
+ case EX_SLOWF:
+ case EX_INTERF:
+ /*
+ * stdin: /dev/null
+ * stdout: /dev/null (EX_SLOWF), printer port (EX_INTERF)
+ * stderr: req#
+ */
+ infile = 0;
+ outfile = 0;
+ errfile = makereqerr(request);
+ break;
+
+ case EX_NOTIFY:
+ /*
+ * stdin: req#
+ * stdout: /dev/null
+ * stderr: /dev/null
+ */
+ infile = makereqerr(request);
+ outfile = 0;
+ errfile = 0;
+
+ break;
+
+ case EX_ALERT:
+ case EX_FALERT:
+ case EX_PALERT:
+ case EX_FAULT_MESSAGE:
+ case EX_FORM_MESSAGE:
+ /*
+ * stdin: /dev/null
+ * stdout: /dev/null
+ * stderr: /dev/null
+ */
+ infile = 0;
+ outfile = 0;
+ errfile = 0;
+ break;
+
+ }
+
+ if (infile) {
+ if (Open(infile, O_RDONLY) == -1)
+ Done (EXEC_EXIT_NOPEN, errno);
+ } else {
+ if (Open("/dev/null", O_RDONLY) == -1)
+ Done (EXEC_EXIT_NOPEN, errno);
+ }
+
+ if (outfile) {
+ if (Open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
+ Done (EXEC_EXIT_NOPEN, errno);
+ } else {
+ /*
+ * If EX_INTERF, this is still needed to cause the
+ * standard error channel to be #2.
+ */
+ if (Open("/dev/null", O_WRONLY) == -1)
+ Done (EXEC_EXIT_NOPEN, errno);
+ }
+
+ if (errfile) {
+ if (Open(errfile, O_CREAT|O_TRUNC|O_WRONLY, 0600) == -1)
+ Done (EXEC_EXIT_NOPEN, errno);
+ } else {
+ if (Open("/dev/null", O_WRONLY) == -1)
+ Done (EXEC_EXIT_NOPEN, errno);
+ }
+
+ switch (type) {
+
+ case EX_INTERF:
+ /*
+ * Opening a ``port'' can be dangerous to our health:
+ *
+ * - Hangups can occur if the line is dropped.
+ * - The printer may send an interrupt.
+ * - A FIFO may be closed, generating SIGPIPE.
+ *
+ * We catch these so we can complain nicely.
+ */
+ trap_fault_signals ();
+
+ (void)Close (1);
+
+ procuid = request->secure->uid;
+ procgid = request->secure->gid;
+
+ if (printer->printer->dial_info)
+ {
+ ret = open_dialup(request->printer_type,
+ printer->printer);
+ if (ret == 0)
+ do_undial = 1;
+ }
+ else
+ {
+ ret = open_direct(request->printer_type,
+ printer->printer);
+ do_undial = 0;
+ /* this is a URI */
+ if (is_printer_uri(printer->printer->device) == 0)
+ addenv(&envp, "DEVICE_URI",
+ printer->printer->device);
+ }
+ addenv(&envp, "DEVICE_URI",
+ printer->printer->device);
+ if (ret != 0)
+ Done (ret, errno);
+
+ if (!(request->request->outcome & RS_FILTERED))
+ file_list = request->request->file_list;
+
+ else {
+ register int count = 0;
+ register char * num = BIGGEST_REQID_S;
+ register char * prefix;
+
+ prefix = makestr(
+ Lp_Temp,
+ "/F",
+ getreqno(request->secure->req_id),
+ "-",
+ (char *)0
+ );
+
+ file_list = (char **)Malloc(
+ (lenlist(request->request->file_list) + 1)
+ * sizeof(char *)
+ );
+
+ for (
+ listp = request->request->file_list;
+ *listp;
+ listp++
+ ) {
+ sprintf (num, "%d", count + 1);
+ file_list[count] = makestr(
+ prefix,
+ num,
+ (char *)0
+ );
+ count++;
+ }
+ file_list[count] = 0;
+ }
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * Check if the PAPI job attribute file exists, if it does
+ * pass the file's pathname to the printer interface script
+ * in an environment variable. This file is created when
+ * print jobs are submitted via the PAPI interface.
+ */
+ snprintf(tmpName, sizeof (tmpName), "%s-%s",
+ getreqno(request->secure->req_id), LP_PAPIATTRNAME);
+ path = makepath(Lp_Temp, tmpName, (char *)0);
+ if ((path != NULL) && (stat(path, &tmpBuf) == 0))
+ {
+ /*
+ * IPP job attribute file exists for this job so
+ * set the environment variable
+ */
+ addenv(&envp, "ATTRPATH", path);
+ }
+ Free(path);
+
+ /*
+ * now set environment variable for the printer's PostScript
+ * Printer Description (PPD) file, this is used by the filter
+ * when forming the print data for this printer.
+ */
+ if ((request->printer != NULL) &&
+ (request->printer->printer != NULL) &&
+ (request->printer->printer->name != NULL))
+ {
+ snprintf(tmpName, sizeof (tmpName), "%s.ppd",
+ request->printer->printer->name);
+ path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
+ if ((path != NULL) && (stat(path, &tmpBuf) == 0))
+ {
+ addenv(&envp, "PPD", path);
+ }
+ Free(path);
+ }
+#endif
+
+ if (request->printer_type)
+ addenv(&envp, "TERM", request->printer_type);
+
+ if (!(printer->printer->daisy)) {
+ register char * chset = 0;
+ register char * csp;
+
+ if (
+ request->form
+ && request->form->form->chset
+ && request->form->form->mandatory
+ && !STREQU(NAME_ANY, request->form->form->chset)
+ )
+ chset = request->form->form->chset;
+
+ else if (
+ request->request->charset
+ && !STREQU(NAME_ANY, request->request->charset)
+ )
+ chset = request->request->charset;
+
+ if (chset) {
+ csp = search_cslist(
+ chset,
+ printer->printer->char_sets
+ );
+
+ /*
+ * The "strtok()" below wrecks the string
+ * for future use, but this is a child
+ * process where it won't be needed again.
+ */
+ addenv (&envp, "CHARSET",
+ (csp? strtok(csp, "=") : chset)
+ );
+ }
+ }
+
+ if (request->fast)
+ addenv(&envp, "FILTER", request->fast);
+
+ /*
+ * Add the sensitivity label to the environment for
+ * banner page and header/footer processing
+ */
+
+ if (is_system_labeled() && request->secure->slabel != NULL)
+ addenv(&envp, "SLABEL", request->secure->slabel);
+
+ /*
+ * Add the system name to the user name (ala system!user)
+ * unless it is already there. RFS users may have trouble
+ * here, sorry!
+ */
+ cp = strchr(request->secure->user, '@');
+
+ allTraysWithForm(printer, request->form);
+
+ /*
+ * Fix for 4137389
+ * Remove double quotes from title string.
+ */
+ fr_flg = 1;
+ clean_title = strdup(NB(request->request->title));
+ if (clean_title == NULL) {
+ /*
+ * strdup failed. We're probably hosed
+ * but try setting clean_title
+ * to original title and continuing.
+ */
+ clean_title = NB(request->request->title);
+ fr_flg = 0;
+ } else if (strcmp(clean_title, "") != 0) {
+ char *ct_p;
+
+ for (ct_p = clean_title; *ct_p != NULL; ct_p++) {
+ if (*ct_p == '"')
+ *ct_p = ' ';
+ }
+ }
+
+ av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_A_Interfaces,
+ printer->printer->name);
+ /*
+ * Read the options field of the request
+ * In case of remote lpd request
+ * the options field will have
+ * job-id-requested. This is the
+ * id sent by the client
+ */
+ if (request->request->options != NULL) {
+ char *options = NULL, *temp = NULL;
+ options = temp = strdup(request->request->options);
+
+ /*
+ * Search for job-id-requested in
+ * options string
+ */
+ options = strstr(options, "job-id-requested");
+ if (options != NULL) {
+ /*
+ * Extract the ridno from the string
+ * job-id-requested=xxx
+ * In this case ridno = xxx
+ */
+ if (STRNEQU(options, "job-id-requested=", 17)) {
+ ridno = strdup(options + 17);
+ tmprid = strstr(ridno, " ");
+ if (ridno != NULL) {
+ /*
+ * Read job-id-requested
+ * successfully
+ */
+ tmprid = strstr(ridno, " ");
+ if (tmprid != NULL)
+ *tmprid = '\0';
+
+ setid = 0;
+ } else
+ /*
+ * could not read
+ * ridno from the string
+ * job-id-requested=xxx
+ */
+ setid = 1;
+ } else
+ /*
+ * could not read
+ * ridno from the string
+ * job-id-requested=xxx
+ */
+ setid = 1;
+ } else
+ /*
+ * No job-id-requested in
+ * request options
+ */
+ setid = 1;
+
+ if (temp != NULL)
+ free(temp);
+
+ } else
+ /*
+ * options field in request structure
+ * not set
+ */
+ setid = 1;
+
+
+ /*
+ * setid = 1 means the job-id-requested attribute
+ * is not set so read the request->secure->req_id
+ */
+ if (setid)
+ av[ac++] = arg_string(TRUSTED, "%s",
+ request->secure->req_id);
+ else {
+ /*
+ * From request->secure->req_id extract the
+ * printer-name.
+ * request->secure->req_id = <printer-name>-<req_id>
+ * The final req-id will be
+ * <printer-name>-<ridno>
+ */
+ char *r1 = NULL, *r2 = NULL, *tmp = NULL;
+ r1 = r2 = tmp = strdup(request->secure->req_id);
+ r2 = strrchr(r1, '-');
+ if (r2 != NULL) {
+ char *r3 = NULL;
+ int lr1 = strlen(r1);
+ int lr2 = strlen(r2);
+ r1[lr1 - lr2 + 1] = '\0';
+
+ /*
+ * Now r1 = <printer-name>-
+ */
+ lr1 = strlen(r1);
+ lr2 = strlen(ridno);
+
+ r3 = (char *)malloc(lr1+lr2+1);
+ if (r3 != NULL) {
+ strcpy(r3, r1);
+ strcat(r3, ridno);
+ /*
+ * Here r3 = <printer-name>-<ridno>
+ */
+ av[ac++] = arg_string(TRUSTED,
+ "%s", r3);
+ free(r3);
+ } else
+ av[ac++] = arg_string(TRUSTED, "%s",
+ request->secure->req_id);
+
+ } else
+ av[ac++] = arg_string(TRUSTED, "%s",
+ request->secure->req_id);
+
+ if (tmp != NULL)
+ free(tmp);
+
+ if (ridno != NULL)
+ free(ridno);
+ }
+
+ av[ac++] = arg_string(UNTRUSTED, "%s", request->request->user);
+ av[ac++] = arg_string(TRUSTED, "%s", clean_title);
+ av[ac++] = arg_string(TRUSTED, "%d", request->copies);
+
+ if (fr_flg)
+ free (clean_title);
+
+ sep = "";
+
+ /*
+ * Do the administrator defined key=value pair options
+ */
+
+ argbuf[0] = '\0';
+
+ if (printer->printer->options) {
+ char **tmp = printer->printer->options;
+ while(*tmp != NULL) {
+ STRLCAT(argbuf, sep, sizeof (argbuf));
+ sep = " ";
+ STRLCAT(argbuf, *tmp++, sizeof (argbuf));
+ }
+ }
+
+ /*
+ * Do the administrator defined ``stty'' stuff before
+ * the user's -o options, to allow the user to override.
+ */
+ if (printer->printer->stty) {
+ STRLCAT (argbuf, sep, sizeof (argbuf));
+ sep = " ";
+ STRLCAT (argbuf, "stty='", sizeof (argbuf));
+ STRLCAT (argbuf, printer->printer->stty,
+ sizeof (argbuf));
+ STRLCAT (argbuf, "'", sizeof (argbuf));
+ }
+
+ /*
+ * Do all of the user's options except the cpi/lpi/etc.
+ * stuff, which is done separately.
+ */
+ if (request->request->options) {
+ listp = dashos(request->request->options);
+ while (*listp) {
+ if (
+ !STRNEQU(*listp, "cpi=", 4)
+ && !STRNEQU(*listp, "lpi=", 4)
+ && !STRNEQU(*listp, "width=", 6)
+ && !STRNEQU(*listp, "length=", 7)
+ ) {
+ STRLCAT (argbuf, sep, sizeof (argbuf));
+ sep = " ";
+ STRLCAT (argbuf, *listp,
+ sizeof (argbuf));
+ }
+ listp++;
+ }
+ }
+
+ /*
+ * The "pickfilter()" routine (from "validate()")
+ * stored the cpi/lpi/etc. stuff that should be
+ * used for this request. It chose form over user,
+ * and user over printer.
+ */
+ if (request->cpi) {
+ STRLCAT (argbuf, sep, sizeof (argbuf));
+ sep = " ";
+ STRLCAT (argbuf, "cpi=", sizeof (argbuf));
+ STRLCAT (argbuf, request->cpi, sizeof (argbuf));
+ }
+ if (request->lpi) {
+ STRLCAT (argbuf, sep, sizeof (argbuf));
+ sep = " ";
+ STRLCAT (argbuf, "lpi=", sizeof (argbuf));
+ STRLCAT (argbuf, request->lpi, sizeof (argbuf));
+ }
+ if (request->pwid) {
+ STRLCAT (argbuf, sep, sizeof (argbuf));
+ sep = " ";
+ STRLCAT (argbuf, "width=", sizeof (argbuf));
+ STRLCAT (argbuf, request->pwid, sizeof (argbuf));
+ }
+ if (request->plen) {
+ STRLCAT (argbuf, sep, sizeof (argbuf));
+ sep = " ";
+ STRLCAT (argbuf, "length=", sizeof (argbuf));
+ STRLCAT (argbuf, request->plen, sizeof (argbuf));
+ }
+
+ /*
+ * Do the ``raw'' bit last, to ensure it gets
+ * done. If the user doesn't want this, then he or
+ * she can do the correct thing using -o stty=
+ * and leaving out the -r option.
+ */
+ if (request->request->actions & ACT_RAW) {
+ STRLCAT (argbuf, sep, sizeof (argbuf));
+ sep = " ";
+ STRLCAT (argbuf, "stty=-opost", sizeof (argbuf));
+ }
+
+
+ /* the "options" */
+ av[ac++] = arg_string(UNTRUSTED, "%s", argbuf);
+
+ for (listp = file_list; *listp; listp++)
+ av[ac++] = arg_string(TRUSTED, "%s", *listp);
+
+ (void)chfiles (file_list, procuid, procgid);
+
+ break;
+
+
+ case EX_SLOWF:
+ if (request->slow)
+ addenv(&envp, "FILTER", request->slow);
+
+ procuid = request->secure->uid;
+ procgid = request->secure->gid;
+
+ cp = _alloc_files(
+ lenlist(request->request->file_list),
+ getreqno(request->secure->req_id),
+ procuid, procgid);
+
+ av[ac++] = arg_string(TRUSTED, "%s", Lp_Slow_Filter);
+ av[ac++] = arg_string(TRUSTED, "%s/%s", Lp_Temp, cp);
+ for (listp = request->request->file_list; *listp; listp++)
+ av[ac++] = arg_string(TRUSTED, "%s", *listp);
+
+ (void)chfiles (request->request->file_list, procuid, procgid);
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * Check if the PAPI job attribute file exists, if it does
+ * pass the file's pathname to the slow-filters in an
+ * environment variable. Note: this file is created when
+ * print jobs are submitted via the PAPI interface.
+ */
+ snprintf(tmpName, sizeof (tmpName), "%s-%s",
+ getreqno(request->secure->req_id), LP_PAPIATTRNAME);
+ path = makepath(Lp_Temp, tmpName, (char *)0);
+ if ((path != NULL) && (stat(path, &tmpBuf) == 0))
+ {
+ /*
+ * IPP job attribute file exists for this job so
+ * set the environment variable
+ */
+ addenv(&envp, "ATTRPATH", path);
+ }
+ Free(path);
+
+
+ /*
+ * now set environment variable for the printer's PostScript
+ * Printer Description (PPD) file, this is used by the filter
+ * when forming the print data for this printer.
+ */
+ if ((request->printer != NULL) &&
+ (request->printer->printer != NULL) &&
+ (request->printer->printer->name != NULL))
+ {
+ snprintf(tmpName, sizeof (tmpName), "%s.ppd",
+ request->printer->printer->name);
+ path = makepath(ETCDIR, "ppd", tmpName, (char *)0);
+ if ((path != NULL) && (stat(path, &tmpBuf) == 0))
+ {
+ addenv(&envp, "PPD", path);
+ }
+ Free(path);
+ }
+#endif
+ break;
+
+ case EX_ALERT:
+ procuid = Lp_Uid;
+ procgid = Lp_Gid;
+ (void)Chown (printer->alert->msgfile, procuid, procgid);
+
+ av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
+ printer->printer->name, ALERTSHFILE);
+ av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
+
+ break;
+
+ case EX_PALERT:
+ procuid = Lp_Uid;
+ procgid = Lp_Gid;
+ (void)Chown (pwheel->alert->msgfile, procuid, procgid);
+
+ av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_PrintWheels,
+ pwheel->pwheel->name, ALERTSHFILE);
+ av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
+
+ break;
+
+ case EX_FALERT:
+ procuid = Lp_Uid;
+ procgid = Lp_Gid;
+ (void)Chown (form->alert->msgfile, procuid, procgid);
+
+ av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
+ form->form->name, ALERTSHFILE);
+ av[ac++] = arg_string(TRUSTED, "%s", printer->alert->msgfile);
+
+ break;
+
+ case EX_FORM_MESSAGE:
+ procuid = Lp_Uid;
+ procgid = Lp_Gid;
+
+ av[ac++] = arg_string(TRUSTED, "%s/form", Lp_A_Faults);
+ av[ac++] = arg_string(TRUSTED, "%s", form->form->name);
+ av[ac++] = arg_string(TRUSTED, "%s", time_buf);
+ av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Forms,
+ form->form->name, FORMMESSAGEFILE);
+
+ break;
+
+ case EX_FAULT_MESSAGE:
+ procuid = Lp_Uid;
+ procgid = Lp_Gid;
+
+ av[ac++] = arg_string(TRUSTED, "%s/printer", Lp_A_Faults);
+ av[ac++] = arg_string(TRUSTED, "%s", printerNameToShow);
+ av[ac++] = arg_string(TRUSTED, "%s", time_buf);
+ av[ac++] = arg_string(TRUSTED, "%s/%s/%s", Lp_A_Printers,
+ printerName, FAULTMESSAGEFILE);
+
+ break;
+
+ case EX_NOTIFY:
+ if (request->request->alert) {
+ procuid = request->secure->uid;
+ procgid = request->secure->gid;
+
+ av[ac++] = arg_string(TRUSTED, "%s",
+ request->request->alert);
+ } else {
+ char *user = strdup(request->request->user);
+ clean_string(user);
+ slabel = request->secure->slabel;
+
+ if (request->request->actions & ACT_WRITE) {
+ av[ac++] = arg_string(TRUSTED, "%s", BINWRITE);
+ snprintf(argbuf, sizeof (argbuf),
+ "%s %s || %s %s",
+ BINWRITE, user,
+ BINMAIL, user
+ );
+ av[ac++] = arg_string(TRUSTED, "/bin/sh");
+ av[ac++] = arg_string(TRUSTED, "-c");
+ av[ac++] = arg_string(TRUSTED, "%s", argbuf);
+ } else if ((getzoneid() == GLOBAL_ZONEID) &&
+ is_system_labeled() && (slabel != NULL)) {
+ /*
+ * If in the global zone and the system is
+ * labeled, mail is handled via a local
+ * labeled zone that is the same label as
+ * the request.
+ */
+ if ((mail_zonename =
+ get_labeled_zonename(slabel)) ==
+ (char *)-1) {
+ /*
+ * Cannot find labeled zone, just
+ * return 0.
+ */
+ return(0);
+ }
+ }
+ if (mail_zonename == NULL) {
+ procuid = Lp_Uid;
+ procgid = Lp_Gid;
+ av[ac++] = arg_string(TRUSTED, "%s", BINMAIL);
+ av[ac++] = arg_string(UNTRUSTED, "%s", user);
+ } else {
+ procuid = getuid();
+ procgid = getgid();
+ av[ac++] = arg_string(TRUSTED, "%s",
+ "/usr/sbin/zlogin");
+ av[ac++] = arg_string(TRUSTED, "%s",
+ mail_zonename);
+ av[ac++] = arg_string(TRUSTED, "%s",
+ BINMAIL);
+ av[ac++] = arg_string(UNTRUSTED, "%s",
+ user);
+ Free(mail_zonename);
+ }
+
+ free(user);
+ }
+ break;
+ }
+
+ av[ac++] = NULL;
+
+ Fork2 ();
+ /* only the child returns */
+
+ /*
+ * Correctly set up the supplemental group list
+ * for proper file access (before execl the interface program)
+ */
+
+ pwp = getpwuid(procuid);
+ if (pwp == NULL) {
+ note("getpwuid(%d) call failed\n", procuid);
+ } else if (initgroups(pwp->pw_name, procgid) < 0) {
+ note("initgroups() call failed %d\n", errno);
+ }
+
+ setgid (procgid);
+ setuid (procuid);
+
+ /*
+ * The shell doesn't allow the "trap" builtin to set a trap
+ * for a signal ignored when the shell is started. Thus, don't
+ * turn off signals in the last child!
+ */
+
+#ifdef DEBUG
+ for (i = 0; av[i] != NULL; i++)
+ note("exec(%s): av[%d] = %s", _exec_name(type), i, av[i]);
+ for (i = 0; envp[i] != NULL; i++)
+ note("exec(%s): envp[%d] = %s", _exec_name(type), i, envp[i]);
+#endif
+
+ execvpe(av[0], av, envp);
+ Done (EXEC_EXIT_NEXEC, errno);
+ /*NOTREACHED*/
+ return (0);
+}
+
+/**
+ ** addenv() - ADD A VARIABLE TO THE ENVIRONMENT
+ **/
+
+static void
+addenv(char ***envp, char *name, char *value)
+{
+ register char * cp;
+
+ if ((name == NULL) || (value == NULL))
+ return;
+
+ if ((cp = makestr(name, "=", value, (char *)0)))
+ addlist(envp, cp);
+ return;
+}
+
+/**
+ ** Fork1() - FORK FIRST CHILD, SET UP CONNECTION TO IT
+ **/
+
+static int
+Fork1(EXEC *ep)
+{
+ int pid;
+ int fds[2];
+
+ if (pipe(fds) == -1) {
+ note("Failed to create pipe for child process (%s).\n", PERROR);
+ errno = EAGAIN ;
+ return(-1);
+ }
+
+ ep->md = mconnect((char *)0, fds[0], fds[1]);
+
+ switch (pid = fork()) {
+
+ case -1:
+ mdisconnect(ep->md);
+ close(fds[0]);
+ close(fds[1]);
+ ep->md = 0;
+ return (-1);
+
+ case 0:
+ ChildMd = mconnect(NULL, fds[1], fds[1]);
+ return (0);
+
+ default:
+ mlistenadd(ep->md, POLLIN);
+ return (pid);
+ }
+}
+
+/**
+ ** Fork2() - FORK SECOND CHILD AND WAIT FOR IT
+ **/
+
+static void
+Fork2(void)
+{
+ switch ((ChildPid = fork())) {
+
+ case -1:
+ Done (EXEC_EXIT_NFORK, errno);
+ /*NOTREACHED*/
+
+ case 0:
+ return;
+
+ default:
+ /*
+ * Delay calling "ignore_fault_signals()" as long
+ * as possible, to give the child a chance to exec
+ * the interface program and turn on traps.
+ */
+
+ cool_heels ();
+ /*NOTREACHED*/
+
+ }
+}
+
+
+/**
+ ** cool_heels() - WAIT FOR CHILD TO "DIE"
+ **/
+
+static void
+cool_heels(void)
+{
+ int status;
+
+ /*
+ * At this point our only job is to wait for the child process.
+ * If we hang out for a bit longer, that's okay.
+ * By delaying before turning off the fault signals,
+ * we increase the chance that the child process has completed
+ * its exec and has turned on the fault traps. Nonetheless,
+ * we can't guarantee a zero chance of missing a fault.
+ * (We don't want to keep trapping the signals because the
+ * interface program is likely to have a better way to handle
+ * them; this process provides only rudimentary handling.)
+ *
+ * Note that on a very busy system, or with a very fast interface
+ * program, the tables could be turned: Our sleep below (coupled
+ * with a delay in the kernel scheduling us) may cause us to
+ * detect the fault instead of the interface program.
+ *
+ * What we need is a way to synchronize with the child process.
+ */
+ sleep (1);
+ ignore_fault_signals ();
+
+ WaitedChildPid = 0;
+ while ((WaitedChildPid = wait(&status)) != ChildPid)
+ ;
+
+ if (
+ EXITED(status) > EXEC_EXIT_USER
+ && EXITED(status) != EXEC_EXIT_FAULT
+ )
+ Done (EXEC_EXIT_EXIT, EXITED(status));
+
+ done (status, 0); /* Don't use Done() */
+ /*NOTREACHED*/
+}
+
+
+/**
+ ** trap_fault_signals() - TRAP SIGNALS THAT CAN OCCUR ON PRINTER FAULT
+ ** ignore_fault_signals() - IGNORE SAME
+ **/
+
+static void
+trap_fault_signals(void)
+{
+ signal (SIGHUP, sigtrap);
+ signal (SIGINT, sigtrap);
+ signal (SIGQUIT, sigtrap);
+ signal (SIGPIPE, sigtrap);
+ return;
+}
+
+static void
+ignore_fault_signals(void)
+{
+ signal (SIGHUP, SIG_IGN);
+ signal (SIGINT, SIG_IGN);
+ signal (SIGQUIT, SIG_IGN);
+ signal (SIGPIPE, SIG_IGN);
+ return;
+}
+
+/**
+ ** sigtrap() - TRAP VARIOUS SIGNALS
+ **/
+
+static void
+sigtrap(int sig)
+{
+ signal (sig, SIG_IGN);
+ switch (sig) {
+
+ case SIGHUP:
+ Done (EXEC_EXIT_HUP, 0);
+ /*NOTREACHED*/
+
+ case SIGQUIT:
+ case SIGINT:
+ Done (EXEC_EXIT_INTR, 0);
+ /*NOTREACHED*/
+
+ case SIGPIPE:
+ Done (EXEC_EXIT_PIPE, 0);
+ /*NOTREACHED*/
+
+ case SIGTERM:
+ /*
+ * If we were killed with SIGTERM, it should have been
+ * via the Spooler who should have killed the entire
+ * process group. We have to wait for the children,
+ * since we're their parent, but WE MAY HAVE WAITED
+ * FOR THEM ALREADY (in cool_heels()).
+ */
+ if (ChildPid != WaitedChildPid) {
+ register int cpid;
+
+ while (
+ (cpid = wait((int *)0)) != ChildPid
+ && (cpid != -1 || errno != ECHILD)
+ )
+ ;
+ }
+
+ /*
+ * We can't rely on getting SIGTERM back in the wait()
+ * above, because, for instance, some shells trap SIGTERM
+ * and exit instead. Thus we force it.
+ */
+ done (SIGTERM, 0); /* Don't use Done() */
+ /*NOTREACHED*/
+ }
+}
+
+/**
+ ** done() - TELL SPOOLER THIS CHILD IS DONE
+ **/
+
+static void
+done(int status, int err)
+{
+ if (do_undial)
+ undial (1);
+
+ mputm (ChildMd, S_CHILD_DONE, key, status, err);
+ mdisconnect (ChildMd);
+
+ exit (0);
+ /*NOTREACHED*/
+}
+
+/**
+ ** child_mallocfail()
+ **/
+
+static void
+child_mallocfail(void)
+{
+ Done (EXEC_EXIT_NOMEM, ENOMEM);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/faults.c b/usr/src/cmd/lp/cmd/lpsched/faults.c
new file mode 100644
index 0000000000..d6ee713356
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/faults.c
@@ -0,0 +1,220 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "lpsched.h"
+#include <syslog.h>
+
+static char *
+shortenReason(char *reason)
+{
+ register char *ptr, *pe;
+ int peLen;
+
+ if (strncmp(reason,"%%[",3) == 0)
+ reason += 3;
+
+ while (*reason == ' ')
+ reason++;
+
+ pe = "PrinterError:";
+ peLen = strlen(pe);
+ if (strncmp(reason,pe,peLen) == 0)
+ reason += peLen;
+
+ if (((ptr = strchr(reason,']')) != NULL) && (strncmp(ptr,"]%%",3) == 0))
+ *ptr = 0;
+
+ pe = reason + strlen(reason) -1;
+ pe = reason;
+ while (pe = strchr(pe,'\n'))
+ *pe = ' ';
+
+ pe = reason + strlen(reason) -1;
+ while ((pe > reason) && (*pe == ' ')) {
+ *pe = 0;
+ pe--;
+ }
+ return(reason);
+}
+
+/**
+ ** printer_fault() - RECOGNIZE PRINTER FAULT
+ **/
+
+void
+printer_fault(register PSTATUS *pps, register RSTATUS *prs, char *alert_text,
+ int err)
+{
+ register char *why,*shortWhy;
+
+ pps->status |= PS_FAULTED;
+
+ /* -F wait */
+ if (STREQU(pps->printer->fault_rec, NAME_WAIT))
+ disable (pps, CUZ_FAULT, DISABLE_STOP);
+
+ /* -F beginning */
+ else if (STREQU(pps->printer->fault_rec, NAME_BEGINNING))
+ terminate (pps->exec);
+
+ /* -F continue AND the interface program died */
+ else if (!(pps->status & PS_LATER) && !pps->request) {
+ load_str (&pps->dis_reason, CUZ_STOPPED);
+ schedule (EV_LATER, WHEN_PRINTER, EV_ENABLE, pps);
+ }
+
+ if (err) {
+ errno = err;
+ why = makestr(alert_text, "(", PERROR, ")\n", (char *)0);
+ } else if (! alert_text)
+ why = makestr("exec exit fault", (char *) 0);
+ else
+ why = makestr(alert_text, (char *) 0);
+
+ if (!why)
+ why = alert_text;
+
+ shortWhy = (why != alert_text ? shortenReason(why) : why);
+
+ load_str (&pps->fault_reason, shortWhy);
+ dump_fault_status (pps);
+ if (STREQU(pps->printer->fault_alert.shcmd,"show fault"))
+ pps->status |= PS_SHOW_FAULT;
+ else
+ pps->status &= ~PS_SHOW_FAULT;
+
+ note("printer fault. type: %s, status: %x\nmsg: (%s)\n",
+ (pps->printer->fault_alert.shcmd ?
+ pps->printer->fault_alert.shcmd : "??"),
+ pps->status, shortWhy);
+
+ if (pps->status & PS_SHOW_FAULT)
+ schedule (EV_MESSAGE, pps);
+ else {
+ alert(A_PRINTER, pps, prs, shortWhy);
+ }
+ if (why != alert_text)
+ Free (why);
+}
+
+/**
+ ** clear_printer_fault() - RECOGNIZE PRINTER FAULT
+ **/
+
+void
+clear_printer_fault(register PSTATUS *pps, char *alert_text)
+{
+ register char *why, *shortWhy;
+
+ pps->status &= ~PS_FAULTED;
+
+ why = makestr(alert_text, (char *) 0);
+
+ shortWhy = (why ? shortenReason(why) : alert_text);
+
+ load_str (&pps->fault_reason, shortWhy);
+ dump_fault_status (pps);
+ if (STREQU(pps->printer->fault_alert.shcmd,"show fault"))
+ pps->status |= PS_SHOW_FAULT;
+ else
+ pps->status &= ~PS_SHOW_FAULT;
+
+ if (pps->status & PS_SHOW_FAULT)
+ schedule (EV_MESSAGE, pps);
+ if (why != alert_text)
+ Free(why);
+ schedule(EV_ENABLE, pps);
+}
+
+/**
+ ** dial_problem() - ADDRESS DIAL-OUT PROBLEM
+ **/
+
+void
+dial_problem(register PSTATUS *pps, RSTATUS *prs, int rc)
+{
+ static struct problem {
+ char *reason;
+ int retry_max,
+ dial_error;
+ } problems[] = {
+ "DIAL FAILED", 10, 2, /* D_HUNG */
+ "CALLER SCRIPT FAILED", 10, 3, /* NO_ANS */
+ "CAN'T ACCESS DEVICE", 0, 6, /* L_PROB */
+ "DEVICE LOCKED", 20, 8, /* DV_NT_A */
+ "NO DEVICES AVAILABLE", 0, 10, /* NO_BD_A */
+ "SYSTEM NOT IN Systems FILE", 0, 13, /* BAD_SYS */
+ "UNKNOWN dial() FAILURE", 0, 0
+ };
+
+ register struct problem *p;
+
+ register char *msg;
+
+#define PREFIX "Connect problem: "
+#define SUFFIX "This problem has occurred several times.\nPlease check the dialing instructions for this printer.\n"
+
+
+ for (p = problems; p->dial_error; p++)
+ if (p->dial_error == rc)
+ break;
+
+ if (!p->retry_max) {
+ msg = Malloc(strlen(PREFIX) + strlen(p->reason) + 2);
+ sprintf (msg, "%s%s\n", PREFIX, p->reason);
+ printer_fault (pps, prs, msg, 0);
+ Free (msg);
+
+ } else if (pps->last_dial_rc != rc) {
+ pps->nretry = 1;
+ pps->last_dial_rc = (short)rc;
+
+ } else if (pps->nretry++ > p->retry_max) {
+ pps->nretry = 0;
+ pps->last_dial_rc = (short)rc;
+ msg = Malloc(
+ strlen(PREFIX) + strlen(p->reason) + strlen(SUFFIX) + 2
+ );
+ sprintf (msg, "%s%s%s\n", PREFIX, p->reason, SUFFIX);
+ printer_fault (pps, prs, msg, 0);
+ Free (msg);
+ }
+
+ if (!(pps->status & PS_FAULTED)) {
+ load_str (&pps->dis_reason, p->reason);
+ schedule (EV_LATER, WHEN_PRINTER, EV_ENABLE, pps);
+ }
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/files.c b/usr/src/cmd/lp/cmd/lpsched/files.c
new file mode 100644
index 0000000000..00f2ac85be
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/files.c
@@ -0,0 +1,456 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "lpsched.h"
+#include <syslog.h>
+#include <strings.h>
+
+static char time_buf[50];
+#ifdef LP_USE_PAPI_ATTR
+static char *extractReqno(char *req_file);
+#endif
+
+/**
+ ** chfiles() - CHANGE OWNERSHIP OF FILES, RETURN TOTAL SIZE
+ **/
+
+off_t chfiles ( char * * list, uid_t uid, gid_t gid ) /* funcdef */
+{
+ size_t total;
+ struct stat stbuf;
+ char *file;
+
+ total = 0;
+
+ while(file = *list++)
+ {
+ if (STRNEQU(Lp_Temp, file, strlen(Lp_Temp)) ||
+ STRNEQU(Lp_Tmp, file, strlen(Lp_Tmp)))
+ {
+ /*
+ * Once this routine (chfiles) is called for a request,
+ * any temporary files are ``ours'', i.e. they are on our
+ * machine. A user running on an RFS-connected remote machine
+ * can't necessarily know our machine name, so can't put
+ * the files where they belong (Lp_Tmp/machine). But now we
+ * can. Of course, this is all done with mirrors, as Lp_Temp
+ * and Lp_Tmp/local-machine are symbolicly linked. So we just
+ * change the name. This saves on wear and tear later.
+ */
+ if (STRNEQU(Lp_Temp, file, strlen(Lp_Temp)))
+ {
+ char *newfile = makepath(Lp_Tmp, Local_System,
+ file + strlen(Lp_Temp) + 1, NULL);
+
+ Free(file);
+ list[-1] = file = newfile;
+ }
+
+ (void) chownmod(file, uid, gid, 0600);
+ }
+
+ if (Stat(file, &stbuf) == -1)
+ return(-1);
+
+ switch (stbuf.st_mode & S_IFMT) {
+ case 0:
+ case S_IFREG:
+ break;
+
+ case S_IFIFO:
+ if (!isadmin(uid))
+ return(-1);
+ /*
+ * If any of the files is a FIFO, the size indicator
+ * becomes meaningless. On the other hand, returning
+ * a total of zero causes the request to be rejected,
+ * so we return something > 0.
+ */
+ stbuf.st_size = 1;
+ break;
+
+ case S_IFDIR:
+ case S_IFCHR:
+ case S_IFBLK:
+ default:
+ return(-1);
+ }
+
+ total += stbuf.st_size;
+ }
+ return(total);
+}
+
+/**
+ ** rmfiles() - DELETE/LOG FILES FOR DEFUNCT REQUEST
+ **/
+
+void rmfiles ( RSTATUS * rp, int log_it ) /* funcdef */
+{
+ char **file = rp->request->file_list;
+ char *path;
+ char num[STRSIZE(MOST_FILES) + 1];
+ static int fd = -1;
+ int reqfd;
+ int count = 0;
+#ifdef LP_USE_PAPI_ATTR
+ struct stat tmpBuf;
+ char *idno = NULL;
+ char tmpName[BUFSIZ];
+#endif
+
+
+ if (rp->req_file) {
+ char *p, *q;
+
+ /*
+ * The secure request file is removed first to prevent
+ * reloading should the system crash while in rmfiles().
+ */
+ path = makepath(Lp_Requests, rp->req_file, (char *)0);
+ (void) Unlink(path);
+ Free(path);
+
+ /*
+ * Copy the request file to the log file, if asked,
+ * or simply remove it.
+ */
+ path = makepath(Lp_Tmp, rp->req_file, (char *)0);
+ if (log_it && rp->secure && rp->secure->req_id) {
+ if (fd == -1)
+ fd = open_locked(Lp_ReqLog, "a", MODE_NOREAD);
+ if ((fd >= 0) && (reqfd = Open(path, O_RDONLY, 0)) != -1) {
+ register int n;
+ char buf[BUFSIZ];
+
+ (void) strftime(time_buf, sizeof (time_buf),
+ NULL, localtime(&(rp->secure->date)));
+ fdprintf(fd, "= %s, uid %u, gid %u, size %ld, %s\n",
+ rp->secure->req_id, rp->secure->uid, rp->secure->gid,
+ rp->secure->size, time_buf);
+ if (rp->slow)
+ fdprintf(fd, "x %s\n", rp->slow);
+ if (rp->fast)
+ fdprintf(fd, "y %s\n", rp->fast);
+ if (rp->printer && rp->printer->printer)
+ fdprintf(fd, "z %s\n", rp->printer->printer->name);
+ while ((n = Read(reqfd, buf, BUFSIZ)) > 0)
+ write (fd, buf, n);
+ Close (reqfd);
+ }
+ }
+ (void)Unlink (path); /* remove request file */
+ Free (path);
+
+ p = strdup(rp->req_file); /* remove host/id file */
+ if (q = strrchr(p, '-')) {
+ *q = NULL;
+ path = makepath(Lp_Tmp, p, NULL);
+ (void) Unlink(path);
+ Free(path);
+ }
+ Free(p);
+
+#ifdef LP_USE_PAPI_ATTR
+ /* Look for a PAPI job attribute file, if it exists remove it */
+ idno = extractReqno(rp->req_file);
+ snprintf(tmpName, sizeof (tmpName), "%s-%s", idno, LP_PAPIATTRNAME);
+ path = makepath(Lp_Temp, tmpName, (char *)0);
+
+ if (((path != NULL) && (idno != NULL)) && (stat(path, &tmpBuf) == 0))
+ {
+ /* PAPI job attribute file exists for this job so remove it */
+ (void) Unlink(path);
+ }
+
+ Free(idno);
+ Free(path);
+#endif
+ }
+
+ if (file) /* remove file in filelist */
+ while(*file)
+ {
+ /*
+ * The copies of user files.
+ */
+ if ((STRNEQU(Lp_Temp, *file, strlen(Lp_Temp)) ||
+ STRNEQU(Lp_Tmp, *file, strlen(Lp_Tmp))) &&
+ (! strstr(*file, "../")))
+
+ (void) Unlink(*file);
+
+ count++;
+ file++;
+ }
+
+ if (rp->secure && rp->secure->req_id) {
+ char *p;
+ p = getreqno(rp->secure->req_id);
+
+ /*
+ * The filtered files. We can't rely on just the RS_FILTERED
+ * flag, since the request may have been cancelled while
+ * filtering. On the other hand, just checking "rp->slow"
+ * doesn't mean that the files exist, because the request
+ * may have been canceled BEFORE filtering started. Oh well.
+ */
+ if (rp->slow)
+ while(count > 0)
+ {
+ sprintf(num, "%d", count--);
+ path = makestr(Lp_Temp, "/F", p, "-", num, (char *)0);
+ Unlink(path);
+ Free(path);
+ }
+
+ /*
+ * The notify/error file.
+ */
+ path = makepath(Lp_Temp, p, (char *)0);
+ (void) Unlink(path);
+ Free(path);
+ }
+}
+
+/**
+ ** _alloc_req_id(void) - ALLOCATE NEXT REQUEST ID
+ **/
+
+#define SEQF_DEF_START 1
+#define SEQF_DEF_END 59999
+#define SEQF_DEF_INCR 1
+#define SEQF ".SEQF"
+
+
+long
+_alloc_req_id ( void )
+{
+ static short started = 0;
+
+ static int fd;
+
+ static long start;
+ static long end;
+ static long incr;
+ static long curr;
+ static long wrap;
+
+ static char fmt[
+ STRSIZE(BIGGEST_REQID_S)/* start */
+ + 1 /* : */
+ + STRSIZE(BIGGEST_REQID_S)/* end */
+ + 1 /* : */
+ + STRSIZE(BIGGEST_REQID_S)/* incr */
+ + 1 /* : */
+ + 4 /* %ld\n */
+ + 1 /* (nul) */
+ ];
+
+ char buf[256];
+ int len;
+
+ long ret;
+
+
+ if (!started) {
+ snprintf(buf, sizeof (buf), "%s/%s", Lp_Temp, SEQF);
+ if (((fd = open_locked(buf, "r+", 0644)) < 0) &&
+ ((fd = open_locked(buf, "w", 0644)) < 0))
+ fail ("Can't open file %s (%s).\n", buf, PERROR);
+
+ lseek(fd, 0, SEEK_SET);
+
+ read(fd, buf, sizeof (buf));
+ if (sscanf(buf, "%ld:%ld:%ld:%ld\n", &start, &end, &incr, &curr) != 4) {
+ start = SEQF_DEF_START;
+ end = SEQF_DEF_END;
+ curr = start;
+ incr = SEQF_DEF_INCR;
+ }
+
+ if (start < 0)
+ start = SEQF_DEF_START;
+ if (end > SEQF_DEF_END)
+ end = SEQF_DEF_END;
+ if (curr < start || curr > end)
+ curr = start;
+
+ sprintf (fmt, "%ld:%ld:%ld:%%ld\n", start, end, incr);
+ started = 1;
+ }
+
+ wrap = curr;
+ do {
+ ret = curr;
+ if ((curr += incr) > end)
+ curr = start;
+
+ } while ( wrap != curr && ((RSTATUS *)request_by_id_num(ret)) ) ;
+
+ /* write the new id file */
+ lseek(fd, 0, SEEK_SET);
+ len = sprintf(buf, fmt, curr);
+ write(fd, buf, len);
+ ftruncate(fd, len);
+
+ if (curr == wrap) {
+ note("alloc_req_id(): out of ids\n");
+ errno = EEXIST;
+ return(SEQF_DEF_START-1);
+ } else
+ return (ret);
+}
+
+/**
+ ** _alloc_file() - ALLOCATE FILES FOR A REQUEST
+ **/
+
+char *
+_alloc_files (
+ int num,
+ char * prefix,
+ uid_t uid,
+ gid_t gid
+)
+{
+ static char base[
+ 1 /* F */
+ + STRSIZE(BIGGEST_REQID_S)/* req-id */
+ + 1 /* - */
+ + STRSIZE(MOST_FILES_S) /* file-no */
+ + 1 /* (nul) */
+ ];
+
+ char * file;
+ char * cp;
+
+ int fd;
+ int plus;
+
+
+ if (num > BIGGEST_REQID)
+ return (0);
+
+ if (!prefix) {
+ int id;
+
+ if ((id = _alloc_req_id()) < SEQF_DEF_START )
+ return(NULL); /* Out of request IDs (errno = EEXIST) */
+ snprintf (base, sizeof (base), "%d-%d", id, MOST_FILES);
+ plus = 0;
+ } else {
+ if (strlen(prefix) > (size_t) 6)
+ return (0);
+ snprintf (base, sizeof (base), "F%s-%d", prefix, MOST_FILES);
+ plus = 1;
+ }
+
+ file = makepath(Lp_Temp, base, (char *)0);
+
+ cp = strrchr(file, '-') + 1;
+ while (num--) {
+ sprintf (cp, "%d", num + plus);
+ if ((fd = Open(file, O_CREAT|O_TRUNC, 0600)) == -1) {
+ Free (file);
+ return (0);
+ } else {
+ Close (fd);
+ (void) chownmod(file, uid, gid, 0600);
+ }
+ }
+
+#ifdef LP_USE_PAPI_ATTR
+ if (prefix == NULL)
+ {
+ /*
+ * Initial job request (s_alloc_files) so create an empty PAPI
+ * Attribute file; note, this file will only be used if the
+ * print job has been submitted via the PAPI interface.
+ */
+
+ file = (char *)Realloc(file, strlen(file) +
+ strlen(LP_PAPIATTRNAME) + 1);
+ if (file != NULL)
+ {
+ cp = strrchr(file, '-') + 1;
+ sprintf(cp, "%s", LP_PAPIATTRNAME);
+
+ if ((fd = Open(file, O_CREAT|O_TRUNC, 0600)) == -1)
+ {
+ Free(file);
+ return (0);
+ }
+ else
+ {
+ Close(fd);
+ (void) chownmod(file, uid, gid, 0600);
+ }
+
+ Free(file);
+ }
+ }
+#endif
+
+
+ if ((cp = strrchr(base, '-')))
+ *cp = 0;
+
+ return (base);
+}
+
+
+#ifdef LP_USE_PAPI_ATTR
+static char *extractReqno(char *req_file)
+
+{
+ char *start = NULL;
+ char *end = NULL;
+ char *result = NULL;
+
+ start = strrchr(req_file, '/');
+ end = strrchr(req_file, '-');
+
+ if ((start != NULL) && (end != NULL))
+ {
+ start++;
+ if (end > start)
+ {
+ int n = end - start;
+ result = (char *)Malloc(n+1);
+ strncpy(result, start, n);
+ result[n] = '\0';
+ }
+ }
+
+ return (result);
+} /* extractReqno() */
+#endif
diff --git a/usr/src/cmd/lp/cmd/lpsched/flt.c b/usr/src/cmd/lp/cmd/lpsched/flt.c
new file mode 100644
index 0000000000..dc96387354
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/flt.c
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+# include <stdarg.h>
+# include "lpsched.h"
+
+typedef struct fault FLT;
+
+struct fault
+{
+ FLT * next;
+ int type;
+ int i1;
+ char * s1;
+ RSTATUS * r1;
+ MESG * ident;
+};
+
+static void free_flt ( FLT * );
+static void do_flt_acts ( MESG * );
+
+static FLT Fault_Head = { NULL, 0, 0, NULL, NULL, NULL };
+static FLT * Fault_List = &Fault_Head;
+
+void
+add_flt_act(MESG * md, ...)
+{
+ va_list arg;
+ FLT *f;
+
+ va_start (arg, md);
+
+ f = (FLT *)Malloc(sizeof(FLT));
+
+ (void) memset((char *)f, 0, sizeof(FLT));
+
+ f->type = (int)va_arg(arg, int);
+ f->ident = md;
+
+ if (md->on_discon == NULL)
+ if (mon_discon(md, do_flt_acts))
+ mallocfail();
+
+ switch(f->type)
+ {
+ case FLT_FILES:
+ f->s1 = Strdup((char *)va_arg(arg, char *));
+ f->i1 = (int)va_arg(arg, int);
+ break;
+
+ case FLT_CHANGE:
+ f->r1 = (RSTATUS *)va_arg(arg, RSTATUS *);
+ break;
+ }
+
+ va_end(arg);
+
+ f->next = Fault_List->next;
+ Fault_List->next = f;
+}
+
+
+void
+del_flt_act(MESG *md, ...)
+{
+ va_list arg;
+ int type;
+ FLT *fp;
+ FLT *f;
+
+ va_start(arg, md);
+
+ type = (int)va_arg(arg, int);
+
+ for (f = Fault_List; f->next; f = f->next)
+ if (f->next->type == type && f->next->ident == md)
+ {
+ fp = f->next;
+ f->next = f->next->next;
+ free_flt(fp);
+ break;
+ }
+
+ va_end(arg);
+}
+
+static void
+do_flt_acts(MESG *md)
+{
+ FLT *f;
+ FLT *fp;
+ char *file;
+ char id[15];
+#ifdef LP_USE_PAPI_ATTR
+ struct stat tmpBuf;
+ char attrFile[BUFSIZ];
+#endif
+
+ for (f = Fault_List; f && f->next; f = f->next)
+ if (f->next->ident == md)
+ {
+ fp = f->next;
+ f->next = f->next->next;
+
+ switch (fp->type)
+ {
+ case FLT_FILES:
+ /* remove files created with alloc_files */
+
+ while(fp->i1--)
+ {
+ (void) snprintf(id, sizeof (id), "%s-%d", fp->s1, fp->i1);
+ file = makepath(Lp_Temp, id, (char *)0);
+ (void) Unlink(file);
+ Free(file);
+ }
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * check if the PAPI attribute file exists, if it does delete it
+ */
+ (void) snprintf(attrFile, sizeof (attrFile),
+ "%s-%s", fp->s1, LP_PAPIATTRNAME);
+ file = makepath(Lp_Temp, attrFile, (char *)0);
+ if ((file != NULL) && (stat(file, &tmpBuf) == 0))
+ {
+ (void) Unlink(file);
+ }
+ Free(file);
+#endif
+ break;
+
+
+ case FLT_CHANGE:
+ /* clear RS_CHANGE bit, write request file, and schedule */
+ fp->r1->request->outcome &= ~RS_CHANGING;
+ putrequest(fp->r1->req_file, fp->r1->request);
+ if (NEEDS_FILTERING(fp->r1))
+ schedule(/* LP_FILTER */ EV_SLOWF, fp->r1);
+ else
+ schedule(/* LP_PRINTER */ EV_INTERF, fp->r1->printer);
+ break;
+ }
+ free_flt(fp);
+ }
+}
+
+static void
+free_flt(FLT *f)
+{
+ if (f->s1)
+ Free(f->s1);
+ Free((char *)f);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/fncs.c b/usr/src/cmd/lp/cmd/lpsched/fncs.c
new file mode 100644
index 0000000000..b99815b0f1
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/fncs.c
@@ -0,0 +1,996 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "unistd.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "errno.h"
+#include "fcntl.h"
+#include "stdlib.h"
+#include "string.h"
+
+#include "lpsched.h"
+
+static int __list_increment = 16;
+
+int
+list_append(void ***list, void *item)
+{
+ int count;
+
+ if ((list == NULL) || (item == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (item != NULL) {
+ if (*list == NULL)
+ *list = (void **)calloc(__list_increment,
+ sizeof (void *));
+
+ if (*list == NULL)
+ return (-1);
+
+ for (count = 0; (*list)[count] != NULL; count++);
+
+ if ((count + 1) % __list_increment == 0) { /* expand the list */ void **new_list = NULL;
+ int new_size = (((count + 1) / __list_increment) + 1) *
+ __list_increment;
+
+ new_list = (void **)calloc(new_size, sizeof (void *));
+ if (new_list == NULL)
+ return (-1);
+
+ for (count = 0; (*list)[count] != NULL; count++)
+ new_list[count] = (*list)[count];
+ free(*list);
+ *list = new_list;
+ }
+
+ (*list)[count] = item;
+ }
+
+ return (0);
+}
+
+void
+list_remove(void ***list, void *item)
+{
+ int i, count;
+ void **tmp = NULL;
+
+ if ((list == NULL) || (*list == NULL) || (item == NULL))
+ return;
+
+ for (count = 0; (*list)[count] != NULL; count++)
+ ;
+
+ if (count > 0) {
+ int new_size = (((count + 1) / __list_increment) + 1) *
+ __list_increment;
+
+ if ((tmp = (void **)calloc(new_size, sizeof (void *))) == NULL)
+ tmp = *list;
+
+ /* copy up to item */
+ for (i = 0; (((*list)[i] != NULL) && ((*list)[i] != item)); i++)
+ tmp[i] = (*list)[i];
+ /* copy after item */
+ if ((*list)[i] == item)
+ for (++i; ((*list)[i] != NULL); i++)
+ tmp[i-1] = (*list)[i];
+ }
+
+ /* replace the list */
+ if (tmp != *list) {
+ free(*list);
+ *list = tmp;
+ }
+}
+
+void
+free_exec(EXEC *ep)
+{
+ if (ep != NULL) {
+ free(ep);
+ list_remove((void ***)&Exec_Table, (void *)ep);
+ }
+}
+
+EXEC *
+new_exec(int type, void *ex)
+{
+ EXEC *result = calloc(1, sizeof (*result));
+
+ if (result != NULL) {
+ result->type = type;
+ switch (type) {
+ case EX_ALERT:
+ case EX_INTERF:
+ case EX_FAULT_MESSAGE:
+ result->ex.printer = ex;
+ break;
+ case EX_FALERT:
+ result->ex.form = ex;
+ break;
+ case EX_PALERT:
+ result->ex.pwheel = ex;
+ break;
+ case EX_SLOWF:
+ case EX_NOTIFY:
+ break;
+ }
+ list_append((void ***)&Exec_Table, (void *)result);
+ }
+
+ return (result);
+}
+
+void
+free_alert(ALERT *ap)
+{
+ if (ap != NULL) {
+ if (ap->msgfile != NULL)
+ free(ap->msgfile);
+ if (ap->exec != NULL)
+ free_exec(ap->exec);
+ free(ap);
+ }
+}
+
+ALERT *
+new_alert(char *fmt, int i)
+{
+ ALERT *result = calloc(1, sizeof (*result));
+
+ if (result != NULL) {
+ char buf[15];
+
+ snprintf(buf, sizeof (buf), fmt, i);
+ result->msgfile = makepath(Lp_Temp, buf, (char *)0);
+ (void) Unlink(result->msgfile);
+ }
+
+ return (result);
+}
+
+void
+free_pstatus(PSTATUS *psp)
+{
+ if (psp != NULL) {
+ if (psp->alert != NULL)
+ free_alert(psp->alert);
+ if (psp->exec != NULL)
+ free_exec(psp->exec);
+ if (psp->fault_exec != NULL)
+ free_exec(psp->fault_exec);
+ if (psp->printer != NULL)
+ freeprinter(psp->printer);
+ if (psp->pwheel_name != NULL)
+ free(psp->pwheel_name);
+ if (psp->dis_reason != NULL)
+ free(psp->dis_reason);
+ if (psp->rej_reason != NULL)
+ free(psp->rej_reason);
+ if (psp->users_allowed != NULL)
+ unload_list(&psp->users_allowed);
+ if (psp->users_denied != NULL)
+ unload_list(&psp->users_denied);
+ if (psp->forms_allowed != NULL)
+ unload_list(&psp->forms_allowed);
+ if (psp->forms_denied != NULL)
+ unload_list(&psp->forms_denied);
+ if (psp->cpi != NULL)
+ free(psp->cpi);
+ if (psp->lpi != NULL)
+ free(psp->lpi);
+ if (psp->plen != NULL)
+ free(psp->plen);
+ if (psp->pwid != NULL)
+ free(psp->pwid);
+ if (psp->fault_reason != NULL)
+ free(psp->fault_reason);
+ if (psp->paper_allowed != NULL)
+ unload_list(&psp->paper_allowed);
+ free(psp);
+ }
+}
+
+void
+pstatus_add_printer(PSTATUS *ps, PRINTER *p)
+{
+ if ((ps != NULL) && (p != NULL)) {
+ char **paperDenied = NULL;
+
+ ps->printer = p;
+ load_userprinter_access(p->name, &(ps->users_allowed),
+ &(ps->users_denied));
+ load_formprinter_access(p->name, &(ps->forms_allowed),
+ &(ps->forms_denied));
+ load_paperprinter_access(p->name, &ps->paper_allowed,
+ &paperDenied);
+ freelist(paperDenied);
+ load_sdn(&(ps->cpi), p->cpi);
+ load_sdn(&(ps->lpi), p->lpi);
+ load_sdn(&(ps->plen), p->plen);
+ load_sdn(&(ps->pwid), p->pwid);
+ }
+}
+
+PSTATUS *
+new_pstatus(PRINTER *p)
+{
+ PSTATUS *result = calloc(1, sizeof (*result));
+
+ if (result != NULL) {
+ static int i = 0;
+ char **paperDenied = NULL;
+
+ result->alert = new_alert("A-%d", i++);
+ result->alert->exec = new_exec(EX_ALERT, result);
+ result->exec = new_exec(EX_INTERF, result);
+ result->fault_exec = new_exec(EX_FAULT_MESSAGE, result);
+
+ if (p != NULL)
+ pstatus_add_printer(result, p);
+
+ list_append((void ***)&PStatus, (void *)result);
+ }
+
+ return (result);
+}
+
+void
+free_cstatus(CSTATUS *csp)
+{
+ if (csp != NULL) {
+ if (csp->rej_reason != NULL)
+ free(csp->rej_reason);
+ if (csp->class != NULL)
+ freeclass(csp->class);
+ free(csp);
+ }
+}
+
+CSTATUS *
+new_cstatus(CLASS *c)
+{
+ CSTATUS *result = calloc(1, sizeof (*result));
+
+ if (result != NULL) {
+ if (c != NULL)
+ result->class = c;
+ else
+ result->class = calloc(1, sizeof (CLASS));
+
+ list_append((void ***)&CStatus, result);
+ }
+
+ return (result);
+}
+
+void
+free_fstatus(FSTATUS *fsp)
+{
+ if (fsp != NULL) {
+ if (fsp->form != NULL)
+ free_form(fsp->form);
+ if (fsp->alert != NULL)
+ free_alert(fsp->alert);
+ if (fsp->users_allowed != NULL)
+ unload_list(&fsp->users_allowed);
+ if (fsp->users_denied != NULL)
+ unload_list(&fsp->users_denied);
+ if (fsp->cpi != NULL)
+ free(fsp->cpi);
+ if (fsp->lpi != NULL)
+ free(fsp->lpi);
+ if (fsp->plen != NULL)
+ free(fsp->plen);
+ if (fsp->pwid != NULL)
+ free(fsp->pwid);
+ free(fsp);
+ }
+}
+
+FSTATUS *
+new_fstatus(_FORM *f)
+{
+ FSTATUS *result = calloc(1, sizeof (*result));
+
+ if (result != NULL) {
+ static int i = 0;
+
+ if (f != NULL)
+ result->form = f;
+ else
+ result->form = calloc(1, sizeof (_FORM));
+
+ result->alert = new_alert("F-%d", i++);
+ result->alert->exec = new_exec(EX_FALERT, result);
+ result->trigger = result->form->alert.Q;
+
+ if (f != NULL) {
+ load_userform_access(f->name, &(result->users_allowed),
+ &(result->users_denied));
+ load_sdn (&(result->cpi), f->cpi);
+ load_sdn (&(result->lpi), f->lpi);
+ load_sdn (&(result->plen), f->plen);
+ load_sdn (&(result->pwid), f->pwid);
+ }
+
+ list_append((void ***)&FStatus, (void *)result);
+ }
+
+ return (result);
+}
+
+void
+free_pwstatus(PWSTATUS *pwp)
+{
+ if (pwp != NULL) {
+ if (pwp->pwheel)
+ freepwheel(pwp->pwheel);
+ if (pwp->alert != NULL)
+ free_alert(pwp->alert);
+ free(pwp);
+ }
+}
+
+PWSTATUS *
+new_pwstatus(PWHEEL *p)
+{
+ PWSTATUS *result = calloc(1, sizeof (*result));
+
+ if (result != NULL) {
+ static int i = 0;
+
+ if (p != NULL)
+ result->pwheel = p;
+ else
+ result->pwheel = calloc(1, sizeof (*result));
+
+ result->alert = new_alert("P-%d", i++);
+ result->alert->exec = new_exec(EX_PALERT, result);
+ result->trigger = result->pwheel->alert.Q;
+
+ list_append((void ***)&PWStatus, (void *)result);
+ }
+
+ return (result);
+}
+
+void
+free_rstatus(RSTATUS *rsp)
+{
+ if (rsp != NULL) {
+ remover(rsp);
+
+ if (rsp->request != NULL)
+ freerequest(rsp->request);
+ if (rsp->secure != NULL)
+ freesecure(rsp->secure);
+ if (rsp->req_file)
+ Free (rsp->req_file);
+ if (rsp->slow)
+ Free (rsp->slow);
+ if (rsp->fast)
+ Free (rsp->fast);
+ if (rsp->pwheel_name)
+ Free (rsp->pwheel_name);
+ if (rsp->printer_type)
+ Free (rsp->printer_type);
+ if (rsp->output_type)
+ Free (rsp->output_type);
+ if (rsp->cpi)
+ Free (rsp->cpi);
+ if (rsp->lpi)
+ Free (rsp->lpi);
+ if (rsp->plen)
+ Free (rsp->plen);
+ if (rsp->pwid)
+ Free (rsp->pwid);
+ free(rsp);
+ }
+}
+
+RSTATUS *
+new_rstatus(REQUEST *r, SECURE *s)
+{
+ RSTATUS *result = calloc(1, sizeof (*result));
+
+ if (result != NULL) {
+ if ((result->request = r) == NULL)
+ result->request = calloc(1, sizeof (REQUEST));
+ if ((result->secure = s) == NULL)
+ result->secure = calloc(1, sizeof (SECURE));
+ }
+
+ return (result);
+}
+
+/**
+ ** search_pstatus() - SEARCH PRINTER TABLE
+ ** search_fstatus() - SEARCH FORMS TABLE
+ ** search_cstatus() - SEARCH CLASS TABLE
+ ** search_pwstatus() - SEARCH PRINT WHEEL TABLE
+ **/
+
+PSTATUS *
+search_pstatus(register char *name)
+{
+ PSTATUS *ps = NULL;
+
+ if (name != NULL) {
+ if (PStatus != NULL) {
+ int i;
+
+ for (i = 0; ((PStatus[i] != NULL) && (ps == NULL)); i++)
+ if (SAME(PStatus[i]->printer->name, name))
+ ps = PStatus[i];
+ }
+ } else
+ ps = new_pstatus(NULL);
+
+ return (ps);
+}
+
+
+FSTATUS *
+search_fstatus(register char *name)
+{
+ FSTATUS *ps = NULL;
+
+ if (name != NULL) {
+ if (FStatus != NULL) {
+ int i;
+
+ for (i = 0; ((FStatus[i] != NULL) && (ps == NULL)); i++)
+ if (SAME(FStatus[i]->form->name, name))
+ ps = FStatus[i];
+ }
+ } else
+ ps = new_fstatus(NULL);
+
+ return (ps);
+}
+
+FSTATUS *
+search_fptable(register char *paper)
+{
+ FSTATUS *ps = NULL;
+ int i;
+
+ if (FStatus != NULL) {
+ for (i = 0; ((FStatus[i] != NULL) && (ps == NULL)); i++)
+ if (SAME(FStatus[i]->form->paper, paper)) {
+ if (ps->form->isDefault)
+ ps = FStatus[i];
+ }
+ }
+
+ return (ps);
+}
+
+CSTATUS *
+search_cstatus(register char *name)
+{
+ CSTATUS *ps = NULL;
+
+ if (name != NULL) {
+ if (CStatus != NULL) {
+ int i;
+
+ for (i = 0; ((CStatus[i] != NULL) && (ps == NULL)); i++)
+ if (SAME(CStatus[i]->class->name, name))
+ ps = CStatus[i];
+ }
+ } else
+ ps = new_cstatus(NULL);
+
+ return (ps);
+}
+
+PWSTATUS *
+search_pwstatus(register char *name)
+{
+ PWSTATUS *ps = NULL;
+
+ if (name != NULL) {
+ if (PWStatus != NULL) {
+ int i;
+
+ for (i = 0; ((PWStatus[i] != NULL) && (ps == NULL)); i++)
+ if (SAME(PWStatus[i]->pwheel->name, name))
+ ps = PWStatus[i];
+ }
+ } else
+ ps = new_pwstatus(NULL);
+
+ return (ps);
+}
+
+
+/**
+ ** load_str() - LOAD STRING WHERE ALLOC'D STRING MAY BE
+ ** unload_str() - REMOVE POSSIBLE ALLOC'D STRING
+ **/
+
+void
+load_str(char **pdst, char *src)
+{
+ if (*pdst)
+ Free (*pdst);
+ *pdst = Strdup(src);
+ return;
+}
+
+void
+unload_str(char **pdst)
+{
+ if (*pdst)
+ Free (*pdst);
+ *pdst = 0;
+ return;
+}
+
+/**
+ ** unload_list() - REMOVE POSSIBLE ALLOC'D LIST
+ **/
+
+void
+unload_list(char ***plist)
+{
+ if (*plist)
+ freelist (*plist);
+ *plist = 0;
+ return;
+}
+
+/**
+ ** load_sdn() - LOAD STRING WITH ASCII VERSION OF SCALED DECIMAL NUMBER
+ **/
+
+void
+load_sdn(char **p, SCALED sdn)
+{
+ if (!p)
+ return;
+
+ if (*p)
+ Free (*p);
+ *p = 0;
+
+ if (sdn.val <= 0 || 999999 < sdn.val)
+ return;
+
+ *p = Malloc(sizeof("999999.999x"));
+ sprintf (
+ *p,
+ "%.3f%s",
+ sdn.val,
+ (sdn.sc == 'c'? "c" : (sdn.sc == 'i'? "i" : ""))
+ );
+
+ return;
+}
+
+/**
+ ** Getform() - EASIER INTERFACE TO "getform()"
+ **/
+
+_FORM *
+Getform(char *form)
+{
+ _FORM *_form;
+
+ FORM formbuf;
+
+ FALERT alertbuf;
+
+ int ret;
+
+
+ while (
+ (ret = getform(form, &formbuf, &alertbuf, (FILE **)0)) == -1
+ && errno == EINTR
+ )
+ ;
+ if (ret == -1)
+ return (0);
+
+ _form = calloc(1, sizeof (*_form));
+ _form->plen = formbuf.plen;
+ _form->pwid = formbuf.pwid;
+ _form->lpi = formbuf.lpi;
+ _form->cpi = formbuf.cpi;
+ _form->np = formbuf.np;
+ _form->chset = formbuf.chset;
+ _form->mandatory = formbuf.mandatory;
+ _form->rcolor = formbuf.rcolor;
+ _form->comment = formbuf.comment;
+ _form->conttype = formbuf.conttype;
+ _form->name = formbuf.name;
+ _form->paper = formbuf.paper;
+ _form->isDefault = formbuf.isDefault;
+
+ if ((_form->alert.shcmd = alertbuf.shcmd) != NULL) {
+ _form->alert.Q = alertbuf.Q;
+ _form->alert.W = alertbuf.W;
+ } else {
+ _form->alert.Q = 0;
+ _form->alert.W = 0;
+ }
+
+ return (_form);
+}
+
+/**
+ ** Getprinter()
+ ** Getrequest()
+ ** Getuser()
+ ** Getclass()
+ ** Getpwheel()
+ ** Getsecure()
+ ** Loadfilters()
+ **/
+
+PRINTER *
+Getprinter(char *name)
+{
+ register PRINTER *ret;
+
+ while (!(ret = getprinter(name)) && errno == EINTR)
+ ;
+ return (ret);
+}
+
+REQUEST *
+Getrequest(char *file)
+{
+ register REQUEST *ret;
+
+ while (!(ret = getrequest(file)) && errno == EINTR)
+ ;
+ return (ret);
+}
+
+USER *
+Getuser(char *name)
+{
+ register USER *ret;
+
+ while (!(ret = getuser(name)) && errno == EINTR)
+ ;
+ return (ret);
+}
+
+CLASS *
+Getclass(char *name)
+{
+ register CLASS *ret;
+
+ while (!(ret = getclass(name)) && errno == EINTR)
+ ;
+ return (ret);
+}
+
+PWHEEL *
+Getpwheel(char *name)
+{
+ register PWHEEL *ret;
+
+ while (!(ret = getpwheel(name)) && errno == EINTR)
+ ;
+ return (ret);
+}
+
+SECURE *
+Getsecure(char *file)
+{
+ register SECURE *ret;
+
+ while (!(ret = getsecure(file)) && errno == EINTR)
+ ;
+ return ((SECURE *) ret);
+}
+
+
+int
+Loadfilters(char *file)
+{
+ register int ret;
+
+ while ((ret = loadfilters(file)) == -1 && errno == EINTR)
+ ;
+ return (ret);
+}
+
+/**
+ ** free_form() - FREE MEMORY ALLOCATED FOR _FORM STRUCTURE
+ **/
+
+void
+free_form(register _FORM *pf)
+{
+ if (!pf)
+ return;
+ if (pf->chset)
+ Free (pf->chset);
+ if (pf->rcolor)
+ Free (pf->rcolor);
+ if (pf->comment)
+ Free (pf->comment);
+ if (pf->conttype)
+ Free (pf->conttype);
+ if (pf->name)
+ Free (pf->name);
+ if (pf->paper)
+ Free (pf->paper);
+ pf->name = 0;
+ if (pf->alert.shcmd)
+ Free (pf->alert.shcmd);
+ return;
+}
+
+/**
+ ** getreqno() - GET NUMBER PART OF REQUEST ID
+ **/
+
+char *
+getreqno(char *req_id)
+{
+ register char *cp;
+
+
+ if (!(cp = strrchr(req_id, '-')))
+ cp = req_id;
+ else
+ cp++;
+ return (cp);
+}
+
+/* Putsecure(): Insurance for writing out the secure request file.
+ * input: char ptr to name of the request file,
+ * ptr to the SECURE structure to be written.
+ * ouput: 0 if successful, -1 otherwise.
+ *
+ * Description:
+ * The normal call to putsecure() is woefully lacking.
+ * The bottom line here is that there
+ * is no way to make sure that the file has been written out
+ * as expected. This can cause rude behaviour later on.
+ *
+ * This routine calls putsecure(), and then does a getsecure().
+ * The results are compared to the original structure. If the
+ * info obtained by getsecure() doesn't match, we retry a few
+ * times before giving up (presumably something is very seriously
+ * wrong at that point).
+ */
+
+
+int
+Putsecure(char *file, SECURE *secbufp)
+{
+ SECURE *pls;
+ int retries = 5; /* # of attempts */
+ int status; /* 0 = success, nonzero otherwise */
+
+
+ while (retries--) {
+ status = 1; /* assume the worst, hope for the best */
+ if (putsecure(file, secbufp) == -1) {
+ rmsecure(file);
+ continue;
+ }
+
+ if ((pls = getsecure(file)) == (SECURE *) NULL) {
+ rmsecure(file);
+ status = 2;
+ continue;
+ }
+
+ /* now compare each field */
+
+ /*
+ * A comparison is only valid if secbufp and pls point to
+ * different locations. In reality getsecure() will have
+ * already been called, allocating the same STATIC memory
+ * location to both structures making the following compare
+ * meaningless.
+ * Therefore test for this condition to prevent us from
+ * calling freesecure which will destroy uid and
+ * req_id fields in the strucure
+ */
+
+ status = 0;
+ if (secbufp != pls) {
+ if (strcmp(pls->req_id, secbufp->req_id) != 0) {
+ rmsecure(file);
+ status = 3;
+ continue;
+ }
+
+ if (pls->uid != secbufp->uid) {
+ rmsecure(file);
+ status = 4;
+ continue;
+ }
+
+ if (strcmp(pls->user, secbufp->user) != 0) {
+ rmsecure(file);
+ status = 5;
+ continue;
+ }
+
+ if (pls->gid != secbufp->gid) {
+ rmsecure(file);
+ status = 6;
+ continue;
+ }
+
+ if (pls->size != secbufp->size) {
+ rmsecure(file);
+ status = 7;
+ continue;
+ }
+
+ if (pls->date != secbufp->date) {
+ rmsecure(file);
+ status = 8;
+ continue;
+ }
+
+ freesecure(pls);
+ }
+ break;
+ }
+
+ if (status != 0) {
+ note("Putsecure failed, status=%d\n", status);
+ return -1;
+ }
+
+ return 0;
+}
+
+void GetRequestFiles(REQUEST *req, char *buffer, int length)
+{
+ char buf[BUFSIZ];
+
+ memset(buf, 0, sizeof(buf));
+
+ if (req->title) {
+ char *r = req->title;
+ char *ptr = buf;
+
+ while ( *r && strncmp(r,"\\n",2)) {
+ *ptr++ = *r++;
+ }
+ } else if (req->file_list)
+ strlcpy(buf, *req->file_list, sizeof (buf));
+
+ if (*buf == NULL || !strncmp(buf, SPOOLDIR, sizeof(SPOOLDIR)-1))
+ strcpy(buf, "<File name not available>");
+
+ if (strlen(buf) > (size_t) 24) {
+ char *r;
+
+ if (r = strrchr(buf, '/'))
+ r++;
+ else
+ r = buf;
+
+ snprintf(buffer, length, "%-.24s", r);
+ } else
+ strlcpy(buffer, buf, length);
+ return;
+}
+
+
+/**
+ ** _Malloc()
+ ** _Realloc()
+ ** _Calloc()
+ ** _Strdup()
+ ** _Free()
+ **/
+
+void (*lp_alloc_fail_handler)( void ) = 0;
+
+typedef void *alloc_type;
+
+alloc_type
+_Malloc(size_t size, const char *file, int line)
+{
+ alloc_type ret;
+
+ ret = malloc(size);
+ if (!ret) {
+ if (lp_alloc_fail_handler)
+ (*lp_alloc_fail_handler)();
+ errno = ENOMEM;
+ }
+ return (ret);
+}
+
+alloc_type
+_Realloc(void *ptr, size_t size, const char *file, int line)
+{
+ alloc_type ret = realloc(ptr, size);
+
+ if (!ret) {
+ if (lp_alloc_fail_handler)
+ (*lp_alloc_fail_handler)();
+ errno = ENOMEM;
+ }
+ return (ret);
+}
+
+alloc_type
+_Calloc(size_t nelem, size_t elsize, const char *file, int line)
+{
+ alloc_type ret = calloc(nelem, elsize);
+
+ if (!ret) {
+ if (lp_alloc_fail_handler)
+ (*lp_alloc_fail_handler)();
+ errno = ENOMEM;
+ }
+ return (ret);
+}
+
+char *
+_Strdup(const char *s, const char *file, int line)
+{
+ char * ret;
+
+ if (!s)
+ return( (char *) 0);
+
+ ret = strdup(s);
+
+ if (!ret) {
+ if (lp_alloc_fail_handler)
+ (*lp_alloc_fail_handler)();
+ errno = ENOMEM;
+ }
+ return (ret);
+}
+
+void
+_Free(void *ptr, const char *file, int line)
+{
+ free (ptr);
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/getkey.c b/usr/src/cmd/lp/cmd/lpsched/getkey.c
new file mode 100644
index 0000000000..b0722e06f5
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/getkey.c
@@ -0,0 +1,44 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1.1.4 */
+
+#include "sys/types.h"
+#include "time.h"
+#include "stdlib.h"
+
+#include "lpsched.h"
+
+long
+getkey (void)
+{
+ static int started = 0;
+
+ if (!started) {
+ srand48 (time((time_t *)0));
+ started = 1;
+ }
+ return (lrand48());
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/init.c b/usr/src/cmd/lp/cmd/lpsched/init.c
new file mode 100644
index 0000000000..fe318e1e81
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/init.c
@@ -0,0 +1,281 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "lpsched.h"
+#include <syslog.h>
+
+CSTATUS **CStatus = NULL; /* Status of same */
+PSTATUS **PStatus = NULL; /* Status of same */
+FSTATUS **FStatus = NULL; /* status of same */
+PWSTATUS **PWStatus = NULL; /* Status of same */
+EXEC **Exec_Table = NULL; /* Running processes */
+EXEC **Exec_Slow = NULL; /* Slow filters */
+EXEC **Exec_Notify = NULL; /* Notifications */
+RSTATUS *Request_List = NULL; /* Queue of print requests */
+
+int ET_SlowSize = 1,
+ ET_NotifySize = 1;
+
+static void init_printers(),
+ init_classes(),
+ init_forms(),
+ init_pwheels(),
+ init_exec();
+
+
+static void init_requests();
+
+void
+init_memory(void)
+{
+ init_exec();
+ init_printers();
+ init_classes();
+ init_forms();
+ init_pwheels();
+
+ /*
+ * Load the status after the basic structures have been loaded,
+ * but before loading requests still in the queue. This is so
+ * the requests can be compared against accurate status information
+ * (except rejection status--accept the jobs anyway).
+ */
+ load_status();
+
+ Loadfilters(Lp_A_Filters);
+
+ init_requests();
+}
+
+static void
+init_printers()
+{
+ PRINTER *p;
+ int i = 0;
+
+ while((p = Getprinter(NAME_ALL)) != NULL || errno != ENOENT) {
+ if ((!p) || (p->remote)) /* NULL or this is remote, ignore it */
+ continue;
+
+ (void) new_pstatus(p);
+ syslog(LOG_DEBUG, "Loaded printer: %s", p->name);
+ }
+}
+
+static void
+init_classes()
+{
+ CLASS *c;
+
+ while((c = Getclass(NAME_ALL)) != NULL) {
+ (void) new_cstatus(c);
+ syslog(LOG_DEBUG, "Loaded class: %s", c->name);
+ }
+}
+
+static void
+init_forms()
+{
+ _FORM *f;
+ int i = 0;
+
+ while ((f = Getform(NAME_ALL)) != NULL) {
+ (void) new_fstatus(f);
+ syslog(LOG_DEBUG, "Loaded form: %s", f->name);
+ }
+}
+
+static void
+init_pwheels()
+{
+ PWHEEL *p;
+ int i = 0;
+
+ while((p = Getpwheel(NAME_ALL)) != NULL || errno != ENOENT)
+ {
+ if (!p) /* NULL, ignore it. */
+ continue;
+
+ (void) new_pwstatus(p);
+ syslog(LOG_DEBUG, "Loaded print-wheel: %s", p->name);
+ }
+}
+
+static void
+init_requests(void)
+{
+ RSTATUS **table = NULL;
+ REQUEST *r;
+ SECURE *s;
+ char *name;
+ char *sysdir;
+ char *sysname;
+ char *reqfile = NULL;
+ long addr = -1;
+ long sysaddr = -1;
+ short vr_ret;
+
+ while((sysname = next_dir(Lp_Requests, &addr)) != NULL) {
+ RSTATUS *rsp;
+
+ sysdir = makepath(Lp_Requests, sysname, NULL);
+
+ while((name = next_file(sysdir, &sysaddr)) != NULL) {
+ reqfile = makepath(sysname, name, NULL);
+ Free(name);
+
+ if ((s = Getsecure(reqfile)) == NULL) {
+ RSTATUS tmp;
+
+ memset(&tmp, 0, sizeof (tmp));
+ tmp.req_file = reqfile; /* fix for 1103890 */
+ rmfiles(&tmp, 0);
+ free(tmp.req_file);
+ continue;
+ }
+ syslog(LOG_DEBUG, "Loaded request: %s", reqfile);
+
+ if((r = Getrequest(reqfile)) == NULL) {
+ RSTATUS tmp;
+
+ memset(&tmp, 0, sizeof (tmp));
+ tmp.req_file = reqfile; /* fix for 1103890 */
+ rmfiles(&tmp, 0);
+ freesecure(s);
+ free(tmp.req_file);
+ continue;
+ }
+ syslog(LOG_DEBUG, "Loaded secure: %s", s->req_id);
+
+ rsp = new_rstatus(r, s);
+
+ r->outcome &= ~RS_ACTIVE; /* it can't be! */
+ rsp->req_file = reqfile;
+
+ if ((r->outcome & (RS_CANCELLED|RS_FAILED)) &&
+ !(r->outcome & RS_NOTIFY)) {
+ rmfiles(rsp, 0);
+ free_rstatus(rsp);
+ continue;
+ }
+
+ /*
+ * So far, the only way RS_NOTIFY can be set without there
+ * being a notification file containing the message to the
+ * user, is if the request was cancelled. This is because
+ * cancelling a request does not cause the creation of the
+ * message if the request is currently printing or filtering.
+ * (The message is created after the child process dies.)
+ * Thus, we know what to say.
+ *
+ * If this behaviour changes, we may have to find another way
+ * of determining what to say in the message.
+ */
+ if (r->outcome & RS_NOTIFY) {
+ char *file = makereqerr(rsp);
+
+ if (Access(file, F_OK) == -1) {
+ if (!(r->outcome & RS_CANCELLED)) {
+ Free(file);
+ rmfiles(rsp, 0);
+ free_rstatus(rsp);
+ continue;
+ }
+ notify(rsp, NULL, 0, 0, 0);
+ }
+ Free(file);
+ }
+
+ /* fix for bugid 1103709. if validate_request returns
+ * MNODEST, then the printer for the request doesn't exist
+ * anymore! E.g. lpadmin -x was issued, and the request
+ * hasn't been cleaned up. In this case, the "printer"
+ * element of table[] will be NULL, and cancel will
+ * core dump! So we clean this up here.
+ */
+
+ /*
+ * Well actually this happens with MDENYDEST too. The real problem
+ * is if the printer is NULL, so test for it
+ */
+
+ if ((vr_ret=validate_request(rsp, NULL, 1)) != MOK) {
+ if (vr_ret == MNODEST || (rsp->printer == NULL)) {
+ rmfiles(rsp, 0);
+ free_rstatus(rsp);
+ continue;
+ }
+ cancel(rsp, 1);
+ }
+
+ list_append((void ***)&table, (void *)rsp);
+ }
+ Free(sysdir);
+ Free(sysname);
+ sysaddr = -1;
+ }
+
+ if (table != NULL) {
+ unsigned long i;
+
+ for (i = 0; table[i] != NULL; i++);
+
+ qsort((void *)table, i, sizeof(RSTATUS *),
+ (int (*)(const void * , const void *))rsort);
+
+ for (i = 0; table[i] != NULL; i++) {
+ table[i]->next = table[i + 1];
+ if (table[i + 1] != NULL)
+ table[i + 1]->prev = table[i];
+ }
+
+ Request_List = *table;
+ Free(table);
+ }
+}
+
+static void
+init_exec()
+{
+ EXEC *ep;
+ int i;
+
+ for (i = 0; i < ET_SlowSize; i++) {
+ ep = new_exec(EX_SLOWF, NULL);
+ list_append((void ***)&Exec_Slow, (void *)ep);
+ }
+
+ for (i = 0; i < ET_NotifySize; i++) {
+ ep = new_exec(EX_NOTIFY, NULL);
+ list_append((void ***)&Exec_Notify, (void *)ep);
+ }
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/log.c b/usr/src/cmd/lp/cmd/lpsched/log.c
new file mode 100644
index 0000000000..7c2041de70
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/log.c
@@ -0,0 +1,220 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdarg.h"
+#include "lpsched.h"
+#include <syslog.h>
+
+static void log(char *, va_list);
+
+/**
+ ** open_logfile() - OPEN FILE FOR LOGGING MESSAGE
+ **/
+
+static int
+open_logfile(char *name)
+{
+ char path[80];
+
+ snprintf(path, sizeof (path), "%s/%s", Lp_Logs, name);
+ return (open_locked(path, "a", 0640));
+}
+
+
+/**
+ ** fail() - LOG MESSAGE AND EXIT (ABORT IF DEBUGGING)
+ **/
+
+/*VARARGS1*/
+void
+fail(char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ log (format, ap);
+ va_end (ap);
+
+#if defined(DEBUG)
+ if (debug & DB_ABORT)
+ abort ();
+ else
+#endif
+ exit (1);
+ /*NOTREACHED*/
+}
+
+/**
+ ** note() - LOG MESSAGE
+ **/
+
+/*VARARGS1*/
+void
+note(char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ log (format, ap);
+ va_end (ap);
+}
+
+
+
+/**
+ ** mallocfail() - COMPLAIN ABOUT MEMORY ALLOCATION FAILURE
+ **/
+
+void
+mallocfail(void)
+{
+ fail ("Memory allocation failed!\n");
+ /*NOTREACHED*/
+}
+
+/**
+ ** log() - LOW LEVEL ROUTINE THAT LOGS MESSSAGES
+ **/
+
+static void
+log(char *format, va_list ap)
+{
+ int close_it;
+ int fd;
+ static int nodate = 0;
+ char buf[BUFSIZ];
+
+ vsyslog(LOG_DEBUG, format, ap);
+
+ if (!am_in_background) {
+ fd = 1;
+ close_it = 0;
+ } else {
+ if ((fd = open_logfile("lpsched")) < 0)
+ return;
+ close_it = 1;
+ }
+
+ if (am_in_background && !nodate) {
+ time_t curtime;
+ struct tm *tm;
+
+ time(&curtime);
+ if ((tm = localtime(&curtime)) != NULL)
+ fdprintf (fd, "%.2d/%.2d %.2d:%.2d:%.2d: ",
+ tm->tm_mon+1, tm->tm_mday, tm->tm_hour,
+ tm->tm_min, tm->tm_sec);
+ else
+ fdprintf(fd, "bad date: ");
+ }
+ nodate = 0;
+
+ vsnprintf (buf, sizeof (buf), format, ap);
+ write(fd, buf, strlen(buf));
+ if (format[strlen(format) - 1] != '\n')
+ nodate = 1;
+
+ if (close_it)
+ close(fd);
+}
+
+/**
+ ** execlog()
+ **/
+
+/*VARARGS1*/
+void
+execlog(char *format, ...)
+{
+ va_list ap;
+
+#if defined(DEBUG)
+ int fd = open_logfile("exec");
+ char buf[BUFSIZ];
+ EXEC * ep;
+ static int nodate = 0;
+
+ va_start (ap, format);
+ if (fd >= 0) {
+ if (!nodate) {
+ time_t now = time((time_t *)0);
+
+ fdprintf (fd, "%24.24s: ", ctime(&now));
+ }
+ nodate = 0;
+ if (!STREQU(format, "%e")) {
+ vsnprintf (buf, sizeof (buf), format, ap);
+ write(fd, buf, strlen(buf));
+ if (format[strlen(format) - 1] != '\n')
+ nodate = 1;
+ } else switch ((ep = va_arg(ap, EXEC *))->type) {
+ case EX_INTERF:
+ fdprintf(fd, " EX_INTERF %s %s\n",
+ ep->ex.printer->printer->name,
+ ep->ex.printer->request->secure->req_id);
+ break;
+ case EX_SLOWF:
+ fdprintf(fd, " EX_SLOWF %s\n",
+ ep->ex.request->secure->req_id);
+ break;
+ case EX_ALERT:
+ fdprintf(fd, " EX_ALERT %s\n",
+ ep->ex.printer->printer->name);
+ break;
+ case EX_FAULT_MESSAGE:
+ fdprintf(fd, " EX_FAULT_MESSAGE %s\n",
+ ep->ex.printer->printer->name);
+ break;
+ case EX_FORM_MESSAGE:
+ fdprintf(fd, " EX_FORM_MESSAGE %s\n",
+ ep->ex.form->form->name);
+ break;
+ case EX_FALERT:
+ fdprintf(fd, " EX_FALERT %s\n",
+ ep->ex.form->form->name);
+ break;
+ case EX_PALERT:
+ fdprintf(fd, " EX_PALERT %s\n",
+ ep->ex.pwheel->pwheel->name);
+ break;
+ case EX_NOTIFY:
+ fdprintf(fd, " EX_NOTIFY %s\n",
+ ep->ex.request->secure->req_id);
+ break;
+ default:
+ fdprintf (fd, " EX_???\n");
+ break;
+ }
+ close(fd);
+ }
+#endif
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/lpfsck.c b/usr/src/cmd/lp/cmd/lpsched/lpfsck.c
new file mode 100644
index 0000000000..3175ae2d17
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/lpfsck.c
@@ -0,0 +1,397 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdarg.h"
+#include "stdlib.h"
+#include "fcntl.h"
+#include <sys/param.h>
+#include "lpsched.h"
+
+
+static void check_link();
+
+/**
+ ** lpfsck()
+ **/
+
+#define F 0
+#define D 1
+#define P 2
+#define S 3
+
+static void proto (int, int, ...);
+static int va_makepath(va_list *, char **);
+static void _rename (char *, char *, ...);
+
+void
+lpfsck(void)
+{
+ struct stat stbuf;
+ int real_am_in_background = am_in_background;
+
+
+ /*
+ * Force log messages to go into the log file instead of stdout.
+ */
+ am_in_background = 1;
+
+ /*
+ * Most of these lines repeat the prototype file from the
+ * packaging and should match those items exactly.
+ * (In fact, they probably ought to be generated from that file,
+ * but that work is for a rainy day...)
+ */
+
+ /*
+ * DIRECTORIES:
+ */
+proto (D, 0, Lp_A, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_A_Classes, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_A_Forms, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_A_Interfaces, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_A_Printers, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_A_PrintWheels, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 0, "/var/lp", NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_Logs, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_Spooldir, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_Admins, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_Requests, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_Requests, Local_System, NULL, 0770, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_System, NULL, 0775, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_Tmp, NULL, 0771, Lp_Uid, Lp_Gid);
+proto (D, 1, Lp_Tmp, Local_System, NULL, 0775, Lp_Uid, Lp_Gid);
+
+ /*
+ * DIRECTORIES: not described in the packaging
+ */
+proto (D, 0, Lp_Spooldir, FIFOSDIR, NULL, 0775, Lp_Uid, Lp_Gid);
+
+ /*
+ * THE MAIN FIFO:
+ */
+proto (P, 1, Lp_FIFO, NULL, 0666, Lp_Uid, Lp_Gid);
+
+ /*
+ * SYMBOLIC LINKS:
+ * Watch out! These names are given in the reverse
+ * order found in the prototype file (sorry!)
+ */
+proto (S, 1, Lp_Model, NULL, "/etc/lp/model", NULL);
+proto (S, 1, Lp_Logs, NULL, "/etc/lp/logs", NULL);
+/* S, 1, Lp_Tmp, Local_System, ... DONE BELOW */
+proto (S, 1, Lp_Bin, NULL, Lp_Spooldir, "bin", NULL);
+proto (S, 1, Lp_A, NULL, Lp_Admins, "lp", NULL);
+
+ /*
+ * OTHER FILES:
+ */
+
+ /*
+ * SPECIAL CASE:
+ * If the "temp" symbolic link already exists,
+ * but is not correct, assume the machine's nodename changed.
+ * Rename directories that include the nodename, if possible,
+ * so that unprinted requests are saved. Then change the
+ * symbolic link.
+ * Watch out for a ``symbolic link'' that isn't!
+ */
+ if (Lstat(Lp_Temp, &stbuf) == 0)
+ switch (stbuf.st_mode & S_IFMT) {
+
+ default:
+ Unlink (Lp_Temp);
+ break;
+
+ case S_IFDIR:
+ Rmdir (Lp_Temp);
+ break;
+
+ case S_IFLNK:
+ check_link();
+ break;
+ }
+
+ proto(S, 1, Lp_Tmp, Local_System, NULL, Lp_Temp, NULL);
+
+ am_in_background = real_am_in_background;
+ return;
+}
+
+static void
+check_link()
+{
+ int len;
+ char symbolic[MAXPATHLEN + 1];
+ char *real_dir;
+ char *old_system;
+
+ if ((len = Readlink(Lp_Temp, symbolic, MAXPATHLEN)) <= 0) {
+ Unlink(Lp_Temp);
+ return;
+ }
+
+ /*
+ * If the symbolic link contained trailing slashes, remove
+ * them.
+ */
+ while ((len > 1) && (symbolic[len - 1] == '/')) {
+ len--;
+ }
+ symbolic[len] = 0;
+
+ /* check that symlink points into /var/spool/lp/tmp */
+ if (strncmp(Lp_Tmp, symbolic, strlen(Lp_Tmp)) != 0) {
+ Unlink(Lp_Temp);
+ return;
+ }
+
+ /*
+ * Check that symlink points to something.
+ * There should be at least 2 characters
+ * after the string '/var/spool/lp/tmp':
+ * a '/' and another character.
+ */
+ if (len <= strlen(Lp_Tmp) + 1) {
+ Unlink(Lp_Temp);
+ return;
+ }
+
+ real_dir = makepath(Lp_Tmp, Local_System, NULL);
+ if (!STREQU(real_dir, symbolic)) {
+ if (!(old_system = strrchr(symbolic, '/')))
+ old_system = symbolic;
+ else
+ old_system++;
+
+ /*
+ * The "rename()" system call (buried
+ * inside the "_rename()" routine) should
+ * succeed, even though we blindly created
+ * the new directory earlier, as the only
+ * directory entries should be . and ..
+ * (although if someone already created
+ * them, we'll note the fact).
+ */
+ _rename(old_system, Local_System, Lp_Tmp, NULL);
+ _rename(old_system, Local_System, Lp_Requests, NULL);
+
+ Unlink(Lp_Temp);
+ }
+ Free(real_dir);
+}
+
+
+/**
+ ** proto()
+ **/
+
+static void
+proto(int type, int rm_ok, ...)
+{
+ va_list ap;
+
+ char *path,
+ *symbolic;
+
+ int exist,
+ err;
+
+ mode_t mode;
+
+ uid_t uid;
+
+ gid_t gid;
+
+ struct stat stbuf;
+
+
+ va_start(ap, rm_ok);
+
+ if ((err = va_makepath(&ap, &path)) < 0)
+ fail ("\"%s\" is a truncated name!\n", path);
+
+ exist = (stat(path, &stbuf) == 0);
+
+ switch (type) {
+
+ case S:
+ if (!exist)
+ fail ("%s is missing!\n", path);
+ if ((err = va_makepath(&ap, &symbolic)) < 0)
+ fail ("\"%s\" is a truncated name!\n", symbolic);
+ Symlink (path, symbolic);
+ Free (symbolic);
+ Free (path);
+ return;
+
+ case D:
+ if (exist && !S_ISDIR(stbuf.st_mode)) {
+ if (!rm_ok)
+ fail ("%s is not a directory!\n", path);
+ else {
+ Unlink (path);
+ exist = 0;
+ }
+ }
+ if (!exist)
+ Mkdir (path, 0);
+ break;
+
+ case F:
+ if (exist && !S_ISREG(stbuf.st_mode)) {
+ if (!rm_ok)
+ fail ("%s is not a file!\n", path);
+ else {
+ Unlink (path);
+ exist = 0;
+ }
+ }
+ if (!exist)
+ Close(Creat(path, 0));
+ break;
+
+ case P:
+ /*
+ * Either a pipe or a file.
+ */
+ if (exist &&
+ !S_ISREG(stbuf.st_mode) && !S_ISFIFO(stbuf.st_mode)) {
+ if (!rm_ok)
+ fail ("%s is not a file or pipe!\n", path);
+ else {
+ Unlink (path);
+ exist = 0;
+ }
+ }
+ if (!exist)
+ Close(Creat(path, 0));
+ break;
+
+ }
+
+ mode = va_arg(ap, mode_t);
+ uid = va_arg(ap, uid_t);
+ gid = va_arg(ap, gid_t);
+ (void) chownmod(path, uid, gid, mode);
+
+ Free (path);
+ return;
+}
+
+/*
+ * va_makepath()
+ *
+ * Takes a variable length list of path components and attempts to string them
+ * together into a path. It returns a heap-allocated string via the output
+ * parameter 'ret', and returns an integer success value: < 0 indicates failure,
+ * 0 indicates success. Note that 'ret' will never be NULL (unless the system
+ * is so overloaded that it can't allocate a single byte), and should always be
+ * free()d.
+ */
+static int
+va_makepath (va_list *pap, char **ret)
+{
+ char *component;
+ char buf[MAXPATHLEN];
+ int buflen;
+
+ memset(buf, NULL, sizeof (buf));
+ while ((component = va_arg((*pap), char *)) != NULL) {
+ if (strlcat(buf, component, sizeof (buf)) >= sizeof (buf) ||
+ strlcat(buf, "/", sizeof (buf)) >= sizeof (buf)) {
+ if ((*ret = strdup(buf)) == NULL)
+ *ret = strdup("");
+ return (-1);
+ }
+ }
+
+ /* remove the trailing slash */
+ buflen = strlen(buf);
+ if ((buflen > 1) && (buf[buflen - 1] == '/')) {
+ buf[buflen - 1] = '\0';
+ }
+
+ if ((*ret = strdup(buf)) == NULL) {
+ *ret = strdup("");
+ return (-1);
+ }
+ return (0);
+}
+
+/**
+ ** _rename()
+ **/
+
+static void
+_rename(char *old_system, char *new_system, ...)
+{
+ va_list ap;
+
+ char * prefix;
+ char * old;
+ char * new;
+ int err;
+
+
+ va_start (ap, new_system);
+ if ((err = va_makepath(&ap, &prefix)) < 0)
+ fail (
+ "Rename failed; prefix \"%s\" is a truncated name.\n",
+ prefix
+ );
+ va_end (ap);
+
+ old = makepath(prefix, old_system, (char *)0);
+ new = makepath(prefix, new_system, (char *)0);
+
+ if (Rename(old, new) == 0)
+ note ("Renamed %s to %s.\n", old, new);
+ else if (errno == EEXIST)
+ note (
+ "Rename of %s to %s failed because %s exists.\n",
+ old,
+ new,
+ new
+ );
+ else
+ fail (
+ "Rename of %s to %s failed (%s).\n",
+ old,
+ new,
+ PERROR
+ );
+
+ Free (new);
+ Free (old);
+ Free (prefix);
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/lpsched.c b/usr/src/cmd/lp/cmd/lpsched/lpsched.c
new file mode 100644
index 0000000000..f4c8d7fad4
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/lpsched.c
@@ -0,0 +1,441 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "limits.h"
+#include "ulimit.h"
+#include "sys/utsname.h"
+
+#include "lpsched.h"
+
+#include <sys/stat.h>
+#include <sys/time.h> /* to up the max # of fds */
+#include <sys/resource.h>
+#include <syslog.h>
+#include <locale.h>
+#include <stdio_ext.h>
+
+
+int lock_fd = -1;
+int isStartingForms = 0;
+int Starting = 0;
+int Shutdown = 0;
+int DoneChildren = 0;
+int Sig_Alrm = 0;
+int OpenMax = OPEN_MAX;
+int Reserve_Fds = 0;
+
+char *Local_System = 0;
+char *SHELL = 0;
+
+gid_t Lp_Gid;
+uid_t Lp_Uid;
+
+#if defined(DEBUG)
+unsigned long debug = 0;
+static int signals = 0;
+#endif
+
+extern int errno;
+extern void shutdown_messages();
+
+int am_in_background = 0;
+
+static void disable_signals();
+static void startup();
+static void process();
+static void ticktock(int);
+static void background();
+static void usage();
+static void Exit();
+static void disable_signals();
+
+/**
+ ** main()
+ **/
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ extern char *optarg;
+ extern int optopt;
+ extern int opterr;
+ char * cp;
+ struct rlimit rlim;
+ int fd_limit = 4096;
+
+ (void) setlocale(LC_ALL, "");
+ if ((cp = strrchr(argv[0], '/')) == NULL)
+ cp = argv[0];
+ else
+ cp++;
+
+ /* open the syslog() */
+ openlog(cp, LOG_PID|LOG_NDELAY|LOG_NOWAIT, LOG_LPR);
+
+ SHELL = DEFAULT_SHELL;
+
+ opterr = 0;
+ while((c = getopt(argc, (char * const *)argv, "dsf:n:r:M:p:")) != EOF)
+ switch(c)
+ {
+# if defined (DEBUG)
+ case 'd':
+ debug = DB_ALL;
+ syslog(LOG_DEBUG, "debug = DB_ALL");
+ break;
+
+ case 's':
+ signals++;
+ break;
+# endif /* DEBUG */
+
+ case 'f':
+ if ((ET_SlowSize = atoi(optarg)) < 1)
+ ET_SlowSize = 1;
+ syslog(LOG_DEBUG, "-f option is %d", ET_SlowSize);
+ break;
+
+ case 'n':
+ if ((ET_NotifySize = atoi(optarg)) < 1)
+ ET_NotifySize = 1;
+ syslog(LOG_DEBUG, "-n option is %d", ET_NotifySize);
+ break;
+
+ case 'r':
+ if ((Reserve_Fds = atoi(optarg)) < 0)
+ Reserve_Fds = 0;
+ syslog(LOG_DEBUG, "-r option is %d", Reserve_Fds);
+ break;
+
+ case 'p':
+ if ((fd_limit = atoi(optarg)) < 16)
+ fd_limit = 4096;
+ syslog(LOG_DEBUG, "-p option is %d", fd_limit);
+ break;
+
+ case '?':
+ if (optopt == '?') {
+ usage ();
+ exit (0);
+ } else
+ fail ("%s: illegal option -- %c\n", argv[0], optopt);
+ }
+
+ /* reset the fd resource limit */
+ rlim.rlim_max = rlim.rlim_cur = fd_limit;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ getrlimit(RLIMIT_NOFILE, &rlim);
+ (void) enable_extended_FILE_stdio(-1, -1);
+ syslog(LOG_DEBUG, "file descriptor resource limit is %d (~%d printers)",
+ rlim.rlim_cur, (rlim.rlim_cur - 12)/ 2);
+
+ lp_alloc_fail_handler = mallocfail;
+
+ startup();
+
+ process();
+
+ lpshut(1); /* one last time to clean up */
+ /*NOTREACHED*/
+ return (0);
+}
+
+static void
+startup()
+{
+ struct passwd *p;
+
+
+ Starting = 1;
+ getpaths();
+
+ /*
+ * There must be a user named "lp".
+ */
+ if ((p = getpwnam(LPUSER)) == NULL)
+ fail ("Can't find the user \"lp\" on this system!\n");
+
+ Lp_Uid = p->pw_uid;
+ Lp_Gid = p->pw_gid;
+
+ /*
+ * Only "root" is allowed to run us.
+ */
+ if ((getuid() != 0) && (geteuid() != 0))
+ fail ("You must be \"root\" to run this program.\n");
+
+ setuid (0);
+
+ Local_System = Strdup("localhost");
+
+ /*
+ * Make sure that all critical directories are present and that
+ * symbolic links are correct.
+ */
+ lpfsck();
+
+ /*
+ * Try setting the lock file to see if another Spooler is running.
+ * We'll release it immediately; this allows us to fork the child
+ * that will run in the background. The child will relock the file.
+ */
+ if ((lock_fd = open_locked(Lp_Schedlock, "a", 0664)) < 0)
+ if (errno == EAGAIN)
+ fail ("Print services already active.\n");
+ else
+ fail ("Can't open file \"%s\" (%s).\n", NB(Lp_Schedlock), PERROR);
+ close(lock_fd);
+
+ background();
+ /*
+ * We are the child process now.
+ */
+
+ if ((lock_fd = open_locked(Lp_Schedlock, "w", 0664)) < 0)
+ fail ("Failed to lock the file \"%s\" (%s).\n", NB(Lp_Schedlock), PERROR);
+
+ Close (0);
+ Close (2);
+ if (am_in_background)
+ Close (1);
+
+ if ((OpenMax = ulimit(4, 0L)) == -1)
+ OpenMax = OPEN_MAX;
+
+ disable_signals();
+
+ init_messages();
+
+ init_memory();
+
+ note ("Print services started.\n");
+ Starting = 0;
+}
+
+void
+lpshut(int immediate)
+{
+ int i;
+ extern MESG * Net_md;
+
+
+ /*
+ * If this is the first time here, stop all running
+ * child processes, and shut off the alarm clock so
+ * it doesn't bug us.
+ */
+ if (!Shutdown) {
+ mputm (Net_md, S_SHUTDOWN, 1);
+ for (i = 0; Exec_Table != NULL && Exec_Table[i] != NULL; i++)
+ terminate (Exec_Table[i]);
+ alarm (0);
+ Shutdown = (immediate? 2 : 1);
+ }
+
+ /*
+ * If this is an express shutdown, or if all the
+ * child processes have been cleaned up, clean up
+ * and get out.
+ */
+ if (Shutdown == 2) {
+
+ /*
+ * We don't shut down the message queues until
+ * now, to give the children a chance to answer.
+ * This means an LP command may have been snuck
+ * in while we were waiting for the children to
+ * finish, but that's OK because we'll have
+ * stored the jobs on disk (that's part of the
+ * normal operation, not just during shutdown phase).
+ */
+ shutdown_messages();
+
+ (void) close(lock_fd);
+ (void) Unlink(Lp_Schedlock);
+
+ note ("Print services stopped.\n");
+ exit (0);
+ /*NOTREACHED*/
+ }
+}
+
+static void
+process()
+{
+ FSTATUS *pfs;
+ PWSTATUS *ppws;
+ int i;
+
+
+ /*
+ * Call the "check_..._alert()" routines for each form/print-wheel;
+ * we need to do this at this point because these routines
+ * short-circuit themselves while we are in startup mode.
+ * Calling them now will kick off any necessary alerts.
+ */
+ isStartingForms = 1;
+ for (i = 0; FStatus != NULL && FStatus[i] != NULL; i++)
+ check_form_alert (FStatus[i], (_FORM *)0);
+ isStartingForms = 0;
+
+ for (i = 0; PWStatus != NULL && PWStatus[i] != NULL; i++)
+ check_pwheel_alert (PWStatus[i], (PWHEEL *)0);
+
+ /*
+ * Clear the alarm, then schedule an EV_ALARM. This will clear
+ * all events that had been scheduled for later without waiting
+ * for the next tick.
+ */
+ alarm (0);
+ schedule (EV_ALARM);
+
+ /*
+ * Start the ball rolling.
+ */
+ schedule (EV_INTERF, (PSTATUS *)0);
+ schedule (EV_NOTIFY, (RSTATUS *)0);
+ schedule (EV_SLOWF, (RSTATUS *)0);
+
+ for (EVER) {
+ take_message ();
+
+ if (Sig_Alrm)
+ schedule (EV_ALARM);
+
+ if (DoneChildren)
+ dowait ();
+
+ if (Shutdown)
+ check_children();
+ if (Shutdown == 2)
+ break;
+ }
+}
+
+/*ARGSUSED*/
+static void
+ticktock(int sig)
+{
+ Sig_Alrm = 1;
+ (void)signal (SIGALRM, ticktock);
+ return;
+}
+
+static void
+background()
+{
+#if defined(DEBUG)
+ if (debug & DB_SDB)
+ return;
+#endif
+
+ switch(fork())
+ {
+ case -1:
+ fail ("Failed to fork child process (%s).\n", PERROR);
+ /*NOTREACHED*/
+
+ case 0:
+ (void) setpgrp();
+ am_in_background = 1;
+ return;
+
+ default:
+ note ("Print services started.\n");
+ exit(0);
+ /* NOTREACHED */
+ }
+}
+
+static void
+usage()
+{
+ note ("\
+usage: lpsched [ options ]\n\
+ [ -f #filter-slots ] (increase no. concurrent slow filters)\n\
+ [ -n #notify-slots ] (increase no. concurrent notifications)\n\
+ [ -r #reserved-fds ] (increase margin of file descriptors)\n"
+ );
+
+#if defined(DEBUG)
+ note ("\
+ [ -d ] (same as -D ALL)\n\
+ [ -s ] (don't trap most signals)\n"
+ );
+#endif
+
+ note ("\
+WARNING: all these options are currently unsupported\n"
+ );
+
+ return;
+}
+
+static void
+Exit(n)
+ int n;
+{
+ fail ("Received unexpected signal %d; terminating.\n", n);
+}
+
+static void
+disable_signals()
+{
+ int i;
+
+# if defined(DEBUG)
+ if (!signals)
+# endif
+ for (i = 0; i < NSIG; i++)
+ if (signal(i, SIG_IGN) != SIG_IGN)
+ signal (i, Exit);
+
+ (void) signal(SIGHUP, SIG_IGN);
+ (void) signal(SIGINT, SIG_IGN);
+ (void) signal(SIGQUIT, SIG_IGN);
+ (void) signal(SIGALRM, ticktock);
+ (void) signal(SIGTERM, lpshut); /* needs arg, but sig# OK */
+ (void) signal(SIGCLD, SIG_IGN);
+ (void) signal(SIGTSTP, SIG_IGN);
+ (void) signal(SIGCONT, SIG_DFL);
+ (void) signal(SIGTTIN, SIG_IGN);
+ (void) signal(SIGTTOU, SIG_IGN);
+ (void) signal(SIGXFSZ, SIG_IGN); /* could be a problem */
+ (void) signal(SIGWINCH, SIG_IGN); /* if started in a window */
+ (void) signal(SIGTHAW, SIG_IGN); /* used by CPR - energystar */
+
+#if defined(DEBUG)
+ if (debug & DB_ABORT)
+ (void) signal(SIGABRT, SIG_DFL);
+#endif
+
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/lpsched.h b/usr/src/cmd/lp/cmd/lpsched/lpsched.h
new file mode 100644
index 0000000000..c9a4d95b99
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/lpsched.h
@@ -0,0 +1,417 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdio.h"
+#include "sys/types.h"
+#include "memory.h"
+#include "string.h"
+#include "pwd.h"
+#include "fcntl.h"
+#include "errno.h"
+#include "signal.h"
+#include "unistd.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "access.h"
+#include "form.h"
+#include "requests.h"
+#include "filters.h"
+#include "printers.h"
+#include "class.h"
+#include "users.h"
+#include "secure.h"
+#include "msgs.h"
+
+#include "nodes.h"
+
+/**
+ ** Defines:
+ **/
+
+/*
+ * These are the fields in the PSTATUS and CSTATUS files,
+ * found in the SYSTEM directory.
+ */
+
+#define PST_MAX 8
+# define PST_BRK 0
+# define PST_NAME 1
+# define PST_STATUS 2
+# define PST_DATE 3
+# define PST_DISREAS 4
+# define PST_REJREAS 5
+# define PST_PWHEEL 6
+# define PST_FORM 7
+
+#define CST_MAX 5
+# define CST_BRK 0
+# define CST_NAME 1
+# define CST_STATUS 2
+# define CST_DATE 3
+# define CST_REJREAS 4
+
+/*
+ * Exit codes from child processes:
+ *
+ * 0 <= exit <= 0177 (127) are reserved for ``normal'' exits.
+ * 0200 <= exit <= 0377 (255) are reserved for special failures.
+ *
+ * If bit 0200 is set, then we have three sets of special error
+ * codes available, with 32 values in each set (except the first):
+ *
+ * 0201 - 0237 Printer faults
+ * 0240 - 0277 Dial problems
+ * 0300 - 0337 Port problems
+ * 0340 - 0377 Exec problems
+ *
+ * 0200 Interface received SIGTERM
+ */
+#define EXEC_EXIT_OKAY 0 /* success */
+#define EXEC_EXIT_USER 0177 /* user exit codes, 7 bits */
+#define EXEC_EXIT_NMASK 0340 /* mask to uncover reason bits */
+#define EXEC_EXIT_FAULT 0201 /* printer fault */
+#define EXEC_EXIT_HUP 0202 /* got hangup early in exec */
+#define EXEC_EXIT_INTR 0203 /* got interrupt early in exec */
+#define EXEC_EXIT_PIPE 0204 /* got close of FIFO early in exec */
+#define EXEC_EXIT_EXIT 0237 /* interface used reserved exit code */
+#define EXEC_EXIT_NDIAL 0240 /* can't dial, low 5 bits abs(dial()) */
+#define EXEC_EXIT_NPORT 0300 /* can't open port */
+#define EXEC_EXIT_TMOUT 0301 /* can't open port in N seconds */
+#define EXEC_EXIT_NOPEN 0340 /* can't open input/output file */
+#define EXEC_EXIT_NEXEC 0341 /* can't exec */
+#define EXEC_EXIT_NOMEM 0342 /* malloc failed */
+#define EXEC_EXIT_NFORK 0343 /* fork failed, must try again */
+#define EXEC_EXIT_NPUSH 0344 /* could not push streams module(s) */
+
+#define EXIT_RETRY 129 /* interface failed, try again */
+
+/*
+ * If killed, return signal, else 0.
+ */
+#define KILLED(x) (!(x & 0xFF00)? (x & 0x7F) : 0)
+
+/*
+ * If exited, return exit code, else -1.
+ */
+#define EXITED(x) (!(x & 0xFF)? ((x >> 8) & 0xFF) : -1)
+
+/*
+ * Events that can be scheduled:
+ */
+#define EV_SLOWF 1
+#define EV_INTERF 2
+#define EV_NOTIFY 3
+#define EV_LATER 4
+#define EV_ALARM 5
+#define EV_MESSAGE 6
+#define EV_ENABLE 7
+#define EV_FORM_MESSAGE 8
+
+/*
+ * How long to wait before retrying an event:
+ * (For best results, make CLOCK_TICK a factor of 60.)
+ */
+#define CLOCK_TICK 10 /* no. seconds between alarms */
+#define MINUTE (60/CLOCK_TICK) /* number of ticks per minute */
+#define WHEN_FORK (MINUTE) /* retry forking child process */
+#define WHEN_PRINTER (1*MINUTE) /* retry faulted printer */
+
+/*
+ * Alert types:
+ */
+#define A_PRINTER 1
+#define A_PWHEEL 2
+#define A_FORM 3
+
+/*
+ * How to handle active requests when disabling a printer:
+ */
+#define DISABLE_STOP 0
+#define DISABLE_FINISH 1
+#define DISABLE_CANCEL 2
+
+/*
+ * validate_request() - VERIFY REQUEST CAN BE PRINTED
+ * evaluate_request() - TRY REQUEST ON A PARTICULAR PRINTER
+ * reevaluate_request() - TRY TO MOVE REQUEST TO ANOTHER PRINTER
+ */
+
+#define validate_request(PRS,PREFIXP,MOVING) \
+ _validate((PRS), (PSTATUS *)0, (PSTATUS *)0, (PREFIXP), (MOVING))
+
+#define evaluate_request(PRS,PPS,MOVING) \
+ _validate((PRS), (PPS), (PSTATUS *)0, (char **)0, (MOVING))
+
+#define reevaluate_request(PRS,PPS) \
+ _validate((PRS), (PSTATUS *)0, (PPS), (char **)0, 0)
+
+/*
+ * Request is ready to be slow-filtered:
+ */
+#define NEEDS_FILTERING(PRS) \
+ ((PRS)->slow && !((PRS)->request->outcome & RS_FILTERED))
+
+/*
+ * Misc:
+ */
+
+#define isadmin(ID) (!(ID) || (ID) == Lp_Uid)
+
+#define makereqerr(PRS) \
+ makepath( \
+ Lp_Temp, \
+ getreqno((PRS)->secure->req_id), \
+ (char *)0 \
+ )
+
+#define EVER ;;
+
+#define DEFAULT_SHELL "/bin/sh"
+
+#define BINMAIL "/bin/mail"
+#define BINWRITE "/bin/write"
+
+#define RMCMD "/usr/bin/rm -f"
+
+
+#if defined(MLISTENDEL_WORKS)
+#define DROP_MD(MD) if (MD) { \
+ mlistendel (MD); \
+ mdisconnect (MD); \
+ MD = 0; \
+ } else /*EMPTY*/
+#else
+#define DROP_MD(MD) if (MD) { \
+ Close ((MD)->readfd); \
+ if ((MD)->writefd == (MD)->readfd) \
+ (MD)->writefd = -1; \
+ (MD)->readfd = -1; \
+ MD = 0; \
+ } else /*EMPTY*/
+#endif
+
+/**
+ ** External routines:
+ **/
+
+typedef int (*qchk_fnc_type)( RSTATUS * );
+
+CLASS * Getclass ( char * );
+
+extern void GetRequestFiles(REQUEST *req, char *buffer, int length);
+
+
+PRINTER * Getprinter ( char * );
+
+PWHEEL * Getpwheel ( char * );
+
+
+REQUEST * Getrequest ( char * );
+
+RSTATUS * request_by_id ( char * );
+RSTATUS * request_by_id_num ( long );
+RSTATUS * request_by_jobid ( char * , char * );
+
+SECURE * Getsecure ( char * );
+
+USER * Getuser ( char * );
+
+_FORM * Getform ( char * );
+
+char * _alloc_files ( int , char * , uid_t , gid_t);
+char * dispatchName(int);
+char * statusName(int);
+char * getreqno ( char * );
+
+int Loadfilters ( char * );
+int Putsecure(char *, SECURE *);
+int cancel ( RSTATUS * , int );
+int disable ( PSTATUS * , char * , int );
+int enable ( PSTATUS * );
+int exec ( int , ... );
+int one_printer_with_charsets ( RSTATUS * );
+int open_dialup ( char * , PRINTER * );
+int open_direct ( char * , PRINTER * );
+int qchk_filter ( RSTATUS * );
+int qchk_form ( RSTATUS * );
+int qchk_pwheel ( RSTATUS * );
+int qchk_waiting ( RSTATUS * );
+int queue_repel ( PSTATUS * , int , int (*)( RSTATUS * ) );
+int rsort ( RSTATUS ** , RSTATUS ** );
+
+long getkey ( void );
+long _alloc_req_id ( void );
+
+off_t chfiles ( char ** , uid_t , gid_t );
+
+short _validate ( RSTATUS * , PSTATUS * , PSTATUS * , char ** , int );
+
+void add_flt_act ( MESG * , ... );
+void alert ( int , ... );
+void cancel_alert ( int , ... );
+void check_children ( void );
+void check_form_alert ( FSTATUS * , _FORM * );
+void check_pwheel_alert ( PWSTATUS * , PWHEEL * );
+void check_request ( RSTATUS * );
+void del_flt_act ( MESG * , ... );
+void dial_problem ( PSTATUS * , RSTATUS * , int );
+void dispatch ( int , char * , MESG * );
+void dowait ( void );
+void dump_cstatus ( void );
+void dump_fault_status(PSTATUS *);
+void dump_pstatus ( void );
+void dump_status ( void );
+void execlog ( char * , ... );
+void fail ( char * , ... );
+void free_form ( _FORM * );
+void freerstatus ( register RSTATUS * );
+void init_memory ( void );
+void init_messages ( void );
+void insertr ( RSTATUS * );
+void load_sdn ( char ** , SCALED );
+void load_status ( void );
+void load_str ( char ** , char * );
+void lp_endpwent ( void );
+void lp_setpwent ( void );
+void lpfsck ( void );
+void lpshut ( int );
+void mallocfail ( void );
+void maybe_schedule ( RSTATUS * );
+void note ( char * , ... );
+void notify ( RSTATUS * , char * , int , int , int );
+void printer_fault ( PSTATUS * , RSTATUS * , char * , int );
+void clear_printer_fault ( PSTATUS * , char * );
+void putjobfiles ( RSTATUS * );
+void queue_attract ( PSTATUS * , int (*)( RSTATUS * ) , int );
+void queue_check ( int (*)( RSTATUS * ) );
+void queue_form ( RSTATUS * , FSTATUS * );
+void queue_pwheel ( RSTATUS * , char * );
+void remount_form(register PSTATUS *, FSTATUS *, short);
+void remover ( RSTATUS * );
+void rmfiles ( RSTATUS * , int );
+void rmreq ( RSTATUS * );
+void schedule ( int , ... );
+void take_message ( void );
+void terminate ( EXEC * );
+void unload_list ( char *** );
+void unload_str ( char ** );
+void unqueue_form ( RSTATUS * );
+void unqueue_pwheel ( RSTATUS * );
+void update_req ( char * , long );
+int isFormMountedOnPrinter ( PSTATUS *, FSTATUS * );
+int isFormUsableOnPrinter ( PSTATUS *, FSTATUS * );
+char *allTraysWithForm ( PSTATUS *, FSTATUS * );
+extern int list_append(void ***, void *);
+extern void list_remove(void ***, void *);
+
+extern RSTATUS *new_rstatus(REQUEST *, SECURE *);
+extern PSTATUS *new_pstatus(PRINTER *);
+extern CSTATUS *new_cstatus(CLASS *);
+extern FSTATUS *new_fstatus(_FORM *f);
+extern PWSTATUS *new_pwstatus(PWHEEL *p);
+extern ALERT *new_alert(char *fmt, int i);
+extern EXEC *new_exec(int type, void *ex);
+
+extern void pstatus_add_printer(PSTATUS *, PRINTER *);
+
+extern void free_exec(EXEC *);
+extern void free_alert(ALERT *);
+extern void free_pwstatus(PWSTATUS *);
+extern void free_fstatus(FSTATUS *);
+extern void free_cstatus(CSTATUS *);
+extern void free_pstatus(PSTATUS *);
+extern void free_rstatus(RSTATUS *);
+
+extern CSTATUS *search_cstatus ( char * );
+extern FSTATUS *search_fptable(register char *);
+extern FSTATUS *search_fstatus ( char * );
+extern PSTATUS *search_pstatus ( char * );
+extern PWSTATUS *search_pwstatus ( char * );
+
+/*
+ * Things that can't be passed as parameters:
+ */
+
+extern FSTATUS *form_in_question;
+
+extern char *pwheel_in_question;
+
+/**
+ ** External tables, lists:
+ **/
+
+extern CSTATUS **CStatus; /* Status of classes */
+extern PSTATUS **PStatus; /* Status of printers */
+extern FSTATUS **FStatus; /* Status of forms */
+extern PWSTATUS **PWStatus; /* Status of print wheels */
+
+extern EXEC **Exec_Table; /* Running processes */
+extern EXEC **Exec_Slow, /* First slow filter exec */
+ **Exec_Notify; /* First notification exec */
+
+extern RSTATUS *Request_List; /* Queue of print requests */
+extern RSTATUS *NewRequest; /* Not in Request_List yet */
+
+extern int ET_SlowSize, /* Number of filter execs */
+ ET_NotifySize; /* Number of notify execs */
+
+#if defined(DEBUG)
+#define DB_ABORT 0x00000008
+#define DB_SDB 0x00000020
+#define DB_ALL 0xFFFFFFFF
+
+extern unsigned long debug;
+#endif
+
+extern char *Local_System, /* Node name of local system */
+ *SHELL; /* value of $SHELL, or default */
+
+extern int lock_fd;
+
+extern uid_t Lp_Uid;
+
+extern gid_t Lp_Gid;
+
+extern int Starting,
+ OpenMax,
+ Sig_Alrm,
+ DoneChildren,
+ am_in_background,
+ Shutdown;
+
+extern unsigned long chkprinter_result;
+
+#if defined(MDL)
+#include "mdl.h"
+#endif
+# define CLOSE_ON_EXEC(fd) (void) Fcntl(fd, F_SETFD, 1)
diff --git a/usr/src/cmd/lp/cmd/lpsched/msgs.c b/usr/src/cmd/lp/cmd/lpsched/msgs.c
new file mode 100644
index 0000000000..a9e51c6224
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/msgs.c
@@ -0,0 +1,253 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+# include <stdarg.h>
+# include <limits.h>
+# include <sys/types.h>
+# include <poll.h>
+# include <stropts.h>
+# include <unistd.h>
+#include <syslog.h>
+
+# include "lpsched.h"
+
+#define TURN_OFF(X,F) (void)Fcntl(X, F_SETFL, (Fcntl(X, F_GETFL, 0) & ~(F)))
+
+
+static void conn_shutdown();
+
+extern int Filter_Status;
+extern void dispatch();
+extern int Waitrequest;
+void shutdown_messages();
+static char *Message;
+static int MaxClients = 0,
+ do_msg();
+extern int Reserve_Fds;
+extern int Shutdown;
+
+MESG *Net_md;
+
+/*
+** take_message() - WAIT FOR INTERRUPT OR ONE MESSAGE FROM USER PROCESS
+*/
+
+void take_message(void)
+{
+ int bytes;
+ int i;
+ MESG * md;
+
+ for (EVER) { /* not really forever...returns are in the loop */
+ if ((md = mlisten()) == NULL)
+ switch(errno) {
+ case EAGAIN:
+ case EINTR:
+ return;
+
+ case ENOMEM:
+ mallocfail();
+ /* NOTREACHED */
+
+ default:
+ fail ("Unexpected streams error in mlisten (%s).\n" , PERROR);
+ }
+
+ /*
+ * Check for a dropped connection to a child.
+ * Normally a child should tell us that it is dying
+ * (with S_SHUTDOWN or S_SEND_CHILD), but it may have
+ * died a fast death. We'll simulate the message we
+ * wanted to get so we can use the same code to clean up.
+ */
+ if ((md->event & POLLHUP) && !(md->event & POLLIN) ||
+ (md->event & (POLLERR|POLLNVAL))) {
+ switch (md->type) {
+
+ case MD_CHILD:
+ /*
+ * If the message descriptor is found in the
+ * exec table, it must be an interface pgm,
+ * notification, etc. Otherwise, it must be
+ * a network child.
+ */
+ for (i = 0; Exec_Table[i] != NULL; i++)
+ if (Exec_Table[i]->md == md)
+ break;
+
+ if (Exec_Table[i] != NULL) {
+ (void) putmessage(Message, S_CHILD_DONE,
+ Exec_Table[i]->key, 0, 0);
+ } else {
+ (void) putmessage(Message, S_SHUTDOWN, 1);
+ }
+ bytes = 1;
+ break;
+
+ default:
+ bytes = -1;
+ break;
+
+ }
+
+ } else {
+ if (md->readfd == -1) { /* something happened to the readfd */
+ syslog(LOG_DEBUG, "take_message: readfd is -1");
+ return;
+ }
+ bytes = mread(md, Message, MSGMAX);
+ }
+
+ switch (bytes) {
+ case -1:
+ if (errno == EINTR)
+ return;
+ else
+ fail ("Unexpected streams error (%s).\n" , PERROR);
+ break;
+
+ case 0:
+ break;
+
+ default:
+ if (do_msg(md))
+ return;
+ break;
+ }
+ }
+}
+
+/*
+** do_msg() - HANDLE AN INCOMING MESSAGE
+*/
+
+static int
+do_msg(MESG *md)
+{
+ int type = mtype(Message);
+
+ if (type != S_GOODBYE) {
+ md->wait = 0;
+ dispatch (type, Message, md);
+ /*
+ * The message may have caused the need to
+ * schedule something, so go back and check.
+ */
+ return(1);
+ }
+ return(0);
+}
+
+/*
+** calculate_nopen() - DETERMINE # FILE DESCRIPTORS AVAILABLE FOR QUEUES
+*/
+
+static void
+calculate_nopen(void)
+{
+ int fd, nopen;
+
+ /*
+ * How many file descriptorss are currently being used?
+ */
+ for (fd = nopen = 0; fd < OpenMax; fd++)
+ if (fcntl(fd, F_GETFL, 0) != -1)
+ nopen++;
+
+ /*
+ * How many file descriptors are available for use
+ * as open FIFOs? Leave one spare as a way to tell
+ * clients we don't have any to spare (hmmm....) and
+ * one for the incoming fifo.
+ */
+
+ MaxClients = OpenMax;
+ MaxClients -= nopen; /* current overhead */
+ MaxClients -= Reserve_Fds;
+ MaxClients -= 2; /* incoming FIFO and spare outgoing */
+ MaxClients--; /* the requests log */
+ MaxClients--; /* HPI routines and lpsched log */
+
+ return;
+}
+
+static void conn_shutdown ( )
+{
+ if (!Shutdown) {
+ note ("The public connection \"%s\", has failed.\n", Lp_FIFO);
+ lpshut(1);
+ }
+}
+
+/*
+** init_messages() - INITIALIZE MAIN MESSAGE QUEUE
+*/
+
+void
+init_messages(void)
+{
+ char *cmd;
+ MESG * md;
+
+ (void) signal(SIGPIPE, SIG_IGN);
+
+ calculate_nopen ();
+
+ Message = (char *)Malloc(MSGMAX);
+
+ (void) Chmod(Lp_Tmp, 0711);
+
+ if ((md = mcreate(Lp_FIFO)) == NULL)
+ fail ("Can't create public message device (%s).\n", PERROR);
+ mon_discon(md, conn_shutdown);
+
+ if (mlisteninit(md) != 0)
+ if (errno == ENOMEM)
+ mallocfail();
+ else
+ fail ("Unexpected streams error (%s).\n" , PERROR);
+
+ (void) Chmod(Lp_FIFO, 0666);
+ return;
+}
+
+
+void
+shutdown_messages(void)
+{
+ MESG *md;
+
+ (void) Chmod(Lp_Tmp, 0700);
+ (void) Chmod(Lp_FIFO, 0600);
+ md = mlistenreset();
+ mdestroy(md);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/nodes.h b/usr/src/cmd/lp/cmd/lpsched/nodes.h
new file mode 100644
index 0000000000..3ace135c23
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/nodes.h
@@ -0,0 +1,212 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+typedef struct alert_node ALERT;
+typedef struct cstat_node CSTATUS;
+typedef struct exec_node EXEC;
+typedef struct form_node _FORM;
+typedef struct fstat_node FSTATUS;
+typedef struct pfstat_node PFSTATUS;
+typedef struct pstat_node PSTATUS;
+typedef struct pwstat_node PWSTATUS;
+typedef struct rstat_node RSTATUS;
+
+struct alert_node
+{
+ short active; /* Non-zero if triggered */
+ EXEC *exec; /* Index into EXEC table */
+ char *msgfile;
+};
+
+struct cstat_node
+{
+ short status;
+ char *rej_reason;
+ time_t rej_date;
+ CLASS *class;
+};
+
+struct exec_node
+{
+ int pid; /* process-id of exec */
+ int status; /* low order bits from wait */
+ long key; /* private key for security */
+ short Errno; /* copy of child's errno */
+ short type; /* type of exec, EX_... */
+ ushort flags; /* flags, EXF_... */
+ MESG *md;
+ union ex
+ {
+ RSTATUS *request;
+ FSTATUS *form;
+ PWSTATUS *pwheel;
+ PSTATUS *printer;
+ } ex;
+};
+
+#define EX_INTERF 1 /* exec interface for ex.printer */
+#define EX_SLOWF 2 /* exec slow filter for ex.request */
+#define EX_ALERT 3 /* exec alert for ex.printer */
+#define EX_FALERT 4 /* exec alert for ex.form */
+#define EX_PALERT 5 /* exec alert for ex.pwheel */
+#define EX_NOTIFY 6 /* exec notification for ex.request */
+#define EX_FAULT_MESSAGE 7 /* exec fault message*/
+#define EX_FORM_MESSAGE 8 /* form fault message*/
+
+#define EXF_RESTART 0x0001 /* restart the exec */
+#define EXF_KILLED 0x0002 /* terminate() has killed the exec */
+#define EXF_GONE 0x0004 /* child has disappeared */
+
+/*
+** Possible values for FLT.type
+*/
+#define FLT_FILES 1 /* remove alloc'd files */
+#define FLT_CHANGE 2 /* clear RS_CHANGING for .r1 */
+
+struct fstat_node
+{
+ _FORM *form;
+ ALERT *alert;
+ short requests; /* Number of events thus far */
+ short requests_last; /* # when alert last sent */
+ short trigger; /* Trigger when this value */
+ short mounted; /* # times currently mounted */
+ char **users_allowed;
+ char **users_denied;
+ char *cpi;
+ char *lpi;
+ char *plen;
+ char *pwid;
+};
+
+struct pfstat_node
+{
+ FSTATUS *form;
+ short isAvailable;
+};
+
+struct pstat_node
+{
+ short status; /* Current Status of printer */
+ RSTATUS *request;
+ PRINTER *printer;
+ ALERT *alert;
+ EXEC *exec;
+ PFSTATUS *forms;
+ char *pwheel_name;
+ PWSTATUS *pwheel;
+ char *dis_reason;
+ char *rej_reason;
+ char **users_allowed;
+ char **users_denied;
+ char **forms_allowed;
+ char **forms_denied;
+ char *cpi;
+ char *lpi;
+ char *plen;
+ char *pwid;
+ time_t dis_date;
+ time_t rej_date;
+ short last_dial_rc; /* last exit from dial() */
+ short nretry; /* number of dial attempts */
+ short nrequests; /* TEMP ONLY! (used variously) */
+ char *fault_reason;
+ EXEC *fault_exec;
+ short numForms;
+ char **paper_allowed;
+};
+
+struct pwstat_node
+{
+ PWHEEL *pwheel;
+ ALERT *alert;
+ short requests;
+ short requests_last; /* # when alert last sent */
+ short trigger;
+ short mounted;
+};
+
+#define send mputm
+
+struct rstat_node
+{
+ long status;
+ MESG *md;
+
+ char *req_file;
+ char *slow;
+ char *fast;
+ short copies; /* # copies interface is to make */
+ short reason; /* reason for failing _validate() */
+
+ SECURE *secure;
+ REQUEST *request;
+ PSTATUS *printer;
+ FSTATUS *form;
+ char *pwheel_name;
+ PWSTATUS *pwheel;
+ EXEC *exec; /* Pointer to running filter or notify */
+
+ char *printer_type;
+ char *output_type;
+ char *cpi;
+ char *lpi;
+ char *plen;
+ char *pwid;
+
+ RSTATUS *next;
+ RSTATUS *prev;
+ short msgType; /* for getting status */
+ short trayNum; /* for mounting trays remotely */
+ char *formName; /* for mounting forms remotely */
+};
+
+# define RSS_PWMAND 0x00000008 /* pwheel must be mounted */
+# define RSS_SEND_FAULT_MESSAGE 0x00000040 /* need to send message*/
+# define RSS_SEND_FORM_MESSAGE 0x00000080 /* need to send form message*/
+
+struct form_node
+{
+ SCALED plen;
+ SCALED pwid;
+ SCALED lpi;
+ SCALED cpi;
+ int np;
+ char *chset;
+ short mandatory;
+ char *rcolor;
+ char *comment;
+ char *conttype;
+ char *name;
+ FALERT alert;
+ char *paper;
+ short isDefault;
+};
diff --git a/usr/src/cmd/lp/cmd/lpsched/notify.c b/usr/src/cmd/lp/cmd/lpsched/notify.c
new file mode 100644
index 0000000000..bd5987718b
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/notify.c
@@ -0,0 +1,215 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "lpsched.h"
+
+static char *N_Msg[] = {
+ "Subject: Status of lp request %s\n\nYour request %s destined for %s%s\n",
+ "has completed successfully on printer %s.\n",
+ "was canceled by the lpsched daemon%s\n", /* bugfix 1100252 */
+ "encountered an error during filtering.\n",
+ "encountered an error while printing on printer %s.\n",
+ "Filtering stopped with an exit code of %d.\n",
+ "Printing stopped with an exit code of %d.\n",
+ "Filtering was interrupted with a signal %d.\n",
+ "Printing was interrupted with a signal %d.\n",
+ "\nReason for failure:\n\n%s\n",
+ "\nReason for being canceled:\n\n%s\n",
+};
+
+static struct reason {
+ short reason;
+ char *msg;
+} N_Reason[] = {
+ {
+ MNODEST,
+ "The requested print destination has been removed."
+ }, {
+ MERRDEST,
+ "All candidate destinations are rejecting further requests."
+ }, {
+ MDENYDEST,
+ "You are no longer allowed to use any printer suitable for\nthe request."
+ }, {
+ MDENYDEST,
+ "No candidate printer can handle these characteristics:"
+ }, {
+ MNOMEDIA,
+ "The form you requested no longer exists."
+ }, {
+ MDENYMEDIA,
+ "You are no longer allowed to use the form you requested."
+ }, {
+ MDENYMEDIA,
+ "The form you wanted now requires a different character set."
+ }, {
+ MNOFILTER,
+ "There is no longer a filter that will convert your file for printing."
+ }, {
+ MNOMOUNT,
+ "The form or print wheel you requested is not allowed on any\nprinter otherwise suitable for the request."
+ }, {
+ MNOSPACE,
+ "Memory allocation problem."
+ }, {
+ -1,
+ ""
+ }
+};
+
+
+static void print_reason(int, int);
+
+
+/**
+ ** notify() - NOTIFY USER OF FINISHED REQUEST
+ **/
+
+void
+notify(register RSTATUS *prs, char *errbuf, int k, int e, int slow)
+{
+ register char *cp;
+ char *file;
+ int fd;
+
+
+ /*
+ * Screen out cases where no notification is needed.
+ */
+ if (!(prs->request->outcome & RS_NOTIFY))
+ return;
+ if (
+ !(prs->request->actions & (ACT_MAIL|ACT_WRITE|ACT_NOTIFY))
+ && !prs->request->alert
+ && !(prs->request->outcome & RS_CANCELLED)
+ && !e && !k && !errbuf /* exited normally */
+ )
+ return;
+
+ /*
+ * Create the notification message to the user.
+ */
+ file = makereqerr(prs);
+ if ((fd = open_locked(file, "w", MODE_NOREAD)) >= 0) {
+ fdprintf(fd, N_Msg[0], prs->secure->req_id, prs->secure->req_id,
+ prs->request->destination,
+ STREQU(prs->request->destination, NAME_ANY)? " printer"
+ : "");
+
+ if (prs->request) {
+ char file[BUFSIZ];
+
+ GetRequestFiles(prs->request, file, sizeof(file));
+ fdprintf(fd, "\nThe job title was:\t%s\n", file);
+ fdprintf(fd, " submitted by:\t%s\n",
+ prs->request->user);
+ fdprintf(fd, " at:\t%s\n",
+ ctime(&prs->secure->date));
+ }
+
+ if (prs->request->outcome & RS_PRINTED)
+ fdprintf(fd, N_Msg[1], prs->printer->printer->name);
+
+ if (prs->request->outcome & RS_CANCELLED)
+ fdprintf(fd, N_Msg[2],
+ (prs->request->outcome & RS_FAILED)? ", and"
+ : ".");
+
+
+ if (prs->request->outcome & RS_FAILED) {
+ if (slow)
+ fdprintf(fd, N_Msg[3]);
+ else
+ fdprintf(fd, N_Msg[4],
+ prs->printer->printer->name);
+
+ if (e > 0)
+ fdprintf(fd, N_Msg[slow? 5 : 6], e);
+ else if (k)
+ fdprintf(fd, N_Msg[slow? 7 : 8], k);
+ }
+
+ if (errbuf) {
+ for (cp = errbuf; *cp && *cp == '\n'; cp++)
+ ;
+ fdprintf(fd, N_Msg[9], cp);
+ if (prs->request->outcome & RS_CANCELLED)
+ fdprintf(fd, "\n");
+ }
+
+ /* start fix for bugid 1100252 */
+ if (prs->request->outcome & RS_CANCELLED) {
+ print_reason (fd, prs->reason);
+ }
+
+ close(fd);
+ schedule (EV_NOTIFY, prs);
+
+ }
+ if (file)
+ Free (file);
+
+ return;
+}
+
+/**
+ ** print_reason() - PRINT REASON FOR AUTOMATIC CANCEL
+ **/
+
+static void
+print_reason(int fd, int reason)
+{
+ register int i;
+
+
+#define P(BIT,MSG) if (chkprinter_result & BIT) fdprintf(fd, MSG)
+
+ for (i = 0; N_Reason[i].reason != -1; i++)
+ if (N_Reason[i].reason == reason) {
+ if (reason == MDENYDEST && chkprinter_result)
+ i++;
+ if (reason == MDENYMEDIA && chkprinter_result)
+ i++;
+ fdprintf(fd, N_Msg[10], N_Reason[i].msg);
+ if (reason == MDENYDEST && chkprinter_result) {
+ P (PCK_TYPE, "\tprinter type\n");
+ P (PCK_CHARSET, "\tcharacter set\n");
+ P (PCK_CPI, "\tcharacter pitch\n");
+ P (PCK_LPI, "\tline pitch\n");
+ P (PCK_WIDTH, "\tpage width\n");
+ P (PCK_LENGTH, "\tpage length\n");
+ P (PCK_BANNER, "\tno banner\n");
+ }
+ break;
+ }
+
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/pickfilter.c b/usr/src/cmd/lp/cmd/lpsched/pickfilter.c
new file mode 100644
index 0000000000..e5aa5b817b
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/pickfilter.c
@@ -0,0 +1,496 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1996 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2.1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "limits.h"
+
+#include "lpsched.h"
+
+#include "validate.h"
+
+/*
+ * Transform consecutive "LP_SEP" characters to a single comma and n-1 LP_SEP;
+ *
+ * BUT we'll leave LP_SEP inside single quotes alone!
+ *
+ * This is to allow the following case (and the like) to work correctly:
+ * prtitle='standard input'
+ */
+
+void
+transform_WS_to_SEP(char *cp)
+{ char *p;
+ int inside_quote = 0;
+ int done_one_already = 0;
+
+ for (p = cp; *p != '\0'; p++) {
+ if (*p == '\'') {
+ inside_quote = (inside_quote + 1) % 2;
+ continue;
+ }
+ if (inside_quote)
+ continue;
+ if (*p == ' ') {
+ if (!done_one_already) {
+ *p = ',';
+ done_one_already = 1;
+ } else {
+ /* multiple LP_WS into one LP_SEP */
+ }
+ } else {
+ done_one_already = 0;
+ }
+ }
+}
+
+/**
+ ** pickfilter() - SEE IF WE CAN FIND A FILTER FOR THIS REQUEST
+ **/
+
+int
+pickfilter(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs)
+{
+ register char ** pp;
+ register char ** pl;
+
+ register PSTATUS * pps = pc->pps;
+
+ char * pipes[2] = { 0 , 0 };
+ char * cp;
+ char * output_type;
+
+ char ** modes = 0;
+ char ** parms = 0;
+ char ** valid_printer_types;
+ char ** p_cpi = 0;
+ char ** p_lpi = 0;
+ char ** p_pwid = 0;
+ char ** p_plen = 0;
+
+ FILTERTYPE ret = fl_none;
+
+ int got_cpi = 0;
+ int got_lpi = 0;
+ int got_plen = 0;
+ int got_pwid = 0;
+ int must_have_filter= 0;
+
+ unsigned long chk;
+
+
+ /* fix for bugid 1097387 */
+ output_type = (char *) NULL;
+
+ /*
+ * The bulk of the code below is building a parameter list "parms"
+ * to send to "insfilter()".
+ */
+
+ if (prs->request->modes) {
+ cp = Strdup(prs->request->modes);
+ transform_WS_to_SEP(cp);
+ modes = getlist(cp, "", LP_SEP);
+ Free (cp);
+ }
+
+ pp = parms = (char **)Malloc(
+ 2 * (NPARM_SPEC + lenlist(modes) + 1) * sizeof(char *)
+ );
+
+ /*
+ * Add to the parameter list the appropriate cpi/lpi/etc.
+ * characteristics (aka ``stuff'') that will be used for
+ * this job. The printer defaults are questionable.
+ * Take this opportunity to also save the ``stuff'' in
+ * the request structure.
+ */
+
+ unload_str (&(prs->cpi));
+ unload_str (&(prs->lpi));
+ unload_str (&(prs->plen));
+ unload_str (&(prs->pwid));
+
+ /*
+ * If a form is involved, pick up its page size and print
+ * spacing requirements.
+ */
+ if (pfs) {
+ if (pfs->cpi) {
+ *pp++ = PARM_CPI;
+ *pp++ = prs->cpi = pfs->cpi;
+ got_cpi = 1;
+ }
+ if (pfs->lpi) {
+ *pp++ = PARM_LPI;
+ *pp++ = prs->lpi = pfs->lpi;
+ got_lpi = 1;
+ }
+ if (pfs->plen) {
+ *pp++ = PARM_LENGTH;
+ *pp++ = prs->plen = pfs->plen;
+ got_plen = 1;
+ }
+ if (pfs->pwid) {
+ *pp++ = PARM_WIDTH;
+ *pp++ = prs->pwid = pfs->pwid;
+ got_pwid = 1;
+ }
+
+ /*
+ * If no form is involved, pick up whatever page size and print
+ * spacing requirements were given by the user.
+ */
+ } else {
+ if (o_cpi) {
+ *pp++ = PARM_CPI;
+ *pp++ = prs->cpi = o_cpi;
+ got_cpi = 1;
+ }
+ if (o_lpi) {
+ *pp++ = PARM_LPI;
+ *pp++ = prs->lpi = o_lpi;
+ got_lpi = 1;
+ }
+ if (o_length) {
+ *pp++ = PARM_LENGTH;
+ *pp++ = prs->plen = o_length;
+ got_plen = 1;
+ }
+ if (o_width) {
+ *pp++ = PARM_WIDTH;
+ *pp++ = prs->pwid = o_width;
+ got_pwid = 1;
+ }
+ }
+
+ /*
+ * Pick up whatever page size and print spacing requirements
+ * haven't been specified yet from the printer defaults.
+ *
+ * Note: The following cpi/lpi/etc are guaranteed to work
+ * for at least one type of the printer at hand, but not
+ * necessarily all types. Once we pick a type that works
+ * we'll verify that the cpi/lpi/etc stuff works, too.
+ * The code that does that assumes that we do the following last,
+ * after picking up the form and/or user stuff. If this changes,
+ * then the later code will have to be changed, too.
+ */
+ if (!got_cpi && pps->cpi) {
+ *pp++ = PARM_CPI;
+ *(p_cpi = pp++) = prs->cpi = pps->cpi;
+ }
+ if (!got_lpi && pps->lpi) {
+ *pp++ = PARM_LPI;
+ *(p_lpi = pp++) = prs->lpi = pps->lpi;
+ }
+ if (!got_plen && pps->plen) {
+ *pp++ = PARM_LENGTH;
+ *(p_plen = pp++) = prs->plen = pps->plen;
+ }
+ if (!got_pwid && pps->pwid) {
+ *pp++ = PARM_WIDTH;
+ *(p_pwid = pp++) = prs->pwid = pps->pwid;
+ }
+
+ /*
+ * Pick up the number of pages, character set (the form's
+ * or the user's), the form name, the number of copies,
+ * and the modes.
+ */
+
+ if (prs->request->pages) {
+ *pp++ = PARM_PAGES;
+ *pp++ = prs->request->pages;
+ must_have_filter = 1;
+ }
+
+ if (prs->request->charset) {
+ *pp++ = PARM_CHARSET;
+ *pp++ = prs->request->charset;
+
+ } else if (pfs && pfs->form->chset) {
+ *pp++ = PARM_CHARSET;
+ *pp++ = pfs->form->chset;
+ }
+
+ if (prs->request->form) {
+ *pp++ = PARM_FORM;
+ *pp++ = prs->request->form;
+ }
+
+ if (prs->request->copies > 1) {
+ *pp++ = PARM_COPIES;
+ sprintf ((*pp++ = BIGGEST_NUMBER_S), "%d", prs->request->copies);
+ }
+
+ if (modes) {
+ for (pl = modes; *pl; pl++) {
+ *pp++ = PARM_MODES;
+ *pp++ = *pl;
+ }
+ must_have_filter = 1;
+ }
+
+ *pp = 0; /* null terminated list! */
+
+
+ /*
+ * If the printer type(s) are not ``unknown'', then include
+ * them as possible ``output'' type(s) to match
+ * with the user's input type (directly, or through a filter).
+ */
+ if (!STREQU(*(pps->printer->printer_types), NAME_UNKNOWN))
+ valid_printer_types = pc->printer_types;
+ else {
+ valid_printer_types = 0;
+ must_have_filter = 0;
+ }
+
+ pc->fast = 0;
+ pc->slow = 0;
+ pc->output_type = 0;
+ pc->flags = 0;
+ ret = fl_none;
+
+ /*
+ * If we don't really need a filter and the types match,
+ * then that's good enough. Some ``broadly defined''
+ * filters might match our needs, but if the printer
+ * can do what we need, then why pull in a filter?
+
+
+
+ * Besides, Section 3.40 in the requirements imply
+ * that we don't use a filter if the printer can handle
+ * the file.
+ */
+ if (!must_have_filter ) {
+
+ if (
+ valid_printer_types
+ && searchlist_with_terminfo(
+ prs->request->input_type,
+ valid_printer_types
+ )
+ ) {
+ ret = fl_both; /* not really, but ok */
+ pc->printer_type = Strdup(prs->request->input_type);
+
+ } else if (
+ pps->printer->input_types
+ && searchlist_with_terminfo(
+ prs->request->input_type,
+ pps->printer->input_types
+ )
+ ) {
+ ret = fl_both; /* not really, but ok */
+
+ /*
+ * (1) There is one printer type, might even
+ * be ``unknown'';
+ * (2) There are several printer types, but that
+ * means only one input type, ``simple'',
+ * which any of the printer types can handle.
+ */
+ pc->printer_type = Strdup(*(pc->printer_types));
+
+ }
+ }
+
+ /*
+ * Don't try using a filter if the user doesn't want
+ * a filter to be used! He or she would rather see an
+ * error message than (heaven forbid!) a filter being
+ * used.
+ */
+ if (ret == fl_none && !(prs->request->actions & ACT_RAW)) {
+
+ /*
+ * For each printer type, and each input type the printer
+ * accepts, see if we have a filter that matches the
+ * request to the printer. Each time we try, save the
+ * output type we use in case of success; we just might
+ * need that value later....
+ */
+
+ for (
+ pl = valid_printer_types;
+ pl && *pl && ret == fl_none;
+ pl++
+ )
+ ret = insfilter(
+ pipes,
+ prs->request->input_type,
+ (output_type = *pl),
+ *pl,
+ pps->printer->name,
+ parms,
+ &(pc->flags)
+ );
+ if (ret != fl_none)
+ pc->printer_type = Strdup(*pl);
+
+ for (
+ pl = pps->printer->input_types;
+ pl && *pl && ret == fl_none;
+ pl++
+ )
+ /*
+ * Don't waste time with check we've already made.
+ */
+ if ((must_have_filter == 1) ||
+ !valid_printer_types
+ || !searchlist(*pl, valid_printer_types)
+ )
+ /*
+ * Either we have one (or less) printer
+ * types and many input types, or we have
+ * one input type, ``simple''; regardless,
+ * using the first printer type is OK.
+ */
+ ret = insfilter(
+ pipes,
+ prs->request->input_type,
+ (output_type = *pl),
+ *(pc->printer_types),
+ pps->printer->name,
+ parms,
+ &(pc->flags)
+ );
+ if (ret != fl_none)
+ pc->printer_type = Strdup(*(pc->printer_types));
+
+ }
+
+ /*
+ * If we were successful, check that the printer type
+ * we picked can handle the PRINTER'S cpi/lpi/etc. defaults.
+ * (We know that ALL the printer's types can handle the stuff
+ * the user gave or the stuff in the form.)
+ * Each printer's default that doesn't pass muster gets dropped.
+ * This may mean re-instantiating the filter(s) (if any).
+ */
+ if (ret != fl_none && (p_cpi || p_lpi || p_pwid || p_plen)) {
+
+#define NZ(X) ((X)? *(X) : (char *)0)
+ chk = chkprinter(
+ pc->printer_type,
+ NZ(p_cpi),
+ NZ(p_lpi),
+ NZ(p_plen),
+ NZ(p_pwid),
+ (char *)0
+ );
+
+ if (chk) {
+ register char ** _pp;
+
+ char * hole = "";
+
+
+ /*
+ * Remove the offending printer defaults from the
+ * request list of cpi/lpi/etc. stuff, and punch
+ * (non-null!) holes in the parameter list.
+ */
+#define DROP(P,R) if (P) {P[-1] = P[0] = hole; R = 0;} else/*EMPTY*/
+ if (chk & PCK_CPI) DROP (p_cpi, prs->cpi);
+ if (chk & PCK_LPI) DROP (p_lpi, prs->lpi);
+ if (chk & PCK_WIDTH) DROP (p_pwid, prs->pwid);
+ if (chk & PCK_LENGTH) DROP (p_plen, prs->plen);
+
+ /*
+ * If there are filters, we have to re-instantiate
+ * them. (Can't check "ret" here, because it may
+ * be misleading.)
+ */
+ if (pipes[0] || pipes[1]) {
+
+ /*
+ * First, close up the gaps we punched in
+ * the parameter list.
+ */
+ for (pp = _pp = parms; *pp; pp++)
+ if (*pp != hole)
+ *_pp++ = *pp;
+ *_pp = 0;
+
+ /*
+ * Re-instantiate the filter(s). This
+ * CAN'T fail, because it is not mandatory
+ * that filters handle cpi/lpi/etc. stuff.
+ */
+ ret = insfilter(
+ pipes,
+ prs->request->input_type,
+ output_type,
+ pc->printer_type,
+ pps->printer->name,
+ parms,
+ &(pc->flags)
+ );
+ }
+ }
+ }
+
+ /*
+ * Save the filters, if any. Note: although "ret" can be
+ * misleading, i.e. set to "fl_both" when there really aren't
+ * any filters, the declaration of "pipes" ensured they'd be
+ * zero if not set.
+ */
+ if (ret == fl_both || ret == fl_slow)
+ pc->slow = pipes[0];
+ if (ret == fl_both || ret == fl_fast)
+ pc->fast = pipes[1];
+
+ if (ret != fl_none)
+ pc->output_type = Strdup (output_type);
+
+ /*
+ * Wait until now to allocate storage for the cpi/etc.
+ * stuff, to make life easier above.
+ */
+ if (prs->cpi) prs->cpi = Strdup(prs->cpi);
+ if (prs->lpi) prs->lpi = Strdup(prs->lpi);
+ if (prs->plen) prs->plen = Strdup(prs->plen);
+ if (prs->pwid) prs->pwid = Strdup(prs->pwid);
+
+
+ if (parms)
+ Free ((char *)parms);
+ if (modes)
+ freelist (modes);
+
+ return ((ret != fl_none));
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/ports.c b/usr/src/cmd/lp/cmd/lpsched/ports.c
new file mode 100644
index 0000000000..cf1e8a226f
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/ports.c
@@ -0,0 +1,330 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include "termio.h"
+#include "dial.h"
+#include "unistd.h"
+
+#include "lpsched.h"
+
+#include <sys/ioccom.h>
+#include <sys/ecppsys.h>
+
+static void sigalrm(int);
+static int push_module(int, char *, char *);
+
+static int SigAlrm;
+
+/*
+ * open_dialup() - OPEN A PORT TO A ``DIAL-UP'' PRINTER
+ */
+
+int
+open_dialup(char *ptype, PRINTER *pp)
+{
+ static char *baud_table[] = {
+ 0,
+ "50",
+ "75",
+ "110",
+ "134",
+ "150",
+ "200",
+ "300",
+ "600",
+ "1200",
+ "1800",
+ "2400",
+ "4800",
+ "9600",
+ "19200",
+ "38400",
+ "57600",
+ "76800",
+ "115200",
+ "153600",
+ "230400",
+ "307200",
+ "460800",
+ "921600"
+ };
+
+ struct termio tio;
+ struct termios tios;
+
+ CALL call;
+
+ int speed, fd;
+
+ char *sspeed;
+
+
+ if (pp->speed == NULL || (speed = atoi(pp->speed)) <= 0)
+ speed = -1;
+
+ call.attr = 0;
+ call.speed = speed;
+ call.line = 0;
+ call.telno = pp->dial_info;
+
+ if ((fd = dial(call)) < 0)
+ return (EXEC_EXIT_NDIAL | (~EXEC_EXIT_NMASK & abs(fd)));
+
+ /*
+ * "dial()" doesn't guarantee which file descriptor
+ * it uses when it opens the port, so we probably have to
+ * move it.
+ */
+ if (fd != 1) {
+ dup2(fd, 1);
+ Close(fd);
+ }
+
+ /*
+ * The "printermgmt()" routines move out of ".stty"
+ * anything that looks like a baud rate, and puts it
+ * in ".speed", if the printer port is dialed. Thus
+ * we are saved the task of cleaning out spurious
+ * baud rates from ".stty".
+ *
+ * However, we must determine the baud rate and
+ * concatenate it onto ".stty" so that that we can
+ * override the default in the interface progam.
+ * Putting the override in ".stty" allows the user
+ * to override us (although it would be probably be
+ * silly for him or her to do so.)
+ */
+ if (ioctl(1, TCGETS, &tios) < 0) {
+ ioctl(1, TCGETA, &tio);
+ tios.c_cflag = tio.c_cflag;
+ }
+ if ((sspeed = baud_table[cfgetospeed(&tios)]) != NULL) {
+
+ if (pp->stty == NULL)
+ pp->stty = "";
+
+ {
+ char *new_stty = Malloc(
+ strlen(pp->stty) + 1 + strlen(sspeed) + 1);
+
+ sprintf(new_stty, "%s %s", pp->stty, sspeed);
+
+ /*
+ * We can trash "pp->stty" because
+ * the parent process has the good copy.
+ */
+ pp->stty = new_stty;
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * open_direct() - OPEN A PORT TO A DIRECTLY CONNECTED PRINTER
+ */
+
+int
+open_direct(char *ptype, PRINTER *pp)
+{
+ short bufsz = -1, cps = -1;
+ int open_mode, fd;
+ register unsigned int oldalarm, newalarm = 0;
+ char *device;
+
+ struct ecpp_transfer_parms ecpp_params; /* for ECPP port checking */
+ char **modules = NULL;
+
+ struct flock lck;
+ struct stat buf;
+
+ register void (*oldsig)() = signal(SIGALRM, sigalrm);
+
+
+ /*
+ * Set an alarm to wake us from trying to open the port.
+ * We'll try at least 60 seconds, or more if the printer
+ * has a huge buffer that, in the worst case, would take
+ * a long time to drain.
+ */
+ tidbit(ptype, "bufsz", &bufsz);
+ tidbit(ptype, "cps", &cps);
+ if (bufsz > 0 && cps > 0)
+ newalarm = (((long)bufsz * 1100) / cps) / 1000;
+ if (newalarm < 60)
+ newalarm = 60;
+ oldalarm = alarm(newalarm);
+
+ device = pp->device;
+ if (is_printer_uri(device) == 0) {
+ /*
+ * if it's a device uri and the endpoint contains a valid
+ * path, that path should be opened/locked by lpsched for
+ * the backend. If not, the uri isn't associated with a
+ * local device, so use /dev/null.
+ */
+ device = strstr(device, "://");
+ if (device != NULL)
+ device = strchr(device + 3, '/');
+
+ if ((device == NULL) || (access(device, F_OK) < 0))
+ device = "/dev/null";
+ }
+
+ /*
+ * The following open must be interruptable.
+ * O_APPEND is set in case the ``port'' is a file.
+ * O_RDWR is set in case the interface program wants
+ * to get input from the printer. Don't fail, though,
+ * just because we can't get read access.
+ */
+
+ open_mode = O_WRONLY;
+ if (access(device, R_OK) == 0)
+ open_mode = O_RDWR;
+ open_mode |= O_APPEND;
+
+ SigAlrm = 0;
+
+ while ((fd = open(device, open_mode, 0)) == -1) {
+ if (errno != EINTR)
+ return (EXEC_EXIT_NPORT);
+ else if (SigAlrm)
+ return (EXEC_EXIT_TMOUT);
+ }
+
+ alarm(oldalarm);
+ signal(SIGALRM, oldsig);
+
+ /*
+ * Lock the file in case two "printers" are defined on the
+ * same port. Don't lock /dev/null.
+ */
+
+ lck.l_type = F_WRLCK;
+ lck.l_whence = 0;
+ lck.l_start = 0L;
+ lck.l_len = 0L;
+
+ if (strcmp(device, "/dev/null") && Fcntl(fd, F_SETLKW, &lck) < 0) {
+ execlog("lock error: %s\n", pp->device);
+ return (EXEC_EXIT_NPORT);
+ }
+
+ /*
+ * We should get the correct channel number (1), but just
+ * in case....
+ */
+ if (fd != 1) {
+ dup2(fd, 1);
+ Close(fd);
+ }
+
+ /*
+ * Handle streams modules:
+ */
+ if (fstat(1, &buf))
+ buf.st_mode = 0;
+
+ /*
+ * for some unknown reason, lpsched appears to pop the streams
+ * modules off the device and push back some "default" ones,
+ * unless a specific set were specified with the printer configuration.
+ * This behaviour causes problems with the ECPP port, so if we have
+ * an ECPP port, and nobody specified a set of modules to use, we
+ * should leave it alone. Normally, we would not bother to play with
+ * the streams modules, but it is possible that someone has come
+ * to rely on this behaviour for other devices.
+ */
+ if ((pp->modules != NULL) && (pp->modules[0] != NULL) &&
+ (strcmp(pp->modules[0], "default") != 0))
+ modules = pp->modules;
+
+ if ((modules == NULL) && (ioctl(1, ECPPIOC_GETPARMS, &ecpp_params) < 0))
+ modules = getlist(DEFMODULES, LP_WS, LP_SEP);
+
+ /* if "nopush" is supplied, leave the modules alone */
+ if ((modules != NULL) && (modules[0] != NULL) &&
+ (strcasecmp(modules[0], "nopush") == 0))
+ modules = NULL;
+
+ /*
+ * If we have a stream and a list of modules to use, then pop the old
+ * modules and push the new ones.
+ */
+ if ((modules != NULL) && !S_ISFIFO(buf.st_mode) && isastream(1)) {
+ /*
+ * First, pop all current modules off, unless
+ * instructed not to.
+ */
+ while (ioctl(1, I_POP, 0) == 0)
+ ;
+
+ /*
+ * Now push either the administrator specified modules
+ * or the standard modules, unless instructed to push
+ * nothing.
+ */
+
+ if ((modules[1] == NULL) &&
+ (strcasecmp(modules[0], "none") == 0))
+ return (0);
+
+ while (*modules)
+ if (push_module(1, device, *modules++) == -1)
+ return (EXEC_EXIT_NPUSH);
+ }
+
+ return (0);
+}
+
+/*
+ * sigalrm()
+ */
+static void
+sigalrm(int ignore)
+{
+ signal(SIGALRM, SIG_IGN);
+ SigAlrm = 1;
+}
+
+
+/*
+ * push_module()
+ */
+
+static int
+push_module(int fd, char *device, char *module)
+{
+ int ret = ioctl(fd, I_PUSH, module);
+
+ if (ret == -1)
+ note("push (%s) on %s failed (%s)\n", module, device, PERROR);
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/print-svc b/usr/src/cmd/lp/cmd/lpsched/print-svc
new file mode 100644
index 0000000000..97c48a9c68
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/print-svc
@@ -0,0 +1,167 @@
+#!/sbin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+. /lib/svc/share/smf_include.sh
+. /lib/svc/share/ipf_include.sh
+
+# SERVICE = parent service name
+SERVICE=`echo $SMF_FMRI | /usr/bin/cut -f1,2 -d":"`
+
+case "$1" in
+'start')
+
+isopts=`/usr/sbin/svccfg <<-EOF
+ select $SMF_FMRI
+ listpg cmd_opts
+
+ EOF`
+
+if [ "$isopts" ] ; then
+
+#called by /usr/lib/lpsched; use cmd_opts properties only
+
+ num_notifiers=`/bin/svcprop -p cmd_opts/num_notifiers $SMF_FMRI`
+
+ if [ "$num_notifiers" != "" ] ; then
+ OPTS="$OPTS -n $num_notifiers"
+ fi
+
+ num_filters=`/bin/svcprop -p cmd_opts/num_filters $SMF_FMRI`
+
+ if [ "$num_filters" != "" ] ; then
+ OPTS="$OPTS -f $num_filters"
+ fi
+
+ fd_limit=`/bin/svcprop -p cmd_opts/fd_limit $SMF_FMRI`
+
+ if [ "$fd_limit" != "" ] ; then
+ OPTS="$OPTS -p $fd_limit"
+ fi
+
+ reserved_fds=`/bin/svcprop -p cmd_opts/reserved_fds $SMF_FMRI`
+
+ if [ "$reserved_fds" != "" ] ; then
+ OPTS="$OPTS -r $reserved_fds"
+ fi
+
+# clear out cmd_opts property group
+
+ svccfg <<-EOF
+ select $SMF_FMRI
+ delpg cmd_opts
+
+ EOF
+
+else
+
+# We are here through enable; use lpsched properties
+# Check for saved properties
+
+ num_notifiers=`/bin/svcprop -p lpsched/num_notifiers $SERVICE`
+ if [ "$num_notifiers" != "" ] && [ "$num_notifiers" != "0" ] ; then
+ OPTS="$OPTS -n $num_notifiers"
+ fi
+
+ num_filters=`/bin/svcprop -p lpsched/num_filters $SERVICE`
+ if [ "$num_filters" != "" ] && [ "$num_filters" != "0" ] ; then
+ OPTS="$OPTS -f $num_filters"
+ fi
+
+ fd_limit=`/bin/svcprop -p lpsched/fd_limit $SERVICE`
+ if [ "$fd_limit" != "" ] && [ "$fd_limit" != "0" ]; then
+ OPTS="$OPTS -p $fd_limit"
+ fi
+
+ reserved_fds=`/bin/svcprop -p lpsched/reserved_fds $SERVICE`
+ if [ "$reserved_fds" != "" ] && [ "$reserved_fds" != "0" ] ; then
+ OPTS="$OPTS -r $reserved_fds"
+ fi
+fi
+
+# set temporary or permanent properties from OPTS
+
+ [ -f /usr/lib/lp/local/lpsched ] || exit $SMF_EXIT_ERR_CONFIG
+
+ /usr/lib/lp/local/lpsched ${OPTS}
+
+ ;;
+
+'stop')
+ [ -f /usr/lib/lp/local/lpshut ] || exit $SMF_EXIT_ERR_CONFIG
+
+ /usr/lib/lp/local/lpshut
+ ;;
+
+'ipfilter')
+ FMRI=$2
+ IPP_FMRI="svc:/application/print/ipp-listener:default"
+ RFC1179_FMRI="svc:/application/print/rfc1179:default"
+ IPP_CONF=/etc/apache/httpd-standalone-ipp.conf
+ ip="any"
+
+ policy=`get_policy $FMRI`
+
+ file=`fmri_to_file $RFC1179_FMRI $IPF_SUFFIX`
+ echo "# $RFC1179_FMRI" >$file
+ service_is_enabled ${RFC1179_FMRI}
+ if [ $? -eq 0 ]; then
+ rfc_name=`svcprop -p inetd/name ${RFC1179_FMRI} 2>/dev/null`
+ rfc_proto=`svcprop -p inetd/proto ${RFC1179_FMRI} 2>/dev/null | \
+ sed 's/6/ /'`
+ rfc_port=`$SERVINFO -p -t -s $rfc_name`
+ generate_rules $FMRI $policy $rfc_proto $ip $rfc_port $file
+ fi
+
+ file=`fmri_to_file $IPP_FMRI $IPF_SUFFIX`
+ echo "# $IPP_FMRI" >$file
+ service_is_enabled ${IPP_FMRI}
+ if [ $? -eq 0 ]; then
+ #
+ # If Listen directives are used, it's possibie to listen on
+ # more than one ports. Process the Port directives only when Listen
+ # directives don't exist.
+ #
+ ipp_ports=`grep '^[ \t]*[^# ]*Listen' ${IPP_CONF} | awk '{print $2}'`
+
+ if [ -z "$ipp_ports" ]; then
+ ipp_ports=`grep '^[ \t]*[^# ]*Port' ${IPP_CONF} | \
+ awk '{print $2}' | tail -1`
+ fi
+
+ for port in $ipp_ports; do
+ generate_rules $FMRI $policy "tcp" $ip $port $file
+ done
+ fi
+
+ ;;
+
+*)
+ echo "Usage: $0 { start | stop }"
+ exit 1
+ ;;
+esac
+exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/lp/cmd/lpsched/requeue.c b/usr/src/cmd/lp/cmd/lpsched/requeue.c
new file mode 100644
index 0000000000..47798de6b3
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/requeue.c
@@ -0,0 +1,271 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "lpsched.h"
+#include "validate.h"
+
+/*
+ * The routines in this file are used to examine queued requests
+ * to see if something must be done about them. We don't bother
+ * checking requests that are:
+ *
+ * - printing (we could, to allow the administrator to stop
+ * a request by making a configuration change, but that
+ * can lead to trouble (yet another way to terminate a child)
+ * and the administrator can always disable the request to
+ * force it to stop printing and be reevaluated);
+ *
+ * - changing, since once the change is complete the request
+ * will be reevaluated again anyway;
+ *
+ * - notifying, since the request is essentially finished
+ *
+ * - being sent or already sent to a remote machine;
+ *
+ * - done.
+ *
+ * Requests that are being held or are filtering ARE to be considered,
+ * because things may have changed to make them impossible to print.
+ */
+#define RS_SKIP ((RS_ACTIVE & ~RS_FILTERING) | RS_DONE)
+#define SKIP_IT(PRS) ((PRS)->request->outcome & RS_SKIP)
+
+/**
+ ** queue_attract() - REASSIGN REQUEST(S) TO PRINTER, IF POSSIBLE
+ **/
+
+void
+queue_attract(PSTATUS *pps, int (*qchk_p)(RSTATUS *), int attract_just_one)
+{
+ register RSTATUS *prs;
+ register CSTATUS *pcs;
+ int called_schedule = 0;
+
+
+ /*
+ * Evaluate requests that:
+ * - meet a criteria set by a function passed.
+ * - are already queued for the printer
+ * - are destined for a class containing this printer
+ * - or are destined for any printer
+ * We stop on the first one that will work on the printer,
+ * and schedule an interface for the printer (which will
+ * find the first request ready, namely the one we stopped on).
+ */
+
+#define SAMECLASS(PRS,PPS) \
+ ( \
+ ((pcs = search_cstatus(PRS->request->destination)) != NULL) \
+ && searchlist(PPS->printer->name, pcs->class->members) \
+ )
+
+#define ISANY(PRS) STREQU(PRS->request->destination, NAME_ANY)
+
+ for (prs = Request_List; prs; prs = prs->next) {
+ if (
+ !SKIP_IT(prs)
+ && (!qchk_p || (*qchk_p)(prs))
+ && (
+ prs->printer == pps
+ || ISANY(prs)
+ || SAMECLASS(prs, pps)
+ )
+ )
+ /*
+ * Don't need to evaluate the request if it
+ * is already queued!
+ */
+ if (
+ prs->printer == pps
+ || evaluate_request(prs, pps, 0) == MOK
+ ) {
+ /*
+ * This request was attracted to the
+ * printer but maybe it now needs to be
+ * filtered. If so, filter it but see if
+ * there's another request all set to go.
+ */
+ if (NEEDS_FILTERING(prs))
+ schedule (EV_SLOWF, prs);
+ else {
+ if (!called_schedule) {
+ schedule (EV_INTERF, pps);
+ called_schedule = 1;
+ }
+ if (attract_just_one)
+ break;
+ }
+ }
+ }
+
+ return;
+}
+
+/**
+ ** queue_repel() - REASSIGN REQUESTS TO ANOTHER PRINTER, IF POSSIBLE
+ **/
+
+int
+queue_repel(PSTATUS *pps, int move_off, int (*qchk_p)(RSTATUS *))
+{
+ register RSTATUS *prs;
+ register int all_can = 1;
+ register PSTATUS *stop_pps = (move_off? pps : 0);
+
+ /*
+ * Reevaluate all requests that are assigned to this
+ * printer, to see if there's another printer that
+ * can handle them.
+ *
+ * If the "move_off" flag is set, don't consider the current
+ * printer when reevaluating, but also don't cancel the request
+ * if it can't be moved off the printer.
+ * (Currently this is only used when deciding if a printer
+ * can be deleted.)
+ */
+ for (prs = Request_List; prs != NULL; prs = prs->next) {
+ if (prs->printer != pps)
+ continue;
+
+ /*
+ * "all_can" keeps track of whether all of the requests
+ * of interest to the caller (governed by "qchk_p") can
+ * be moved to another printer. Now we don't move certain
+ * requests (active, done, gone remote), and some of those
+ * matter in the ``all can'' consideration.
+ */
+ if (qchk_p && !(*qchk_p)(prs))
+ continue;
+ else if (SKIP_IT(prs)) {
+ if ( !(prs->request->outcome & RS_DONE) )
+ all_can = 0;
+ continue;
+
+ } else
+
+ if (reevaluate_request(prs, stop_pps) == MOK) {
+
+ /*
+ * If this request needs to be filtered,
+ * try to schedule it for filtering,
+ * otherwise schedule it for printing.
+ * We are inefficient here, because we may
+ * try to schedule many requests but the
+ * filtering slot(s) and printers are
+ * busy; but the requests may languish
+ * if we don't check here.
+ */
+ if (NEEDS_FILTERING(prs))
+ schedule (EV_SLOWF, prs);
+ else
+ schedule (EV_INTERF, prs->printer);
+
+ } else {
+ all_can = 0;
+ if (!move_off)
+ cancel (prs, 1);
+ else
+ prs->reason = MOK;
+ }
+ }
+
+ return (all_can);
+}
+
+/**
+ ** queue_check() - CHECK ALL REQUESTS AGAIN
+ **/
+
+void
+queue_check(int (*qchk_p)( RSTATUS * ))
+{
+ register RSTATUS *prs;
+
+
+ for (prs = Request_List; prs; prs = prs->next)
+ if (!SKIP_IT(prs) && (!qchk_p || (*qchk_p)(prs)))
+ if (reevaluate_request(prs, (PSTATUS *)0) == MOK)
+ if (NEEDS_FILTERING(prs))
+ schedule (EV_SLOWF, prs);
+ else
+ schedule (EV_INTERF, prs->printer);
+ else
+ cancel (prs, 1);
+
+ return;
+}
+
+/**
+ ** qchk_waiting() - CHECK IF REQUEST IS READY TO PRINT
+ ** qchk_filter() - CHECK IF REQUEST NEEDS A FILTER
+ ** qchk_form() - CHECK IF REQUEST NEEDS A FORM
+ ** qchk_pwheel() - CHECK IF REQUEST NEEDS PRINT A WHEEL
+ **/
+
+int
+qchk_waiting(RSTATUS *prs)
+{
+ return (
+ !(prs->request->outcome & (RS_HELD|RS_DONE|RS_ACTIVE))
+ && !NEEDS_FILTERING(prs)
+ );
+}
+
+int
+qchk_filter(RSTATUS *prs)
+{
+ /*
+ * No need to reevaluate this request if it isn't using a filter
+ * or if it is done or is being changed.
+ */
+ return (
+ !(prs->request->outcome & (RS_DONE|RS_CHANGING|RS_NOTIFY))
+ && (prs->slow || prs->fast)
+ );
+}
+
+FSTATUS * form_in_question;
+
+int
+qchk_form(RSTATUS *prs)
+{
+ return (prs->form == form_in_question);
+}
+
+char * pwheel_in_question;
+
+int
+qchk_pwheel(RSTATUS *prs)
+{
+ return (SAME(prs->pwheel_name, pwheel_in_question));
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/rstatus.c b/usr/src/cmd/lp/cmd/lpsched/rstatus.c
new file mode 100644
index 0000000000..791ba432a0
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/rstatus.c
@@ -0,0 +1,203 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "lpsched.h"
+
+
+/**
+ ** insertr()
+ **/
+
+void
+insertr(RSTATUS *r)
+{
+ RSTATUS *prs;
+
+
+ if (!Request_List) {
+ Request_List = r;
+ return;
+ }
+
+ for (prs = Request_List; prs; prs = prs->next) {
+ if (rsort(&r, &prs) < 0) {
+ r->prev = prs->prev;
+ if (r->prev)
+ r->prev->next = r;
+ r->next = prs;
+ prs->prev = r;
+ if (prs == Request_List)
+ Request_List = r;
+ return;
+ }
+
+ if (prs->next)
+ continue;
+
+ r->prev = prs;
+ prs->next = r;
+ return;
+ }
+}
+
+/**
+ ** remover()
+ **/
+
+void
+remover(RSTATUS *r)
+{
+ if (r == Request_List) /* on the request chain */
+ Request_List = r->next;
+
+ if (r->next)
+ r->next->prev = r->prev;
+
+ if (r->prev)
+ r->prev->next = r->next;
+
+ r->next = 0;
+ r->prev = 0;
+ return;
+}
+
+/**
+ ** request_by_id()
+ **/
+
+RSTATUS *
+request_by_id(char *id)
+{
+ register RSTATUS *prs;
+
+ for (prs = Request_List; prs; prs = prs->next)
+ if (STREQU(id, prs->secure->req_id))
+ return (prs);
+ return (0);
+}
+
+RSTATUS *
+request_by_id_num( long num )
+{
+ register RSTATUS *prs;
+
+ for (prs = Request_List; prs; prs = prs->next) {
+ char *tmp = strrchr(prs->secure->req_id, '-');
+
+ if (tmp && (num == atol(++tmp)))
+ return (prs);
+ }
+ return(0);
+}
+
+
+/**
+ ** rsort()
+ **/
+
+static int later ( RSTATUS * , RSTATUS * );
+
+int
+rsort (RSTATUS **p1, RSTATUS **p2)
+{
+ /*
+ * Of two requests needing immediate handling, the first
+ * will be the request with the LATER date. In case of a tie,
+ * the first is the one with the larger request ID (i.e. the
+ * one that came in last).
+ */
+ if ((*p1)->request->outcome & RS_IMMEDIATE)
+ if ((*p2)->request->outcome & RS_IMMEDIATE)
+ if (later(*p1, *p2))
+ return (-1);
+ else
+ return (1);
+ else
+ return (-1);
+
+ else if ((*p2)->request->outcome & RS_IMMEDIATE)
+ return (1);
+
+ /*
+ * Of two requests not needing immediate handling, the first
+ * will be the request with the highest priority. If both have
+ * the same priority, the first is the one with the EARLIER date.
+ * In case of a tie, the first is the one with the smaller ID
+ * (i.e. the one that came in first).
+ */
+ else if ((*p1)->request->priority == (*p2)->request->priority)
+ if (!later(*p1, *p2))
+ return (-1);
+ else
+ return (1);
+
+ else
+ return ((*p1)->request->priority - (*p2)->request->priority);
+ /*NOTREACHED*/
+}
+
+static int
+later(RSTATUS *prs1, RSTATUS *prs2)
+{
+ if (prs1->secure->date > prs2->secure->date)
+ return (1);
+
+ else if (prs1->secure->date < prs2->secure->date)
+ return (0);
+
+ /*
+ * The dates are the same, so compare the request IDs.
+ * One problem with comparing request IDs is that the order
+ * of two IDs may be reversed if the IDs wrapped around. This
+ * is a very unlikely problem, because the cycle should take
+ * more than one second to wrap!
+ */
+ else {
+ register int len1 = strlen(prs1->req_file),
+ len2 = strlen(prs2->req_file);
+
+ /*
+ * Use the request file name (ID-0) for comparison,
+ * because the real request ID (DEST-ID) won't compare
+ * properly because of the destination prefix.
+ * The strlen() comparison is necessary, otherwise
+ * IDs like "99-0" and "100-0" will compare wrong.
+ */
+ if (len1 > len2)
+ return (1);
+ else if (len1 < len2)
+ return (0);
+ else
+ return (strcmp(prs1->req_file, prs2->req_file) > 0);
+ }
+ /*NOTREACHED*/
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/schedule.c b/usr/src/cmd/lp/cmd/lpsched/schedule.c
new file mode 100644
index 0000000000..01fbe4213a
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/schedule.c
@@ -0,0 +1,605 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdarg.h"
+#include "lpsched.h"
+#include <syslog.h>
+
+extern int isStartingForms;
+
+typedef struct later {
+ struct later * next;
+ int event,
+ ticks;
+ union arg {
+ PSTATUS * printer;
+ RSTATUS * request;
+ FSTATUS * form;
+ } arg;
+} LATER;
+
+static LATER LaterHead = { 0 },
+ TempHead;
+
+static void ev_interf(PSTATUS *);
+static void ev_message(PSTATUS *);
+static void ev_form_message(FSTATUS *);
+static int ev_slowf(RSTATUS *);
+static int ev_notify(RSTATUS *);
+
+static EXEC *find_exec_slot(EXEC **);
+
+static char *_event_name(int event)
+{
+ static char *_names[] = {
+ "", "EV_SLOWF", "EV_INTERF", "EV_NOTIFY", "EV_LATER", "EV_ALARM",
+ "EV_MESSAGE", "EV_ENABLE", "EV_FORM_MESSAGE", NULL };
+
+ if ((event < 0) || (event > EV_FORM_MESSAGE))
+ return ("BAD_EVENT");
+ else
+ return (_names[event]);
+}
+
+/*
+ * schedule() - SCHEDULE BY EVENT
+ */
+
+/*VARARGS1*/
+void
+schedule(int event, ...)
+{
+ va_list ap;
+
+ LATER * plprev;
+ LATER * pl;
+ LATER * plnext = 0;
+
+ register PSTATUS * pps;
+ register RSTATUS * prs;
+ register FSTATUS * pfs;
+
+ int i;
+ /*
+ * If we're in the process of shutting down, don't
+ * schedule anything.
+ */
+ syslog(LOG_DEBUG, "schedule(%s)", _event_name(event));
+
+ if (Shutdown)
+ return;
+
+ va_start (ap, event);
+
+ /*
+ * If we're still in the process of starting up, don't start
+ * anything! Schedule it for one tick later. While we're starting
+ * ticks aren't counted, so the events won't be started.
+ * HOWEVER, with a count of 1, a single EV_ALARM after we're
+ * finished starting will be enough to clear all things scheduled
+ * for later.
+ */
+ if (Starting) {
+ switch (event) {
+
+ case EV_INTERF:
+ case EV_ENABLE:
+ pps = va_arg(ap, PSTATUS *);
+ schedule (EV_LATER, 1, event, pps);
+ goto Return;
+
+ case EV_SLOWF:
+ case EV_NOTIFY:
+ prs = va_arg(ap, RSTATUS *);
+ schedule (EV_LATER, 1, event, prs);
+ goto Return;
+
+ case EV_MESSAGE:
+ pps = va_arg(ap, PSTATUS *);
+ schedule (EV_LATER, 1, event, pps);
+ goto Return;
+
+ case EV_FORM_MESSAGE:
+ pfs = va_arg(ap, FSTATUS *);
+ schedule (EV_LATER, 1, event, pfs);
+ goto Return;
+
+ case EV_LATER:
+ /*
+ * This is okay--in fact it may be us!
+ */
+ break;
+
+ case EV_ALARM:
+ /*
+ * The alarm will go off again, hold off for now.
+ */
+ goto Return;
+
+ }
+ }
+
+ /*
+ * Schedule something:
+ */
+ switch (event) {
+
+ case EV_INTERF:
+ if ((pps = va_arg(ap, PSTATUS *)) != NULL)
+ ev_interf (pps);
+
+ else
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ ev_interf (PStatus[i]);
+
+ break;
+
+ /*
+ * The EV_ENABLE event is used to get a printer going again
+ * after waiting for a fault to be cleared. We used to use
+ * just the EV_INTERF event, but this wasn't enough: For
+ * requests that can go on several different printers (e.g.
+ * queued for class, queued for ``any''), a printer is
+ * arbitrarily assigned. The EV_INTERF event just checks
+ * assignments, not possibilities, so a printer with no
+ * assigned requests but still eligible to handle one or
+ * more requests would never automatically start up again after
+ * a fault. The EV_ENABLE event calls "enable()" which eventually
+ * gets around to invoking the EV_INTERF event. However, it first
+ * calls "queue_attract()" to get an eligible request assigned
+ * so that things proceed. This also makes sense from the
+ * following standpoint: The documented method of getting a
+ * printer going, while it is waiting for auto-retry, is to
+ * manually issue the enable command!
+ *
+ * Note: "enable()" will destroy the current record of the fault,
+ * so if the fault is still with us any new alert will not include
+ * the history of each repeated fault. This is a plus and a minus,
+ * usually a minus: While a repeated fault may occasionally show
+ * a varied record, usually the same reason is given each time;
+ * before switching to EV_ENABLE we typically saw a boring, long
+ * list of identical reasons.
+ */
+ case EV_ENABLE:
+ if ((pps = va_arg(ap, PSTATUS *)) != NULL)
+ enable (pps);
+ else
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ enable (PStatus[i]);
+ break;
+
+ case EV_SLOWF:
+ if ((prs = va_arg(ap, RSTATUS *)) != NULL)
+ (void) ev_slowf (prs);
+ else
+ for (prs = Request_List; prs && ev_slowf(prs) != -1;
+ prs = prs->next);
+ break;
+
+ case EV_NOTIFY:
+ if ((prs = va_arg(ap, RSTATUS *)) != NULL)
+ (void) ev_notify (prs);
+ else
+ for (prs = Request_List; prs && ev_notify(prs) != -1;
+ prs = prs->next);
+ break;
+
+ case EV_MESSAGE:
+ pps = va_arg(ap, PSTATUS *);
+ ev_message(pps);
+ break;
+
+ case EV_FORM_MESSAGE:
+ pfs = va_arg(ap, FSTATUS *);
+ ev_form_message(pfs);
+ break;
+
+ case EV_LATER:
+ pl = (LATER *)Malloc(sizeof (LATER));
+
+ if (!LaterHead.next)
+ alarm (CLOCK_TICK);
+
+ pl->next = LaterHead.next;
+ LaterHead.next = pl;
+
+ pl->ticks = va_arg(ap, int);
+ pl->event = va_arg(ap, int);
+ switch (pl->event) {
+
+ case EV_MESSAGE:
+ case EV_INTERF:
+ case EV_ENABLE:
+ pl->arg.printer = va_arg(ap, PSTATUS *);
+ if (pl->arg.printer)
+ pl->arg.printer->status |= PS_LATER;
+ break;
+
+ case EV_FORM_MESSAGE:
+ pl->arg.form = va_arg(ap, FSTATUS *);
+ break;
+
+ case EV_SLOWF:
+ case EV_NOTIFY:
+ pl->arg.request = va_arg(ap, RSTATUS *);
+ break;
+
+ }
+ break;
+
+ case EV_ALARM:
+ Sig_Alrm = 0;
+
+ /*
+ * The act of scheduling some of the ``laters'' may
+ * cause new ``laters'' to be added to the list.
+ * To ease the handling of the linked list, we first
+ * run through the list and move all events ready to
+ * be scheduled to another list. Then we schedule the
+ * events off the new list. This leaves the main ``later''
+ * list ready for new events.
+ */
+ TempHead.next = 0;
+ for (pl = (plprev = &LaterHead)->next; pl; pl = plnext) {
+ plnext = pl->next;
+ if (--pl->ticks)
+ plprev = pl;
+ else {
+ plprev->next = plnext;
+
+ pl->next = TempHead.next;
+ TempHead.next = pl;
+ }
+ }
+
+ for (pl = TempHead.next; pl; pl = plnext) {
+ plnext = pl->next;
+ switch (pl->event) {
+
+ case EV_MESSAGE:
+ case EV_INTERF:
+ case EV_ENABLE:
+ pl->arg.printer->status &= ~PS_LATER;
+ schedule (pl->event, pl->arg.printer);
+ break;
+
+ case EV_FORM_MESSAGE:
+ schedule (pl->event, pl->arg.form);
+ break;
+
+ case EV_SLOWF:
+ case EV_NOTIFY:
+ schedule (pl->event, pl->arg.request);
+ break;
+
+ }
+ Free ((char *)pl);
+ }
+
+ if (LaterHead.next)
+ alarm (CLOCK_TICK);
+ break;
+
+ }
+
+Return: va_end (ap);
+
+ return;
+}
+
+/*
+ * maybe_schedule() - MAYBE SCHEDULE SOMETHING FOR A REQUEST
+ */
+
+void
+maybe_schedule(RSTATUS *prs)
+{
+ /*
+ * Use this routine if a request has been changed by some
+ * means so that it is ready for filtering or printing,
+ * but a previous filtering or printing process for this
+ * request MAY NOT have finished yet. If a process is still
+ * running, then the cleanup of that process will cause
+ * "schedule()" to be called. Calling "schedule()" regardless
+ * might make another request slip ahead of this request.
+ */
+
+ /*
+ * "schedule()" will refuse if this request is filtering.
+ * It will also refuse if the request ``was'' filtering
+ * but the filter was terminated in "validate_request()",
+ * because we can not have heard from the filter process
+ * yet. Also, when called with a particular request,
+ * "schedule()" won't slip another request ahead.
+ */
+ if (NEEDS_FILTERING(prs))
+ schedule (EV_SLOWF, prs);
+
+ else if (!(prs->request->outcome & RS_STOPPED))
+ schedule (EV_INTERF, prs->printer);
+
+ return;
+}
+
+static void
+ev_message(PSTATUS *pps)
+{
+ register RSTATUS *prs;
+ char toSelf;
+
+ syslog(LOG_DEBUG, "ev_message(%s)",
+ (pps && pps->request && pps->request->req_file ?
+ pps->request->req_file : "NULL"));
+
+ toSelf = 0;
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if (prs->printer == pps) {
+ note("prs (%d) pps (%d)\n", prs, pps);
+ if (!toSelf) {
+ toSelf = 1;
+ exec(EX_FAULT_MESSAGE, pps, prs);
+ }
+ }
+}
+
+static void
+ev_form_message_body(FSTATUS *pfs, RSTATUS *prs, char *toSelf, char ***sysList)
+{
+ syslog(LOG_DEBUG, "ev_form_message_body(%s, %d, 0x%x)",
+ (pfs && pfs->form && pfs->form->name ? pfs->form->name : "NULL"),
+ (toSelf ? *toSelf : 0),
+ sysList);
+
+ if (!*toSelf) {
+ *toSelf = 1;
+ exec(EX_FORM_MESSAGE, pfs);
+ }
+}
+
+static void
+ev_form_message(FSTATUS *pfs)
+{
+ register RSTATUS *prs;
+ char **sysList;
+ char toSelf;
+
+ syslog(LOG_DEBUG, "ev_form_message(%s)",
+ (pfs && pfs->form && pfs->form->name ?
+ pfs->form->name : "NULL"));
+
+ toSelf = 0;
+ sysList = NULL;
+
+ for (prs = Request_List; prs != NULL; prs = prs->next)
+ if (prs->form == pfs)
+ ev_form_message_body(pfs, prs, &toSelf, &sysList);
+
+ if (NewRequest && (NewRequest->form == pfs))
+ ev_form_message_body(pfs, NewRequest, &toSelf, &sysList);
+
+ freelist(sysList);
+}
+
+/*
+ * ev_interf() - CHECK AND EXEC INTERFACE PROGRAM
+ */
+
+/*
+ * Macro to check if the request needs a print wheel or character set (S)
+ * and the printer (P) has it mounted or can select it. Since the request
+ * has already been approved for the printer, we don't have to check the
+ * character set, just the mount. If the printer has selectable character
+ * sets, there's nothing to check so the request is ready to print.
+ */
+#define MATCH(PRS, PPS) (\
+ !(PPS)->printer->daisy || \
+ !(PRS)->pwheel_name || \
+ !((PRS)->status & RSS_PWMAND) || \
+ STREQU((PRS)->pwheel_name, NAME_ANY) || \
+ ((PPS)->pwheel_name && \
+ STREQU((PPS)->pwheel_name, (PRS)->pwheel_name)))
+
+
+static void
+ev_interf(PSTATUS *pps)
+{
+ register RSTATUS *prs;
+
+ syslog(LOG_DEBUG, "ev_interf(%s)",
+ (pps && pps->request && pps->request->req_file ?
+ pps->request->req_file : "NULL"));
+
+
+ /*
+ * If the printer isn't tied up doing something
+ * else, and isn't disabled, see if there is a request
+ * waiting to print on it. Note: We don't include
+ * PS_FAULTED here, because simply having a printer
+ * fault (without also being disabled) isn't sufficient
+ * to keep us from trying again. (In fact, we HAVE TO
+ * try again, to see if the fault has gone away.)
+ *
+ * NOTE: If the printer is faulted but the filter controlling
+ * the printer is waiting for the fault to clear, a
+ * request will still be attached to the printer, as
+ * evidenced by "pps->request", so we won't try to
+ * schedule another request!
+ */
+ if (pps->request || pps->status & (PS_DISABLED|PS_LATER|PS_BUSY))
+ return;
+
+ for (prs = Request_List; prs != NULL; prs = prs->next) {
+ if ((prs->printer == pps) && (qchk_waiting(prs)) &&
+ isFormUsableOnPrinter(pps, prs->form) && MATCH(prs, pps)) {
+ /*
+ * Just because the printer isn't busy and the
+ * request is assigned to this printer, don't get the
+ * idea that the request can't be printing (RS_ACTIVE),
+ * because another printer may still have the request
+ * attached but we've not yet heard from the child
+ * process controlling that printer.
+ *
+ * We have the waiting request, we have
+ * the ready (local) printer. If the exec fails
+ * because the fork failed, schedule a
+ * try later and claim we succeeded. The
+ * later attempt will sort things out,
+ * e.g. will re-schedule if the fork fails
+ * again.
+ */
+ pps->request = prs;
+ if (exec(EX_INTERF, pps) == 0) {
+ pps->status |= PS_BUSY;
+ return;
+ }
+ pps->request = 0;
+ if (errno == EAGAIN) {
+ load_str (&pps->dis_reason, CUZ_NOFORK);
+ schedule (EV_LATER, WHEN_FORK, EV_ENABLE, pps);
+ return;
+ }
+ }
+ }
+
+ return;
+}
+
+/*
+ * ev_slowf() - CHECK AND EXEC SLOW FILTER
+ */
+
+static int
+ev_slowf(RSTATUS *prs)
+{
+ register EXEC *ep;
+
+ syslog(LOG_DEBUG, "ev_slowf(%s)",
+ (prs && prs->req_file ? prs->req_file : "NULL"));
+
+ /*
+ * Return -1 if no more can be executed (no more exec slots)
+ * or if it's unwise to execute any more (fork failed).
+ */
+
+ if (!(ep = find_exec_slot(Exec_Slow))) {
+ syslog(LOG_DEBUG, "ev_slowf(%s): no slot",
+ (prs && prs->req_file ? prs->req_file : "NULL"));
+ return (-1);
+ }
+
+ if (!(prs->request->outcome & (RS_DONE|RS_HELD|RS_ACTIVE)) &&
+ NEEDS_FILTERING(prs)) {
+ (prs->exec = ep)->ex.request = prs;
+ if (exec(EX_SLOWF, prs) != 0) {
+ ep->ex.request = 0;
+ prs->exec = 0;
+ if (errno == EAGAIN) {
+ schedule (EV_LATER, WHEN_FORK, EV_SLOWF, prs);
+ return (-1);
+ }
+ }
+ }
+ return (0);
+}
+
+/*
+ * ev_notify() - CHECK AND EXEC NOTIFICATION
+ */
+
+static int
+ev_notify(RSTATUS *prs)
+{
+ register EXEC *ep;
+
+ syslog(LOG_DEBUG, "ev_notify(%s)",
+ (prs && prs->req_file ? prs->req_file : "NULL"));
+
+ /*
+ * Return -1 if no more can be executed (no more exec slots)
+ * or if it's unwise to execute any more (fork failed, already
+ * sent one to remote side).
+ */
+
+ /*
+ * If the job came from a remote machine, we forward the
+ * outcome of the request to the network manager for sending
+ * to the remote side.
+ */
+ if (prs->request->actions & ACT_NOTIFY) {
+ if (prs->request->outcome & RS_NOTIFY) {
+ prs->request->actions &= ~ACT_NOTIFY;
+ return (0); /* but try another request */
+ }
+ /*
+ * If the job didn't come from a remote system,
+ * we'll try to start a process to send the notification
+ * to the user. But we only allow so many notifications
+ * to run at the same time, so we may not be able to
+ * do it.
+ */
+ } else if (!(ep = find_exec_slot(Exec_Notify)))
+ return (-1);
+
+ else if (prs->request->outcome & RS_NOTIFY &&
+ !(prs->request->outcome & RS_NOTIFYING)) {
+
+ (prs->exec = ep)->ex.request = prs;
+ if (exec(EX_NOTIFY, prs) != 0) {
+ ep->ex.request = 0;
+ prs->exec = 0;
+ if (errno == EAGAIN) {
+ schedule (EV_LATER, WHEN_FORK, EV_NOTIFY, prs);
+ return (-1);
+ }
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * find_exec_slot() - FIND AVAILABLE EXEC SLOT
+ */
+
+static EXEC *
+find_exec_slot(EXEC **exec_table)
+{
+ int i;
+
+ for (i = 0; exec_table[i] != NULL; i++)
+ if (exec_table[i]->pid == 0)
+ return (exec_table[i]);
+
+ syslog(LOG_DEBUG, "find_exec_slot(0x%8.8x): after %d, no slots",
+ exec_table, i);
+ return (0);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/server.xml b/usr/src/cmd/lp/cmd/lpsched/server.xml
new file mode 100644
index 0000000000..790355f873
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/server.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWpsr:lpsched'>
+
+<service
+ name='application/print/server'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+ <single_instance />
+
+ <dependency
+ name='fs-local'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/local' />
+ </dependency>
+
+ <dependency
+ name='filesystem'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/usr'/>
+ </dependency>
+
+ <dependency
+ name='identity'
+ grouping='require_all'
+ restart_on='refresh'
+ type='service'>
+ <service_fmri value='svc:/system/identity:domain' />
+ </dependency>
+
+ <dependency
+ name='system-log'
+ grouping='optional_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/system-log' />
+ </dependency>
+
+ <dependent
+ name='print-server_multi-user'
+ grouping='optional_all'
+ restart_on='none'>
+ <service_fmri value='svc:/milestone/multi-user' />
+ </dependent>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/print-svc start'
+ timeout_seconds='60' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec='/lib/svc/method/print-svc stop'
+ timeout_seconds='60' />
+
+ <property_group name='lpsched' type='framework'>
+ <propval name='num_notifiers' type='count' value='0' />
+ <propval name='num_filters' type='count' value='0' />
+ <propval name='fd_limit' type='count' value='0' />
+ <propval name='reserved_fds' type='count' value='0' />
+ </property_group>
+
+ <property_group name='general' type='framework'>
+ <!-- to start/stop spooling daemon -->
+ <propval name='action_authorization' type='astring'
+ value='solaris.print.admin' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.print.admin' />
+ </property_group>
+
+ <property_group name='firewall_context' type='com.sun,fw_definition'>
+ <propval name='ipf_method' type='astring'
+ value='/lib/svc/method/print-svc ipfilter' />
+ </property_group>
+
+ <property_group name='firewall_config' type='com.sun,fw_configuration'>
+ <propval name='policy' type='astring' value='use_global' />
+ <propval name='apply_to' type='astring' value='' />
+ <propval name='exceptions' type='astring' value='' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.smf.value.firewall.config' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ LP print server
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='lpsched' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/lp/cmd/lpsched/status.c b/usr/src/cmd/lp/cmd/lpsched/status.c
new file mode 100644
index 0000000000..893ffa3c05
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/status.c
@@ -0,0 +1,721 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdlib.h"
+#include "string.h"
+#include "unistd.h"
+#include <syslog.h>
+
+#include "lpsched.h"
+
+#define NCMP(X,Y) (STRNEQU((X), (Y), sizeof(Y)-1))
+
+static void load_pstatus ( void );
+static void load_fault_status ( void );
+static void load_cstatus ( void );
+static void put_multi_line ( int , char * );
+static PFSTATUS * parseFormList ( char *,short *);
+static void markFormsMounted( PSTATUS *);
+
+
+#define FAULT_MESSAGE_FILE "faultMessage"
+static char *pstatus = 0,
+ *cstatus = 0;
+
+/**
+ ** load_status() - LOAD PRINTER/CLASS STATUS FILES
+ **/
+
+void
+load_status(void)
+{
+ load_pstatus ();
+
+ load_cstatus ();
+ load_fault_status ();
+ return;
+}
+
+/**
+ ** load_pstatus() - LOAD PRITNER STATUS FILE
+ **/
+
+static void
+load_pstatus(void)
+{
+ PSTATUS *pps;
+
+ char *rej_reason,
+ *dis_reason,
+ *pwheel_name,
+ buf[BUFSIZ],
+ *name,
+ *p;
+
+ time_t rej_date,
+ dis_date;
+
+ short status;
+
+ PFSTATUS *ppfs;
+
+ PWSTATUS *ppws;
+
+ int i,
+ len,
+ total;
+
+ time_t now;
+
+ int fd;
+
+ register int f;
+ short numForms;
+
+
+ (void) time(&now);
+
+ if (!pstatus)
+ pstatus = makepath(Lp_System, PSTATUSFILE, (char *)0);
+ if ((fd = open_locked(pstatus, "r", 0)) >= 0) {
+ char *tmp = pstatus; /* not NULL */
+
+ while (tmp != NULL) {
+ status = 0;
+ total = 0;
+ name = 0;
+ rej_reason = 0;
+ dis_reason = 0;
+ ppfs = 0;
+
+ errno = 0;
+ for (f = 0;
+ (f < PST_MAX) && (tmp = fdgets(buf, BUFSIZ, fd));
+ f++) {
+ if (p = strrchr(buf, '\n'))
+ *p = '\0';
+
+ switch (f) {
+ case PST_BRK:
+ break;
+
+ case PST_NAME:
+ name = Strdup(buf);
+ break;
+
+ case PST_STATUS:
+ if (NCMP(buf, NAME_DISABLED))
+ status |= PS_DISABLED;
+ p = strchr(buf, ' ');
+ if (!p || !*(++p))
+ break;
+ if (NCMP(p, NAME_REJECTING))
+ status |= PS_REJECTED;
+ break;
+
+ case PST_DATE:
+ dis_date = (time_t)atol(buf);
+ p = strchr(buf, ' ');
+ if (!p || !*(++p))
+ break;
+ rej_date = (time_t)atol(p);
+ break;
+
+ case PST_DISREAS:
+ len = strlen(buf);
+ if (buf[len - 1] == '\\') {
+ buf[len - 1] = '\n';
+ f--;
+ }
+ if (dis_reason) {
+ total += len;
+ dis_reason = Realloc(
+ dis_reason,
+ total+1
+ );
+ strcat (dis_reason, buf);
+ } else {
+ dis_reason = Strdup(buf);
+ total = len;
+ }
+ break;
+
+ case PST_REJREAS:
+ len = strlen(buf);
+ if (buf[len - 1] == '\\') {
+ buf[len - 1] = '\n';
+ f--;
+ }
+ if (rej_reason) {
+ total += len;
+ rej_reason = Realloc(
+ rej_reason,
+ total+1
+ );
+ strcat (rej_reason, buf);
+ } else {
+ rej_reason = Strdup(buf);
+ total = len;
+ }
+ break;
+
+ case PST_PWHEEL:
+ if (*buf) {
+ ppws = search_pwstatus(buf);
+ pwheel_name = Strdup(buf);
+ } else {
+ ppws = 0;
+ pwheel_name = 0;
+ }
+ break;
+
+ case PST_FORM:
+ ppfs = parseFormList (buf,&numForms);
+ break;
+ }
+ }
+
+ if ((errno != 0) || f && f != PST_MAX) {
+ close(fd);
+ note("Had trouble reading file %s", pstatus);
+ return;
+ }
+
+ if ((tmp != NULL) && name &&
+ (pps = search_pstatus(name))) {
+ pps->rej_date = rej_date;
+ pps->status |= status;
+ pps->forms = ppfs;
+ if (ppfs) markFormsMounted(pps);
+ pps->numForms = numForms;
+ pps->pwheel_name = pwheel_name;
+ if ((pps->pwheel = ppws) != NULL)
+ ppws->mounted++;
+ pps->rej_reason = rej_reason;
+ load_str(&pps->fault_reason, CUZ_PRINTING_OK);
+ if (pps->printer->login) {
+ pps->dis_date = now;
+ pps->dis_reason =
+ Strdup(CUZ_LOGIN_PRINTER);
+ } else {
+ pps->dis_date = dis_date;
+ pps->dis_reason = dis_reason;
+ }
+
+ } else {
+ if (ppfs)
+ Free(ppfs);
+ if (dis_reason)
+ Free (dis_reason);
+ if (rej_reason)
+ Free (rej_reason);
+ }
+ if (name)
+ Free (name);
+ }
+ }
+
+ if (fd >= 0) {
+ if (errno != 0) {
+ close(fd);
+ note("Had trouble reading file %s", pstatus);
+ return;
+ }
+ close(fd);
+ }
+
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
+ if (PStatus[i]->printer->name && !PStatus[i]->rej_reason) {
+ PStatus[i]->dis_reason = Strdup(CUZ_NEW_PRINTER);
+ PStatus[i]->rej_reason = Strdup(CUZ_NEW_DEST);
+ PStatus[i]->fault_reason = Strdup(CUZ_PRINTING_OK);
+ PStatus[i]->dis_date = now;
+ PStatus[i]->rej_date = now;
+ PStatus[i]->status |= PS_DISABLED | PS_REJECTED;
+ }
+
+ return;
+}
+
+/**
+ ** load_fault_status() - LOAD PRITNER Fault STATUS FILE
+ **/
+
+static void
+load_fault_status(void)
+{
+ char *fault_reason = NULL,
+ buf[BUFSIZ],
+ *fault_status,
+ *printerName,
+ *p;
+
+ int i,
+ len,
+ total;
+
+
+ int fd;
+
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
+ PSTATUS *pps = PStatus[i];
+
+ printerName = pps->printer->name;
+ if (printerName) {
+ fault_status = makepath(Lp_A_Printers, printerName,
+ FAULT_MESSAGE_FILE , (char *) 0);
+ fault_reason = NULL;
+ total = 0;
+
+ if ((fd = open_locked(fault_status, "r", 0)) >= 0) {
+ while (fdgets(buf, BUFSIZ, fd)) {
+ len = strlen(buf);
+ if (fault_reason) {
+ total += len;
+ fault_reason =
+ Realloc(fault_reason,
+ total+1);
+ strcat (fault_reason, buf);
+ } else {
+ fault_reason = Strdup(buf);
+ total = len;
+ }
+ }
+
+ if (fault_reason &&
+ (pps = search_pstatus(printerName))) {
+ p = fault_reason + strlen(fault_reason)
+ - 1;
+ if (*p == '\n')
+ *p = 0;
+ load_str(&pps->fault_reason,
+ fault_reason);
+ }
+ if (fault_reason)
+ Free(fault_reason);
+
+ close(fd);
+ }
+ Free(fault_status);
+ }
+ }
+}
+
+
+/**
+ ** load_cstatus() - LOAD CLASS STATUS FILE
+ **/
+
+static void
+load_cstatus(void)
+{
+ CSTATUS *pcs;
+ char *rej_reason,
+ buf[BUFSIZ],
+ *name,
+ *p;
+ time_t rej_date;
+ short status;
+ int i,
+ len,
+ total;
+ time_t now;
+ int fd;
+ register int f;
+
+
+ (void) time(&now);
+
+ if (!cstatus)
+ cstatus = makepath(Lp_System, CSTATUSFILE, (char *)0);
+
+ if ((fd = open_locked(cstatus, "r", 0)) >= 0) {
+ char *tmp = cstatus; /* not NULL */
+
+ errno = 0;
+ while (tmp != NULL) {
+ status = 0;
+
+ total = 0;
+ name = 0;
+
+ rej_reason = 0;
+ for (f = 0;
+ (f < CST_MAX) && (tmp = fdgets(buf, BUFSIZ, fd));
+ f++) {
+ if (p = strrchr(buf, '\n'))
+ *p = '\0';
+ switch (f) {
+ case CST_BRK:
+ break;
+
+ case CST_NAME:
+ name = Strdup(buf);
+ break;
+
+ case CST_STATUS:
+ if (NCMP(buf, NAME_REJECTING))
+ status |= PS_REJECTED;
+ break;
+
+ case CST_DATE:
+ rej_date = (time_t)atol(buf);
+ break;
+
+ case CST_REJREAS:
+ len = strlen(buf);
+ if (buf[len - 1] == '\\') {
+ buf[len - 1] = '\n';
+ f--;
+ }
+ if (rej_reason) {
+ total += len;
+ rej_reason = Realloc(
+ rej_reason,
+ total+1
+ );
+ strcat (rej_reason, buf);
+ } else {
+ rej_reason = Strdup(buf);
+ total = len;
+ }
+ break;
+ }
+ }
+
+ if ((errno != 0) || f && f != CST_MAX) {
+ close(fd);
+ note("Had trouble reading file %s", cstatus);
+ return;
+ }
+
+ if ((tmp != NULL) && name &&
+ (pcs = search_cstatus(name))) {
+ pcs->rej_reason = rej_reason;
+ pcs->rej_date = rej_date;
+ pcs->status |= status;
+
+ } else
+ if (rej_reason)
+ Free (rej_reason);
+
+ if (name)
+ Free (name);
+ }
+ }
+
+ if (fd >= 0) {
+ if (errno != 0) {
+ close(fd);
+ note("Had trouble reading file %s", cstatus);
+ return;
+ }
+ close(fd);
+ }
+
+ for (i = 0; CStatus != NULL && CStatus[i] != NULL; i++)
+ if (CStatus[i]->class->name && !CStatus[i]->rej_reason) {
+ CStatus[i]->status |= CS_REJECTED;
+ CStatus[i]->rej_reason = Strdup(CUZ_NEW_DEST);
+ CStatus[i]->rej_date = now;
+ }
+
+ return;
+}
+
+/**
+ ** showForms()
+ **/
+char *
+showForms(PSTATUS *pps)
+{
+ int i;
+ char *formList = NULL;
+ char buf[100];
+ FSTATUS *pfs;
+ PFSTATUS *ppfs;
+ short numForms;
+
+ numForms = pps->numForms;
+ ppfs = pps->forms;
+ if (ppfs) {
+ for (i = 0; i < numForms; i++) {
+ pfs = ppfs[i].form;
+ snprintf(buf, sizeof (buf), "%s%c",
+ (pfs ? pfs->form->name : ""),
+ ((i + 1 < numForms) ? *LP_SEP : '\0'));
+
+ if (addstring(&formList,buf)) { /* allocation failed */
+ if (formList) {
+ Free(formList);
+ formList = NULL;
+ }
+ return(NULL);
+ }
+ }
+ }
+ return(formList);
+}
+
+/**
+ ** markFormsMounted()
+ **/
+
+void
+markFormsMounted(PSTATUS *pps)
+{
+ int i;
+ int numTrays;
+ PFSTATUS *ppfs;
+ FSTATUS *pfs;
+
+
+ ppfs = pps->forms;
+ if (ppfs) {
+ numTrays = pps->numForms;
+ for (i = 0; i < numTrays; i++) {
+ pfs = ppfs[i].form;
+ if (pfs)
+ pfs->mounted++;
+ }
+ }
+}
+
+/**
+ ** parseFormList()
+ **/
+
+static PFSTATUS *
+parseFormList(char *formList, short *num)
+{
+ int i;
+ FSTATUS *pfs;
+ PFSTATUS *ppfs;
+ short numForms=0;
+ char *endPtr,*ptr;
+
+
+ ptr = strchr(formList,*LP_SEP);
+ while (ptr) {
+ numForms++;
+ ptr = strchr(ptr+1,*LP_SEP);
+ }
+ if ((numForms == 0) && (*formList))
+ numForms = 1;
+
+ if (numForms &&
+ (ppfs = (PFSTATUS *) Calloc(numForms, sizeof(PFSTATUS)))) {
+ endPtr = strchr(formList,*LP_SEP);
+ if (!endPtr)
+ endPtr = formList + strlen(formList);
+
+ ptr = formList;
+ for (i = 0; endPtr && (i < numForms); i++) {
+ *endPtr = 0;
+ ppfs[i].form = pfs = search_fstatus(ptr);
+ ppfs[i].isAvailable = (pfs ? 1 : 0);
+ ptr = endPtr+1;
+ endPtr = strchr(ptr,*LP_SEP);
+ }
+ *num = numForms;
+ } else {
+ ppfs = NULL;
+ *num = 0;
+ }
+ return(ppfs);
+}
+
+/**
+ ** dump_pstatus() - DUMP PRINTER STATUS FILE
+ **/
+
+void
+dump_pstatus(void)
+{
+ PSTATUS *ppsend;
+ int fd;
+ register PSTATUS *pps;
+ register int f;
+ int i;
+
+ if (!pstatus)
+ pstatus = makepath(Lp_System, PSTATUSFILE, (char *)0);
+ if ((fd = open_locked(pstatus, "w", MODE_READ)) < 0) {
+ note ("Can't open file \"%s\" (%s).\n", pstatus, PERROR);
+ return;
+ }
+
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
+ PSTATUS *pps = PStatus[i];
+
+ if (pps->printer->name)
+ for (f = 0; f < PST_MAX; f++) switch (f) {
+ case PST_BRK:
+ (void)fdprintf(fd, "+%s\n", STATUS_BREAK);
+ break;
+ case PST_NAME:
+ (void)fdprintf(fd, "%s\n",
+ NB(pps->printer->name));
+ break;
+ case PST_STATUS:
+ (void)fdprintf(fd, "%s %s\n",
+ (pps->status & PS_DISABLED ?
+ NAME_DISABLED : NAME_ENABLED),
+ (pps->status & PS_REJECTED ?
+ NAME_REJECTING : NAME_ACCEPTING));
+ break;
+ case PST_DATE:
+ (void)fdprintf(fd, "%ld %ld\n", pps->dis_date,
+ pps->rej_date);
+ break;
+ case PST_DISREAS:
+ put_multi_line(fd, pps->dis_reason);
+ break;
+ case PST_REJREAS:
+ put_multi_line(fd, pps->rej_reason);
+ break;
+ case PST_PWHEEL:
+ (void)fdprintf(fd, "%s\n",
+ NB(pps->pwheel_name));
+ break;
+ case PST_FORM: {
+ char *list;
+ list = showForms(pps);
+ (void)fdprintf(fd, "%s\n", (list ? list : ""));
+ if (list)
+ Free(list);
+ break;
+ }
+ }
+ }
+ close(fd);
+
+ return;
+}
+
+/**
+ ** dump_fault_status() - DUMP PRINTER FAULT STATUS FILE
+ **/
+
+void
+dump_fault_status(PSTATUS *pps)
+{
+ int fd;
+ char *fault_status, *printerName;
+
+ printerName = pps->printer->name;
+ fault_status = makepath(Lp_A_Printers, printerName, FAULT_MESSAGE_FILE,
+ (char *) 0);
+ if ((fd = open_locked(fault_status, "w", MODE_READ)) < 0) {
+ syslog(LOG_DEBUG, "Can't open file %s (%m)", fault_status);
+ } else {
+ fdprintf(fd, "%s\n", pps->fault_reason);
+ close(fd);
+ }
+
+ Free(fault_status);
+ return;
+}
+
+
+/**
+ ** dump_cstatus() - DUMP CLASS STATUS FILE
+ **/
+
+void
+dump_cstatus(void)
+{
+ int fd;
+ register int f;
+ int i;
+
+
+ if (!cstatus)
+ cstatus = makepath(Lp_System, CSTATUSFILE, (char *)0);
+ if ((fd = open_locked(cstatus, "w", MODE_READ)) < 0) {
+ syslog(LOG_DEBUG, "Can't open file %s (%m)", cstatus);
+ return;
+ }
+
+ for (i = 0; CStatus != NULL && CStatus[i] != NULL; i++) {
+ CSTATUS *pcs = CStatus[i];
+
+ if (pcs->class->name)
+ for (f = 0; f < CST_MAX; f++) switch (f) {
+ case CST_BRK:
+ (void)fdprintf(fd, "%s\n", STATUS_BREAK);
+ break;
+ case CST_NAME:
+ (void)fdprintf(fd, "%s\n",
+ NB(pcs->class->name));
+ break;
+ case CST_STATUS:
+ (void)fdprintf(fd, "%s\n",
+ (pcs->status & CS_REJECTED ?
+ NAME_REJECTING : NAME_ACCEPTING)
+ );
+ break;
+ case CST_DATE:
+ (void)fdprintf(fd, "%ld\n", pcs->rej_date);
+ break;
+ case CST_REJREAS:
+ put_multi_line(fd, pcs->rej_reason);
+ break;
+ }
+ }
+ close(fd);
+
+ return;
+}
+
+/**
+ ** put_multi_line() - PRINT OUT MULTI-LINE TEXT
+ **/
+
+static void
+put_multi_line(int fd, char *buf)
+{
+ register char *cp,
+ *p;
+
+ if (!buf) {
+ (void)fdprintf(fd, "\n");
+ return;
+ }
+
+ for (p = buf; (cp = strchr(p, '\n')); ) {
+ *cp++ = 0;
+ (void)fdprintf(fd, "%s\\\n", p);
+ p = cp;
+ }
+ (void)fdprintf(fd, "%s\n", p);
+ return;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/terminate.c b/usr/src/cmd/lp/cmd/lpsched/terminate.c
new file mode 100644
index 0000000000..919123115f
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/terminate.c
@@ -0,0 +1,115 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "lpsched.h"
+
+/*
+ * terminate() - STOP A CHILD PROCESS
+ *
+ * Note: If you're trying to debug lpsched, and worried about
+ * seeing lots of calls to terminate() in the debug output,
+ * don't be; it gets called once for each entry in the child
+ * process table, whether or not there's such a child.
+ */
+
+void
+terminate(register EXEC *ep)
+{
+ int retries; /* fix for sunsoft bugid 1108465 */
+
+ if (ep->pid <= 0)
+ return;
+
+ if (ep->flags & EXF_KILLED)
+ return;
+ ep->flags |= EXF_KILLED;
+
+ /*
+ * Theoretically, the following "if-then" is not needed,
+ * but there's some bug in the code that occasionally
+ * prevents us from hearing from a finished child.
+ * (Kill -9 on the child would do that, of course, but
+ * the problem has occurred in other cases.)
+ */
+ if (kill(-ep->pid, SIGTERM) == -1 && errno == ESRCH) {
+ ep->pid = -99;
+ ep->status = SIGTERM;
+ ep->Errno = 0;
+ DoneChildren++;
+ return;
+ }
+
+ /*
+ * Start fix for sunsoft bugid 1108465
+ * the original code here was extremely optimistic, and
+ * under certain circumstances, the pid's would still be
+ * left around. here we get really serious about killing
+ * the sucker.
+ * we patiently wait for the pid to die. if it doesn't
+ * do so in a reasonable amount of time, we get more forceful.
+ * note that the original "ep->pid == -99" is a crude hack;
+ * but that the convention is being followed. sigh.
+ */
+ for (retries = 5; retries > 0; retries--) {
+ /* see if the process is still there */
+ if ((kill(-ep->pid, 0) == -1) && (errno == ESRCH)) {
+ ep->pid = -99;
+ ep->status = SIGTERM;
+ ep->Errno = 0;
+ DoneChildren++;
+ return;
+ } else if (errno == EINTR)
+ break;
+
+ sleep(2);
+ }
+
+ /* if it's still not dead, then get more forceful */
+ for (retries = 5; retries > 0; retries--) {
+ if ((kill(-ep->pid, SIGKILL) == -1) && (errno == ESRCH)) {
+ ep->pid = -99;
+ ep->status = SIGTERM;
+ ep->Errno = 0;
+ DoneChildren++;
+ return;
+ }
+ sleep(3);
+ }
+ /* end of sunsoft bugfix 1108465 */
+ /*
+ * well hardkill didn't work so just flag this request as done
+ */
+ ep->pid = -99;
+ ep->status = SIGTERM;
+ ep->Errno = 0;
+ DoneChildren++;
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/validate.c b/usr/src/cmd/lp/cmd/lpsched/validate.c
new file mode 100644
index 0000000000..bec1434f9b
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/validate.c
@@ -0,0 +1,1075 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* SVr4.0 1.11.1.10 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "lpsched.h"
+
+#include "validate.h"
+
+#include <syslog.h>
+#include <errno.h>
+#include <deflt.h>
+#include <tsol/label.h>
+#include <auth_list.h>
+
+#define register auto
+
+
+int pickfilter ( RSTATUS * , CANDIDATE * , FSTATUS * );
+
+unsigned long chkprinter_result = 0;
+char * o_cpi = 0;
+char * o_lpi = 0;
+char * o_width = 0;
+char * o_length = 0;
+
+static int wants_nobanner = 0;
+static int wants_nolabels = 0;
+static int lp_or_root = 0;
+
+static int _chkopts ( RSTATUS *, CANDIDATE * , FSTATUS * );
+static void free_candidate ( CANDIDATE * );
+static int tsol_check_printer_label_range(char *, const char *);
+static int tsol_lpauth(char *, char *);
+static int secpolicy_chkpolicy(char *policyp);
+
+/**
+ ** _validate() - FIND A PRINTER TO HANDLE A REQUEST
+ **/
+
+short
+_validate(RSTATUS *prs, PSTATUS *pps, PSTATUS *stop_pps, char **prefixp,
+ int moving)
+{
+ register CANDIDATE *pc = 0,
+ *pcend,
+ *best_pc = 0;
+
+ register FSTATUS *pfs = 0;
+
+ register CSTATUS *pcs = 0;
+
+ CANDIDATE *arena = 0,
+ single;
+
+ size_t n;
+ int i;
+
+ short ret;
+
+ chkprinter_result = 0;
+ o_cpi = o_lpi = o_width = o_length = 0;
+ wants_nobanner = 0;
+ memset (&single, 0, sizeof(single));
+
+ wants_nolabels = 0;
+ /*
+ * If the system is labeled, the printing of postscript files
+ * is restricted. All users can print postscript files if the
+ * file /etc/default/print contains "PRINT_POSTSCRIPT=1".
+ * (this is checked by secpolicy_chkpolicy). Otherwise the
+ * user must have PRINT_POSTSCRIPT_AUTH to print postscript files.
+ */
+ if ((is_system_labeled() &&
+ strcmp(prs->request->input_type, "postscript") == 0) &&
+ (secpolicy_chkpolicy("PRINT_POSTSCRIPT=") == 0)) {
+ if (tsol_lpauth(PRINT_POSTSCRIPT_AUTH, prs->secure->user)
+ == 0) {
+ ret = MDENYDEST;
+ goto Return;
+ }
+ }
+ lp_or_root = 0;
+
+ if (bangequ(prs->secure->user, "root") ||
+ bangequ(prs->secure->user, "lp"))
+ lp_or_root = 1;
+
+ if (prefixp)
+ *prefixp = prs->request->destination;
+
+ /*
+ * If a destination other than "any" was given,
+ * see if it exists in our internal tables.
+ */
+ if (!pps && prs->request->destination &&
+ !STREQU(prs->request->destination, NAME_ANY))
+ if (((pps = search_pstatus(prs->request->destination)) != NULL) ||
+ ((pcs = search_cstatus(prs->request->destination)) != NULL) &&
+ pcs->class->members)
+ /*EMPTY*/;
+ else {
+ ret = MNODEST;
+ goto Return;
+ }
+
+ /*
+ * If we are trying to avoid a printer, but the request
+ * was destined for just that printer, we're out.
+ */
+ if (pps && pps == stop_pps) {
+ ret = MERRDEST;
+ goto Return;
+ }
+
+ /*
+ * If a form was given, see if it exists; if so,
+ * see if the user is allowed to use it.
+ * If a remote printer was specified, then don't use any local
+ * form knowledge.
+ */
+ if (prs && prs->request && prs->request->form && (pps || pcs)) {
+ if ((pfs = search_fstatus(prs->request->form))) {
+ if (lp_or_root || allowed(prs->secure->user,
+ pfs->users_allowed, pfs->users_denied))
+ /*EMPTY*/;
+ else {
+ ret = MDENYMEDIA;
+ goto Return;
+ }
+ } else {
+ ret = MNOMEDIA;
+ goto Return;
+ }
+ }
+
+ /*
+ * If the request includes -o options there may be pitch and
+ * size and no-banner requests that have to be checked. One
+ * could argue that this shouldn't be in the Spooler, because
+ * the Spooler's job is SPOOLING, not PRINTING. That's right,
+ * except that the Spooler will be making a choice of printers
+ * so it has to evaluate carefully: E.g. user wants ANY printer,
+ * so we should pick one that can handle what he/she wants.
+ *
+ * Parse out the important stuff here so we have it when we
+ * need it.
+ */
+ {
+ register char **list,
+ **pl;
+
+ if (
+ prs->request->options
+ && (list = dashos(prs->request->options))
+ ) {
+ for (pl = list ; *pl; pl++)
+ if (STRNEQU(*pl, "cpi=", 4))
+ o_cpi = Strdup(*pl + 4);
+ else if (STRNEQU(*pl, "lpi=", 4))
+ o_lpi = Strdup(*pl + 4);
+ else if (STRNEQU(*pl, "width=", 6))
+ o_width = Strdup(*pl + 6);
+ else if (STRNEQU(*pl, "length=", 7))
+ o_length = Strdup(*pl + 7);
+ else if (STREQU(*pl, "nobanner"))
+ wants_nobanner = 1;
+ else if (STREQU(*pl, "nolabels"))
+ wants_nolabels = 1;
+ freelist (list);
+ }
+ }
+
+ /*
+ * This macro checks that a form has a mandatory print wheel
+ * (or character set).
+ */
+#define CHKMAND(PFS) \
+ ( \
+ (PFS) \
+ && (PFS)->form->chset \
+ && !STREQU((PFS)->form->chset, NAME_ANY) \
+ && (PFS)->form->mandatory \
+ )
+
+ /*
+ * This macro checks that the user is allowed to use the
+ * printer.
+ */
+#define CHKU(PRS,PPS) \
+ ( \
+ lp_or_root \
+ || allowed( \
+ (PRS)->secure->user, \
+ (PPS)->users_allowed, \
+ (PPS)->users_denied \
+ ) \
+ )
+
+ /*
+ * This macro checks that the form is allowed on the printer,
+ * or is already mounted there.
+ * Note: By doing this check we don't have to check that the
+ * characteristics of the form, such as pitch, size, or
+ * character set, against the printer's capabilities, ASSUMING,
+ * of course, that the allow list is correct. That is, the
+ * allow list lists forms that have already been checked against
+ * the printer!
+ */
+#define CHKF(PFS,PPS) \
+ ( \
+ isFormMountedOnPrinter(PPS,PFS) \
+ || allowed( \
+ (PFS)->form->name, \
+ (PPS)->forms_allowed, \
+ (PPS)->forms_denied \
+ ) \
+ )
+
+ /*
+ * This macro checks that the print wheel is acceptable
+ * for the printer or is mounted. Note: If the printer doesn't
+ * take print wheels, the check passes. The check for printers
+ * that don't take print wheels is below.
+ */
+#define CHKPW(PW,PPS) \
+ ( \
+ !(PPS)->printer->daisy \
+ || ( \
+ (PPS)->pwheel_name \
+ && STREQU((PPS)->pwheel_name, (PW)) \
+ ) \
+ || searchlist((PW), (PPS)->printer->char_sets) \
+ )
+
+ /*
+ * This macro checks the pitch, page size, and (if need be)
+ * the character set. The character set isn't checked if the
+ * printer takes print wheels, or if the character set is
+ * listed in the printer's alias list.
+ * The form has to be checked as well; while we're sure that
+ * at least one type for each printer can handle the form's
+ * cpi/lpi/etc. characteristics (lpadmin made sure), we aren't
+ * sure that ALL the types work.
+ */
+#define CHKOPTS(PRS,PC,PFS) _chkopts((PRS),(PC),(PFS)) /* was a macro */
+
+ /*
+ * This macro checks the acceptance status of a printer.
+ * If the request is already assigned to that printer,
+ * then it's okay. It's ambiguous what should happen if
+ * originally a "-d any" request was accepted, temporarily
+ * assigned one printer, then the administrator (1) rejected
+ * further requests for the printers and (2) made the
+ * temporarily assigned printer unusable for the request.
+ * What will happen, of course, is that the request will
+ * be canceled, even though the other printers would be okay
+ * if not rejecting....but if we were to say, gee it's okay,
+ * the request has already been accepted, we may be allowing
+ * it on printers that were NEVER accepting. Thus we can
+ * continue to accept it only for the printer already assigned.
+ */
+#define CHKACCEPT(PRS,PPS) \
+ ( \
+ !((PPS)->status & PS_REJECTED) \
+ || (PRS)->printer == (PPS) \
+ || moving \
+ )
+
+ /*
+ * If a print wheel or character set is given, see if it
+ * is allowed on the form.
+ */
+ if (prs->request->charset)
+ if (
+ !CHKMAND(pfs)
+ || STREQU(prs->request->charset, pfs->form->chset)
+ )
+ /*EMPTY*/;
+ else {
+ ret = MDENYMEDIA;
+ chkprinter_result |= PCK_CHARSET;
+ goto Return;
+ }
+
+ /*
+ * If a single printer was named, check the request against it.
+ * Do the accept/reject check late so that we give the most
+ * useful information to the user.
+ */
+ if (pps) {
+ (pc = &single)->pps = pps;
+
+ /* Does the printer allow the user? */
+ if (!CHKU(prs, pps)) {
+ ret = MDENYDEST;
+ goto Return;
+ }
+
+ /* Check printer label range */
+ if (is_system_labeled() && prs->secure->slabel != NULL) {
+ if (tsol_check_printer_label_range(
+ prs->secure->slabel,
+ pps->printer->name) == 0) {
+ ret = MDENYDEST;
+ goto Return;
+ }
+ }
+
+ /* Does the printer allow the form? */
+ if (pfs && !CHKF(pfs, pps)) {
+ ret = MNOMOUNT;
+ goto Return;
+ }
+
+ /* Does the printer allow the pwheel? */
+ if (
+ prs->request->charset
+ && !CHKPW(prs->request->charset, pps)
+ ) {
+ ret = MNOMOUNT;
+ goto Return;
+ }
+
+ /* Can printer handle the pitch/size/charset/nobanner? */
+ if (!CHKOPTS(prs, pc, pfs)) {
+ ret = MDENYDEST;
+ goto Return;
+ }
+
+ /* Is the printer allowing requests? */
+ if (!CHKACCEPT(prs, pps)) {
+ ret = MERRDEST;
+ goto Return;
+ }
+
+ /* Is there a filter which will convert the input? */
+ if (!pickfilter(prs, pc, pfs)) {
+ ret = MNOFILTER;
+ goto Return;
+ }
+
+ best_pc = pc;
+ ret = MOK;
+ goto Return;
+ }
+
+ /*
+ * Do the acceptance check on the class (if we have one)
+ * now so we can proceed with checks on individual printers
+ * in the class. Don't toss out the request if it is already
+ * assigned a printer just because the class is NOW rejecting.
+ */
+ if (
+ pcs
+ && (pcs->status & CS_REJECTED)
+ && !moving
+ && !prs->printer
+ ) {
+ ret = MERRDEST;
+ goto Return;
+ }
+
+ /*
+ * Construct a list of printers based on the destination
+ * given. Cross off those that aren't accepting requests,
+ * that can't take the form, or which the user can't use.
+ * See if the list becomes empty.
+ */
+
+ if (pcs)
+ n = lenlist(pcs->class->members);
+ else {
+ for (n = 0; PStatus != NULL && PStatus[n] != NULL; n++) ;
+ }
+ pcend = arena = (CANDIDATE *)Calloc(n, sizeof(CANDIDATE));
+
+ /*
+ * Start with a list of printers that are accepting requests.
+ * Don't skip a printer if it's rejecting but the request
+ * has already been accepted for it.
+ */
+ if (pcs) {
+ register char **pn;
+
+ for (pn = pcs->class->members; *pn; pn++)
+ if (
+ ((pps = search_pstatus(*pn)) != NULL)
+ && pps != stop_pps
+ )
+ (pcend++)->pps = pps;
+
+
+ } else
+ for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++) {
+ pps = PStatus[i];
+
+ if (CHKACCEPT(prs, pps) && pps != stop_pps)
+ (pcend++)->pps = pps;
+ }
+
+ if (pcend == arena) {
+ ret = MERRDEST;
+ goto Return;
+ }
+
+ /*
+ * Clean out printers that the user can't use. We piggy-back
+ * the pitch/size/banner checks here because the same error return
+ * is given (strange, eh?).
+ */
+ {
+ register CANDIDATE *pcend2;
+
+ for (pcend2 = pc = arena; pc < pcend; pc++) {
+ if (CHKU(prs, pc->pps) && CHKOPTS(prs, pc, pfs))
+ *pcend2++ = *pc;
+ else
+ free_candidate (pc);
+ }
+
+ if (pcend2 == arena) {
+ ret = MDENYDEST;
+ goto Return;
+ }
+ pcend = pcend2;
+
+ }
+
+ /*
+ * Clean out printers that can't mount the form,
+ * EXCEPT for printers that already have it mounted:
+ */
+ if (pfs) {
+ register CANDIDATE *pcend2;
+
+ for (pcend2 = pc = arena; pc < pcend; pc++)
+ if (CHKF(pfs, pc->pps))
+ *pcend2++ = *pc;
+ else
+ free_candidate (pc);
+
+ if (pcend2 == arena) {
+ ret = MNOMOUNT;
+ goto Return;
+ }
+ pcend = pcend2;
+
+ }
+
+ /*
+ * Clean out printers that can't take the print wheel
+ * EXCEPT for printers that already have it mounted
+ * or printers for which it is a selectable character set:
+ */
+ if (prs->request->charset) {
+ register CANDIDATE *pcend2;
+
+ for (pcend2 = pc = arena; pc < pcend; pc++)
+ if (CHKPW(prs->request->charset, pc->pps))
+ *pcend2++ = *pc;
+ else
+ free_candidate (pc);
+
+ if (pcend2 == arena) {
+ ret = MNOMOUNT;
+ goto Return;
+ }
+ pcend = pcend2;
+
+ }
+
+ /*
+ * Clean out printers that can't handle the printing
+ * and for which there's no filter to convert the input.
+ *
+ */
+
+ /*
+ * Is the form mounted, or is none needed?
+ */
+#define CHKFMNT(PFS,PPS) (isFormUsableOnPrinter(PPS,PFS))
+
+ /*
+ * Is the print-wheel mounted, or is none needed?
+ */
+#define CHKPWMNT(PRS,PPS) SAME((PPS)->pwheel_name, (PRS)->request->charset)
+
+ /*
+ * Do we NOT need a special character set, or can we select
+ * it on the printer? Note: Getting this far means that IF
+ * the printer has selectable character sets (!daisy) then
+ * it can select the one we want.
+ */
+#define CHKCHSET(PRS,PPS) \
+ ( \
+ !(PRS)->request->charset \
+ || !(PPS)->printer->daisy \
+ )
+
+ /*
+ * Is the printer able to print now?
+ */
+#define CHKENB(PPS) (!((PPS)->status & (PS_DISABLED|PS_FAULTED)))
+
+ /*
+ * Is the printer not busy printing another request, or
+ * not awaiting an auto-retry after a fault?
+ */
+#define CHKFREE(PPS) (!((PPS)->status & (PS_BUSY|PS_LATER)))
+
+ {
+ register CANDIDATE *pcend2;
+
+ for (pcend2 = pc = arena; pc < pcend; pc++)
+ if (pickfilter(prs, pc, pfs)) {
+
+ /*
+ * Compute a ``weight'' for this printer,
+ * based on its status. We'll later pick
+ * the printer with the highest weight.
+ */
+ pc->weight = 0;
+ if (!pc->fast && !pc->slow)
+ pc->weight += WEIGHT_NOFILTER;
+ if (CHKFREE(pc->pps))
+ pc->weight += WEIGHT_FREE;
+ if (CHKENB(pc->pps))
+ pc->weight += WEIGHT_ENABLED;
+ if (CHKFMNT(pfs, pc->pps))
+ pc->weight += WEIGHT_MOUNTED;
+ if (CHKPWMNT(prs, pc->pps))
+ pc->weight += WEIGHT_MOUNTED;
+ if (CHKCHSET(prs, pc->pps))
+ pc->weight += WEIGHT_SELECTS;
+
+#if defined(FILTER_EARLY_OUT)
+ if (pc->weight == WEIGHT_MAX) {
+ /*
+ * This is the one!
+ */
+ best_pc = pc;
+ ret = MOK;
+ goto Return;
+ }
+#endif
+ /*
+ * This is a candidate!
+ */
+ *pcend2++ = *pc;
+
+ } else
+ /*
+ * No filter for this one!
+ */
+ free_candidate (pc);
+
+ if (pcend2 == arena) {
+ ret = MNOFILTER;
+ goto Return;
+ }
+ pcend = pcend2;
+
+ }
+
+ if (pcend - arena == 1) {
+ best_pc = arena;
+ ret = MOK;
+ goto Return;
+ }
+ /*
+ * Clean out local printers
+ * where the request is outside the printer label range.
+ */
+ {
+ register CANDIDATE *pcend2 = pcend;
+
+ if (is_system_labeled()) {
+ for (pcend2 = pc = arena; pc < pcend; pc++) {
+ if (tsol_check_printer_label_range(
+ prs->secure->slabel,
+ pps->printer->name) == 1)
+ *pcend2++ = *pc;
+ else
+ free_candidate(pc);
+ }
+ }
+
+ if (pcend2 == arena) {
+ ret = MDENYDEST;
+ goto Return;
+ }
+ pcend = pcend2;
+ }
+
+#if defined(OTHER_FACTORS)
+ /*
+ * Here you might want to add code that considers
+ * other factors: the size of the file(s) to be
+ * printed ("prs->secure->size") in relation to the
+ * printer (e.g. printer A gets mostly large
+ * files, printer B gets mostly small files); the
+ * number/total-size of requests currently queued
+ * for the printer; etc.
+ *
+ * If your code includes eliminating printers drop them
+ * from the list (as done in several places above).
+ * Otherwise, your code should add weights to the weight
+ * already computed. Change the WEIGHT_MAX, increase the
+ * other WEIGHT_X values to compensate, etc., as appropriate.
+ */
+ ;
+#endif
+
+ /*
+ * Pick the best printer from a list of eligible candidates.
+ */
+ best_pc = arena;
+ for (pc = arena + 1; pc < pcend; pc++)
+ if (pc->weight > best_pc->weight)
+ best_pc = pc;
+ ret = MOK;
+
+ /*
+ * Branch to here if MOK and/or if things have been allocated.
+ */
+Return: if (ret == MOK) {
+ register USER *pu = Getuser(prs->secure->user);
+
+ register char *pwheel_name;
+
+ PSTATUS *oldpps = prs->printer;
+
+
+ /*
+ * We are going to accept this print request, having
+ * found a printer for it. This printer will be assigned
+ * to the request, although this assignment may be
+ * temporary if other printers qualify and this printer
+ * is changed to no longer qualify. Qualification in
+ * this context includes being ready to print!
+ */
+ prs->printer = best_pc->pps;
+ load_str (&(prs->printer_type), best_pc->printer_type);
+
+ /*
+ * Assign the form (if any) to the request. Adjust
+ * the number of requests queued for old and new form
+ * accordingly.
+ */
+ if (prs->form != pfs) {
+ unqueue_form (prs);
+ queue_form (prs, pfs);
+ }
+
+ /*
+ * Ditto for the print wheel, except include here the
+ * print wheel needed by the form.
+ * CAUTION: When checking this request later, don't
+ * refuse to service it if the print wheel for the
+ * form isn't mounted but the form is; a mounted form
+ * overrides its other needs. Don't be confused by the
+ * name of the bit, RSS_PWMAND; a printer that prints
+ * this request MUST have the print wheel mounted
+ * (if it takes print wheels) if the user asked for
+ * a particular print wheel.
+ */
+ prs->status &= ~RSS_PWMAND;
+ if (CHKMAND(pfs))
+ pwheel_name = pfs->form->chset;
+ else
+ if ((pwheel_name = prs->request->charset) != NULL)
+ prs->status |= RSS_PWMAND;
+
+ if (!SAME(pwheel_name, prs->pwheel_name)) {
+ unqueue_pwheel (prs);
+ queue_pwheel (prs, pwheel_name);
+ }
+
+ /*
+ * Adjust the priority to lie within the limits allowed
+ * for the user (this is a silent adjustment as required).
+ * CURRENTLY, ONLY NEW REQUESTS WILL GET QUEUED ACCORDING
+ * TO THIS PRIORITY. EXISTING REQUESTS BEING (RE)EVALUATED
+ * WILL NOT BE REQUEUED.
+ * A wild priority is changed to the default, or the
+ * limit, whichever is the lower priority (higher value).
+ */
+ if (prs->request->priority < 0 || 39 < prs->request->priority)
+ prs->request->priority = getdfltpri();
+ if (pu && prs->request->priority < pu->priority_limit)
+ prs->request->priority = pu->priority_limit;
+
+ /*
+ * If a filter is involved, change the number of
+ * copies to 1 (if the filter handles it).
+ */
+ if (
+ (best_pc->fast || best_pc->slow)
+ && (best_pc->flags & FPARM_COPIES)
+ && prs->request->copies > 1
+ )
+ prs->copies = 1;
+ else
+ /*
+ * We use two ".copies" because we don't
+ * want to lose track of the number requested,
+ * but do want to mark the number the interface
+ * program is to handle. Here is the best
+ * place to know this.
+ */
+ prs->copies = prs->request->copies;
+
+ if (best_pc->slow) {
+ /*
+ * If the filter has changed, the request will
+ * have to be refiltered. This may mean stopping
+ * a currently running filter or interface.
+ */
+ if (!SAME(best_pc->slow, prs->slow)) {
+
+ if (prs->request->outcome & RS_FILTERED)
+ prs->request->outcome &= ~RS_FILTERED;
+
+ if (
+ prs->request->outcome & RS_FILTERING
+ && !(prs->request->outcome & RS_STOPPED)
+ ) {
+ prs->request->outcome |= RS_REFILTER;
+ prs->request->outcome |= RS_STOPPED;
+ terminate (prs->exec);
+
+ } else if (
+ prs->request->outcome & RS_PRINTING
+ && !(prs->request->outcome & RS_STOPPED)
+ ) {
+ prs->request->outcome |= RS_STOPPED;
+ terminate (oldpps->exec);
+ }
+
+ }
+
+ load_str (&(prs->slow), best_pc->slow);
+ /* Assumption: if there is a slow filter,
+ * there is an output_type
+ */
+
+ load_str (&(prs->output_type), best_pc->output_type);
+ } else
+ unload_str (&(prs->slow));
+
+ load_str (&(prs->fast), best_pc->fast);
+
+ if (prs->request->actions & ACT_FAST && prs->slow) {
+ if (prs->fast) {
+ prs->fast = makestr(
+ prs->slow,
+ "|",
+ prs->fast,
+ (char *)0
+ );
+ Free (prs->slow);
+ } else
+ prs->fast = prs->slow;
+ prs->slow = 0;
+ }
+
+ }
+
+
+ /*
+ * Free the space allocated for the candidates, INCLUDING
+ * the one chosen. Any allocated space in the chosen candidate
+ * that has to be saved should have been COPIED already.
+ */
+ if (arena) {
+ for (pc = arena; pc < pcend; pc++)
+ free_candidate (pc);
+ Free ((char *)arena);
+ } else if (best_pc)
+ free_candidate (best_pc);
+
+ if (o_length)
+ Free (o_length);
+ if (o_width)
+ Free (o_width);
+ if (o_lpi)
+ Free (o_lpi);
+ if (o_cpi)
+ Free (o_cpi);
+
+
+ /*
+ * The following value is valid ONLY IF the request
+ * is canceled or rejected. Not all requests that
+ * we fail in this routine are tossed out!
+ */
+ prs->reason = ret;
+
+
+ return (ret);
+}
+
+/**
+ ** _chkopts() - CHECK -o OPTIONS
+ **/
+
+static int
+_chkopts(RSTATUS *prs, CANDIDATE *pc, FSTATUS *pfs)
+{
+ unsigned long ret = 0;
+ unsigned long chk = 0;
+
+ char * charset;
+ char * cpi = 0;
+ char * lpi = 0;
+ char * width = 0;
+ char * length = 0;
+ char * paper = NULL;
+
+ char ** pt;
+ int nobanner_not_allowed = 0;
+
+
+ /*
+ * If we have a form, it overrides whatever print characteristics
+ * the user gave.
+ */
+ if (pfs) {
+ cpi = pfs->cpi;
+ lpi = pfs->lpi;
+ width = pfs->pwid;
+ length = pfs->plen;
+ paper = pfs->form->paper;
+ } else {
+ cpi = o_cpi;
+ lpi = o_lpi;
+ width = o_width;
+ length = o_length;
+ }
+
+ /*
+ * If the printer takes print wheels, or the character set
+ * the user wants is listed in the character set map for this
+ * printer, we needn't check if the printer can handle the
+ * character set. (Note: The check for the print wheel case
+ * is done elsewhere.)
+ */
+
+ if (pc->pps->printer->daisy ||
+ search_cslist(prs->request->charset, pc->pps->printer->char_sets))
+ charset = 0;
+ else
+ charset = prs->request->charset;
+
+ pc->printer_types = 0;
+ for (pt = pc->pps->printer->printer_types; *pt; pt++) {
+ unsigned long this;
+
+ if (paper) {
+ if (allowed(paper,pc->pps->paper_allowed,NULL)) {
+ addlist (&(pc->printer_types), *pt);
+ } else {
+ ret |= PCK_PAPER;
+ }
+ } else {
+ this = chkprinter(*pt, cpi, lpi, length, width,
+ charset);
+ if (this == 0)
+ addlist(&(pc->printer_types), *pt);
+ chk |= this;
+ }
+ }
+ if (!pc->printer_types)
+ ret |= chk;
+
+ /*
+ * If the sytem is labeled, then user who wants 'nolabels' must
+ * have PRINT_UNLABELED_AUTH authorizations to allow it.
+ */
+ if (is_system_labeled() && (wants_nolabels == 1)) {
+ if (!tsol_lpauth(PRINT_UNLABELED_AUTH, prs->secure->user)) {
+ /* if not authorized, remove "nolabels" from options */
+ register char **list;
+ if (prs->request->options &&
+ (list = dashos(prs->request->options))) {
+ dellist(&list, "nolabels");
+ free(prs->request->options);
+ prs->request->options = sprintlist(list);
+ }
+ }
+ }
+
+
+ if (pc->pps->printer->banner == BAN_ALWAYS) {
+ /* delete "nobanner" */
+ char **list;
+
+ /*
+ * If the system is labeled, users must have
+ * PRINT_NOBANNER_AUTH authorization to print
+ * without a banner.
+ */
+ if (is_system_labeled()) {
+ if (wants_nobanner == 1) {
+ if (tsol_lpauth(PRINT_NOBANNER_AUTH,
+ prs->secure->user) == 0) {
+ nobanner_not_allowed = 1;
+ }
+ }
+
+ }
+ else if ((wants_nobanner == 1) && (lp_or_root != 1)) {
+ nobanner_not_allowed = 1;
+ }
+ if (nobanner_not_allowed == 1) {
+ /* Take out 'nobanner' from request options. */
+ if (prs->request->options &&
+ (list = dashos(prs->request->options))) {
+ dellist(&list, "nobanner");
+ free(prs->request->options);
+ prs->request->options = sprintlist(list);
+ }
+ }
+ } else if (pc->pps->printer->banner == BAN_NEVER) {
+ if (wants_nobanner == 0) {
+ /* add "nobanner" */
+ char **list = NULL;
+
+ if (prs->request->options) {
+ list = dashos(prs->request->options);
+ free(prs->request->options);
+ }
+ appendlist(&list, "nobanner");
+ prs->request->options = sprintlist(list);
+ }
+ } else /* if (pc->pps->printer->banner == BAN_OPTIONAL) */ {
+ /* it is optional, leave it alone */
+ }
+
+ chkprinter_result |= ret;
+ return (ret == 0);
+}
+
+/**
+ ** free_candidate()
+ **/
+
+static void
+free_candidate(CANDIDATE *pc)
+{
+ if (pc->slow)
+ unload_str (&(pc->slow));
+ if (pc->fast)
+ unload_str (&(pc->fast));
+ if (pc->printer_types) {
+ freelist (pc->printer_types);
+ pc->printer_types = 0;
+ }
+ if (pc->printer_type)
+ unload_str (&(pc->printer_type));
+ if (pc->output_type)
+ unload_str (&(pc->output_type));
+ return;
+}
+
+static int
+tsol_check_printer_label_range(char *slabel, const char *printer)
+{
+ int in_range = 0;
+ int err = 0;
+ m_range_t *range;
+ m_label_t *sl = NULL;
+
+ if (slabel == NULL)
+ return (0);
+
+ if ((err =
+ (str_to_label(slabel, &sl, USER_CLEAR, L_NO_CORRECTION, &in_range)))
+ == -1) {
+ /* stobsl error on printer max label */
+ return (0);
+ }
+ if ((range = getdevicerange(printer)) == NULL) {
+ m_label_free(sl);
+ return (0);
+ }
+
+ /* blinrange returns true (1) if in range, false (0) if not */
+ in_range = blinrange(sl, range);
+
+ m_label_free(sl);
+ m_label_free(range->lower_bound);
+ m_label_free(range->upper_bound);
+ free(range);
+
+ return (in_range);
+}
+
+/*
+ * Given a character string with a "username" or "system!username"
+ * this function returns a pointer to "username"
+ */
+static int
+tsol_lpauth(char *auth, char *in_name)
+{
+ char *cp;
+ int res;
+
+ if ((cp = strchr(in_name, '@')) != NULL) {
+ /* user@system */
+ *cp = '\0';
+ res = chkauthattr(auth, in_name);
+ *cp = '@';
+ } else if ((cp = strchr(in_name, '!')) != NULL)
+ /* system!user */
+ res = chkauthattr(auth, cp+1);
+ else
+ /* user */
+ res = chkauthattr(auth, in_name);
+
+ return (res);
+}
+
+#define POLICY_FILE "/etc/default/print"
+
+int
+secpolicy_chkpolicy(char *policyp)
+{
+ char *option;
+ int opt_val;
+
+ if (policyp == NULL)
+ return (0);
+ opt_val = 0;
+ if (defopen(POLICY_FILE) == 0) {
+
+ defcntl(DC_SETFLAGS, DC_STD & ~DC_CASE); /* ignore case */
+
+ if ((option = defread(policyp)) != NULL)
+ opt_val = atoi(option);
+ }
+ (void) defopen((char *)NULL);
+ syslog(LOG_DEBUG, "--- Policy %s, opt_val==%d",
+ policyp ? policyp : "NULL", opt_val);
+ return (opt_val);
+}
diff --git a/usr/src/cmd/lp/cmd/lpsched/validate.h b/usr/src/cmd/lp/cmd/lpsched/validate.h
new file mode 100644
index 0000000000..cf415a0b0b
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpsched/validate.h
@@ -0,0 +1,80 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * The old LP Spooler would take a job destined for a class of printers
+ * if the class was accepting, regardless of the acceptance status of
+ * the printers. This sounds a bit silly, so we thought we'd change it.
+ * Well, that's not compatible. So YOU decide. Define the following if
+ * you want compatibility, don't define it if you want to require BOTH
+ * the printers (at least one) and the class to be accepting.
+ */
+#define CLASS_ACCEPT_PRINTERS_REJECT_SOWHAT 1 /* */
+
+/*
+ * Define the following if we should stop examing a list of printers
+ * on the first one that meets all the needs of the request.
+ * Currently this is done because to continue wouldn't matter. However,
+ * you may add additional code that considers other factors (e.g. size
+ * of queue for printer, size of file under consideration.)
+ */
+#define FILTER_EARLY_OUT 1 /* */
+
+typedef struct candidate {
+ PSTATUS * pps;
+ char * slow;
+ char * fast;
+ char ** printer_types;
+ char * printer_type;
+ char * output_type;
+ unsigned short flags;
+ unsigned short weight;
+} CANDIDATE;
+
+#define WEIGHT_NOFILTER 1
+#define WEIGHT_FREE 2
+#define WEIGHT_ENABLED 4
+#define WEIGHT_MOUNTED 8
+#define WEIGHT_SELECTS 16
+#define WEIGHT_MAX ( \
+ WEIGHT_NOFILTER \
+ + WEIGHT_FREE \
+ + WEIGHT_ENABLED \
+ + 2 * WEIGHT_MOUNTED \
+ + WEIGHT_SELECTS \
+ )
+
+extern int pick_filter();
+
+extern char *o_cpi,
+ *o_lpi,
+ *o_width,
+ *o_length;
diff --git a/usr/src/cmd/lp/cmd/lpshut.c b/usr/src/cmd/lp/cmd/lpshut.c
new file mode 100644
index 0000000000..925b669f5b
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpshut.c
@@ -0,0 +1,204 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <locale.h>
+#include "stdio.h"
+#include "signal.h"
+#include "string.h"
+#include "sys/types.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "msgs.h"
+
+#define WHO_AM_I I_AM_LPSHUT
+#include "oam.h"
+
+void startup(),
+ cleanup(),
+ done();
+
+/*
+ * There are no sections of code in this progam that have to be
+ * protected from interrupts. We do want to catch them, however,
+ * so we can clean up properly.
+ */
+
+/**
+ ** main()
+ **/
+
+int
+main(int argc, char *argv[])
+{
+ char msgbuf[MSGMAX];
+ char * tempo;
+
+ int mtype;
+
+ short status;
+
+
+ (void) setlocale (LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ if (argc > 1)
+ if (STREQU(argv[1], "-?")) {
+ printf (gettext("usage: lpshut\n"));
+ exit (0);
+
+ } else {
+ LP_ERRMSG1 (ERROR, E_LP_OPTION, argv[1]);
+ exit (1);
+ }
+
+
+ startup ();
+
+ if ((tempo = getenv("LPSHUT")) && STREQU(tempo, "slow"))
+ (void)putmessage (msgbuf, S_SHUTDOWN, 0);
+ else
+ (void)putmessage (msgbuf, S_SHUTDOWN, 1);
+
+ if (msend(msgbuf) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MSEND);
+ done (1);
+ }
+ if (mrecv(msgbuf, sizeof(msgbuf)) == -1) {
+ LP_ERRMSG (ERROR, E_LP_MRECV);
+ done (1);
+ }
+
+ mtype = getmessage(msgbuf, R_SHUTDOWN, &status);
+ if (mtype != R_SHUTDOWN) {
+ LP_ERRMSG1 (ERROR, E_LP_BADREPLY, mtype);
+ done (1);
+ }
+
+ switch (status) {
+
+ case MOK:
+ printf (gettext("Print services stopped.\n"));
+ done (0);
+
+ case MNOPERM:
+ LP_ERRMSG (WARNING, E_SHT_CANT);
+ done (1);
+
+ default:
+ LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, status);
+ done (1);
+ }
+ /*NOTREACHED*/
+ return (0);
+}
+
+/**
+ ** startup() - OPEN MESSAGE QUEUE TO SPOOLER
+ **/
+
+void startup ()
+{
+ void catch();
+
+ /*
+ * Open a private queue for messages to the Spooler.
+ * An error is deadly.
+ */
+ if (mopen() == -1) {
+
+ switch (errno) {
+ case ENOMEM:
+ case ENOSPC:
+ LP_ERRMSG (ERROR, E_LP_MLATER);
+ exit (1);
+ /*NOTREACHED*/
+
+ default:
+ printf (gettext("Print services already stopped.\n"));
+ exit (1);
+ /*NOTREACHED*/
+ }
+ }
+
+ /*
+ * Now that the queue is open, quickly trap signals
+ * that we might get so we'll be able to close the
+ * queue again, regardless of what happens.
+ */
+ if(signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, catch);
+ if(signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, catch);
+ if(signal(SIGQUIT, SIG_IGN) != SIG_IGN)
+ signal(SIGQUIT, catch);
+ if(signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, catch);
+
+ return;
+}
+
+/**
+ ** catch() - CATCH INTERRUPT, HANGUP, ETC.
+ **/
+
+void catch (sig)
+ int sig;
+{
+ signal (sig, SIG_IGN);
+ done (1);
+}
+
+/**
+ ** cleanup() - CLOSE THE MESSAGE QUEUE TO THE SPOOLER
+ **/
+
+void cleanup ()
+{
+ mclose ();
+ return;
+}
+
+/**
+ ** done() - CLEANUP AND EXIT
+ **/
+
+void done (ec)
+ int ec;
+{
+ cleanup ();
+ exit (ec);
+}
diff --git a/usr/src/cmd/lp/cmd/lptest/Makefile b/usr/src/cmd/lp/cmd/lptest/Makefile
new file mode 100644
index 0000000000..9c2aea6eb7
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lptest/Makefile
@@ -0,0 +1,71 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+#
+# cmd/lp/cmd/lptest/Makefile
+#
+
+include ../../Makefile.lp
+
+PROG= lptest
+
+ROOTUSRUCBSYMLINK= $(ROOTUSRUCB)/$(PROG)
+ROOTUSRBINPROG= $(PROG:%=$(ROOTBIN)/%)
+
+SRCS= lptest.c
+
+OBJS= $(SRCS:.c=.o)
+
+CPPFLAGS = -I$(LPINC) $(CPPFLAGS.master)
+LDLIBS += $(LIBBSD) $(LIBREQ) $(LIBMSG) $(LIBOAM)
+
+POFILE= lp_cmd_lptest.po
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all .WAIT $(ROOTUSRBINPROG) $(ROOTUSRUCBSYMLINK)
+
+$(ROOTUSRUCBSYMLINK):
+ $(RM) $@; $(SYMLINK) ../bin/$(PROG) $@
+
+clean:
+ $(RM) $(OBJS)
+
+clobber: clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint:
+ $(LINT.c) $(PROG).c $(LDLIBS)
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE b/usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE
new file mode 100644
index 0000000000..522cd49165
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE
@@ -0,0 +1,32 @@
+Copyright (c) 1983 Regents of the University of California.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ 3. All advertising materials mentioning features or use of this
+ software must display the following acknowledgement:
+ This product includes software developed by the University
+ of California, Berkeley and its contributors.
+ 4. Neither the name of the University nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE.descrip b/usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE.descrip
new file mode 100644
index 0000000000..a0ae5f87c7
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE.descrip
@@ -0,0 +1 @@
+PORTIONS OF LPTEST COMMAND FUNCTIONALITY
diff --git a/usr/src/cmd/lp/cmd/lptest/lptest.c b/usr/src/cmd/lp/cmd/lptest/lptest.c
new file mode 100644
index 0000000000..9e5ff775e7
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lptest/lptest.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * lptest -- line printer test program (and other devices).
+ */
+
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ int len, count;
+ register int i, j, fc, nc;
+ char outbuf[BUFSIZ];
+
+ setbuf(stdout, outbuf);
+ if (argc >= 2)
+ len = atoi(argv[1]);
+ else
+ len = 79;
+ if (argc >= 3)
+ count = atoi(argv[2]);
+ else
+ count = 200;
+ fc = ' ';
+ for (i = 0; i < count; i++) {
+ if (++fc == 0177)
+ fc = ' ';
+ nc = fc;
+ for (j = 0; j < len; j++) {
+ putchar(nc);
+ if (++nc == 0177)
+ nc = ' ';
+ }
+ putchar('\n');
+ }
+ (void) fflush(stdout);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/cmd/lpusers.c b/usr/src/cmd/lp/cmd/lpusers.c
new file mode 100644
index 0000000000..b862e788ac
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/lpusers.c
@@ -0,0 +1,215 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/* lpusers [-q priority-level] -u (user-list | "")
+ lpusers -d priority-level
+ lpusers -l
+*/
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <locale.h>
+
+#include "lp.h"
+#include "users.h"
+#include "msgs.h"
+
+#define WHO_AM_I I_AM_LPUSERS
+#include "oam.h"
+
+char message[100],
+ reply[100];
+
+char *PRIORITY;
+
+int add_user(), del_user();
+
+int
+main(int argc, char *argv[])
+{
+ int mtype, size, c,
+ list = FALSE, limit = -1, deflt = -1;
+ int fd;
+ char *userlist = 0, *user, **users, *p;
+ char stroptsw[] = "-X";
+ short status;
+ struct user_priority *ppri_tbl, *ld_priority_file();
+ extern char *optarg;
+ extern int optind, opterr, optopt, errno;
+
+ setlocale(LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+
+ if(argc == 1) {
+usage:
+ (void) printf(gettext("usage: \n"));
+ (void) printf(gettext("(assign priority limit to users)\n"));
+ (void) printf(gettext("\tlpusers -q priority -u user-list\n"));
+
+ (void) printf(gettext(
+ "(assign default priority limit for balance of users)\n"));
+ (void) printf(gettext("\tlpusers -q priority\n"));
+
+ (void) printf(gettext("(put users back to default priority limit)\n"));
+ (void) printf(gettext("\tlpusers -u user-list\n"));
+
+ (void) printf(gettext("(assign default priority)\n"));
+ (void) printf(gettext("\tlpusers -d priority\n"));
+
+ (void) printf(gettext("(examine priority limits, defaults)\n"));
+ (void) printf(gettext("\tlpusers -l\n"));
+
+ exit(argc == 1);
+ }
+
+ opterr = 0; /* disable printing of errors by getopt */
+ while ((c = getopt(argc, argv, "ld:q:u:")) != -1)
+ switch(c) {
+ case 'l':
+ if (list)
+ LP_ERRMSG1(WARNING, E_LP_2MANY, 'l');
+ list = TRUE;
+ break;
+ case 'd':
+ if (deflt != -1)
+ LP_ERRMSG1(WARNING, E_LP_2MANY, 'd');
+ deflt = (int)strtol(optarg,&p,10);
+ if (*p || deflt<PRI_MIN || deflt>PRI_MAX) {
+ LP_ERRMSG1(ERROR, E_LP_BADPRI, optarg);
+ exit(1);
+ }
+ break;
+ case 'q':
+ if (limit != -1)
+ LP_ERRMSG1(WARNING, E_LP_2MANY, 'q');
+ limit = (int)strtol(optarg,&p,10);
+ if (*p || limit<PRI_MIN || limit>PRI_MAX) {
+ LP_ERRMSG1(ERROR, E_LP_BADPRI, optarg);
+ exit(1);
+ }
+ break;
+ case 'u':
+ if (userlist)
+ LP_ERRMSG1(WARNING, E_LP_2MANY, 'u');
+ userlist = optarg;
+ break;
+ case '?':
+ if (optopt == '?')
+ goto usage;
+ stroptsw[1] = optopt;
+ if (strchr("ldqu", optopt))
+ LP_ERRMSG1(ERROR, E_LP_OPTARG, stroptsw);
+ else
+ LP_ERRMSG1(ERROR, E_LP_OPTION, stroptsw);
+ exit(1);
+ }
+
+ if (optind < argc) {
+ LP_ERRMSG1(ERROR, E_LP_EXTRA, argv[optind]);
+ exit(1);
+ }
+
+ if (((list || deflt != -1) && (limit != -1 || userlist))
+ || (list && deflt != -1)) {
+ LP_ERRMSG(ERROR, E_LP_OPTCOMB);
+ /* invalid combination of options */
+ exit(1);
+ }
+
+ PRIORITY = Lp_Users;
+
+ /* load existing priorities from file */
+ if (!(ppri_tbl = ld_priority_file(PRIORITY))) {
+ switch (errno) {
+ case EBADF:
+ LP_ERRMSG1(ERROR, E_LPU_BADFORM, PRIORITY);
+ break;
+ default:
+ LP_ERRMSG2(ERROR, E_LPU_BADFILE, PRIORITY, errno);
+ }
+ exit(1);
+ }
+
+ if (list) {
+ print_tbl(ppri_tbl);
+ exit (0);
+ } else {
+ if (userlist) {
+ users = getlist(userlist, " \t", ",");
+ if (users)
+ while (user = *users++) {
+ if (del_user(ppri_tbl, user) && (limit == -1))
+ LP_ERRMSG1(WARNING, E_LPU_NOUSER, user);
+ if (limit != -1) {
+ if (add_user(ppri_tbl, user, limit))
+ LP_ERRMSG1(WARNING, E_LPU_BADU, user);
+ }
+ }
+ } else if (deflt != -1)
+ ppri_tbl->deflt = deflt;
+ else
+ ppri_tbl->deflt_limit = limit;
+
+ if ((fd = open_locked(PRIORITY, "w", LPU_MODE)) < 0) {
+ LP_ERRMSG1(ERROR, E_LP_ACCESS, PRIORITY);
+ exit(1);
+ }
+ output_tbl(fd, ppri_tbl);
+ close(fd);
+ }
+
+ if (mopen()) /* error on mopen == no spooler, exit quietly */
+ exit(0);
+
+ (void)putmessage (message, S_LOAD_USER_FILE);
+
+ if (msend(message))
+ goto Error;
+ if (mrecv(reply, sizeof(reply)) == -1)
+ goto Error;
+ mtype = getmessage(reply, R_LOAD_USER_FILE, &status);
+ if (mtype != R_LOAD_USER_FILE) {
+ LP_ERRMSG1 (ERROR, E_LP_BADREPLY, mtype);
+ goto NoError;
+ }
+
+ if (status == 0)
+ goto NoError;
+
+Error: LP_ERRMSG (ERROR, E_LPU_NOLOAD);
+
+NoError:(void)mclose ();
+ return (0);
+}
diff --git a/usr/src/cmd/lp/cmd/scripts/Makefile b/usr/src/cmd/lp/cmd/scripts/Makefile
new file mode 100644
index 0000000000..a564e47a62
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/scripts/Makefile
@@ -0,0 +1,80 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/cmd/scripts/Makefile
+#
+
+
+include $(SRC)/cmd/Makefile.cmd
+
+USRSBINPROG = lpshut
+ROOTUSRSBINPROG= $(USRSBINPROG:%=$(ROOTUSRSBIN)/%)
+$(ROOTUSRSBINPROG) := FILEMODE=555
+
+LIBPROG = lpsched
+ROOTLIBPROG= $(LIBPROG:%=$(ROOTLIB)/%)
+$(ROOTLIBPROG) := FILEMODE=555
+
+MSGFILES= lpsched lpshut
+POFILE= lpschedlpshut.po
+
+LIBLINKS = lpshut
+ROOTSYMLINKS= $(LIBLINKS:%=$(ROOTLIB)/%)
+
+.KEEP_STATE:
+
+all: $(USRSBINPROG) $(LIBPROG)
+
+install: $(ROOTUSRSBINPROG) $(ROOTLIBPROG) $(ROOTSYMLINKS)
+
+catalog: $(POFILE)
+ $(CP) $(POFILE) ..
+
+_msg: $(POFILE)
+
+$(POFILE): $(MSGFILES)
+ grep gettext $(MSGFILES) | tr '`' ' ' | sed -e "s/gettext \"/gettext \(\"/" | sed -e "s/$$/);/" > $(POFILE).i
+ $(XGETTEXT) -s $(POFILE).i
+ $(RM) $@ $(POFILE).i
+ mv messages.po $(POFILE)
+
+#
+# Create a message file to test with
+#
+_msg_test:
+ grep gettext $(MSGFILES) | tr '`' ' ' | sed -e "s/gettext \"/gettext \(\"/" | sed -e "s/$$/);/" > $(POFILE).i
+ $(XGETTEXT) -s -m "xxx" $(POFILE).i
+ $(RM) $@ $(POFILE).i
+ mv messages.po $(POFILE)
+
+clean:
+ $(RM) $(POFILE)
+
+clobber: clean
+
+$(ROOTSYMLINKS):
+ $(RM) $@; $(SYMLINK) ../sbin/$(@F) $@
diff --git a/usr/src/cmd/lp/cmd/scripts/lpsched b/usr/src/cmd/lp/cmd/scripts/lpsched
new file mode 100644
index 0000000000..bc30036f65
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/scripts/lpsched
@@ -0,0 +1,134 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+ [ -f /usr/lib/lp/local/lpsched ] || exit 1
+
+# Get command line options and set them in print service
+# -f num_filters
+# -n num_notifiers
+# -p fd_limit
+# -r reserved_fds
+
+# Check to see if lpsched is already running
+
+state=`svcprop -p restarter/state svc:/application/print/server:default`
+if [ "$state" = "online" ] ; then
+ /bin/gettext "Print services already active.\n"
+ exit 1
+fi
+
+OPTS=$*
+
+# no options set
+
+if [ "$OPTS" = "" ] ; then
+ /usr/sbin/svcadm enable -t svc:/application/print/server:default
+ if [ $? = 0 ] ; then
+ /bin/gettext "Print services started.\n"
+ exit 0
+ else
+ exit 1
+ fi
+
+else
+
+# Get and set the options
+
+ /usr/sbin/svccfg <<-EOF 2>/dev/null
+ select svc:/application/print/server:default
+ addpg cmd_opts count P
+
+ EOF
+
+num_filters=0
+num_notifiers=0
+fd_limit=0
+reserved_fds=0
+
+while getopts :f:n:p:r: arg; do
+ case $arg in
+ f)
+ num_filters=$OPTARG
+
+ /usr/sbin/svccfg <<-EOF 2>/dev/null
+ select svc:/application/print/server:default
+ setprop cmd_opts/num_filters = count: ${num_filters}
+
+ EOF
+
+ ;;
+
+ n)
+ num_notifiers=$OPTARG
+
+ /usr/sbin/svccfg <<-EOF 2>/dev/null
+ select svc:/application/print/server:default
+ setprop cmd_opts/num_notifiers = count: ${num_notifiers}
+
+ EOF
+
+ ;;
+
+ p)
+ fd_limit=$OPTARG
+
+ /usr/sbin/svccfg <<-EOF 2>/dev/null
+ select svc:/application/print/server:default
+ setprop cmd_opts/fd_limit = count: ${fd_limit}
+
+ EOF
+
+ ;;
+
+ r)
+ reserved_fds=$OPTARG
+
+ /usr/sbin/svccfg <<-EOF 2>/dev/null
+ select svc:/application/print/server:default
+ setprop cmd_opts/reserved_fds = count: ${reserved_fds}
+
+ EOF
+
+ ;;
+
+ *) echo "Invalid flag -$OPTARG. Exiting"
+ exit 1
+ esac
+done
+
+ /usr/sbin/svcadm enable -t svc:/application/print/server:default
+ if [ $? = 0 ] ; then
+ /bin/gettext "Print services started.\n"
+ exit 0
+ else
+ exit 1
+ fi
+
+fi
+
diff --git a/usr/src/cmd/lp/cmd/scripts/lpshut b/usr/src/cmd/lp/cmd/scripts/lpshut
new file mode 100644
index 0000000000..aff2761852
--- /dev/null
+++ b/usr/src/cmd/lp/cmd/scripts/lpshut
@@ -0,0 +1,41 @@
+#!/sbin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+
+ state=`svcprop -p restarter/state svc:/application/print/server:default`
+ if [ "$state" != "online" ] ; then
+ gettext "Print services already stopped.\n"
+ exit 1
+ fi
+
+ /usr/sbin/svcadm disable -t svc:/application/print/server:default
+ if [ $? != 0 ] ; then
+ exit 1
+ else
+ gettext "Print services stopped.\n"
+ fi
+exit 0
diff --git a/usr/src/cmd/lp/crontab/Makefile b/usr/src/cmd/lp/crontab/Makefile
new file mode 100644
index 0000000000..8dab8c1ab5
--- /dev/null
+++ b/usr/src/cmd/lp/crontab/Makefile
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/crontab/Makefile
+#
+
+include ../Makefile.lp
+
+ROOTCRONTABS = $(ROOT)/var/spool/cron/crontabs
+
+PROG = lp
+ROOTCRONTABPROG = $(PROG:%=$(ROOTCRONTABS)/%)
+
+
+FILEMODE = 400
+
+.KEEP_STATE:
+
+all : $(PROG)
+
+install: all $(ROOTCRONTABPROG)
+
+$(ROOTCRONTABS)/% : %
+ $(INS.file)
+
+clobber clean strip lint:
diff --git a/usr/src/cmd/lp/crontab/lp b/usr/src/cmd/lp/crontab/lp
new file mode 100644
index 0000000000..610cf71a44
--- /dev/null
+++ b/usr/src/cmd/lp/crontab/lp
@@ -0,0 +1,35 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# At 03:13am on Sundays:
+# Move a weeks worth of 'requests' to 'requests.1'.
+# If there was a 'requests.1' move it to 'requests.2'.
+# If there was a 'requests.2' then it is lost.
+#
+13 3 * * 0 cd /var/lp/logs; if [ -f requests ]; then if [ -f requests.1 ]; then /bin/mv requests.1 requests.2; fi; /usr/bin/cp requests requests.1; >requests; fi
+#
+# Rotating of the "lpsched" log files is handled by logadm(1M).
+#
diff --git a/usr/src/cmd/lp/filter/Makefile b/usr/src/cmd/lp/filter/Makefile
new file mode 100644
index 0000000000..bb86e4fde4
--- /dev/null
+++ b/usr/src/cmd/lp/filter/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/Makefile
+#
+
+include ../Makefile.lp
+
+ROOTLIBLPBIN = $(ROOTLIBLP)/bin
+
+SUBDIRS = postscript
+
+
+PROG = slow.filter
+
+ROOTLIBLPBINPROG = $(PROG:%=$(ROOTLIBLPBIN)/%)
+
+.KEEP_STATE :
+
+all : $(PROG) $(SUBDIRS)
+
+install : $(PROG) $(ROOTLIBLPBINPROG) $(SUBDIRS)
+
+$(ROOTLIBLPBIN)/% : %
+ $(INS.file)
+
+clean clobber strip lint catalog: $(SUBDIRS)
+
+$(SUBDIRS) : FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC :
diff --git a/usr/src/cmd/lp/filter/postscript/Makefile b/usr/src/cmd/lp/filter/postscript/Makefile
new file mode 100644
index 0000000000..a730da0d8f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/Makefile
@@ -0,0 +1,64 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/Makefile
+#
+
+include ../../Makefile.lp
+
+COMMON_SUBDIRS = \
+ common \
+ postreverse \
+ dpost \
+ postio \
+ postprint \
+ postscript \
+ postcomm \
+ download \
+ font \
+ filtdesc
+
+SUBDIRS= $(COMMON_SUBDIRS)
+
+ROOTDIRS = $(ROOTLIBLPPOST)
+
+TXTS= README
+
+.KEEP_STATE:
+
+all: $(TXTS) $(SUBDIRS)
+
+install: $(ROOTDIRS) .WAIT $(SUBDIRS)
+
+clean clobber strip lint catalog: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+$(ROOTDIRS):
+ $(INS.dir)
+
+FRC:
diff --git a/usr/src/cmd/lp/filter/postscript/Makefile.msg b/usr/src/cmd/lp/filter/postscript/Makefile.msg
new file mode 100644
index 0000000000..5a978d7830
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/Makefile.msg
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/Makefile.msg
+
+POFILES = $(SRCS:%.c=%.po)
+
+include ../../../Makefile.lp.msg
+
+catalog: $(POFILE)
+ $(CP) $(POFILE) ../../..
diff --git a/usr/src/cmd/lp/filter/postscript/README b/usr/src/cmd/lp/filter/postscript/README
new file mode 100644
index 0000000000..76de6f8678
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/README
@@ -0,0 +1,306 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Version 3.15 source code for a few programs that can be used with PostScript
+printers. Most of the important changes are described in the VERSION file. The
+main Makefile is also slightly different so take a look at the next section or,
+equivalently, check the comments at the beginning of Makefile before you build
+or install the programs.
+
+If you change LIBDIR or FONTDIR (in Makefile) make the corresponding changes to
+the pathnames defined in common/path.h before compiling the programs. If you're
+on a UTS system compile the programs with the native compiler! The new postreverse
+is backwards compatible, but output from the new translators should not be passed
+through old versions of postreverse. The likely result in that case will be no
+output at all. ENCODING (in Makefile) controls how dpost encodes lines of text.
+By setting ENCODING to 2 I've selected the fast, but not thoroughly tested method
+that usually results in a 20% improvement in throughput. If you have problems
+set ENCODING to 0 and recompile dpost. That results in a default version of dpost
+that produces output essentially identical to earlier versions. The -R, -B, and
+-q options usually result in better performance from postio. Take a look at the
+man page or file postio/README if you want to change the default.
+
+There are potential conflicts with earlier versions, so I strongly recommend you
+install the new code on all your systems at about the same time. The new version
+of postreverse is safe and should be included if any new translators are installed.
+The important files that get replaced on a complete install are:
+
+ /usr/lib/postscript/* ie. $(LIBDIR)/* in Makefile
+ /usr/lbin/postscript/* ie. $(BINDIR)/* in Makefile
+ /usr/lib/macros/pictures ie. $(MACRODIR)/pictures in Makefile
+ /usr/lib/macros/color ie. $(MACRODIR)/color in Makefile
+ /usr/lib/font/devpost/* ie. $(FONTDIR)/devpost/* in Makefile
+ /usr/lib/font/PDQ/devpost/* ie. $(FONTDIR)/PDQ/devpost/* in Makefile
+ /usr/bin/dpost only if it's already there
+
+The final pathnames depend on the values assigned to LIBDIR, BINDIR, MACRODIR,
+FONTDIR, MANDIR, and ROOT in Makefile. When Makefile is ready type,
+
+ make all
+
+to build (but not install) everything or,
+
+ make install
+
+to build and install the entire package, although you'll probably have to be root
+before the install will work. If you're just interested in part of the package
+(eg. installing dpost and the font files) type,
+
+ make TARGETS="dpost font" install
+
+There are makefiles in most of the subdirectories, but they're not designed to
+be used on their own, especially not if you're installing things. Each needs
+many of the definitions made in Makefile before they're guaranteed to work. As
+long as you run make in this directory using Makefile you won't have to worry
+about any other changes or additions. The appropriate definitions will be exported
+before any of the other makefiles are used.
+
+There's a long list of people who have made significant contributions to this
+package. Included in that list are Richard Flood, Chris Warth, Guy Riddle, Paul
+Glick, Allan Wilks, Rick Becker, Johnathan Shopiro, Alan Buckwalter, Chi Choy,
+Carmela L'Hommedieu, and Maryann Csaszar. Many thanks to all of them and anyone
+else I (unintentionally) omitted.
+
+----------------------
+
+There's not much you'll need to change, but you may not agree with some of my
+choices, so before you do anything else, check the following definitions in
+Makefile:
+
+
+ ENCODING - An integer (0, 1, 2 or 3) that sets the default text encoding
+ scheme used by dpost. Increasing ENCODING (up to 3) decreases
+ print time and the size of output files produced by dpost. 0 is
+ slow, but the most stable choice and produces output essentially
+ equivalent to previous versions of dpost. 2 and 3 are encoding
+ schemes based on widthshow. Both are fast, perhaps 20% faster
+ than the 0 level scheme, but neither is well tested. Setting
+ encoding to 3 is not recommended, and will result in ragged right
+ margins. The encoding scheme can also be set at run time using
+ the -e option. Setting ENCODING to 2 may be worth a try.
+
+ ROOT - A string that's prepended to all the installation directories
+ (eg. BINDIR). Only used when things are installed, and probably
+ won't be of much use to anyone.
+
+ BINDIR - Where programs, like dpost and postprint, are installed. You may
+ want to change this definition. Things are set up so the programs
+ get put in a directory that's probably not in anyone's PATH.
+
+ FONTDIR - Where the binary font files go. Should be set to troff's font
+ directory on your system. If you change it do the same thing to
+ the definition of FONTDIR in ./common/path.h.
+
+ LIBDIR - All the files from directory ./postscript that end in .ps (plus
+ a few others) get put here. Mostly prologues for translators. If
+ you change it fix the corresponding paths in ./common/path.h
+ before doing a compile.
+
+ MANDIR - Where the manual pages are installed. This one is undoubtedly
+ wrong!
+
+ MACRODIR - Macro packages get installed here. The ones I've included handle
+ picture inclusion and color selection.
+
+ OWNER - Owner of any files that are installed.
+
+ GROUP - The group that's assigned to all installed files.
+
+ SYSTEM - The version of Unix you're running. Recognized choices are,
+
+ SYSV - System V
+ V9 - Ninth Edition
+ BSD4_2 - Berkeley
+
+ Primarily for conditional compilation in postio.
+
+ CFLAGS - Some of the programs use floating point arithmetic, so if you're
+ running on a system without floating point hardware add the -f
+ option before compiling the programs.
+
+ LIST - The command that's run to produce a source listing. Not terribly
+ important, but the default will only be right on MHCC systems.
+
+ TARGETS - The default group of things (ie. source directories) that make
+ operates on when you select targets like install or clobber.
+
+ DKHOSTDIR - If your system has DKHOST software this is where it should be.
+ Used for conditional compilation in postio, and only if SYSTEM
+ is set to SYSV. Needed so dk.h and libdk.a are picked up. To
+ disable the DKHOST stuff just remove this definition.
+
+ DOCDIR - Documentation about the picture drawing macro gets put in this
+ directory. Includes a short paper and the associated PostScript
+ files that describe how to use the macros and submit jobs on
+ MHCC systems. It's undoubtedly not right for your system and
+ won't be installed unless you add docs to the TARGET list. If
+ you're going to install the documentation you'll undoubtedly
+ have to edit docs/pictures. All the .BP calls will have to
+ reflect the new DOCDIR directory, and the command line used to
+ submit jobs will have to change.
+
+----------------------
+
+Brief descriptions of the programs and source directories follow. Check the man
+pages for more detailed information about the programs.
+
+postio
+ A program that can be used to send files to PostScript printers over an
+ RS-232 serial line. If you're on System V, have the DKHOST software
+ package, and request a line that doesn't begin a / postio may treat it
+ as a Datakit destination. The new version of postio can run as a single
+ process or as separate read and write processes, and can also be used to
+ establish an interactive connection to the printer. Check the man page
+ for more details.
+
+ EXAMPLES:
+
+ A typical command line would look like,
+
+ postio -l /dev/tty?? file.ps
+
+ If your printer is running at something other than 9600 baud (eg.
+ 19200) use the -b option to select the appropriate speed,
+
+ postio -l /dev/tty?? -b19200 file.ps
+
+ Adding the -R2 option to to either of the command lines would force
+ postio to run as separate read and write processes.
+
+dpost
+ Translates output produced by the device independent troff into PostScript.
+ The default font files (in /usr/lib/font/devpost) assume a resolution of
+ 720, which isn't expected to match your printer's resolution.
+
+ EXAMPLE:
+
+ A typical command line (assuming you have up to date versions of eqn
+ and pic) would be,
+
+ pic file | tbl | eqn | troff -mm -Tpost | dpost >file.ps
+
+ If old versions of eqn and pic are installed try,
+
+ pic -T720 | tbl | eqn -r720 | troff -mm -Tpost | dpost >file.ps
+
+postprint
+ Translates ASCII files into PostScript.
+
+ EXAMPLE:
+
+ pr -n file | postprint >file.ps
+
+postreverse
+ A simple program that reverses pages in files that conform to Adobe's 1.0
+ or 2.0 file structuring conventions. Can be used with all the translators
+ in this package, even though the output from dpost often doesn't conform
+ to either convention.
+
+ EXAMPLE:
+
+ postprint file | postreverse >file.ps
+
+buildtables
+ A collection of programs and data files that can be used if you want to
+ have a PostScript printer generate new troff width tables for printer or
+ host resident fonts. All the ASCII width tables in ./font/devpost were
+ built this way.
+
+common
+ Common source and header files used when most of the programs are compiled.
+ The only changes here may be to the pathnames defined in common/path.h.
+ The definitions of LIBDIR and FONTDIR in Makefile must agree with what's
+ in path.h.
+
+doc
+ Additional documentation, that right now only includes a short paper that
+ shows how to use the picture inclusion macros. What's supplied will not
+ be right for all systems.
+
+font
+ Font and device description files for many of the standard PostScript
+ fonts. The ASCII files can be found in directory font/devpost, and are
+ built assuming a device resolution of 720 dpi, which isn't expected to
+ match your printer's actual resolution. All the fonts available on the
+ LaserWriter Plus (and a few others) are supported, but all may not be
+ available on your printer. Characters that troff uses but that aren't on
+ PostScript fonts are built up using definitions in font/devpost/charlib.
+
+ The mapping from troff's one or two character font names into PostScript
+ font names is handled by the definitions made in postscript/dpost.ps. If
+ you build a new font file put the ASCII version in directory font/devpost,
+ add an appropriate definition to postscript/dpost.ps, and then build and
+ install the new binary font file and prologue by typing,
+
+ make TARGETS="postscript font" install
+
+ Building new ASCII font files is described in more detail in font/README
+ and buildtables/README. Files that you'll find in the buildtables source
+ directory, once you understand what's there, let the printer generate
+ the width tables for you.
+
+macros
+ Stand-alone troff macro packages that currently support picture inclusion
+ and color selection (also reverse video) and only work with dpost.
+
+man
+ Manual pages for all the programs supplied with this package.
+
+misc
+ Some interesting and perhaps useful programs obtained from various sources.
+ All are unsupported! Included is an example lp interface program that came
+ from Maryann Csaszar.
+
+postscript
+ PostScript files, mostly prologues, used by the translators supplied in
+ this package. All the files in this directory that end in .ps (and a few
+ others) are copied to /usr/lib/postscript (ie. $(LIBDIR)) when you do an
+ install.
+
+template
+ Files that may help if you're writing a PostScript translator. The basic
+ outline of the C code, the PostScript prologue, and the makefile has been
+ included.
+
+tests
+ Simple test files for all the PostScript translators supplied with this
+ package.
+
+----------------------
+
+The new translators all attempt to conform to Adobe's Version 2.0 file structuring
+conventions. dpost falls short, but only because page independence is sacrificed
+for efficiency. None of the translators use their own dictionary, but perhaps the
+most glaring omission is the lack of a %%BoundingBox comment in output produced by
+most of the translators. Both are issues I hope to address in the next release.
+
+Changing the default behavior for dpost and postio isn't difficult. You get the
+fast (but not completely tested) version of dpost by setting ENCODING in Makefile
+to 2 before compiling dpost - which is what I've supplied. Speeding up the default
+version of postio requires more work, and isn't strongly recommended. The required
+changes (all simple fixes to the C code), are outlined in postio/README.
+
+
+ Richard Drechsler
+ MH 2F-241 x7442
+ mhuxa!drexler
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/Makefile b/usr/src/cmd/lp/filter/postscript/common/Makefile
new file mode 100644
index 0000000000..3ce1c25073
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/Makefile
@@ -0,0 +1,64 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/common/Makefile
+#
+
+include ../../../Makefile.lp
+
+SRCS = glob.c misc.c request.c tempnam.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+TXTS = README
+
+ENCODING= 2
+CPPFLAGS = -DDFLTENCODING=$(ENCODING) \
+ -DSYSV \
+ -I. \
+ $(CPPFLAGS.master)
+
+POFILE = lp_filter_postscript_common.po
+
+.KEEP_STATE :
+
+all : $(TXTS) $(OBJS)
+
+install strip :
+
+clean :
+ $(RM) $(OBJS)
+
+lint : lint_SRCS
+
+clobber: clean
+ $(RM) $(CLOBBERFILES)
+
+lint_SRCS:
+ $(LINT.c) $(SRCS)
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/filter/postscript/common/README b/usr/src/cmd/lp/filter/postscript/common/README
new file mode 100644
index 0000000000..3ccb24a313
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/README
@@ -0,0 +1,26 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Common header and source files used when you compile most of the programs in this
+package. Only required changes may be to the pathnames set in path.h. They must
+agree with the LIBDIR and FONTDIR definitions in ../Makefile.
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/comments.h b/usr/src/cmd/lp/filter/postscript/common/comments.h
new file mode 100644
index 0000000000..b2cbfbca2a
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/comments.h
@@ -0,0 +1,154 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ *
+ * Currently defined file structuring comments from Adobe - plus a few others.
+ * Ones that end with a colon expect arguments, while those ending with a newline
+ * stand on their own. Truly overkill on Adobe's part and mine for including them
+ * all!
+ *
+ * All PostScript files should begin with a header that starts with one of the
+ * following comments.
+ *
+ */
+
+#define NONCONFORMING "%!PS\n"
+#define MINCONFORMING "%!PS-Adobe-\n"
+#define OLDCONFORMING "%!PS-Adobe-1.0\n"
+
+#define CONFORMING "%!PS-Adobe-2.0\n"
+#define CONFORMINGEPS "%!PS-Adobe-2.0 EPS\n"
+#define CONFORMINGQUERY "%!PS-Adobe-2.0 Query\n"
+#define CONFORMINGEXITSERVER "%!PS-Adobe-2.0 ExitServer\n"
+
+/*
+ *
+ * Header comments - immediately follow the appropriate document classification
+ * comment.
+ *
+ */
+
+#define TITLE "%%Title:"
+#define CREATOR "%%Creator:"
+#define CREATIONDATE "%%CreationDate:"
+#define FOR "%%For:"
+#define ROUTING "%%Routing:"
+#define BOUNDINGBOX "%%BoundingBox:"
+#define PAGES "%%Pages:"
+#define REQUIREMENTS "%%Requirements:"
+
+#define DOCUMENTFONTS "%%DocumentFonts:"
+#define DOCUMENTNEEDEDFONTS "%%DocumentNeededFonts:"
+#define DOCUMENTSUPPLIEDFONTS "%%DocumentSuppliedFonts:"
+#define DOCUMENTNEEDEDPROCSETS "%%DocumentNeededProcSets:"
+#define DOCUMENTSUPPLIEDPROCSETS "%%DocumentSuppliedProcSets:"
+#define DOCUMENTNEEDEDFILES "%%DocumentNeededFiles:"
+#define DOCUMENTSUPPLIEDFILES "%%DocumentSuppliedFiles:"
+#define DOCUMENTPAPERSIZES "%%DocumentPaperSizes:"
+#define DOCUMENTPAPERFORMS "%%DocumentPaperForms:"
+#define DOCUMENTPAPERCOLORS "%%DocumentPaperColors:"
+#define DOCUMENTPAPERWEIGHTS "%%DocumentPaperWeights:"
+#define DOCUMENTPRINTERREQUIRED "%%DocumentPrinterREquired:"
+#define ENDCOMMENTS "%%EndComments\n"
+#define ENDPROLOG "%%EndProlog\n"
+
+/*
+ *
+ * Body comments - can appear anywhere in a document.
+ *
+ */
+
+#define BEGINSETUP "%%BeginSetup\n"
+#define ENDSETUP "%%EndSetup\n"
+#define BEGINDOCUMENT "%%BeginDocument:"
+#define ENDDOCUMENT "%%EndDocument\n"
+#define BEGINFILE "%%BeginFile:"
+#define ENDFILE "%%EndFile\n"
+#define BEGINPROCSET "%%BeginProcSet:"
+#define ENDPROCSET "%%EndProcSet\n"
+#define BEGINBINARY "%%BeginBinary:"
+#define ENDBINARY "%%EndBinary\n"
+#define BEGINPAPERSIZE "%%BeginePaperSize:"
+#define ENDPAPERSIZE "%%EndPaperSize\n"
+#define BEGINFEATURE "%%BeginFeature:"
+#define ENDFEATURE "%%EndFeature\n"
+#define BEGINEXITSERVER "%%BeginExitServer:"
+#define ENDEXITSERVER "%%EndExitServer\n"
+#define TRAILER "%%Trailer\n"
+
+/*
+ *
+ * Page level comments - usually will occur once per page.
+ *
+ */
+
+#define PAGE "%%Page:"
+#define PAGEFONTS "%%PageFonts:"
+#define PAGEFILES "%%PageFiles:"
+#define PAGEBOUNDINGBOX "%%PageBoundingBox:"
+#define BEGINPAGESETUP "%%BeginPageSetup\n"
+#define BEGINOBJECT "%%BeginObject:"
+#define ENDOBJECT "%%EndObject\n"
+
+/*
+ *
+ * Resource requirements - again can appear anywhere in a document.
+ *
+ */
+
+#define INCLUDEFONT "%%IncludeFont:"
+#define INCLUDEPROCSET "%%IncludeProcSet:"
+#define INCLUDEFILE "%%IncludeFile:"
+#define EXECUTEFILE "%%ExecuteFile:"
+#define CHANGEFONT "%%ChangeFont:"
+#define PAPERFORM "%%PaparForm:"
+#define PAPERCOLOR "%%PaperColor:"
+#define PAPERWEIGHT "%%PaperWeight:"
+#define PAPERSIZE "%%PaperSize:"
+#define FEATURE "%%Feature:"
+#define ENDOFFILE "%%EOF\n"
+
+#define CONTINUECOMMENT "%%+"
+#define ATEND "(atend)"
+
+/*
+ *
+ * Some non-standard document comments. Global definitions are occasionally used
+ * in dpost and are marked by BEGINGLOBAL and ENDGLOBAL. The resulting document
+ * violates page independence, but can easily be converted to a conforming file
+ * using a utililty program.
+ *
+ */
+
+#define BEGINSCRIPT "%%BeginScript\n"
+#define BEGINGLOBAL "%%BeginGlobal\n"
+#define ENDGLOBAL "%%EndGlobal\n"
+#define ENDPAGE "%%EndPage:"
+#define FORMSPERPAGE "%%FormsPerPage:"
+#define VERSION "%%Version:"
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/dev.h b/usr/src/cmd/lp/filter/postscript/common/dev.h
new file mode 100644
index 0000000000..082156991f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/dev.h
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ dev.h: characteristics of a typesetter
+*/
+
+struct dev {
+ unsigned short filesize; /* number of bytes in file, */
+ /* excluding dev part */
+ short res; /* basic resolution in goobies/inch */
+ short hor; /* goobies horizontally */
+ short vert;
+ short unitwidth; /* size at which widths are given, in effect */
+ short nfonts; /* number of fonts physically available */
+ short nsizes; /* number of sizes it has */
+ short sizescale; /* scaling for fractional point sizes */
+ short paperwidth; /* max line length in units */
+ short paperlength; /* max paper length in units */
+ short nchtab; /* number of funny names in chtab */
+ short lchname; /* length of chname table */
+ short biggestfont; /* #chars in largest ever font */
+ short spare2; /* in case of expansion */
+};
+
+struct Font { /* characteristics of a font */
+ char nwfont; /* number of width entries for this font */
+ char specfont; /* 1 == special font */
+ char ligfont; /* 1 == ligatures exist on this font */
+ char spare1; /* unused for now */
+ char namefont[10]; /* name of this font (e.g., "R" */
+ char intname[10]; /* internal name (=number) on device, in ascii */
+};
+
+/* ligatures, ORed into ligfont */
+
+#define LFF 01
+#define LFI 02
+#define LFL 04
+#define LFFI 010
+#define LFFL 020
diff --git a/usr/src/cmd/lp/filter/postscript/common/ext.h b/usr/src/cmd/lp/filter/postscript/common/ext.h
new file mode 100644
index 0000000000..fd17b8f0b9
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/ext.h
@@ -0,0 +1,59 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ *
+ * External varible declarations - many are defined in glob.c.
+ *
+ */
+
+
+extern char **argv; /* global so everyone can use them */
+extern int argc;
+
+extern int x_stat; /* program exit status */
+extern int debug; /* debug flag */
+extern int ignore; /* what we do with FATAL errors */
+
+extern long lineno; /* line number */
+extern long position; /* byte position */
+extern char *prog_name; /* and program name - for errors */
+extern char *temp_file; /* temporary file - for some programs */
+
+
+extern char *optarg; /* for getopt() */
+extern int optind;
+
+extern char *malloc();
+extern char *calloc();
+extern char *tempnam();
+extern char *strtok();
+extern long ftell();
+extern double atof();
+extern double sqrt();
+extern double atan2();
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/gen.h b/usr/src/cmd/lp/filter/postscript/common/gen.h
new file mode 100644
index 0000000000..c29fd7e7d1
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/gen.h
@@ -0,0 +1,69 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ *
+ * A few definitions that shouldn't have to change. They're used by most of the
+ * programs in this package.
+ *
+ */
+
+
+#define PROGRAMVERSION "3.15"
+
+
+#define NON_FATAL 0
+#define FATAL 1
+#define USER_FATAL 2
+
+#define OFF 0
+#define ON 1
+
+#define FALSE 0
+#define TRUE 1
+
+#define BYTE 8
+#define BMASK 0377
+
+#define POINTS 72.3
+
+#ifndef PI
+#define PI 3.141592654
+#endif
+
+
+/*
+ *
+ * A few simple macros.
+ *
+ */
+
+
+#define ABS(A) ((A) >= 0 ? (A) : -(A))
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#define MAX(A, B) ((A) > (B) ? (A) : (B))
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/glob.c b/usr/src/cmd/lp/filter/postscript/common/glob.c
new file mode 100644
index 0000000000..4fa8962729
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/glob.c
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ *
+ * Definition and initialization of some global variables.
+ *
+ */
+
+
+#include <stdio.h>
+#include "gen.h" /* general purpose definitions */
+
+
+char **argv; /* global so everyone can use them */
+int argc;
+
+int x_stat = 0; /* program exit status */
+int debug = OFF; /* debug flag */
+int ignore = OFF; /* what we do with FATAL errors */
+
+long lineno = 0; /* line number */
+long position = 0; /* byte position */
+char *prog_name = ""; /* and program name - for errors */
+char *temp_file = NULL; /* temporary file - for some programs */
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/misc.c b/usr/src/cmd/lp/filter/postscript/common/misc.c
new file mode 100644
index 0000000000..377828109b
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/misc.c
@@ -0,0 +1,283 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * A few general purpose routines.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "gen.h" /* a few general purpose definitions */
+#include "ext.h" /* external variable declarations */
+
+
+int nolist = 0; /* number of specified ranges */
+int olist[50]; /* processing range pairs */
+
+
+
+void
+error(int kind, char *mesg, ...)
+{
+
+
+/*
+ *
+ * Called when we've run into some kind of program error. *mesg is printed using
+ * the control string arguments a?. We'll quit if we're not ignoring errors and
+ * kind is FATAL.
+ *
+ */
+
+
+ if ( mesg != NULL && *mesg != '\0' ) {
+ va_list ap;
+
+ fprintf(stderr, "%s: ", prog_name);
+ va_start(ap, mesg);
+ vfprintf(stderr, mesg, ap);
+ va_end(ap);
+ if ( lineno > 0 )
+ fprintf(stderr, " (line %d)", lineno);
+ if ( position > 0 )
+ fprintf(stderr, " (near byte %d)", position);
+ putc('\n', stderr);
+ } /* End if */
+
+ if ( kind == FATAL && ignore == OFF ) {
+ if ( temp_file != NULL )
+ unlink(temp_file);
+ exit(x_stat | 01);
+ } /* End if */
+
+} /* End of error */
+
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+
+
+void
+out_list(str)
+
+
+ char *str; /* process ranges in this string */
+
+
+{
+
+
+ int start, stop; /* end points */
+
+
+/*
+ *
+ * Called to get the processing ranges that were specified by using the -o option.
+ * The range syntax should be identical to the one used in nroff and troff.
+ *
+ */
+
+
+ while ( *str && nolist < sizeof(olist) - 2 ) {
+ start = stop = str_convert(&str, 0);
+
+ if ( *str == '-' && *str++ )
+ stop = str_convert(&str, 9999);
+
+ if ( start > stop )
+ error(FATAL, "illegal range %d-%d", start, stop);
+
+ olist[nolist++] = start;
+ olist[nolist++] = stop;
+
+ if ( *str != '\0' ) str++;
+
+ } /* End while */
+
+ olist[nolist] = 0;
+
+} /* End of out_list */
+
+
+/*****************************************************************************/
+
+
+int
+in_olist(num)
+
+
+ int num; /* should we print this page? */
+
+
+{
+
+
+ int i; /* just a loop index */
+
+
+/*
+ *
+ * Returns ON if num represents a page that we're supposed to print. If no ranges
+ * were selected nolist will be 0 and we'll print everything.
+ *
+ */
+
+
+ if ( nolist == 0 ) /* everything's included */
+ return(ON);
+
+ for ( i = 0; i < nolist; i += 2 )
+ if ( num >= olist[i] && num <= olist[i+1] )
+ return(ON);
+
+ return(OFF);
+
+} /* End of in_olist */
+
+
+/*****************************************************************************/
+
+
+int
+cat(file)
+
+
+ char *file; /* copy this file to stdout */
+
+
+{
+
+
+ int fd_in; /* for the input */
+ int fd_out; /* and output files */
+ char buf[512]; /* buffer for reads and writes */
+ int count; /* number of bytes we just read */
+
+
+/*
+ *
+ * Copies *file to stdout - mostly for the prologue. Returns FALSE if there was a
+ * problem and TRUE otherwise.
+ *
+ */
+
+
+ fflush(stdout);
+
+ if ( (fd_in = open(file, O_RDONLY)) == -1 )
+ return(FALSE);
+
+ fd_out = fileno(stdout);
+ while ( (count = read(fd_in, buf, sizeof(buf))) > 0 )
+ write(fd_out, buf, count);
+
+ close(fd_in);
+
+ return(TRUE);
+
+} /* End of cat */
+
+
+/*****************************************************************************/
+
+
+int
+str_convert(str, err)
+
+
+ char **str; /* get next number from this string */
+ int err; /* value returned on error */
+
+
+{
+
+
+ int i; /* just a loop index */
+
+
+/*
+ *
+ * Gets the next integer from **str and returns its value to the caller. If **str
+ * isn't an integer err is returned. *str is updated after each digit is processed.
+ *
+ */
+
+
+ if ( ! isdigit(**str) ) /* something's wrong */
+ return(err);
+
+ for ( i = 0; isdigit(**str); *str += 1 )
+ i = 10 * i + **str - '0';
+
+ return(i);
+
+} /* End of str_convert */
+
+
+/*****************************************************************************/
+
+
+
+
+void interrupt(sig)
+
+
+ int sig; /* signal that we caught */
+
+
+{
+
+
+/*
+ *
+ * Called when we get a signal that we're supposed to catch.
+ *
+ */
+
+
+ if ( temp_file != NULL )
+ unlink(temp_file);
+
+ exit(1);
+
+} /* End of interrupt */
+
+
+/*****************************************************************************/
+
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/path.h b/usr/src/cmd/lp/filter/postscript/common/path.h
new file mode 100644
index 0000000000..d4cf2d12c5
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/path.h
@@ -0,0 +1,42 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * pathname definitions for important files and directories.
+ */
+
+
+#define DPOST "/usr/lib/lp/postscript/dpost.ps"
+#define POSTPRINT "/usr/lib/lp/postscript/postprint.ps"
+
+#define BASELINE "/usr/lib/lp/postscript/baseline.ps"
+#define COLOR "/usr/lib/lp/postscript/color.ps"
+#define DRAW "/usr/lib/lp/postscript/draw.ps"
+#define FORMFILE "/usr/lib/lp/postscript/forms.ps"
+#define KERNING "/usr/lib/lp/postscript/kerning.ps"
+#define REQUESTFILE "/usr/lib/lp/postscript/ps.requests"
+
+#define HOSTFONTDIR "/usr/share/lib/hostfontdir"
+#define FONTDIR "/usr/lib/font"
+#define TEMPDIR "/tmp"
diff --git a/usr/src/cmd/lp/filter/postscript/common/request.c b/usr/src/cmd/lp/filter/postscript/common/request.c
new file mode 100644
index 0000000000..b0b0050b9c
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/request.c
@@ -0,0 +1,158 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * Things used to handle special requests (eg. manual feed) globally or on a per
+ * page basis. Requests are passed through to the translator using the -R option.
+ * The argument to -R can be "request", "request:page", or "request:page:file".
+ * If page is omitted (as in the first form) or set to 0 request will be applied
+ * to the global environment. In all other cases it applies only to the selected
+ * page. If a file is given, page must be supplied, and the lookup is in that file
+ * rather than *requestfile.
+ *
+ */
+
+
+#include <stdio.h>
+
+#include "gen.h" /* general purpose definitions */
+#include "request.h" /* a few special definitions */
+#include "path.h" /* for the default request file */
+
+
+Request request[MAXREQUEST]; /* next page or global request */
+int nextreq = 0; /* goes in request[nextreq] */
+char *requestfile = REQUESTFILE; /* default lookup file */
+
+void dumprequest(char *, char *, FILE *);
+
+/*****************************************************************************/
+
+
+void
+saverequest(char *want)
+ /* grab code for this stuff */
+{
+ char *page; /* and save it for this page */
+ char *strtok();
+
+/*
+ *
+ * Save the request until we get to appropriate page - don't even bother with
+ * the lookup right now. Format of *want string is "request", "request:page", or
+ * "request:page:file", and we assume we can change the string here as needed.
+ * If page is omitted or given as 0 the request will be done globally. If *want
+ * includes a file, request and page must also be given, and in that case *file
+ * will be used for the lookup.
+ *
+ */
+
+
+ if ( nextreq < MAXREQUEST ) {
+ request[nextreq].want = strtok(want, ": ");
+ if ( (page = strtok(NULL, ": ")) == NULL )
+ request[nextreq].page = 0;
+ else request[nextreq].page = atoi(page);
+ if ( (request[nextreq].file = strtok(NULL, ": ")) == NULL )
+ request[nextreq].file = requestfile;
+ nextreq++;
+ } else error(NON_FATAL, "too many requests - ignoring %s", want);
+
+} /* End of saverequest */
+
+
+/*****************************************************************************/
+
+
+void
+writerequest(int page, FILE *fp_out)
+ /* page - write everything for this page */
+ /* fp_out - to this file */
+{
+ int i; /* loop index */
+
+/*
+ *
+ * Writes out all the requests that have been saved for page. Page 0 refers to
+ * the global environment and is done during initial setup.
+ *
+ */
+
+
+ for ( i = 0; i < nextreq; i++ )
+ if ( request[i].page == page )
+ dumprequest(request[i].want, request[i].file, fp_out);
+
+} /* End of writerequest */
+
+
+/*****************************************************************************/
+
+
+void
+dumprequest(char *want, char *file, FILE *fp_out)
+ /* want - look for this string */
+ /* file - in this file */
+ /* fp_out - and write the value out here */
+{
+ char buf[100]; /* line buffer for reading *file */
+ FILE *fp_in;
+
+/*
+ *
+ * Looks for *want in the request file and if it's found the associated value
+ * is copied to the output file. Keywords (ie. the *want strings) begin an @ in
+ * the first column of file, while the values (ie. the stuff that's copied to
+ * the output file) starts on the next line and extends to the next keyword or
+ * to the end of file.
+ *
+ */
+
+
+ if ( (fp_in = fopen(file, "r")) != NULL ) {
+ while ( fgets(buf, sizeof(buf), fp_in) != NULL )
+ if ( buf[0] == '@' && strncmp(want, &buf[1], strlen(want)) == 0 )
+ while ( fgets(buf, sizeof(buf), fp_in) != NULL )
+ if ( buf[0] == '#' || buf[0] == '%' )
+ continue;
+ else if ( buf[0] != '@' )
+ fprintf(fp_out, "%s", buf);
+ else break;
+ fclose(fp_in);
+ } /* End if */
+
+} /* End of dumprequest */
+
+
+/*****************************************************************************/
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/request.h b/usr/src/cmd/lp/filter/postscript/common/request.h
new file mode 100644
index 0000000000..b5cdb2d0ea
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/request.h
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ *
+ * Things used to handle special PostScript requests (like manual feed) globally
+ * or on a per page basis. All the translators I've supplied accept the -R option
+ * that can be used to insert special PostScript code before the global setup is
+ * done, or at the start of named pages. The argument to the -R option is a string
+ * that can be "request", "request:page", or "request:page:file". If page isn't
+ * given (as in the first form) or if it's 0 in the last two, the request applies
+ * to the global environment, otherwise request holds only for the named page.
+ * If a file name is given a page number must be supplied, and in that case the
+ * request will be looked up in that file.
+ *
+ */
+
+#define MAXREQUEST 30
+
+typedef struct {
+
+ char *want;
+ int page;
+ char *file;
+
+} Request;
+
+
diff --git a/usr/src/cmd/lp/filter/postscript/common/tempnam.c b/usr/src/cmd/lp/filter/postscript/common/tempnam.c
new file mode 100644
index 0000000000..dfefe86c4b
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/common/tempnam.c
@@ -0,0 +1,55 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#include <stdio.h>
+#include <errno.h>
+
+#if defined(V9) || defined(BSD4_2)
+char *tempnam(dir, pfx)
+char *dir, *pfx;
+{
+ int pid;
+ unsigned int len;
+ char *tnm, *malloc();
+ static int seq = 0;
+
+ pid = getpid();
+ len = strlen(dir) + strlen(pfx) + 10;
+ if ((tnm = malloc(len)) != NULL) {
+ sprintf(tnm, "%s", dir);
+ if (access(tnm, 7) == -1)
+ return(NULL);
+ do {
+ sprintf(tnm, "%s/%s%d%d", dir, pfx, pid, seq++);
+ errno = 0;
+ if (access(tnm, 7) == -1)
+ if (errno == ENOENT)
+ return(tnm);
+ } while (1);
+ }
+ return(tnm);
+}
+#endif
diff --git a/usr/src/cmd/lp/filter/postscript/download/Makefile b/usr/src/cmd/lp/filter/postscript/download/Makefile
new file mode 100644
index 0000000000..b07b2223e4
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/download/Makefile
@@ -0,0 +1,77 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/download/Makefile
+#
+
+include ../../../Makefile.lp
+
+PROG= download
+
+SRCS = download.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+COMMONDIR = ../common
+
+COMMONOBJS = $(COMMONDIR)/glob.o \
+ $(COMMONDIR)/misc.o \
+ $(COMMONDIR)/tempnam.o
+
+TXTS = README
+
+ENCODING = 2
+CPPFLAGS = -DDFLTENCODING=$(ENCODING) \
+ -I. -I$(COMMONDIR) \
+ $(CPPFLAGS.master)
+
+POFILE = lp_filter_postscript_download.po
+
+.KEEP_STATE:
+
+all: $(TXTS) $(PROG)
+
+install: all $(ROOTLIBLPPOSTPROG)
+
+$(PROG): $(OBJS) $(COMMONOBJS)
+ $(LINK.c) -o $@ $(OBJS) $(COMMONOBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+$(COMMONOBJS): $$(@:%.o=%.c)
+ cd $(@D); $(MAKE) $(@F)
+
+clean:
+ $(RM) $(OBJS)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint: lint_PROG
+
+include ../../../../Makefile.targ
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/filter/postscript/download/README b/usr/src/cmd/lp/filter/postscript/download/README
new file mode 100644
index 0000000000..a57c4eaa85
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/download/README
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+A simple program that scans PostScript files for %%DocumentFonts: comments
+and prepends requested host resident font files to the input. The downloaded
+fonts are the ones named in the %%DocumentFonts: comment and listed in a
+special map file (which can be selected using the -m option). See example.map
+and the comments in downloader.c for examples of map files. By default map
+files and font files are in *hostfontdir. It's initialized using HOSTFONTDIR
+(file ../common/path.h) and can be changed on the command line using the
+-m option.
+
diff --git a/usr/src/cmd/lp/filter/postscript/download/download.c b/usr/src/cmd/lp/filter/postscript/download/download.c
new file mode 100644
index 0000000000..1960cd2887
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/download/download.c
@@ -0,0 +1,574 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * download - host resident font downloader
+ *
+ * Prepends host resident fonts to PostScript input files. The program assumes
+ * the input files are part of a single PostScript job and that requested fonts
+ * can be downloaded at the start of each input file. Downloaded fonts are the
+ * ones named in a %%DocumentFonts: comment and listed in a special map table.
+ * Map table pathnames (supplied using the -m option) that begin with a / are
+ * taken as is. Otherwise the final pathname is built using *hostfontdir (-H
+ * option), *mapname (-m option), and *suffix.
+ *
+ * The map table consists of fontname-filename pairs, separated by white space.
+ * Comments are introduced by % (as in PostScript) and extend to the end of the
+ * current line. The only fonts that can be downloaded are the ones listed in
+ * the active map table that point the program to a readable Unix file. A request
+ * for an unlisted font or inaccessible file is ignored. All font requests are
+ * ignored if the map table can't be read. In that case the program simply copies
+ * the input files to stdout.
+ *
+ * An example (but not one to follow) of what can be in a map table is,
+ *
+ * %
+ * % Map requests for Bookman-Light to file *hostfontdir/KR
+ * %
+ *
+ * Bookman-Light KR % Keeping everything (including the map
+ * % table) in *hostfontdir seems like the
+ * % cleanest approach.
+ *
+ * %
+ * % Map Palatino-Roman to file *hostfontdir/palatino/Roman
+ * %
+ * Palatino-Roman palatino/Roman
+ *
+ * % Map ZapfDingbats to file /usr/lib/host/dingbats
+ *
+ * ZapfDingbats /usr/lib/host/dingbats
+ *
+ * Once again, file names that begin with a / are taken as is. All others have
+ * *hostfontdir/ prepended to the file string associated with a particular font.
+ *
+ * Map table can be associated with a printer model (e.g. a LaserWriter), a
+ * printer destination, or whatever - the choice is up to an administrator.
+ * By destination may be best if your spooler is running several private
+ * printers. Host resident fonts are usually purchased under a license that
+ * restricts their use to a limited number of printers. A font licensed for
+ * a single printer should only be used on that printer.
+ *
+ * Was written quickly, so there's much room for improvement. Undoubtedly should
+ * be a more general program (e.g. scan for other comments).
+ *
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "comments.h" /* PostScript file structuring comments */
+#include "gen.h" /* general purpose definitions */
+#include "path.h" /* for temporary directory */
+#include "ext.h" /* external variable declarations */
+#include "download.h" /* a few special definitions */
+
+char *temp_dir = TEMPDIR; /* temp directory - for copying stdin */
+char *hostfontdir = HOSTFONTDIR; /* host resident directory */
+char *mapname = "map"; /* map table - usually in *hostfontdir */
+char *suffix = ""; /* appended to the map table pathname */
+Map *map = NULL; /* device font map table */
+char *stringspace = NULL; /* for storing font and file strings */
+int next = 0; /* next free slot in map[] */
+
+char *residentfonts = NULL; /* list of printer resident fonts */
+char *printer = NULL; /* printer name - only for Unix 4.0 lp */
+
+char buf[2048]; /* input file line buffer */
+char *comment = DOCUMENTFONTS; /* look for this comment */
+int atend = FALSE; /* TRUE only if a comment says so */
+
+FILE *fp_in = stdin; /* next input file */
+FILE *fp_temp = NULL; /* for copying stdin */
+
+static Map *allocate(Map *, int);
+static void arguments(void);
+static void copyfonts(char *);
+static void copyinput(void);
+static void done(void);
+static void download(void);
+static void init_signals(void);
+static int lookup(char *);
+static void options(void);
+static void readmap(void);
+static void readresident(void);
+
+/*****************************************************************************/
+
+int
+main(int agc, char *agv[])
+{
+
+/*
+ *
+ * Host resident font download. The input files are assumed to be part of a
+ * single PostScript job.
+ *
+ */
+
+ argc = agc; /* other routines may want them */
+ argv = agv;
+
+ prog_name = argv[0]; /* just for error messages */
+
+ init_signals(); /* sets up interrupt handling */
+ options(); /* first get command line options */
+ readmap(); /* read the font map table */
+ readresident(); /* and the optional resident font list */
+ arguments(); /* then process non-option arguments */
+ done(); /* and clean things up */
+
+ return (x_stat); /* not much could be wrong */
+
+} /* End of main */
+
+/*****************************************************************************/
+
+static void
+init_signals(void)
+{
+ void interrupt(); /* handles signals if we catching them */
+
+/*
+ *
+ * Makes sure we handle interrupts properly.
+ *
+ */
+
+ if ( signal(SIGINT, interrupt) == SIG_IGN ) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ } else {
+ signal(SIGHUP, interrupt);
+ signal(SIGQUIT, interrupt);
+ } /* End else */
+
+ signal(SIGTERM, interrupt);
+
+} /* End of init_signals */
+
+/*****************************************************************************/
+
+static void
+options(void)
+{
+
+ int ch; /* return value from getopt() */
+ char *optnames = "c:fm:p:r:H:T:DI";
+
+ extern char *optarg; /* used by getopt() */
+ extern int optind;
+
+/*
+ *
+ * Reads and processes the command line options.
+ *
+ */
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
+
+ switch ( ch ) {
+
+ case 'c': /* look for this comment */
+ comment = optarg;
+ break;
+
+ case 'f': /* force a complete input file scan */
+ atend = TRUE;
+ break;
+
+ case 'm': /* printer map table name */
+ mapname = optarg;
+ break;
+
+ case 'p': /* printer name - for Unix 4.0 lp */
+ printer = optarg;
+ break;
+
+ case 'r': /* resident font list */
+ residentfonts = optarg;
+ break;
+
+ case 'H': /* host resident font directory */
+ hostfontdir = optarg;
+ break;
+
+ case 'T': /* temporary file directory */
+ temp_dir = optarg;
+ break;
+
+ case 'D': /* debug flag */
+ debug = ON;
+ break;
+
+ case 'I': /* ignore FATAL errors */
+ ignore = ON;
+ break;
+
+ case '?': /* don't understand the option */
+ error(FATAL, "");
+ break;
+
+ default: /* don't know what to do for ch */
+ error(FATAL, "missing case for option %c\n", ch);
+ break;
+
+ } /* End switch */
+
+ } /* End while */
+
+ argc -= optind; /* get ready for non-option args */
+ argv += optind;
+
+} /* End of options */
+
+/*****************************************************************************/
+
+static void
+readmap(void)
+{
+ char *path;
+ char *ptr;
+ int fd;
+ struct stat sbuf;
+
+/*
+ *
+ * Initializes the map table by reading an ASCII mapping file. If mapname begins
+ * with a / it's the map table. Otherwise hostfontdir, mapname, and suffix are
+ * combined to build the final pathname. If we can open the file we read it all
+ * into memory, erase comments, and separate the font and file name pairs. When
+ * we leave next points to the next free slot in the map[] array. If it's zero
+ * nothing was in the file or we couldn't open it.
+ *
+ */
+
+ if ( hostfontdir == NULL || mapname == NULL )
+ return;
+
+ if ( *mapname != '/' ) {
+ if ( (path = malloc(strlen(hostfontdir) + strlen(mapname) +
+ strlen(suffix) + 2)) == NULL )
+ error(FATAL, "no memory");
+ sprintf(path, "%s/%s%s", hostfontdir, mapname, suffix);
+ } else path = mapname;
+
+ if ( (fd = open(path, 0)) != -1 ) {
+ if ( fstat(fd, &sbuf) == -1 )
+ error(FATAL, "can't fstat %s", path);
+ if ( (stringspace = malloc(sbuf.st_size + 2)) == NULL )
+ error(FATAL, "no memory");
+ if ( read(fd, stringspace, sbuf.st_size) == -1 )
+ error(FATAL, "can't read %s", path);
+ close(fd);
+
+ stringspace[sbuf.st_size] = '\n'; /* just to be safe */
+ stringspace[sbuf.st_size+1] = '\0';
+ for ( ptr = stringspace; *ptr != '\0'; ptr++ ) /* erase comments */
+ if ( *ptr == '%' )
+ for ( ; *ptr != '\n' ; ptr++ )
+ *ptr = ' ';
+
+ for ( ptr = stringspace; ; next++ ) {
+ if ( (next % 50) == 0 )
+ map = allocate(map, next+50);
+ map[next].downloaded = FALSE;
+ map[next].font = strtok(ptr, " \t\n");
+ map[next].file = strtok(ptr = NULL, " \t\n");
+ if ( map[next].font == NULL )
+ break;
+ if ( map[next].file == NULL )
+ error(FATAL, "map table format error - check %s", path);
+ } /* End for */
+ } /* End if */
+
+} /* End of readmap */
+
+/*****************************************************************************/
+
+static void
+readresident(void)
+{
+ FILE *fp;
+ char *path;
+ int ch;
+ int n;
+
+/*
+ *
+ * Reads a file that lists the resident fonts for a particular printer and marks
+ * each font as already downloaded. Nothing's done if the file can't be read or
+ * there's no mapping file. Comments, as in the map file, begin with a % and
+ * extend to the end of the line. Added for Unix 4.0 lp.
+ *
+ */
+
+ if ( next == 0 || (printer == NULL && residentfonts == NULL) )
+ return;
+
+ if ( printer != NULL ) { /* use Unix 4.0 lp pathnames */
+ sprintf(buf, "/etc/lp/printers/%s/residentfonts", printer);
+ path = buf;
+ } else path = residentfonts;
+
+ if ( (fp = fopen(path, "r")) != NULL ) {
+ while ( fscanf(fp, "%s", buf) != EOF )
+ if ( buf[0] == '%' )
+ while ( (ch = getc(fp)) != EOF && ch != '\n' ) ;
+ else if ( (n = lookup(buf)) < next )
+ map[n].downloaded = TRUE;
+ fclose(fp);
+ } /* End if */
+
+} /* End of readresident */
+
+/*****************************************************************************/
+
+static void
+arguments(void)
+{
+
+/*
+ *
+ * Makes sure all the non-option command line arguments are processed. If we get
+ * here and there aren't any arguments left, or if '-' is one of the input files
+ * we'll translate stdin. Assumes input files are part of a single PostScript
+ * job and fonts can be downloaded at the start of each file.
+ *
+ */
+
+ if ( argc < 1 )
+ download();
+ else {
+ while ( argc > 0 ) {
+ fp_temp = NULL;
+ if ( strcmp(*argv, "-") == 0 )
+ fp_in = stdin;
+ else if ( (fp_in = fopen(*argv, "r")) == NULL )
+ error(FATAL, "can't open %s", *argv);
+ download();
+ if ( fp_in != stdin )
+ fclose(fp_in);
+ if ( fp_temp != NULL )
+ fclose(fp_temp);
+ argc--;
+ argv++;
+ } /* End while */
+ } /* End else */
+
+} /* End of arguments */
+
+/*****************************************************************************/
+
+static void
+done(void)
+{
+
+/*
+ *
+ * Clean things up before we quit.
+ *
+ */
+
+ if ( temp_file != NULL )
+ unlink(temp_file);
+
+} /* End of done */
+
+/*****************************************************************************/
+
+static void
+download(void)
+{
+ int infontlist = FALSE;
+
+/*
+ *
+ * If next is zero the map table is empty and all we do is copy the input file
+ * to stdout. Otherwise we read the input file looking for %%DocumentFonts: or
+ * continuation comments, add any accessible fonts to the output file, and then
+ * append the input file. When reading stdin we append lines to fp_temp and
+ * recover them when we're ready to copy the input file. fp_temp will often
+ * only contain part of stdin - if there's no %%DocumentFonts: (atend) comment
+ * we stop reading fp_in after the header.
+ *
+ */
+
+ if ( next > 0 ) {
+ if ( fp_in == stdin ) {
+ if ( (temp_file = tempnam(temp_dir, "post")) == NULL )
+ error(FATAL, "can't generate temp file name");
+ if ( (fp_temp = fopen(temp_file, "w+")) == NULL )
+ error(FATAL, "can't open %s", temp_file);
+ unlink(temp_file);
+ temp_file = NULL;
+ } /* End if */
+
+ while ( fgets(buf, sizeof(buf), fp_in) != NULL ) {
+ if ( fp_temp != NULL )
+ fprintf(fp_temp, "%s", buf);
+ if ( buf[0] != '%' || buf[1] != '%' ) {
+ if ( (buf[0] != '%' || buf[1] != '!') && atend == FALSE )
+ break;
+ infontlist = FALSE;
+ } else if ( strncmp(buf, comment, strlen(comment)) == 0 ) {
+ copyfonts(buf);
+ infontlist = TRUE;
+ } else if ( buf[2] == '+' && infontlist == TRUE )
+ copyfonts(buf);
+ else infontlist = FALSE;
+ } /* End while */
+ } /* End if */
+
+ copyinput();
+
+} /* End of download */
+
+/*****************************************************************************/
+
+static void
+copyfonts(char *list)
+{
+ char *font;
+ char *path;
+ int n;
+
+/*
+ *
+ * list points to a %%DocumentFonts: or continuation comment. What follows the
+ * the keyword will be a list of fonts separated by white space (or (atend)).
+ * Look for each font in the map table and if it's found copy the font file to
+ * stdout (once only).
+ *
+ */
+
+ strtok(list, " \n"); /* skip to the font list */
+
+ while ( (font = strtok(NULL, " \t\n")) != NULL ) {
+ if ( strcmp(font, ATEND) == 0 ) {
+ atend = TRUE;
+ break;
+ } /* End if */
+ if ( (n = lookup(font)) < next ) {
+ if ( *map[n].file != '/' ) {
+ if ( (path = malloc(strlen(hostfontdir)+strlen(map[n].file)+2)) == NULL )
+ error(FATAL, "no memory");
+ sprintf(path, "%s/%s", hostfontdir, map[n].file);
+ cat(path);
+ free(path);
+ } else cat(map[n].file);
+ map[n].downloaded = TRUE;
+ } /* End if */
+ } /* End while */
+
+} /* End of copyfonts */
+
+/*****************************************************************************/
+
+static void
+copyinput(void)
+{
+
+/*
+ *
+ * Copies the input file to stdout. If fp_temp isn't NULL seek to the start and
+ * add it to the output file - it's a partial (or complete) copy of stdin made
+ * by download(). Then copy fp_in, but only seek to the start if it's not stdin.
+ *
+ */
+
+ if ( fp_temp != NULL ) {
+ fseek(fp_temp, 0L, 0);
+ while ( fgets(buf, sizeof(buf), fp_temp) != NULL )
+ printf("%s", buf);
+ } /* End if */
+
+ if ( fp_in != stdin )
+ fseek(fp_in, 0L, 0);
+
+ while ( fgets(buf, sizeof(buf), fp_in) != NULL )
+ printf("%s", buf);
+
+} /* End of copyinput */
+
+/*****************************************************************************/
+
+static int
+lookup(char *font)
+{
+ int i;
+
+/*
+ *
+ * Looks for *font in the map table. Return the map table index if found and
+ * not yet downloaded - otherwise return next.
+ *
+ */
+
+ for ( i = 0; i < next; i++ )
+ if ( strcmp(font, map[i].font) == 0 ) {
+ if ( map[i].downloaded == TRUE )
+ i = next;
+ break;
+ } /* End if */
+
+ return(i);
+
+} /* End of lookup */
+
+/*****************************************************************************/
+
+static Map *
+allocate(Map *ptr, int num)
+{
+
+/*
+ *
+ * Allocates space for num Map elements. Calls malloc() if ptr is NULL and
+ * realloc() otherwise.
+ *
+ */
+
+ if ( ptr == NULL )
+ ptr = (Map *)malloc(num * sizeof(Map));
+ else ptr = (Map *)realloc(ptr, num * sizeof(Map));
+
+ if ( ptr == NULL )
+ error(FATAL, "no map memory");
+
+ return(ptr);
+
+} /* End of allocate */
diff --git a/usr/src/cmd/lp/filter/postscript/download/download.h b/usr/src/cmd/lp/filter/postscript/download/download.h
new file mode 100644
index 0000000000..985332490d
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/download/download.h
@@ -0,0 +1,57 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#ifndef _DOWNLOAD_H
+#define _DOWNLOAD_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cpluplus
+extern {
+#endif
+
+/*
+ *
+ * The font data for a printer is saved in an array of the following type.
+ *
+ */
+
+typedef struct map {
+
+ char *font; /* a request for this PostScript font */
+ char *file; /* means copy this unix file */
+ int downloaded; /* TRUE after *file is downloaded */
+
+} Map;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DOWNLOAD_H */
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/Makefile b/usr/src/cmd/lp/filter/postscript/dpost/Makefile
new file mode 100644
index 0000000000..bb081538d4
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/Makefile
@@ -0,0 +1,85 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/dpost/Makefile
+#
+
+include ../../../Makefile.lp
+
+PROG= dpost
+
+SRCS = dpost.c draw.c color.c pictures.c ps_include.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+COMMONDIR= ../common
+
+COMMONOBJS = $(COMMONDIR)/glob.o \
+ $(COMMONDIR)/misc.o \
+ $(COMMONDIR)/request.o \
+ $(COMMONDIR)/tempnam.o
+
+TXTS= README
+
+# dpost uses some floating point arithmetic, so if you're running on a system
+# without floating point hardware add the -f option to the definition of CFLAGS.
+
+ENCODING= 2
+CPPFLAGS = -DDFLTENCODING=$(ENCODING) \
+ -I. -I$(COMMONDIR) \
+ $(CPPFLAGS.master)
+
+POFILE = lp_filter_postscript_dpost.po
+
+.KEEP_STATE:
+
+all: $(TXTS) $(PROG)
+
+install: all $(ROOTLIBLPPOSTPROG)
+
+$(PROG): $(OBJS) $(COMMONOBJS)
+ $(LINK.c) -o $@ $(OBJS) $(COMMONOBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+$(COMMONOBJS): $$(@:%.o=%.c)
+ cd $(@D); $(MAKE) $(@F)
+
+ps_include.o: ps_include.h
+ps_include.h: ps_include.ps ps_include.awk
+ $(RM) $@; awk -f ps_include.awk ps_include.ps >$@
+
+clean:
+ $(RM) $(OBJS) ps_include.h
+
+strip:
+ $(STRIP) $(PROG)
+
+lint: lint_SRCS
+
+include ../../../../Makefile.targ
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/README b/usr/src/cmd/lp/filter/postscript/dpost/README
new file mode 100644
index 0000000000..a2ad48ed2f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/README
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Source code for a program that translates device independent troff output into
+PostScript.
+
+Several new text encoding schemes, based on widthshow, have been added. Each can
+be accessed using the -e option and often reduce print time by 20% or more. Level
+0 is the slowest but most stable choice. Level 2 encoding (which right now is the
+default) is fast and does a good job placing text and justifying the right margin.
+You can change the default encoding scheme by adjusting the definition of ENCODING
+in ../Makefile. Levels 0, 1, and 2 are the only reasonable defaults, but at present
+only level 0 is guaranteed. The new encoding schemes are not thoroughly tested,
+but passed the tests I ran.
+
+Other interesting features include color support, the ability to treat complex
+paths built from the standard drawing commands as single entities (eg. for filling
+a polygon with a color), and reverse video printing as a special case of color.
+Also added, although using it is far from trivial, is the ability to set text
+along an arbitrary baseline (see ../postscript/baseline.ps). All are accessed via
+special device control escapes (from routine devcntrl() in dpost.c).
+
+ASCII font and description files for many standard PostScript fonts can be found
+in ../font/devpost. They should be installed in /usr/lib/font/devpost, and are
+read when you add the -Tpost option to troff. A typical command line would be,
+
+ pic file | tbl | eqn | troff -mm -Tpost | dpost >file.ps
+
+while,
+
+ pic -T720 file | tbl | eqn -r720 | troff -mm -Tpost | dpost >file.ps
+
+should work if you're using old versions of eqn and pic.
+
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/color.c b/usr/src/cmd/lp/filter/postscript/dpost/color.c
new file mode 100644
index 0000000000..0b7f0c25e5
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/color.c
@@ -0,0 +1,251 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * Routines that handle color requests passed through as device control commands
+ * in the form "x X SetColor:red". The following PostScript procedures are needed:
+ *
+ * setcolor
+ *
+ * mark /color setcolor mark
+ * mark /color1 /color2 setcolor mark
+ *
+ * Called whenever we want to change PostScript's current color graphics
+ * state parameter. One or two color arguments can be given. In each case
+ * the colors are looked up in the PostScript colordict dictionary that's
+ * defined in *colorfile. Two named colors implies reverse video printing
+ * with the background given in /color2 and the text printed in /color1.
+ * Unknown colors are mapped into defaults - black for a single color and
+ * white on black for reverse video.
+ *
+ * drawrvbox
+ *
+ * leftx rightx drawrvbox -
+ *
+ * Fills a box that extends from leftx to rightx with the background color
+ * that was requested when setcolor set things up for reverse video mode.
+ * The vertical extent of the box is determined using FontBBox just before
+ * the first string is printed, and the height remains in effect until
+ * there's an explicit color change. In otherwords font or size changes
+ * won't always produce correct result in reverse video mode.
+ *
+ * setdecoding
+ *
+ * num setdecoding -
+ *
+ * Selects the text decoding procedure (ie. what's assigned to PostScript
+ * procedure t) from the decodingdefs array defined in the prologue. num
+ * should be the value assigned to variable encoding (in dpost) and will
+ * remain constant throughout a job, unless special features, like reverse
+ * video printing, are requested. The text encoding scheme can be set on
+ * the command line using the -e option. Print time and the size of the
+ * output file will usually decrease as the value assigned to encoding
+ * increases.
+ *
+ *
+ * The recognized collection of "x X SetColor:" commands are:
+ *
+ * x X SetColor: selects black
+ * x X SetColor:color selects color
+ * x X SetColor:color1 on color2 reverse video
+ * x X SetColor:color1 color2 reverse video again
+ * x X SetColor:num1 num2 num3 rgb explicit rgb color request
+ * x X SetColor:num1 num2 num3 hsb explicit hsb color request
+ *
+ * In the last three examples num1, num2, and num3 should be numbers between 0 and
+ * 1 inclusive and are passed on as aguments to the approrpriate PostScript color
+ * command (eg. setrgbcolor). Unknown color names (ie. the ones that setcolor
+ * doesn't find in colordict) are mapped into defaults. For one color the default
+ * is black, while for reverse video it's white text on a black background.
+ *
+ * dpost makes sure the current color is maintained across page boundaries, which
+ * may not be what you want if you're using a macro package like mm that puts out
+ * page footers and headers. Adding a color request to troff and keeping track of
+ * the color in each environment may be the best solution.
+ *
+ * To get reverse video printing follow the "x X SetColor:" command with two or
+ * three arguments. "x X SetColor:white on black" or "x X SetColor:white black"
+ * both produce white text on a black background. Any two colors named in colordict
+ * (in file *colorfile) can be chosen so "x X SetColor:yellow on blue" also works.
+ * Each reverse video mode request selects the vertical extent of the background
+ * box based on the font and size in use just before the first string is printed.
+ * Font and/or size changes aren't guaranteed to work properly in reverse video
+ * printing.
+ *
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "gen.h" /* general purpose definitions */
+#include "ext.h" /* external variable definitions */
+
+
+#define DEFAULTCOLOR "black"
+
+char color[50] = DEFAULTCOLOR; /* current color */
+int gotcolor = FALSE; /* TRUE after *colorfile is downloaded */
+int wantcolor = FALSE; /* TRUE if we really ask for a color */
+
+
+/*
+ *
+ * All these should be defined in dpost.c.
+ *
+ */
+
+
+extern int lastend;
+extern int encoding;
+extern int maxencoding;
+extern int realencoding;
+
+extern char *colorfile;
+extern FILE *tf;
+
+
+/*****************************************************************************/
+
+
+void
+getcolor(void)
+{
+
+/*
+ *
+ * Responsible for making sure the PostScript color procedures are downloaded from
+ * *colorfile. Done at most once per job, and only if the job really uses color.
+ * For now I've decided not to quit if we can't read the color file.
+ *
+ */
+
+
+ if ( gotcolor == FALSE && access(colorfile, 04) == 0 )
+ doglobal(colorfile);
+
+ if ( tf == stdout )
+ gotcolor = TRUE;
+
+} /* End of getcolor */
+
+
+/*****************************************************************************/
+
+
+void
+newcolor(char *name)
+ /* of the color */
+{
+ char *p; /* next character in *name */
+ int i; /* goes in color[i] */
+
+/*
+ *
+ * Converts *name to lower case and saves the result in color[] for use as the
+ * current color. The first time something other than DEFAULTCOLOR is requested
+ * sets wantcolor to TRUE. Characters are converted to lower case as they're put
+ * in color[] and we quit when we find a newline or get to the end of *name. The
+ * isupper() test is for Berkley systems.
+ *
+ */
+
+
+ for ( p = name; *p && (*p == ' ' || *p == ':'); p++ ) ;
+
+ for ( i = 0; i < sizeof(color) - 1 && *p != '\n' && *p; i++, p++ )
+ if ( isupper(*p) )
+ color[i] = tolower(*p);
+ else color[i] = *p;
+
+ if ( i == 0 )
+ strcpy(color, DEFAULTCOLOR);
+ else color[i] = '\0';
+
+ if ( strcmp(color, DEFAULTCOLOR) != 0 )
+ wantcolor = TRUE;
+
+} /* End of newcolor */
+
+
+/*****************************************************************************/
+
+
+void
+setcolor(void)
+{
+ int newencoding; /* text encoding scheme that's needed */
+ char *p; /* for converting what's in color[] */
+
+/*
+ *
+ * Sets the color being used by the printer to whatever's stored as the current
+ * color (ie. the string in color[]). wantcolor is only set to TRUE if we've been
+ * through newcolor() and asked for something other than DEFAULTCOLOR (probably
+ * black). While in reverse video mode encoding gets set to maxencoding + 1 in
+ * dpost and 0 on the printer. Didn't see much point in trying to extend reverse
+ * video to all the different encoding schemes. realencoding is restored when we
+ * leave reverse video mode.
+ *
+ */
+
+
+ if ( wantcolor == TRUE ) {
+ endtext();
+ getcolor();
+
+ lastend = -1;
+ newencoding = realencoding;
+
+ if ( islower(color[0]) == 0 ) /* explicit rgb or hsb request */
+ fprintf(tf, "%s\n", color);
+ else {
+ putc('/', tf);
+ for ( p = color; *p && *p != ' '; p++ )
+ putc(*p, tf);
+ for ( ; *p && *p == ' '; p++ ) ;
+ if ( strncmp(p, "on ", 3) == 0 ) p += 3;
+ if ( *p != '\0' ) {
+ fprintf(tf, " /%s", p);
+ newencoding = maxencoding + 1;
+ } /* End if */
+ fprintf(tf, " setcolor\n");
+ } /* End else */
+
+ if ( newencoding != encoding ) {
+ encoding = newencoding;
+ fprintf(tf, "%d setdecoding\n", encoding);
+ resetpos();
+ } /* End if */
+ } /* End if */
+
+} /* End of setcolor */
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/dpost.c b/usr/src/cmd/lp/filter/postscript/dpost/dpost.c
new file mode 100644
index 0000000000..28afb1db18
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/dpost.c
@@ -0,0 +1,2826 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * dpost - troff post-processor for PostScript printers.
+ *
+ * A program that translates output generated by the device independent troff
+ * into PostScript. Much was borrowed from dimpress and dps (formally dlzw),
+ * and even though the code has been changed, credit has to be given to Richard
+ * Flood for his early work on the PostScript driver.
+ *
+ * Among the most interesting new features are color support (see devcntrl() and
+ * file color.c) and code to handle complex paths pieced together using any of the
+ * standard drawing commands (see devcntrl() and file draw.c). Reverse video mode
+ * has also been included as a special case of the color support. Two encoding
+ * schemes based on widthshow are also new additions. The safe one is obtained when
+ * you set encoding to 2 (eg. using the -e2 option). The slightly faster method
+ * is obtained by setting encoding to 3 (eg. using the -e3 option), although it's
+ * not recommended. Rounding errors in character widths can accumulate and become
+ * quite noticeable by the time you get to the right margin. More often than not
+ * you end up getting a ragged right margin.
+ *
+ * The program handles files formatted for any device, although the best and
+ * most efficient output is generated when the font and description files match
+ * PostScript's resident fonts. Device emulation is relatively expensive, and
+ * can produce output files that are more than twice the size of the input files.
+ * In most cases output files will be smaller than input files, perhaps by up to
+ * 40 percent, although the results you get depend on what you're doing and the
+ * text encoding you're using. You'll get the worst results if you're emulating
+ * another device, using special bitmap characters, like the logo, or doing lots
+ * of vertical motion or drawing.
+ *
+ * PostScript fonts don't support all of troff's characters, so some have to
+ * be built by special PostScript procedures. Those routines can be found in
+ * *fontdir/devpost/charlib, and are only used when we try to print a character
+ * that has been assigned a code less than 32. Definitions are only made the
+ * first time each character is used. Subsequent requests to print the character
+ * only generate a call to the PostScript procedure that's been copied to the
+ * output file. For example you'll find a file called sq in directory
+ * *fontdir/devpost/charlib. It defines a PostScript procedure called build_sq
+ * that's called whenever we need to print a square. Special characters that
+ * have been assigned a code of 2 are expected to come in two pieces. The
+ * definition part and bitmap part (or whatever). The definition is only made
+ * once, but the contents of the character's .map file are copied to the output
+ * file each time, immediately after charlib() generates the call to the
+ * PostScript procedure (build_?? ) that builds the character. That's typically
+ * how logos built from bitmaps would be handled.
+ *
+ * Several different methods can be used to encode lines of text. What's done
+ * depends on the value assigned to encoding. Print time should decrease as
+ * encoding increases (up to MAXENCODING). Setting encoding to 0, which should
+ * probably be the default, produces output essentially identical to the original
+ * version of dpost. It's the slowest but most stable method of encoding lines of
+ * text, and won't be bothered by rounding errors in the font width tables that
+ * could become noticeable by the time you get to the end of a line. Other schemes
+ * seem to work, but aren't well tested and are not guaranteed for all possible
+ * jobs. encoding can be changed on the command line using the -e option. Part of
+ * the support for different encoding schemes was to move control of all text
+ * related output to separate routines. It makes dpost work harder, but changing
+ * things is easy. For example adding stuff to support widthshow took less than
+ * an hour.
+ *
+ * According to Adobe's structuring conventions, the output produced by dpost is
+ * still nonconforming. Global definitions that are occasionally made in individual
+ * pages are the primary problem. Among other things they handle downloading host
+ * resident fonts and defining special characters not generally available on
+ * PostScript printers. The approach used here works on a demand basis and violates
+ * page independence. A definition is made once in the first page that needs it
+ * and is bracketed by PostScript code that ensures the definition is exported to
+ * the global environment where it will be available for use by all the pages that
+ * follow. Simple changes, like downloading definitions the first time they're
+ * used in each page, restores page independence but wouldn't be an efficient
+ * solution. Other approaches are also available, but every one I've considered
+ * sacrifices much in efficiency - just to maintain page independence. I'll leave
+ * things be for now. Global definitions made in individual pages are bracketed
+ * by %%BeginGlobal and %%EndGlobal comments and can easily be pulled out of
+ * individual pages and put in the prologue by utility programs like postreverse.
+ *
+ * I've also added code that handles the DOCUMENTFONTS comment, although it's
+ * only produced for those fonts in directory /usr/lib/font/devpost that have an
+ * associated .name file. The first string in a .name file should be the (long)
+ * PostScript name (eg. Times-Roman in R.name). For now everything else in the
+ * .name file is ignored, although that may also change. You'll find .name files
+ * for all the supported fonts in the devpost source directory, although they may
+ * not be installed in /usr/lib/font/devpost.
+ *
+ * The PostScript prologue is copied from *prologue before any of the input files
+ * are translated. The program expects the following procedures are avaliable:
+ *
+ * setup
+ *
+ * mark ... setup -
+ *
+ * Handles special initialization stuff that depends on how the program
+ * was called. Expects to find a mark followed by key/value pairs on the
+ * stack. The def operator is applied to each pair up to the mark, then
+ * the default state is set up. An 'x res' command must preceed the
+ * 'x init' command!
+ *
+ * pagesetup
+ *
+ * page pagesetup -
+ *
+ * Called at the start of each page, immediately after the page level
+ * save, to do special initialization on a per page basis. Right now the
+ * only argument is the current page number, and actually nothing of any
+ * importance is currently done.
+ *
+ * setdecoding
+ *
+ * num setdecoding -
+ *
+ * Selects the text decoding procedure (ie. what's assigned to PostScript
+ * procedure t) from the decodingdefs array defined in the prologue. num
+ * should be the value assigned to variable encoding (in dpost) and will
+ * remain constant throughout a job, unless special features, like reverse
+ * video printing, are requested. The text encoding scheme can be set on
+ * the command line using the -e option. Print time and the size of the
+ * output file will usually decrease as the value assigned to encoding
+ * increases.
+ *
+ * f
+ *
+ * size font f -
+ *
+ * Selects the size and font to be used for character imaging. Font names
+ * are defined, in *prologue, so they agree with the one or two character
+ * names used by troff.
+ *
+ * m
+ *
+ * x y m -
+ *
+ * Moves to point (x, y). Normally only used when the vertical position
+ * changes. Horizontal positioning between words (or letters) is handled
+ * in procedure t (below).
+ *
+ * t
+ *
+ * mark text t mark
+ *
+ * Processes everything on the stack, up to the mark, as a single line
+ * of text to be printed at a fixed vertical position. What's put out as
+ * text depends on the encoding scheme. Setting encoding to 0 produces
+ * output essentially identical to the original version of dpost. In that
+ * case everything on the stack, up to a mark, is interpreted (from top
+ * down) as an absolute horizontal position and a string to be printed at
+ * that point. For example the stack might look like,
+ *
+ * mark(this)1000(is)1100(an)1200(example)1300 t
+ *
+ * Procedure t would go through the stack, up to the mark, adjusting the
+ * horizontal position before printing each string. In other encoding
+ * schemes, like the one based on widthshow, strings containing several
+ * space separated words would appear on the stack, and each one would be
+ * preceeded by a number that's expected to be added to the width of a
+ * space. For example we might have,
+ *
+ * mark(an example)30(this is)40 2 1000 2000 t
+ *
+ * where (1000, 2000) is where the first string starts and 2 is the repeat
+ * count (ie. number of string and space pairs on the stack).
+ *
+ * w
+ *
+ * string x y w -
+ *
+ * Prints a single word starting at position (x, y). Only used in the more
+ * complicated encoding schemes (eg. the ones based on widthshow).
+ *
+ * done
+ *
+ * Makes sure the last page is printed. Only needed when we're printing
+ * more than one page on each sheet of paper.
+ *
+ * The PostScript procedures that support troff's drawing commands have been moved
+ * out of *prologue and put in a separate file (ie. DRAW as defined in path.h).
+ * The procedures are used by the routines in file draw.c, and are copied to the
+ * output file at most once and only when needed. Yet another convenient violation
+ * of page independence. If you don't approve append *drawfile to *prologue and
+ * make sure *drawfile can't be read when DPOST runs.
+ *
+ * Many default values, like the magnification and orientation, are defined in
+ * the prologue, which is where they belong. If they're changed (by options), an
+ * appropriate definition is made after the prologue is added to the output file.
+ * The -P option passes arbitrary PostScript through to the output file. Among
+ * other things it can be used to set (or change) values that can't be accessed by
+ * other options.
+ *
+ *
+ * output language from troff:
+ * all numbers are character strings
+ *
+ * sn size in points
+ * fn font as number from 1-n
+ * cx ascii character x
+ * Cxyz funny char xyz. terminated by white space
+ * Hn go to absolute horizontal position n
+ * Vn go to absolute vertical position n (down is positive)
+ * hn go n units horizontally (relative)
+ * vn ditto vertically
+ * nnc move right nn, then print c (exactly 2 digits!)
+ * (this wart is an optimization that shrinks output file size
+ * about 35% and run-time about 15% while preserving ascii-ness)
+ * Dt ...\n draw operation 't':
+ * Dl x y line from here by x,y
+ * Dc d circle of diameter d with left side here
+ * De x y ellipse of axes x,y with left side here
+ * Da x1 y1 x2 y2 arc counter-clockwise from current point (x, y) to
+ * (x + x1 + x2, y + y1 + y2)
+ * D~ x y x y ... wiggly line by x,y then x,y ...
+ * nb a end of line (information only -- no action needed)
+ * b = space before line, a = after
+ * p new page begins -- set v to 0
+ * #...\n comment
+ * x ...\n device control functions:
+ * x i init
+ * x T s name of device is s
+ * x r n h v resolution is n/inch
+ * h = min horizontal motion, v = min vert
+ * x p pause (can restart)
+ * x s stop -- done forever
+ * x t generate trailer
+ * x f n s font position n contains font s
+ * x H n set character height to n
+ * x S n set slant to N
+ *
+ * Subcommands like "i" are often spelled out like "init".
+ *
+ */
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <math.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "comments.h" /* PostScript file structuring comments */
+#include "gen.h" /* general purpose definitions */
+#include "path.h" /* for the prologue and a few other files */
+#include "ext.h" /* external variable definitions */
+#include "dev.h" /* typesetter and font descriptions */
+#include "dpost.h" /* a few definitions just used here */
+
+
+char *prologue = DPOST; /* the basic PostScript prologue */
+char *colorfile = COLOR; /* things needed for color support */
+char *drawfile = DRAW; /* and drawing */
+char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
+char *baselinefile = BASELINE;
+
+char *fontdir = FONTDIR; /* binary device directories found here */
+char *hostfontdir = NULL; /* host resident font directory */
+
+int formsperpage = 1; /* page images on each piece of paper */
+int copies = 1; /* and this many copies of each sheet */
+int picflag = ON; /* enable/disable picture inclusion */
+
+
+/*
+ *
+ * encoding selects the encoding scheme used to output lines of text. Change it
+ * to something other than 0 at your own risk. The other methods seem to work but
+ * aren't well tested and are not guaranteed. Some special features, like reverse
+ * video, may temporarily change the encoding scheme and reset it to realencoding
+ * when done.
+ *
+ */
+
+
+int encoding = DFLTENCODING;
+int realencoding = DFLTENCODING;
+int maxencoding = MAXENCODING;
+
+
+/*
+ *
+ * seenfonts[] keeps track of the fonts we've used, based on internal numbers. It
+ * helps manage host resident fonts and the DOCUMENTFONTS comment, but only works
+ * if all fonts have internal numbers less than MAXINTERNAL. *docfonts counts the
+ * number of font names we've recorded in *temp_file. If it's positive routine
+ * done() adds *temp_file to the output file before quitting.
+ *
+ */
+
+
+char seenfonts[MAXINTERNAL+1];
+int docfonts = 0;
+
+
+/*
+ *
+ * devname[] is the device troff used when the job was formatted, while *realdev
+ * is combined with *fontdir and used to locate the font and device tables that
+ * that control the translation of the input files into PostScript. *realdev can
+ * be changed using the -T option, but if you do you may end up getting garbage.
+ * The character code field must agree with PostScript's font encoding and font
+ * names must be properly mapped into PostScript font names in the prologue.
+ *
+ */
+
+
+char devname[20] = ""; /* job is formatted for this printer */
+char *realdev = DEVNAME; /* a good description of target printer */
+
+
+/*
+ *
+ * Standard things that come from binary font and description files for *realdev.
+ * Most are initialized in fontinit() or loadfont().
+ *
+ */
+
+
+struct dev dev; /* DESC.out starts this way */
+struct Font *fontbase[NFONT+1]; /* FONT.out files begin this way */
+short *pstab; /* list of available sizes */
+int nsizes = 1; /* and the number of sizes in that list */
+int smnt; /* index of first special font */
+int nchtab; /* number of special character names */
+int fsize; /* max size of a font files in bytes */
+int unitwidth; /* set to dev.unitwidth */
+char *chname; /* special character strings */
+short *chtab; /* used to locate character names */
+char *fitab[NFONT+1]; /* locates char info on each font */
+char *widthtab[NFONT+1]; /* character width data for each font */
+char *codetab[NFONT+1]; /* and codes to get characters printed */
+
+
+/*
+ *
+ * Special characters missing from standard PostScript fonts are defined by files
+ * in directory *fontdir/devpost/charlib. Files have the same names as the troff
+ * special character names (for now at least) and each one defines a PostScript
+ * procedure that begins with the prefix build_ and ends with the character's
+ * name.
+ *
+ * For example, the routine used to build character \(12, would be build_12.
+ * downloaded[] points to an array, allocated in fontinit(), that keeps track of
+ * the characters that have already been defined - so we only do it once.
+ *
+ */
+
+
+char *downloaded; /* nonzero means it's been downloaded */
+
+
+/*
+ *
+ * Variables that keep track of troff's requests. All are set from values in the
+ * input files. nfonts is adjusted in t_fp() as new fonts are mounted.
+ *
+ */
+
+
+int nfonts = 0; /* number of font positions */
+int size = 1; /* current size - internal value */
+int font = 0; /* font position we're using now */
+int hpos = 0; /* where troff wants to be - horizontally */
+int vpos = 0; /* same but vertically */
+float lastw = 0; /* width of the last input character */
+int lastc = 0; /* and its name (or index) */
+
+int fontheight = 0; /* points from x H ... */
+int fontslant = 0; /* angle from x S ... */
+
+int res; /* resolution assumed in input file */
+float widthfac = 1.0; /* for emulation = res/dev.res */
+
+
+/*
+ *
+ * Remember some of the same things, but this time for the printer. lastend is only
+ * used when we're doing reverse video, and is where the last character on the
+ * current line was printed.
+ *
+ */
+
+
+int lastsize = -1; /* last internal size we used */
+int lastfont = -1; /* last font we told printer about */
+float lastx = -1; /* printer's current position */
+int lasty = -1;
+int lastend; /* where last character on this line was */
+
+
+/*
+ *
+ * fontname[] keeps track of the mounted fonts. Filled in (by t_fp()) from data
+ * in the binary font files.
+ *
+ */
+
+
+struct {
+
+ char *name; /* name of the font loaded here */
+ int number; /* its internal number */
+
+} fontname[NFONT+1] = {NULL, 0};
+
+
+/*
+ *
+ * All the special fonts will be mounted after the last legitimate font position.
+ * It helps when we're translating files prepared for devices, like the 202, that
+ * have a different set of special fonts. The set of special fonts needed when
+ * *realdev's tables are used may not get mounted when we're emulating another
+ * device. gotspecial keeps track of whether we've done it yet. seenpage is set
+ * to TRUE after we've seen the first page command in the input file. It controls
+ * what's done in t_font() and is needed because nfonts is no longer set when the
+ * DESC.out file is read, but rather is updated from "x font" commands in the
+ * input files.
+ *
+ */
+
+
+int gotspecial = FALSE;
+int seenpage = FALSE;
+
+
+/*
+ *
+ * The amount of horizontal positioning error we accept controls both the size
+ * of the output file and the appearance of the printed text. It's probably most
+ * important when we're emulating other devices, like the APS-5. The error can be
+ * set using the -S option. It's converted from points to machine units in t_init()
+ * after the resolution is known. rvslop is also set in t_init() and only used to
+ * adjust the width of the box that's drawn around text when we're printing in
+ * reverse video mode.
+ *
+ */
+
+
+float pointslop = SLOP; /* horizontal error in points */
+int slop; /* and machine units */
+int rvslop; /* to extend box in reverse video mode */
+
+
+/*
+ *
+ * Characters are accumulated and saved in PostScript strings that are eventually
+ * processed by making a single call to procedure t. textcount counts the number
+ * of individual strings collected but not yet processed, and is primarily used to
+ * make sure PostScript's stack doesn't get too big. When textcount is positive
+ * we've started accumulating strings and need to generate a call to PostScript
+ * procedure t to process the text before anything else (like a font change) is
+ * done.
+ *
+ */
+
+
+int textcount = 0; /* strings accumulated so far */
+int stringstart = 0; /* where the next one starts */
+int spacecount = 0; /* spaces seen so far on current line */
+
+
+/*
+ *
+ * Things that can be used by text line encoding schemes that need to read and
+ * remember an entire line before doing any output. The strings that make up the
+ * line can be saved in array strings[] and accessed by fields in line[]. *strptr
+ * points to the next free slot in strings[].
+ *
+ */
+
+
+char strings[STRINGSPACE];
+char *strptr;
+Line line[MAXSTACK+3];
+
+
+/*
+ *
+ * When we're emulating another device we may want to map font name requests that
+ * come in as "x font pos name" commands into some other font name before anything
+ * else is done (ie. calling loadfont()). Font names can collide or we may just
+ * want to a mapping that depends on the device troff used to format the input
+ * files. devfontmap points to a structure that's filled in by getdevmap() if the
+ * mapping file /usr/lib/font/dev*realdev/fontmaps/devname exists. mapdevfont()
+ * then uses that table to translate font name requests into something else before
+ * loadfont() gets called.
+ *
+ * fontmap[] provides a simple minded translation that maps an unrecognized font
+ * name (in loadfont()) into another font name that we know will be available. It
+ * doesn't provide the fine control available with *devfontmap, but should be good
+ * enough for most jobs. Both structures are only needed when emulating another
+ * device using *realdev's font tables.
+ *
+ */
+
+
+Devfontmap *devfontmap = NULL; /* device level */
+Fontmap fontmap[] = FONTMAP; /* and general mapping tables - emulation */
+
+
+/*
+ *
+ * A few variables that are really only used if we're doing accounting. Designed
+ * for our use at Murray Hill and probably won't suit your needs. Changes should
+ * be easy and can be made in routine account().
+ *
+ */
+
+
+int printed = 0; /* charge for this many pages */
+
+
+/*
+ *
+ * Output and accounting file definitions. The PostScript output always goes to
+ * stdout or /dev/null, while the accounting file can be selected using the -A
+ * option.
+ *
+ */
+
+
+FILE *tf = NULL; /* PostScript output goes here */
+FILE *fp_acct = NULL; /* accounting stuff written here */
+
+
+/*
+ *
+ * Need the list of valid options in header() and options(), so I've moved the
+ * definition here.
+ *
+ */
+
+
+char *optnames = "a:c:e:m:n:o:p:tw:x:y:A:C:J:F:H:L:OP:R:S:T:DI";
+
+
+/*
+ *
+ * Very temporary space that can be used to do things like building up pathnames
+ * immediately before opening a file. Contents may not be preserved across calls
+ * to subroutines defined in this file, so it probably should only be used in low
+ * level subroutines like loadfont() or fontinit() and nowhere else.
+ *
+ */
+
+
+char temp[150];
+
+static void account(void);
+static void addchar(int);
+static void addoctal(int);
+static void arguments(void);
+static void charlib(int);
+static void conv(FILE *);
+static void devcntrl(FILE *);
+static void documentfonts(void);
+static void done(void);
+static void endline(void);
+static void endstring(void);
+void endtext(void);
+static void fontinit(void);
+static void fontprint(int);
+static void getdevmap(void);
+static void header(void);
+void hgoto(int);
+static void hmot(int);
+static void init_signals(void);
+static void loaddefault(void);
+static void loadfont(int, char *, char *);
+static void loadspecial(void);
+static void options(void);
+static void oput(int);
+static void put1(int);
+static void put1s(char *);
+static void redirect(int);
+void reset(void);
+void resetpos(void);
+static void setfont(int);
+static void setpaths(char *);
+static void setsize(int);
+static void setup(void);
+static void starttext(void);
+static void t_charht(int);
+static void t_fp(int, char *, char *);
+static void t_init(void);
+static void t_newline(void);
+static void t_page(int);
+static void t_reset(int);
+void t_sf(void);
+static void t_slant(int);
+static void t_trailer(void);
+void vgoto(int);
+static void vmot(int);
+
+
+/*****************************************************************************/
+
+
+int
+main(int agc, char *agv[])
+{
+
+/*
+ *
+ * A program that translates troff output into PostScript. All the input files
+ * must have been formatted for the same device, which doesn't necessarily have to
+ * be *realdev. If there's more than one input file, each begins on a new page.
+ *
+ */
+
+
+ argc = agc; /* global so everyone can use them */
+ argv = agv;
+
+ prog_name = argv[0]; /* just for error messages */
+
+ init_signals(); /* sets up interrupt handling */
+ header(); /* PostScript file structuring comments */
+ options(); /* command line options */
+ arguments(); /* translate all the input files */
+ done(); /* add trailing comments etc. */
+ account(); /* job accounting data */
+
+ return (x_stat); /* everything probably went OK */
+
+} /* End of main */
+
+
+/*****************************************************************************/
+
+
+static void
+init_signals(void)
+{
+ void interrupt(); /* signal handler */
+
+/*
+ *
+ * Make sure we handle interrupts.
+ *
+ */
+
+
+ if ( signal(SIGINT, interrupt) == SIG_IGN ) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ } else {
+ signal(SIGHUP, interrupt);
+ signal(SIGQUIT, interrupt);
+ } /* End else */
+
+ signal(SIGTERM, interrupt);
+
+} /* End of init_signals */
+
+
+/*****************************************************************************/
+
+static void
+header(void)
+{
+
+
+ int ch; /* return value from getopt() */
+ int old_optind = optind; /* for restoring optind - should be 1 */
+
+
+/*
+ *
+ * Scans the option list looking for things, like the prologue file, that we need
+ * right away but could be changed from the default. Doing things this way is an
+ * attempt to conform to Adobe's latest file structuring conventions. In particular
+ * they now say there should be nothing executed in the prologue, and they have
+ * added two new comments that delimit global initialization calls. Once we know
+ * where things really are we write out the job header, follow it by the prologue,
+ * and then add the ENDPROLOG and BEGINSETUP comments.
+ *
+ */
+
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF )
+ if ( ch == 'L' )
+ setpaths(optarg);
+ else if ( ch == '?' )
+ error(FATAL, "");
+
+ optind = old_optind; /* get ready for option scanning */
+
+ fprintf(stdout, "%s", NONCONFORMING);
+ fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
+ fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
+ fprintf(stdout, "%s %s\n", PAGES, ATEND);
+ fprintf(stdout, "%s", ENDCOMMENTS);
+
+ if ( cat(prologue) == FALSE )
+ error(FATAL, "can't read %s", prologue);
+
+ fprintf(stdout, "%s", ENDPROLOG);
+ fprintf(stdout, "%s", BEGINSETUP);
+ fprintf(stdout, "mark\n");
+
+} /* End of header */
+
+
+/*****************************************************************************/
+
+
+static void
+options(void)
+{
+ int ch; /* name returned by getopt() */
+
+ extern char *optarg; /* option argument set by getopt() */
+ extern int optind;
+
+/*
+ *
+ * Reads and processes the command line options. There are, without a doubt, too
+ * many options!
+ *
+ */
+
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
+
+ switch ( ch ) {
+
+ case 'a': /* aspect ratio */
+ fprintf(stdout, "/aspectratio %s def\n", optarg);
+ break;
+
+ case 'c': /* number of copies */
+ copies = atoi(optarg);
+ fprintf(stdout, "/#copies %s store\n", optarg);
+ break;
+
+ case 'e': /* change the encoding scheme */
+ if ( (encoding = atoi(optarg)) < 0 || encoding > MAXENCODING )
+ encoding = DFLTENCODING;
+ realencoding = encoding;
+ break;
+
+ case 'm': /* magnification */
+ fprintf(stdout, "/magnification %s def\n", optarg);
+ break;
+
+ case 'n': /* forms per page */
+ formsperpage = atoi(optarg);
+ fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
+ fprintf(stdout, "/formsperpage %s def\n", optarg);
+ break;
+
+ case 'o': /* output page list */
+ out_list(optarg);
+ break;
+
+ case 'p': /* landscape or portrait mode */
+ if ( *optarg == 'l' )
+ fprintf(stdout, "/landscape true def\n");
+ else fprintf(stdout, "/landscape false def\n");
+ break;
+
+ case 't': /* just for compatibility */
+ break;
+
+ case 'w': /* line width for drawing */
+ fprintf(stdout, "/linewidth %s def\n", optarg);
+ break;
+
+ case 'x': /* shift horizontally */
+ fprintf(stdout, "/xoffset %s def\n", optarg);
+ break;
+
+ case 'y': /* and vertically on the page */
+ fprintf(stdout, "/yoffset %s def\n", optarg);
+ break;
+
+ case 'A': /* force job accounting */
+ case 'J':
+ if ( (fp_acct = fopen(optarg, "a")) == NULL )
+ error(FATAL, "can't open accounting file %s", optarg);
+ break;
+
+ case 'C': /* copy file to straight to output */
+ if ( cat(optarg) == FALSE )
+ error(FATAL, "can't read %s", optarg);
+ break;
+
+ case 'F': /* font table directory */
+ fontdir = optarg;
+ break;
+
+ case 'H': /* host resident font directory */
+ hostfontdir = optarg;
+ break;
+
+ case 'L': /* PostScript prologue file */
+ setpaths(optarg); /* already been done in header() */
+ break;
+
+ case 'O': /* turn picture inclusion off */
+ picflag = OFF;
+ break;
+
+ case 'P': /* PostScript pass through */
+ fprintf(stdout, "%s\n", optarg);
+ break;
+
+ case 'R': /* special global or page level request */
+ saverequest(optarg);
+ break;
+
+ case 'S': /* horizontal position error */
+ if ( (pointslop = atof(optarg)) < 0 )
+ pointslop = 0;
+ break;
+
+ case 'T': /* target printer */
+ realdev = optarg;
+ break;
+
+ case 'D': /* debug flag */
+ debug = ON;
+ tf = stdout;
+ break;
+
+ case 'I': /* ignore FATAL errors */
+ ignore = ON;
+ break;
+
+ case '?': /* don't know the option */
+ error(FATAL, "");
+ break;
+
+ default:
+ error(FATAL, "missing case for option %c", ch);
+ break;
+
+ } /* End switch */
+ } /* End while */
+
+ argc -= optind; /* get ready for non-options args */
+ argv += optind;
+
+} /* End of options */
+
+
+/*****************************************************************************/
+
+
+static void
+setpaths(char *name)
+ /* string that followed the -L option */
+{
+ char *path; /* start of the pathname */
+
+/*
+ *
+ * Extends the -L option to permit run time modification of pathnames that were
+ * fixed or didn't exist in previous versions of dpost. For example, the PostScript
+ * drawing procedures have been moved out of *prologue and put in *drawfile. The
+ * new syntax can be either -Lfile or -Lname:file. If the "name:" prefix is omitted
+ * file will be used as the prologue, otherwise name should be one of "prologue",
+ * "font", "draw", "color", or "form" and is used to select the pointer that gets
+ * set to string "file".
+ *
+ */
+
+
+ for ( path = name; *path; path++ )
+ if ( *path == ':' || *path == ' ' ) {
+ while ( *path == ':' || *path == ' ' ) path++;
+ break;
+ } /* End if */
+
+ if ( *path == '\0' ) /* didn't find a "name:" prefix */
+ path = name;
+
+ if ( path == name || strncmp(name, "prologue", strlen("prologue")) == 0 )
+ prologue = path;
+ else if ( strncmp(name, "draw", strlen("draw")) == 0 )
+ drawfile = path;
+ else if ( strncmp(name, "color", strlen("color")) == 0 )
+ colorfile = path;
+ else if ( strncmp(name, "form", strlen("form")) == 0 )
+ formfile = path;
+ else if ( strncmp(name, "baseline", strlen("baseline")) == 0 )
+ baselinefile = path;
+
+} /* End of setpaths */
+
+
+/*****************************************************************************/
+
+
+static void
+setup(void)
+{
+
+/*
+ * Handles things that must be done after the options are read but before the
+ * input files are processed. Called from t_init() after an "x init" command is
+ * read, because we need the resolution before we can generate the call to the
+ * setup procedure defined in *prologue. Only allowing one call to setup assumes
+ * all the input files have been prepared for the same device.
+ *
+ */
+
+
+ writerequest(0, stdout); /* global requests eg. manual feed */
+ fprintf(stdout, "/resolution %d def\n", res);
+ fprintf(stdout, "setup\n");
+ fprintf(stdout, "%d setdecoding\n", encoding);
+
+ if ( formsperpage > 1 ) { /* followed by stuff for multiple pages */
+ if ( cat(formfile) == FALSE )
+ error(FATAL, "can't read %s", formfile);
+ fprintf(stdout, "%d setupforms\n", formsperpage);
+ } /* End if */
+
+ fprintf(stdout, "%s", ENDSETUP);
+
+} /* End of setup */
+
+
+/*****************************************************************************/
+
+
+static void
+arguments(void)
+{
+ FILE *fp; /* next input file */
+
+/*
+ *
+ * Makes sure all the non-option command line arguments are processed. If we get
+ * here and there aren't any arguments left, or if '-' is one of the input files
+ * we'll translate stdin.
+ *
+ */
+
+
+ if ( argc < 1 )
+ conv(stdin);
+ else
+ while ( argc > 0 ) {
+ if ( strcmp(*argv, "-") == 0 )
+ fp = stdin;
+ else if ( (fp = fopen(*argv, "r")) == NULL )
+ error(FATAL, "can't open %s", *argv);
+ conv(fp);
+ if ( fp != stdin )
+ fclose(fp);
+ argc--;
+ argv++;
+ } /* End while */
+
+} /* End of arguments */
+
+
+/*****************************************************************************/
+
+
+static void
+done(void)
+{
+
+/*
+ *
+ * Finished with all the input files, so mark the end of the pages with a TRAILER
+ * comment, make sure the last page prints, and add things like the DOCUMENTFONTS
+ * and PAGES comments that can only be determined after all the input files have
+ * been read.
+ *
+ */
+
+
+ fprintf(stdout, "%s", TRAILER);
+ fprintf(stdout, "done\n");
+
+ if ( temp_file != NULL ) {
+ if ( docfonts > 0 ) {
+ cat(temp_file);
+ putc('\n', stdout);
+ } /* End if */
+ unlink(temp_file);
+ } /* End if */
+
+ fprintf(stdout, "%s %d\n", PAGES, printed);
+
+} /* End of done */
+
+
+/*****************************************************************************/
+
+
+static void
+account(void)
+{
+
+/*
+ *
+ * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is
+ * requested using the -A or -J options.
+ *
+ */
+
+ if ( fp_acct != NULL )
+ fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
+
+} /* End of account */
+
+
+/*****************************************************************************/
+
+
+static void
+conv(FILE *fp)
+ /* next input file */
+{
+ int c; /* usually first char in next command */
+ int m, n, n1, m1; /* when we need to read integers */
+ char str[50]; /* for special chars and font numbers */
+
+
+/*
+ *
+ * Controls the translation of troff's device independent output language into
+ * PostScript. The call to t_page() that prints the last page is made when we
+ * exit the loop, but probably belongs in t_trailer().
+ *
+ */
+
+
+ redirect(-1); /* only do output after a page command */
+ lineno = 1; /* line in current file */
+
+ while ((c = getc(fp)) != EOF) {
+
+ switch (c) {
+
+ case '\n': /* just count this line */
+ lineno++;
+ break;
+
+ case ' ': /* when input is text */
+ case 0: /* occasional noise creeps in */
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ /* two motion digits plus a character */
+ hmot((c-'0')*10 + getc(fp)-'0');
+ put1(getc(fp));
+ break;
+
+ case 'c': /* single ascii character */
+ put1(getc(fp));
+ break;
+
+ case 'C': /* special character */
+ fscanf(fp, "%s", str);
+ put1s(str);
+ break;
+
+ case 'N': /* character at position n */
+ fscanf(fp, "%d", &m);
+ endtext();
+ oput(m);
+ break;
+
+ case 'D': /* drawing functions */
+ endtext();
+ getdraw();
+ if ( size != lastsize )
+ t_sf();
+ switch ((c=getc(fp))) {
+ case 'p': /* draw a path */
+ while (fscanf(fp, "%d %d", &n, &m) == 2)
+ drawline(n, m);
+ lineno++;
+ break;
+
+ case 'l': /* draw a line */
+ fscanf(fp, "%d %d %c", &n, &m, &n1);
+ drawline(n, m);
+ break;
+
+ case 'c': /* circle */
+ fscanf(fp, "%d", &n);
+ drawcirc(n);
+ break;
+
+ case 'e': /* ellipse */
+ fscanf(fp, "%d %d", &m, &n);
+ drawellip(m, n);
+ break;
+
+ case 'a': /* counter-clockwise arc */
+ case 'A': /* clockwise arc */
+ fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1);
+ drawarc(n, m, n1, m1, c);
+ break;
+
+ case 'q': /* spline without end points */
+ drawspline(fp, 1);
+ lineno++;
+ break;
+
+ case '~': /* wiggly line */
+ drawspline(fp, 2);
+ lineno++;
+ break;
+
+ default:
+ error(FATAL, "unknown drawing function %c", c);
+ break;
+ } /* End switch */
+ break;
+
+ case 's': /* use this point size */
+ fscanf(fp, "%d", &n); /* ignore fractional sizes */
+ setsize(t_size(n));
+ break;
+
+ case 'f': /* use font mounted here */
+ fscanf(fp, "%s", str);
+ setfont(t_font(str));
+ break;
+
+ case 'H': /* absolute horizontal motion */
+ fscanf(fp, "%d", &n);
+ hgoto(n);
+ break;
+
+ case 'h': /* relative horizontal motion */
+ fscanf(fp, "%d", &n);
+ hmot(n);
+ break;
+
+ case 'w': /* word space */
+ break;
+
+ case 'V': /* absolute vertical position */
+ fscanf(fp, "%d", &n);
+ vgoto(n);
+ break;
+
+ case 'v': /* relative vertical motion */
+ fscanf(fp, "%d", &n);
+ vmot(n);
+ break;
+
+ case 'p': /* new page */
+ fscanf(fp, "%d", &n);
+ t_page(n);
+ break;
+
+ case 'n': /* end of line */
+ while ( (c = getc(fp)) != '\n' && c != EOF ) ;
+ t_newline();
+ lineno++;
+ break;
+
+ case '#': /* comment */
+ while ( (c = getc(fp)) != '\n' && c != EOF ) ;
+ lineno++;
+ break;
+
+ case 'x': /* device control function */
+ devcntrl(fp);
+ lineno++;
+ break;
+
+ default:
+ error(FATAL, "unknown input character %o %c", c, c);
+ done();
+
+ } /* End switch */
+
+ } /* End while */
+
+ t_page(-1); /* print the last page */
+ endtext();
+
+} /* End of conv */
+
+
+/*****************************************************************************/
+
+
+static void
+devcntrl(FILE *fp)
+ /* current input file */
+{
+
+
+ char str[50], buf[256], str1[50];
+ int c, n;
+
+
+/*
+ *
+ * Called from conv() to process the rest of a device control function. There's
+ * a whole family of them and they all start with the string "x ", which we've
+ * already read. The "x X ..." commands are an extensible (and device dependent)
+ * family that we use here for things like picture inclusion. Unrecognized device
+ * control commands are ignored.
+ *
+ */
+
+
+ fscanf(fp, "%s", str); /* get the control function name */
+
+ switch ( str[0] ) { /* only the first character counts */
+
+ case 'i': /* initialize */
+ t_init();
+ break;
+
+ case 'T': /* device name */
+ fscanf(fp, "%s", devname);
+ getdevmap();
+ strcpy(devname, realdev);
+ break;
+
+ case 't': /* trailer */
+ t_trailer();
+ break;
+
+ case 'p': /* pause -- can restart */
+ t_reset('p');
+ break;
+
+ case 's': /* stop */
+ t_reset('s');
+ break;
+
+ case 'r': /* resolution assumed when prepared */
+ fscanf(fp, "%d", &res);
+ break;
+
+ case 'f': /* load font in a position */
+ fscanf(fp, "%d %s", &n, str);
+ fgets(buf, sizeof buf, fp); /* in case there's a filename */
+ ungetc('\n', fp); /* fgets() goes too far */
+ str1[0] = '\0'; /* in case there's nothing to come in */
+ sscanf(buf, "%s", str1);
+ loadfont(n, mapdevfont(str), str1);
+ break;
+
+ /* these don't belong here... */
+ case 'H': /* char height */
+ fscanf(fp, "%d", &n);
+ t_charht(n);
+ break;
+
+ case 'S': /* slant */
+ fscanf(fp, "%d", &n);
+ t_slant(n);
+ break;
+
+ case 'X': /* copy through - from troff */
+ fscanf(fp, " %[^: \n]:", str);
+ fgets(buf, sizeof(buf), fp);
+ ungetc('\n', fp);
+ if ( strcmp(str, "PI") == 0 || strcmp(str, "PictureInclusion") == 0 )
+ picture(buf);
+ else if ( strcmp(str, "InlinePicture") == 0 )
+ inlinepic(fp, buf);
+ else if ( strcmp(str, "BeginPath") == 0 )
+ beginpath(buf, FALSE);
+ else if ( strcmp(str, "DrawPath") == 0 )
+ drawpath(buf, FALSE);
+ else if ( strcmp(str, "BeginObject") == 0 )
+ beginpath(buf, TRUE);
+ else if ( strcmp(str, "EndObject") == 0 )
+ drawpath(buf, TRUE);
+ else if ( strcmp(str, "NewBaseline") == 0 )
+ newbaseline(buf);
+ else if ( strcmp(str, "DrawText") == 0 )
+ drawtext(buf);
+ else if ( strcmp(str, "SetText") == 0 )
+ settext(buf);
+ else if ( strcmp(str, "SetColor") == 0 ) {
+ newcolor(buf);
+ setcolor();
+ } else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 ) {
+ endtext();
+ /* xymove(hpos, vpos); ul90-22006 */
+ fprintf(tf, "%s", buf);
+ } /* End else */
+ break;
+ } /* End switch */
+
+ while ( (c = getc(fp)) != '\n' && c != EOF ) ;
+
+} /* End of devcntrl */
+
+
+/*****************************************************************************/
+
+
+static void
+fontinit(void)
+{
+ int fin; /* for reading the DESC.out file */
+ char *filebase; /* the whole thing goes here */
+ int i; /* loop index */
+
+
+/*
+ *
+ * Reads *realdev's DESC.out file and uses what's there to initialize things like
+ * the list of available point sizes. Old versions of the program used *devname's
+ * DESC.out file to initialize nfonts, but that meant we needed to have *devname's
+ * binary font files available for emulation. That restriction has been removed
+ * and we now set nfonts using the "x font" commands in the input file, so by the
+ * time we get here all we really need is *realdev. In fact devcntrl() reads the
+ * device name from the "x T ..." command, but almost immediately replaces it with
+ * string *realdev so we end up using *realdev's DESC.out file. Later on (in
+ * t_font()) we mount all of *realdev's special fonts after the last legitimate
+ * font position, just to be sure device emulation works reasonably well - there's
+ * no guarantee *devname's special fonts match what's needed when *realdev's tables
+ * are used.
+ *
+ */
+
+
+ sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname);
+ if ( (fin = open(temp, 0)) < 0 )
+ error(FATAL, "can't open tables for %s", temp);
+
+ read(fin, &dev, sizeof(struct dev));
+
+ nfonts = 0; /* was dev.nfonts - now set in t_fp() */
+ nsizes = dev.nsizes;
+ nchtab = dev.nchtab;
+ unitwidth = dev.unitwidth;
+
+ if ( (filebase = malloc(dev.filesize)) == NULL )
+ error(FATAL, "no memory for description file");
+
+ read(fin, filebase, dev.filesize); /* all at once */
+ close(fin);
+
+ pstab = (short *) filebase;
+ chtab = pstab + nsizes + 1;
+ chname = (char *) (chtab + nchtab);
+ fsize = 3 * 255 + nchtab + 128 - 32 + sizeof(struct Font);
+
+ for ( i = 1; i <= NFONT; i++ ) { /* so loadfont() knows nothing's there */
+ fontbase[i] = NULL;
+ widthtab[i] = codetab[i] = fitab[i] = NULL;
+ } /* End for */
+
+ if ( (downloaded = (char *) calloc(nchtab + 128, sizeof(char))) == NULL )
+ error(FATAL, "no memory");
+
+} /* End of fontinit */
+
+
+/*****************************************************************************/
+
+
+static void
+loadfont(int n, char *s, char *s1)
+ /* n - load this font position */
+ /* s - with the .out file for this font */
+ /* s1 - taken from here - possibly */
+{
+ int fin; /* for reading *s.out file */
+ int nw; /* number of width table entries */
+
+
+/*
+ *
+ * Loads font position n with the binary font file for *s.out provided it's not
+ * already there. If *s1 is NULL or points to the empty string we read files from
+ * directory *fontdir/dev*devname, otherwise directory *s1 is used. If the first
+ * open fails we try to map font *s into one we expect will be available, and then
+ * we try again.
+ *
+ */
+
+
+ if ( n < 0 || n > NFONT ) /* make sure it's a legal position */
+ error(FATAL, "illegal fp command %d %s", n, s);
+
+ if ( fontbase[n] != NULL && strcmp(s, fontbase[n]->namefont) == 0 )
+ return;
+
+ if ( s1 == NULL || s1[0] == '\0' )
+ sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, s);
+ else sprintf(temp, "%s/%s.out", s1, s);
+
+ if ( (fin = open(temp, 0)) < 0 ) {
+ sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, mapfont(s));
+ if ( (fin = open(temp, 0)) < 0 )
+ error(FATAL, "can't open font table %s", temp);
+ } /* End if */
+
+ if ( fontbase[n] != NULL ) /* something's already there */
+ free(fontbase[n]); /* so release the memory first */
+
+ fontbase[n] = (struct Font *) malloc(fsize);
+ if ( fontbase[n] == NULL )
+ error(FATAL, "Out of space in loadfont %s", s);
+
+ read(fin, fontbase[n], fsize);
+ close(fin);
+
+ if ( smnt == 0 && fontbase[n]->specfont == 1 )
+ smnt = n;
+
+ nw = fontbase[n]->nwfont & BMASK;
+ widthtab[n] = (char *) fontbase[n] + sizeof(struct Font);
+ codetab[n] = (char *) widthtab[n] + 2 * nw;
+ fitab[n] = (char *) widthtab[n] + 3 * nw;
+
+ t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
+
+ if ( debug == ON )
+ fontprint(n);
+
+} /* End of loadfont */
+
+
+/*****************************************************************************/
+
+
+static void
+loadspecial(void)
+{
+ char *p; /* for next binary font file */
+ int nw; /* width entries in next font */
+ int i; /* loop index */
+
+
+/*
+ *
+ * Loads all the special fonts after the last legal font position. Mostly used
+ * for device emulation, but we'll do it no matter what. Needed because there's
+ * no consistency in special fonts across different devices, and relying on having
+ * them mounted in the input file doesn't guarantee the whole collection will be
+ * there. The special fonts are determined and mounted using the copy of the
+ * DESC.out file that's been read into memory. Initially had this stuff at the
+ * end of fontinit(), but we now don't know nfonts until much later.
+ *
+ */
+
+
+ if ( gotspecial == FALSE )
+ for ( i = 1, p = chname + dev.lchname; i <= dev.nfonts; i++ ) {
+ nw = *p & BMASK;
+ if ( ((struct Font *) p)->specfont == 1 )
+ loadfont(++nfonts, ((struct Font *)p)->namefont, NULL);
+ p += 3 * nw + dev.nchtab + 128 - 32 + sizeof(struct Font);
+ } /* End for */
+
+ gotspecial = TRUE;
+
+} /* End of loadspecial */
+
+
+/*****************************************************************************/
+char *defaultFonts[] =
+ { "R", "I", "B", "BI", "CW", "H", "HB", "HX", "S1", "S", NULL };
+
+static void
+loaddefault(void)
+{
+ int i;
+
+ for (i = 0; defaultFonts[i] != NULL ; i++)
+ loadfont(++nfonts, defaultFonts[i], NULL);
+}
+
+
+static void
+fontprint(int i)
+ /* font's index in fontbase[] */
+{
+ int j, n;
+ char *p;
+
+
+/*
+ *
+ * Debugging routine that dumps data about the font mounted in position i.
+ *
+ */
+
+
+ fprintf(tf, "font %d:\n", i);
+
+ p = (char *) fontbase[i];
+ n = fontbase[i]->nwfont & BMASK;
+
+ fprintf(tf, "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",
+ p, n, fontbase[i]->specfont, fontbase[i]->namefont, widthtab[i], fitab[i]);
+
+ fprintf(tf, "widths:\n");
+ for ( j = 0; j <= n; j++ ) {
+ fprintf(tf, " %2d", widthtab[i][j] & BMASK);
+ if ( j % 20 == 19 ) putc('\n', tf);
+ } /* End for */
+
+ fprintf(tf, "\ncodetab:\n");
+ for ( j = 0; j <= n; j++ ) {
+ fprintf(tf, " %2d", codetab[i][j] & BMASK);
+ if ( j % 20 == 19 ) putc('\n', tf);
+ } /* End for */
+
+ fprintf(tf, "\nfitab:\n");
+ for ( j = 0; j <= dev.nchtab + 128-32; j++ ) {
+ fprintf(tf, " %2d", fitab[i][j] & BMASK);
+ if ( j % 20 == 19 ) putc('\n', tf);
+ } /* End for */
+
+ putc('\n', tf);
+
+} /* End of fontprint */
+
+
+/*****************************************************************************/
+
+
+char *
+mapfont(char *name)
+ /* troff wanted this font */
+{
+ int i; /* loop index */
+
+
+/*
+ *
+ * If loadfont() can't find font *name we map it into something else that should
+ * be available and return a pointer to the new name. Used mostly for emulating
+ * devices like the APS-5.
+ *
+ */
+
+
+ for ( i = 0; fontmap[i].name != NULL; i++ )
+ if ( strcmp(name, fontmap[i].name) == 0 )
+ return(fontmap[i].use);
+
+ switch ( *++name ) {
+ case 'I':
+ return("I");
+
+ case 'B':
+ return("B");
+
+ case 'X':
+ return("BI");
+
+ default:
+ return("R");
+ } /* End switch */
+
+} /* End of mapfont */
+
+
+/*****************************************************************************/
+
+
+static void
+getdevmap(void)
+{
+
+
+ FILE *fp; /* for reading the device fontmap file */
+ int i = 0; /* number of mapping pairs we've read */
+ int c; /* for skipping lines */
+
+
+/*
+ *
+ * Looks for the device font mapping file *fontdir/dev*realdev/fontmaps/devname.
+ * The file, if it exists, should be an ASCII file containing pairs of one or two
+ * character font names per line. The first name is the font troff will be asking
+ * for and the second is the one we'll use. Comments are lines that begin with
+ * a '#' as the first non-white space character on a line. The devfontmap list
+ * ends with a member that has the empty string in the name field.
+ *
+ */
+
+
+ sprintf(temp, "%s/dev%s/fontmaps/%s", fontdir, realdev, devname);
+
+ if ( devfontmap == NULL && (fp = fopen(temp, "r")) != NULL ) {
+ devfontmap = (Devfontmap *) malloc(10 * sizeof(Devfontmap));
+
+ while ( fscanf(fp, "%s", temp) != EOF ) {
+ if ( temp[0] != '#' && strlen(temp) < 3 )
+ if ( fscanf(fp, "%s", &temp[3]) == 1 && strlen(&temp[3]) < 3 ) {
+ strcpy((devfontmap + i)->name, temp);
+ strcpy((devfontmap + i)->use, &temp[3]);
+ if ( ++i % 10 == 0 )
+ devfontmap = (Devfontmap *) realloc(devfontmap, (i + 10) * sizeof(Devfontmap));
+ } /* End if */
+ while ( (c = getc(fp)) != '\n' && c != EOF ) ;
+ } /* End while */
+
+ (devfontmap + i)->name[0] = '\0'; /* end the list we just read */
+ fclose(fp);
+ } /* End if */
+
+} /* End of getdevmap */
+
+
+/*****************************************************************************/
+
+
+char *
+mapdevfont(char *str)
+{
+ int i;
+
+
+/*
+ *
+ * Called immediately before loadfont() after an 'x font' command is recognized.
+ * Takes the font name that troff asked for, looks it up in the devfontmap list,
+ * and returns the mapped name to the caller. No mapping is done if the devfontmap
+ * list is empty or font *str isn't found in the list.
+ *
+ */
+
+
+ if ( devfontmap != NULL )
+ for ( i = 0; (devfontmap + i)->name[0] != '\0'; i++ )
+ if ( strcmp((devfontmap + i)->name, str) == 0 )
+ return((devfontmap + i)->use);
+
+ return(str);
+
+} /* End of mapdevfont */
+
+
+/*****************************************************************************/
+
+
+void
+reset(void)
+{
+
+/*
+ *
+ * Resets the variables that keep track of the printer's current position, font,
+ * and size. Typically used after a restore/save pair (eg. when we finish with a
+ * page) to make sure we force the printer back into sync (in terms of the font
+ * and current point) before text is printed.
+ *
+ */
+
+
+ lastx = -(slop + 1);
+ lasty = -1;
+ lastfont = lastsize = -1;
+
+} /* End of reset */
+
+
+/*****************************************************************************/
+
+
+void
+resetpos(void)
+{
+
+
+/*
+ *
+ * Resets the variables that keep track of the printer's current position. Used
+ * when there's a chance we've lost track of the printer's current position or
+ * done something that may have wiped it out, and we want to force dpost to set
+ * the printer's position before printing text or whatever. For example stroke or
+ * fill implicitly do a newpath, and that wipes out the current point, unless the
+ * calls were bracketed by a gsave/grestore pair.
+ *
+ */
+
+
+ lastx = -(slop + 1);
+ lasty = -1;
+
+} /* End of resetpos */
+
+
+/*****************************************************************************/
+
+
+static void
+t_init(void)
+{
+ static int initialized = FALSE; /* only do most things once */
+
+
+/*
+ *
+ * Called from devcntrl() after an "x init" command is read. Things only work if
+ * we've already seen the "x res" command, and much of the stuff, including the
+ * call to setup, should only be done once. Restricting everything to one call of
+ * setup (ie. the one in the prologue) means all the input files must have been
+ * formatted for the same device.
+ *
+ */
+
+
+ endtext(); /* moved - for cat'ed troff files */
+
+ if ( initialized == FALSE ) { /* only do this stuff once per job */
+ fontinit();
+ gotspecial = FALSE;
+ widthfac = (float) res /dev.res;
+ slop = pointslop * res / POINTS + .5;
+ rvslop = res * .025;
+ setup();
+ initialized = TRUE;
+ } /* End if */
+
+ hpos = vpos = 0; /* upper left corner */
+ setsize(t_size(10)); /* start somewhere */
+ reset(); /* force position and font stuff - later */
+
+} /* End of t_init */
+
+
+/*****************************************************************************/
+
+
+static void
+t_page(int pg)
+ /* troff's current page number */
+{
+ static int lastpg = 0; /* last one we started - for ENDPAGE */
+
+
+/*
+ *
+ * Called whenever we've finished the last page and want to get ready for the
+ * next one. Also used at the end of each input file, so we have to be careful
+ * about what's done. The first time through (up to the redirect(pg) call) output
+ * goes to /dev/null because of the redirect(-1) call made in conv().
+ *
+ * Adobe now recommends that the showpage operator occur after the page level
+ * restore so it can be easily redefined to have side-effects in the printer's VM.
+ * Although it seems reasonable I haven't implemented it, because it makes other
+ * things, like selectively setting manual feed or choosing an alternate paper
+ * tray, clumsy - at least on a per page basis.
+ *
+ */
+
+
+ if ( tf == stdout ) /* count the last page */
+ printed++;
+
+ endtext(); /* print the last line? */
+
+ fprintf(tf, "cleartomark\n");
+ fprintf(tf, "showpage\n");
+ fprintf(tf, "restore\n");
+ fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed);
+
+ redirect(pg);
+
+ fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1);
+ fprintf(tf, "save\n");
+ fprintf(tf, "mark\n");
+ writerequest(printed+1, tf);
+ fprintf(tf, "%d pagesetup\n", printed+1);
+ setcolor();
+
+ lastpg = pg; /* for the next ENDPAGE comment */
+ hpos = vpos = 0; /* get ready for the next page */
+ reset(); /* force position and font stuff - later */
+
+ seenpage = TRUE;
+
+} /* End of t_page */
+
+
+/*****************************************************************************/
+
+
+static void
+t_newline(void)
+{
+
+
+/*
+ *
+ * Just finished the last line. All we do is set the horizontal position to 0,
+ * although even that probably isn't necessary.
+ *
+ */
+
+
+ hpos = 0;
+
+} /* End of t_newline */
+
+
+/*****************************************************************************/
+
+
+int
+t_size(int n)
+ /* convert this to an internal size */
+{
+ int i; /* loop index */
+
+
+/*
+ *
+ * Converts a point size into an internal size that can be used as an index into
+ * pstab[]. The internal size is one plus the index of the least upper bound of
+ * n in pstab[], or nsizes if n is larger than all the listed sizes.
+ *
+ */
+
+
+ if ( n <= pstab[0] )
+ return(1);
+ else if (n >= pstab[nsizes-1])
+ return(nsizes);
+
+ for ( i = 0; n > pstab[i]; i++ ) ;
+
+ return(i+1);
+
+} /* End of t_size */
+
+
+/*****************************************************************************/
+
+
+static void
+setsize(int n)
+ /* new internal size */
+{
+
+
+/*
+ *
+ * Now using internal size n, where pstab[n-1] is the best available approximation
+ * to the size troff asked for.
+ *
+ */
+
+
+ size = n;
+
+} /* End of setsize */
+
+
+/*****************************************************************************/
+
+
+static void
+t_fp(int n, char *s, char *si)
+ /* n - this position */
+ /* s - now has this font mounted */
+ /* si - its internal number */
+
+
+{
+
+
+/*
+ *
+ * Updates nfonts and the array that keeps track of the mounted fonts. Called from
+ * loadfont() after an "x font pos font" command is read, and if pos is larger than
+ * the current value assigned to nfonts we set gotspecial to FALSE to make sure
+ * t_font() loads all the special fonts after the last legitimate font position.
+ *
+ */
+
+
+ fontname[n].name = s;
+ fontname[n].number = atoi(si);
+
+ if ( n == lastfont ) /* force a call to t_sf() */
+ lastfont = -1;
+
+ if ( n > nfonts ) { /* got more positions */
+ nfonts = n;
+ gotspecial = FALSE;
+ } /* End if */
+
+} /* End of t_fp */
+
+
+/*****************************************************************************/
+
+int
+t_font(char *s)
+ /* use font in this position next */
+{
+ int n;
+
+
+/*
+ *
+ * Converts the string *s into an integer and checks to make sure it's a legal
+ * font position. Also arranges to mount all the special fonts after the last
+ * legitimate font (by calling loadspecial()), provided it hasn't already been
+ * done.
+ *
+ */
+
+
+ n = atoi(s);
+
+ if ( seenpage == TRUE ) {
+ if ( n < 0 || n > nfonts )
+ error(FATAL, "illegal font position %d", n);
+
+ if ( gotspecial == FALSE )
+ loadspecial();
+ } /* End if */
+
+ return(n);
+
+} /* End of t_font */
+
+
+/*****************************************************************************/
+
+
+static void
+setfont(int n)
+ /* use the font mounted here */
+{
+
+
+/*
+ *
+ * troff wants to use the font that's been mounted in position n. All we do here
+ * is update the variable that keeps track of the current position. PostScript
+ * font changes are handled in t_sf(), and are only generated right before we're
+ * ready to print or draw something.
+ *
+ */
+
+
+ if ( n < 0 || n > NFONT )
+ error(FATAL, "illegal font %d", n);
+ if ( fontname[n].name == NULL && fontname[n].number == 0)
+ loaddefault();
+ if ( fontname[n].name == NULL && fontname[n].number == 0)
+ error(FATAL,
+ "font %d not loaded: check 'dpost' input for 'x font %d XXX' before 'f%d'",
+ n, n, n);
+
+ font = n;
+
+} /* End of setfont */
+
+
+/*****************************************************************************/
+
+void
+t_sf(void)
+{
+ int fnum; /* internal font number */
+
+
+/*
+ *
+ * Called whenever we need to use a new font or size. Only done right before we
+ * print a character. The seenfonts[] array keeps track of the fonts we've used.
+ * Helps manage host resident fonts and the DOCUMENTFONTS comment that's put out
+ * at the end of the job. The array is indexed by internal number. Only works for
+ * fonts that have internal numbers less than or equal to MAXINTERNAL.
+ *
+ */
+
+
+ if ( fontname[font].name == NULL )
+ return;
+
+ endtext();
+
+ if ( (fnum = fontname[font].number) > MAXINTERNAL || fnum < 0 )
+ fnum = 0;
+
+ if ( fnum > 0 && seenfonts[fnum] == 0 && hostfontdir != NULL ) {
+ sprintf(temp, "%s/%s", hostfontdir, fontname[font].name);
+ if ( access(temp, 04) == 0 )
+ doglobal(temp);
+ } /* End if */
+
+ if ( tf == stdout ) {
+ lastfont = font;
+ lastsize = size;
+ if ( seenfonts[fnum] == 0 )
+ documentfonts();
+ seenfonts[fnum] = 1;
+ } /* End if */
+
+ fprintf(tf, "%d %s f\n", pstab[size-1], fontname[font].name);
+
+ if ( fontheight != 0 || fontslant != 0 )
+ fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : pstab[size-1]);
+
+} /* End of t_sf */
+
+
+/*****************************************************************************/
+
+
+static void
+t_charht(int n)
+ /* use this as the character height */
+{
+
+/*
+ *
+ * Remembers the requested height, from 'x H n'. Forces a call to t_sf(), which
+ * is where the real work is done, by setting lastfont to -1.
+ *
+ */
+
+ fontheight = (n == pstab[size-1]) ? 0 : n;
+ lastfont = -1;
+
+} /* End of t_charht */
+
+
+/*****************************************************************************/
+
+
+static void
+t_slant(int n)
+ /* slant characters this many degrees */
+{
+
+/*
+ *
+ * Remembers the requested slant, from 'x X n'. Forces a call to t_sf(), which
+ * is where the real work is done, by setting lastfont to -1.
+ *
+ */
+
+ fontslant = n;
+ lastfont = -1;
+
+} /* End of t_slant */
+
+
+/*****************************************************************************/
+
+
+static void
+t_reset(int c)
+ /* pause or restart */
+{
+
+/*
+ *
+ * Found an "x stop" or "x pause" command. Although nothing's done here we could
+ * add code to reset everything so dpost could handle multiple files formatted for
+ * different devices.
+ *
+ */
+
+
+} /* End of t_reset */
+
+
+/*****************************************************************************/
+
+
+static void
+t_trailer(void)
+{
+
+/*
+ *
+ * Called after we find an "x trailer" in the input file. Forcing out the last
+ * page is done at the end of conv(), but probably belongs here.
+ *
+ */
+
+
+ endtext();
+
+} /* End of t_trailer */
+
+
+/*****************************************************************************/
+
+
+void
+hgoto(int n)
+ /* new horizontal position */
+{
+
+
+/*
+ *
+ * Want to be at this absolute horizontal position next. Actual motion commands
+ * are generated in oput(), charlib(), and the drawing routines.
+ *
+ */
+
+
+ hpos = n;
+
+} /* End of hgoto */
+
+
+/*****************************************************************************/
+
+
+static void
+hmot(int n)
+ /* move this far horizontally */
+{
+
+/*
+ *
+ * Handles relative horizontal motion. troff's current positon, as recorded in
+ * in hpos, is changed by n units. Usually called right before we're supposed to
+ * print a character.
+ *
+ */
+
+
+ hpos += n;
+
+} /* End of hmot */
+
+
+/*****************************************************************************/
+
+
+void
+vgoto(int n)
+ /* new vertical position */
+{
+
+/*
+ *
+ * Moves vertically in troff's coordinate system to absolute position n.
+ *
+ */
+
+
+ vpos = n;
+
+} /* End of vgoto */
+
+
+/*****************************************************************************/
+
+
+static void
+vmot(int n)
+ /* move this far vertically */
+{
+
+/*
+ *
+ * Handles relative vertical motion of n units in troff's coordinate system.
+ *
+ */
+
+
+ vpos += n;
+
+} /* End of vmot */
+
+
+/*****************************************************************************/
+
+
+void
+xymove(int x, int y)
+ /* this is where we want to be */
+{
+
+/*
+ *
+ * Makes sure the post-processor and printer agree about the current position.
+ *
+ */
+
+
+ hgoto(x);
+ vgoto(y);
+
+ fprintf(tf, "%d %d m\n", hpos, vpos);
+
+ lastx = hpos;
+ lasty = vpos;
+
+} /* End of xymove */
+
+
+/*****************************************************************************/
+
+
+static void
+put1s(char *s)
+ /* find and print this character */
+{
+ static int i = 0; /* last one we found - usually */
+
+/*
+ *
+ * *s points to the start of a two character string that represents one of troff's
+ * special characters. To print it we first look for *s in the chname[] array using
+ * chtab[i] to find the string representing character i in chname[]. If the lookup
+ * is successful we add 128 to i and ask put1() to finish printing the character.
+ * We remember the index where the last character was found because requests to
+ * print a special character often come in bunches (eg. drawing lines with \(ru).
+ *
+ */
+
+
+ if ( strcmp(s, &chname[chtab[i]]) != 0 )
+ for ( i = 0; i < nchtab; i++ )
+ if ( strcmp(&chname[chtab[i]], s) == 0 )
+ break;
+
+ if ( i < nchtab )
+ put1(i + 128);
+ else i = 0;
+
+} /* End of put1s */
+
+
+/*****************************************************************************/
+
+
+static void
+put1(int c)
+ /* want to print this character */
+{
+
+ int i; /* character code from fitab */
+ int j; /* number of fonts we've checked so far */
+ int k; /* font we're currently looking at */
+ char *pw; /* font widthtab and */
+ char *p; /* and codetab where c was found */
+ int code; /* code used to get c printed */
+ int ofont; /* font when we started */
+
+
+/*
+ *
+ * Arranges to have character c printed. If c < 128 it's a simple ASCII character,
+ * otherwise it's a special character. Things done here have to agree with the way
+ * the font tables were built by makedev, and work as follows. First we subtract
+ * 32 from c because the tables don't record the non-graphic ASCII characters.
+ * If fitab[k][c] isn't zero the character is on font k and the value is an index
+ * that can be used to recover width and character code data from the other two
+ * tables. If fitab[k][c] is zero the character isn't defined on font k and we
+ * check the next font, which is found as follows. The current font is the first
+ * one we check, and it's followed by a circular search of all the remaining fonts
+ * that starts with the first special font and skips font position 0. If character
+ * c is found somewhere besides the current font we change to that font and use
+ * fitab[k][c] to locate missing data in the other two tables. The width of the
+ * character can be found at widthtab[k][c] while codetab[k][c] is whatever we
+ * need to tell the printer to have character c printed. lastc records the real
+ * name of the character because it's lost by the time oput() gets called but
+ * charlib() may need it.
+ *
+ * Took all the debugging stuff out because at least this part of the program is
+ * reasonably solid.
+ *
+ */
+
+
+ lastc = c; /* charlib() needs the name not the code */
+ if ( (c -= 32) <= 0 ) /* probably never happens */
+ return;
+
+ k = ofont = font;
+
+ if ( (i = fitab[k][c] & BMASK) != 0 ) { /* it's on this font */
+ p = codetab[font];
+ pw = widthtab[font];
+ } else if ( smnt > 0 ) { /* on special (we hope) */
+ for ( k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1) ) {
+ if ( k == 0 ) continue;
+ if ( (i = fitab[k][c] & BMASK) != 0 ) {
+ p = codetab[k];
+ pw = widthtab[k];
+ setfont(k);
+ break;
+ } /* End if */
+ } /* End for */
+ } /* End else */
+
+ if ( i != 0 && (code = p[i] & BMASK) != 0 ) {
+ lastw = widthfac * (((pw[i] & BMASK) * pstab[size-1] + unitwidth/2) / unitwidth);
+ oput(code);
+ } /* End if */
+
+ if ( font != ofont )
+ setfont(ofont);
+
+} /* End of put1 */
+
+
+/*****************************************************************************/
+
+
+static void
+oput(int c)
+ /* want to print this character */
+{
+
+/*
+ *
+ * Arranges to print the character whose code is c in the current font. All the
+ * actual positioning is done here, in charlib(), or in the drawing routines.
+ *
+ */
+
+
+ if ( textcount > MAXSTACK ) /* don't put too much on the stack? */
+ endtext();
+
+ if ( font != lastfont || size != lastsize )
+ t_sf();
+
+ if ( vpos != lasty )
+ endline();
+
+ starttext();
+
+ if ( ABS(hpos - lastx) > slop )
+ endstring();
+
+ if ( isascii(c) && isprint(c) )
+ switch ( c ) {
+ case '(':
+ case ')':
+ case '\\':
+ addchar('\\');
+
+ default:
+ addchar(c);
+ } /* End switch */
+ else if ( c > 040 )
+ addoctal(c);
+ else charlib(c);
+
+ lastx += lastw;
+
+} /* End of oput */
+
+
+/*****************************************************************************/
+
+
+static void
+starttext(void)
+{
+
+/*
+ * Called whenever we want to be sure we're ready to start collecting characters
+ * for the next call to PostScript procedure t (ie. the one that prints them). If
+ * textcount is positive we've already started, so there's nothing to do. The more
+ * complicated encoding schemes save text strings in the strings[] array and need
+ * detailed information about the strings when they're written to the output file
+ * in endtext().
+ *
+ */
+
+
+ if ( textcount < 1 ) {
+ switch ( encoding ) {
+ case 0:
+ case 1:
+ putc('(', tf);
+ break;
+
+ case 2:
+ case 3:
+ strptr = strings;
+ spacecount = 0;
+ line[1].str = strptr;
+ line[1].dx = 0;
+ line[1].spaces = 0;
+ line[1].start = hpos;
+ line[1].width = 0;
+ break;
+
+ case MAXENCODING+1: /* reverse video */
+ if ( lastend == -1 )
+ lastend = hpos;
+ putc('(', tf);
+ break;
+
+ case MAXENCODING+2: /* follow a funny baseline */
+ putc('(', tf);
+ break;
+ } /* End switch */
+ textcount = 1;
+ lastx = stringstart = hpos;
+ } /* End if */
+
+} /* End of starttext */
+
+
+/*****************************************************************************/
+
+
+void
+endtext(void)
+{
+
+ int i; /* loop index */
+
+
+/*
+ *
+ * Generates a call to the PostScript procedure that processes all the text we've
+ * accumulated - provided textcount is positive.
+ *
+ */
+
+ if ( textcount > 0 ) { /* started working on some text */
+ switch ( encoding ) {
+ case 0:
+ fprintf(tf, ")%d t\n", stringstart);
+ break;
+
+ case 1:
+ fprintf(tf, ")%d %d t\n", stringstart, lasty);
+ break;
+
+ case 2:
+ *strptr = '\0';
+ line[textcount].width = lastx - line[textcount].start;
+ if ( spacecount != 0 || textcount != 1 ) {
+ for ( i = textcount; i > 0; i-- )
+ fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width);
+ fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
+ } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
+ break;
+
+ case 3:
+ *strptr = '\0';
+ if ( spacecount != 0 || textcount != 1 ) {
+ for ( i = textcount; i > 0; i-- )
+ fprintf(tf, "(%s)%d", line[i].str, line[i].dx);
+ fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
+ } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
+ break;
+
+ case MAXENCODING+1:
+ fprintf(tf, ")%d ", stringstart);
+ fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop);
+ fprintf(tf, "t\n", stringstart);
+ lastend = (lastx + .5) + 2 * rvslop;
+ break;
+
+ case MAXENCODING+2:
+ fprintf(tf, ")%d %d t\n", stringstart, lasty);
+ break;
+ } /* End switch */
+ } /* End if */
+
+ textcount = 0;
+
+} /* End of endtext */
+
+
+/*****************************************************************************/
+
+
+static void
+endstring(void)
+{
+ int dx;
+
+/*
+ *
+ * Horizontal positions are out of sync. End the last open string, adjust the
+ * printer's position, and start a new string. Assumes we've already started
+ * accumulating text.
+ *
+ */
+
+
+ switch ( encoding ) {
+ case 0:
+ case 1:
+ fprintf(tf, ")%d(", stringstart);
+ textcount++;
+ lastx = stringstart = hpos;
+ break;
+
+ case 2:
+ case 3:
+ dx = hpos - lastx;
+ if ( spacecount++ == 0 )
+ line[textcount].dx = dx;
+ if ( line[textcount].dx != dx ) {
+ *strptr++ = '\0';
+ line[textcount].width = lastx - line[textcount].start;
+ line[++textcount].str = strptr;
+ *strptr++ = ' ';
+ line[textcount].dx = dx;
+ line[textcount].start = lastx;
+ line[textcount].width = 0;
+ line[textcount].spaces = 1;
+ } else {
+ *strptr++ = ' ';
+ line[textcount].spaces++;
+ } /* End else */
+ lastx += dx;
+ break;
+
+ case MAXENCODING+1:
+ fprintf(tf, ")%d(", stringstart);
+ textcount++;
+ lastx = stringstart = hpos;
+ break;
+
+ case MAXENCODING+2:
+ endtext();
+ starttext();
+ break;
+
+ } /* End switch */
+
+} /* End of endstring */
+
+
+/*****************************************************************************/
+
+
+static void
+endline(void)
+{
+
+/*
+ *
+ * The vertical position has changed. Dump any accumulated text, then adjust
+ * the printer's vertical position.
+ *
+ */
+
+
+ endtext();
+
+ if ( encoding == 0 || encoding == MAXENCODING+1 )
+ fprintf(tf, "%d %d m\n", hpos, vpos);
+
+ lastx = stringstart = lastend = hpos;
+ lasty = vpos;
+
+} /* End of endline */
+
+
+/*****************************************************************************/
+
+
+static void
+addchar(int c)
+ /* next character in current string */
+{
+
+/*
+ *
+ * Does whatever is needed to add character c to the current string.
+ *
+ */
+
+
+ switch ( encoding ) {
+ case 0:
+ case 1:
+ putc(c, tf);
+ break;
+
+ case 2:
+ case 3:
+ *strptr++ = c;
+ break;
+
+ case MAXENCODING+1:
+ case MAXENCODING+2:
+ putc(c, tf);
+ break;
+ } /* End switch */
+
+} /* End of addchar */
+
+
+/*****************************************************************************/
+
+
+static void
+addoctal(int c)
+ /* add it as an octal escape */
+{
+
+
+/*
+ *
+ * Adds c to the current string as an octal escape \ddd.
+ *
+ */
+
+
+ switch ( encoding ) {
+ case 0:
+ case 1:
+ fprintf(tf, "\\%o", c);
+ break;
+
+ case 2:
+ case 3:
+ sprintf(strptr, "\\%o", c);
+ strptr += strlen(strptr);
+ break;
+
+ case MAXENCODING+1:
+ case MAXENCODING+2:
+ fprintf(tf, "\\%o", c);
+ break;
+ } /* End switch */
+
+} /* End of addoctal */
+
+
+/*****************************************************************************/
+
+
+static void
+charlib(int code)
+ /* either 1 or 2 */
+{
+ char *name; /* name of the character */
+ char tname[10]; /* in case it's a single ASCII character */
+
+
+/*
+ *
+ * Called from oput() for characters having codes less than 040. Special files
+ * that define PostScript procedures for certain characters can be found in
+ * directory *fontdir/devpost/charlib. If there's a file that has the same name as
+ * the character we're trying to print it's copied to the output file, otherwise
+ * nothing, except some positioning, is done.
+ *
+ * All character definitions are only made once. Subsequent requests to print the
+ * character generate a call to a procedure that begins with the prefix build_ and
+ * ends with the character's name. Special characters that are assigned codes
+ * other than 1 are assumed to have additional data files that should be copied
+ * to the output file immediately after the build_ call. Those data files should
+ * end in the suffix .map, and usually will be a hex representation of a bitmap.
+ *
+ */
+
+
+ endtext();
+
+ if ( lastc < 128 ) { /* just a simple ASCII character */
+ sprintf(tname, "%.3o", lastc);
+ name = tname;
+ } else name = &chname[chtab[lastc - 128]];
+
+ if ( downloaded[lastc] == 0 ) {
+ sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name);
+ if ( access(temp, 04) == 0 && doglobal(temp) == TRUE ) {
+ downloaded[lastc] = 1;
+ t_sf();
+ } /* End if */
+ } /* End if */
+
+ if ( downloaded[lastc] == 1 ) {
+ xymove(hpos, vpos);
+ fprintf(tf, "%d build_%s\n", (int) lastw, name);
+ if ( code != 1 ) { /* get the bitmap or whatever */
+ sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name);
+ if ( access(temp, 04) == 0 && tf == stdout )
+ cat(temp);
+ } /* End if */
+ fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos);
+ } /* End if */
+
+} /* End of charlib */
+
+
+/*****************************************************************************/
+
+
+int
+doglobal(char *name)
+ /* copy this to the output - globally */
+{
+ int val = FALSE; /* returned to the caller */
+
+
+/*
+ *
+ * Copies file *name to the output file and brackets it with whatever commands are
+ * needed to have it exported to the global environment. TRUE is returned if we
+ * successfully add file *name to the output file.
+ *
+ */
+
+
+ if ( tf == stdout ) {
+ endtext();
+ fprintf(tf, "cleartomark restore\n");
+ fprintf(tf, "%s", BEGINGLOBAL);
+ val = cat(name);
+ fprintf(tf, "%s", ENDGLOBAL);
+ fprintf(tf, "save mark\n");
+ reset();
+ } /* End if */
+
+ return(val);
+
+} /* End of doglobal */
+
+
+/*****************************************************************************/
+
+
+static void
+documentfonts(void)
+{
+ FILE *fp_in; /* PostScript font name read from here */
+ FILE *fp_out; /* and added to this file */
+
+
+/*
+ *
+ * Whenever a new font is used we try to record the appropriate PostScript font
+ * name in *temp_file for the DOCUMENTFONTS comment that's put out in done().
+ * By default PostScript font names are found in /usr/lib/font/devpost. Fonts
+ * that have a .name file are recorded in *temp_file. The first string in that
+ * file is expected to be that font's (long) PostScript name.
+ *
+ */
+
+
+ if ( temp_file == NULL ) /* generate a temp file name */
+ if ( (temp_file = tempnam(TEMPDIR, "dpost")) == NULL )
+ return;
+
+ sprintf(temp, "%s/dev%s/%s.name", fontdir, realdev, fontname[font].name);
+
+ if ( (fp_in = fopen(temp, "r")) != NULL ) {
+ if ( (fp_out = fopen(temp_file, "a")) != NULL ) {
+ if ( fscanf(fp_in, "%s", temp) == 1 ) {
+ if ( docfonts++ == 0 )
+ fprintf(fp_out, "%s", DOCUMENTFONTS);
+ else if ( (docfonts - 1) % 8 == 0 )
+ fprintf(fp_out, "\n%s", CONTINUECOMMENT);
+ fprintf(fp_out, " %s", temp);
+ } /* End if */
+ fclose(fp_out);
+ } /* End if */
+ fclose(fp_in);
+ } /* End if */
+
+} /* End of documentfonts */
+
+
+/*****************************************************************************/
+
+
+static void
+redirect(int pg)
+ /* next page we're printing */
+{
+ static FILE *fp_null = NULL; /* if output is turned off */
+
+
+/*
+ *
+ * If we're not supposed to print page pg, tf will be directed to /dev/null,
+ * otherwise output goes to stdout.
+ *
+ */
+
+
+ if ( pg >= 0 && in_olist(pg) == ON )
+ tf = stdout;
+ else if ( (tf = fp_null) == NULL )
+ tf = fp_null = fopen("/dev/null", "w");
+
+} /* End of redirect */
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/dpost.h b/usr/src/cmd/lp/filter/postscript/dpost/dpost.h
new file mode 100644
index 0000000000..49b469a001
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/dpost.h
@@ -0,0 +1,196 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ *
+ * Definitions used by the troff post-processor for PostScript printers.
+ *
+ * DEVNAME should be the name of a device whose font files accurately describe
+ * what's available on the target printer. It's a string that's combined with
+ * "/usr/lib/font/dev" to locate the final font directory. It can be changed
+ * using the -T option, but you may end up getting garbage - the character code
+ * field must agree with PostScript's character encoding scheme for each font and
+ * troff's one or two character font names must be mapped into the appropriate
+ * PostScript font names (typically in the prologue)
+ *
+ *
+ */
+
+#define DEVNAME "post" /* name of the target printer */
+
+/*
+ *
+ * NFONT is the most font positions we'll allow. It's set ridiculously high for no
+ * good reason.
+ *
+ */
+
+#define NFONT 60 /* max number of font positions */
+
+/*
+ *
+ * SLOP controls how much horizontal positioning error we'll accept and primarily
+ * helps when we're emulating another device. It's used when we output characters
+ * in oput() to check if troff and the printer have gotten too far out of sync.
+ * Given in units of points and can be changed using the -S option. Converted to
+ * machine units in t_init() after the resolution is known.
+ *
+ */
+
+#define SLOP .2 /* horizontal error - in points */
+
+/*
+ *
+ * Fonts are assigned unique internal numbers (positive integers) in their ASCII
+ * font files. MAXINTERNAL is the largest internal font number that lets the host
+ * resident and DOCUMENTFONTS stuff work. Used to allocate space for an array that
+ * keeps track of what fonts we've seen and perhaps downloaded - could be better!
+ *
+ */
+
+#define MAXINTERNAL 256
+
+/*
+ *
+ * Several different text line encoding schemes are supported. Print time should
+ * decrease as the value assigned to encoding (in dpost.c) increases, although the
+ * only encoding that's well tested is the lowest level one, which produces output
+ * essentially identical to the original version of dpost. Setting DFLTENCODING to
+ * 0 will give you the most stable (but slowest) encoding. The encoding scheme can
+ * also be set on the command line using the -e option. Faster methods are based
+ * on widthshow and may not place words exactly where troff wanted, but errors will
+ * usually not be noticeable.
+ *
+ */
+
+#define MAXENCODING 3
+
+#ifndef DFLTENCODING
+#define DFLTENCODING 0
+#endif
+
+/*
+ *
+ * The encoding scheme controls how lines of text are output. In the lower level
+ * schemes words and horizontal positions are put on the stack as they're read and
+ * when they're printed it's done in reverse order - the first string printed is
+ * the one on top of the stack and it's the last one on the line. Faster methods
+ * may be forced to reverse the order of strings on the stack, making the top one
+ * the first string on the line. STRINGSPACE sets the size of a character array
+ * that's used to save the strings that make up a line of text so they can be
+ * output in reverse order or perhaps combined in groups for widthshow.
+ *
+ * MAXSTACK controls how far we let PostScript's operand stack grow and determines
+ * the number of strings we'll save before printing all or part of a line of text.
+ * The internal limit in PostScript printers built by Adobe is 500, so MAXSTACK
+ * should never be bigger than about 240!
+ *
+ * Line is a structure used to keep track of the words (or rather strings) on the
+ * current line that have been read but not printed. dx is the width troff wants
+ * to use for a space in the current string. start is where the string began, width
+ * is the total width of the string, and spaces is the number of space characters
+ * in the current string. *str points to the start of the string in the strings[]
+ * array. The Line structure is only used in the higher level encoding schemes.
+ *
+ */
+
+#define MAXSTACK 50 /* most strings we'll save at once */
+#define STRINGSPACE 2000 /* bytes available for string storage */
+
+typedef struct {
+
+ char *str; /* where the string is stored */
+ int dx; /* width of a space */
+ int spaces; /* number of space characters */
+ int start; /* horizontal starting position */
+ int width; /* and its total width */
+
+} Line;
+
+/*
+ *
+ * Simple stuff used to map unrecognized font names into something reasonable. The
+ * mapping array is initialized using FONTMAP and used in loadfont() whenever the
+ * job tries to use a font that we don't recognize. Normally only needed when we're
+ * emulating another device.
+ *
+ */
+
+typedef struct {
+
+ char *name; /* font name we're looking for */
+ char *use; /* and this is what we should use */
+
+} Fontmap;
+
+#define FONTMAP \
+ \
+ { \
+ "G", "H", \
+ "LO", "S", \
+ "S2", "S", \
+ "GI", "HI", \
+ "HM", "H", \
+ "HK", "H", \
+ "HL", "H", \
+ "PA", "R", \
+ "PI", "I", \
+ "PB", "B", \
+ "PX", "BI", \
+ NULL, NULL, \
+ }
+
+/*
+ *
+ * The Fontmap stuff isn't quite enough if we expect to do a good job emulating
+ * other devices. A recognized font in *realdev's tables may be have a different
+ * name in *devname's tables, and using the *realdev font may not be the best
+ * choice. The fix is to use an optional lookup table for *devname that's used to
+ * map font names into something else before anything else is done. The table we
+ * use is /usr/lib/font/dev*realdev/fontmaps/devname and if it exists getdevmap()
+ * uses the file to fill in a Devfontmap array. Then whenever an "x font pos name"
+ * command is read mapdevfont() uses the lookup table to map name into something
+ * else before loadfont() is called.
+ *
+ */
+
+typedef struct {
+
+ char name[3]; /* map this font name */
+ char use[3]; /* into this one */
+
+} Devfontmap;
+
+/*
+ *
+ * Some of the non-integer valued functions in dpost.c.
+ *
+ */
+
+char *mapfont();
+char *mapdevfont();
+
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/draw.c b/usr/src/cmd/lp/filter/postscript/dpost/draw.c
new file mode 100644
index 0000000000..e357592748
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/draw.c
@@ -0,0 +1,777 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * Drawing routines used by dpost. Almost no real work is done here. Instead
+ * the required calculations are done in special Postscript procedures that
+ * include:
+ *
+ *
+ * Dl
+ *
+ * x1 y1 x y Dl -
+ *
+ * Starts a new path and then draws a line from the current point
+ * (x, y) to (x1, y1).
+ *
+ * De
+ *
+ * x y a b De -
+ *
+ * Starts a new path and then draws an ellipse that has its left side
+ * at the current point (x, y) and horizontal and vertical axes lengths
+ * given by a and b respectively.
+ *
+ * Da
+ *
+ * x y dx1 dy1 dx2 dy2 Da -
+ *
+ * Starts a new segment and then draws a circular arc from the current
+ * point (x, y) to (x + dx1 + dx2, y + dy1 + dy2). The center of the
+ * circle is at (x + dx1, y + dy1). Arcs always go counter-clockwise
+ * from the starting point to the end point.
+ *
+ * DA
+ *
+ * x y dx1 dy1 dx2 dy2 DA -
+ *
+ * Draws a clockwise arc from (x, y) to (x + dx1 + dx2, y + dy1 + dy2)
+ * with center at (x + dx1, y + dy1). Only needed when we're building
+ * large paths that use arcs and want to control the current point. The
+ * arguments passed to drawarc() will be whatever they would have been
+ * for a counter-clockwise arc, so we need to map them into appropriate
+ * arguments for PostScript's arcn operator. The mapping is,
+ *
+ * x = hpos + dx1' + dx2'
+ * y = vpos + dy1' + dy2'
+ * dx1 = -dx2'
+ * dy1 = -dy2'
+ * dx2 = -dx1'
+ * dy2 = -dy1'
+ *
+ * where primed values represent the drawarc() arguments and (hpos, vpos)
+ * is our current position.
+ *
+ * Ds
+ *
+ * x0 y0 x1 y1 x2 y2 Ds -
+ *
+ * Starts a new segment and then draws a quadratic spline connecting
+ * point ((x0 + x1)/2, (y0 + y1)/2) to ((x1 + x2)/2, (y1 + y2)/2).
+ * The points used in Postscript's curveto procedure are given by,
+ *
+ * x0' = (x0 + 5 * x1) / 6
+ * x1' = (x2 + 5 * x1) / 6
+ * x2' = (x1 + x2) / 2
+ *
+ * with similar equations for the y coordinates.
+ *
+ * By default all the PostScript drawing procedures begin with a newpath (just to
+ * be safe) and end with a stroke, which essentially isolates the path elements
+ * built by the drawing procedures. In order to accommodate big paths built from
+ * smaller pieces each of the PostScript drawing procedures can forced to retain
+ * the path that's being built. That's what happens in beginpath() when an "x X
+ * BeginPath" command is read. beginpath() sets the PostScript variable inpath to
+ * true, and that essentially eliminates the newpath/stroke pair that bracket the
+ * individual pieces. In that case the path is terminated and drawn when dpost
+ * reads an "x X DrawPath" command.
+ *
+ * Early versions of dpost included the PostScript drawing procedures as part of
+ * the prologue, and as a result they were included with every job, even if they
+ * were never used. This version has separated the drawing procedures from the
+ * default prologue (they're now in *drawfile) and only includes them if they're
+ * really needed, which is yet another convenient violation of page independence.
+ * Routine getdraw() is responsible for adding *drawfile to the output file, and
+ * if it can't read *drawfile it continues on as if nothing happened. That means
+ * everything should still work if you append *drawfile to *prologue and then
+ * delete *drawfile.
+ *
+ */
+
+
+#include <stdio.h>
+#include <math.h>
+
+#include "gen.h" /* general purpose definitions */
+#include "ext.h" /* external variable definitions */
+
+
+int gotdraw = FALSE; /* TRUE when *drawfile has been added */
+int gotbaseline = FALSE; /* TRUE after *baselinefile is added */
+int inpath = FALSE; /* TRUE if we're putting pieces together */
+
+
+/*
+ *
+ * All these should be defined in file dpost.c.
+ *
+ */
+
+
+extern int hpos;
+extern int vpos;
+extern int encoding;
+extern int maxencoding;
+extern int realencoding;
+
+extern char *drawfile;
+extern char *baselinefile;
+extern FILE *tf;
+
+void drawcirc(int);
+void drawellip(int, int);
+static void parsebuf(char *);
+
+/*****************************************************************************/
+
+
+void
+getdraw(void)
+{
+
+
+/*
+ *
+ * Responsible for making sure the PostScript drawing procedures are downloaded
+ * from *drawfile. Stuff is done at most once per job, and only if the job needs
+ * them. For now I've decided not to quit if we can't read the drawing file. That
+ * pretty much assumes an old version of prologue is being used that includes all
+ * the drawing procedures.
+ *
+ */
+
+
+ if ( gotdraw == FALSE && access(drawfile, 04) == 0 )
+ doglobal(drawfile);
+
+ if ( tf == stdout )
+ gotdraw = TRUE;
+
+} /* End of getdraw */
+
+
+/*****************************************************************************/
+
+
+void
+drawline(int dx, int dy)
+ /* endpoint is (hpos+dx, vpos+dy) */
+{
+
+/*
+ *
+ * Draws a line from (hpos, vpos) to (hpos+dx, vpos+dy), and leaves the current
+ * position at the endpoint.
+ *
+ */
+
+
+ if ( dx == 0 && dy == 0 )
+ drawcirc(1);
+ else fprintf(tf, "%d %d %d %d Dl\n", hpos + dx, vpos + dy, hpos, vpos);
+
+ hgoto(hpos+dx); /* where troff expects to be */
+ vgoto(vpos+dy);
+
+ resetpos(); /* not sure where the printer is */
+
+} /* End of drawline */
+
+
+/*****************************************************************************/
+
+
+void
+drawcirc(int d)
+ /* diameter of the circle */
+{
+
+/*
+ *
+ * Draws a circle of diameter d with the left 'side' of the circle at the
+ * current point. After we're finished drawing we move the current position
+ * to the right side.
+ *
+ */
+
+ drawellip(d, d);
+
+} /* End of drawcirc */
+
+
+/*****************************************************************************/
+
+
+void
+drawellip(int a, int b)
+ /* axes lengths for the ellipse */
+{
+
+/*
+ *
+ * Draws an ellipse having axes lengths horizontally and vertically of a and
+ * b. The left side of the ellipse is at the current point. After we're done
+ * drawing the path we move the current position to the right side.
+ *
+ */
+
+
+ if ( a == 0 && b == 0 )
+ return;
+
+ fprintf(tf, "%d %d %d %d De\n", hpos, vpos, a, b);
+
+ hgoto(hpos + a); /* where troff expects to be */
+ vgoto(vpos);
+
+ resetpos(); /* not sure where the printer is */
+
+} /* End of drawellip */
+
+
+/*****************************************************************************/
+
+
+void
+drawarc(int dx1, int dy1, int dx2, int dy2, int c)
+ /* dx1, dy1 - vector from current pos to center */
+ /* dx2, dy2 - from center to end of the arc */
+ /* c - clockwise if c is A */
+{
+
+/*
+ *
+ * If c isn't set to 'A' a counter-clockwise arc is drawn from the current point
+ * (hpos, vpos) to (hpos+dx1+dx2, vpos+dy1+dy2). The center of the circle is the
+ * point (hpos+dx1, vpos+dy1). If c is 'A' the arc goes clockwise from the point
+ * (hpos+dx1+dx2, vpos+dy1+dy2) to (hpos, vpos). Clockwise arcs are only needed
+ * if we're building a larger path out of pieces that include arcs, and want to
+ * have PostScript manage the path for us. Arguments (for a clockwise arc) are
+ * what would have been supplied if the arc was drawn in a counter-clockwise
+ * direction, and are converted to values suitable for use with PostScript's arcn
+ * operator.
+ *
+ */
+
+
+ if ( (dx1 != 0 || dy1 != 0) && (dx2 != 0 || dy2 != 0) )
+ if ( c != 'A' )
+ fprintf(tf, "%d %d %d %d %d %d Da\n", hpos, vpos, dx1, dy1, dx2, dy2);
+ else fprintf(tf, "%d %d %d %d %d %d DA\n", hpos+dx1+dx2, vpos+dy1+dy2,
+ -dx2, -dy2, -dx1, -dy1);
+
+ hgoto(hpos + dx1 + dx2); /* where troff expects to be */
+ vgoto(vpos + dy1 + dy2);
+
+ resetpos(); /* not sure where the printer is */
+
+} /* End of drawarc */
+
+
+/*****************************************************************************/
+
+
+void
+drawspline(FILE *fp, int flag)
+ /* fp - input for point list */
+ /* flag - flag!=1 connect end points */
+{
+
+
+ int x[100], y[100];
+ int i, N;
+
+
+/*
+ *
+ * Spline drawing routine for Postscript printers. The complicated stuff is
+ * handled by procedure Ds, which should be defined in the library file. I've
+ * seen wrong implementations of troff's spline drawing, so fo the record I'll
+ * write down the parametric equations and the necessary conversions to Bezier
+ * cubic splines (as used in Postscript).
+ *
+ *
+ * Parametric equation (x coordinate only):
+ *
+ *
+ * (x2 - 2 * x1 + x0) 2 (x0 + x1)
+ * x = ------------------ * t + (x1 - x0) * t + ---------
+ * 2 2
+ *
+ *
+ * The coefficients in the Bezier cubic are,
+ *
+ *
+ * A = 0
+ * B = (x2 - 2 * x1 + x0) / 2
+ * C = x1 - x0
+ *
+ *
+ * while the current point is,
+ *
+ * current-point = (x0 + x1) / 2
+ *
+ * Using the relationships given in the Postscript manual (page 121) it's easy to
+ * see that the control points are given by,
+ *
+ *
+ * x0' = (x0 + 5 * x1) / 6
+ * x1' = (x2 + 5 * x1) / 6
+ * x2' = (x1 + x2) / 2
+ *
+ *
+ * where the primed variables are the ones used by curveto. The calculations
+ * shown above are done in procedure Ds using the coordinates set up in both
+ * the x[] and y[] arrays.
+ *
+ * A simple test of whether your spline drawing is correct would be to use cip
+ * to draw a spline and some tangent lines at appropriate points and then print
+ * the file.
+ *
+ */
+
+
+ for ( N = 2; N < sizeof(x)/sizeof(x[0]); N++ )
+ if (fscanf(fp, "%d %d", &x[N], &y[N]) != 2)
+ break;
+
+ x[0] = x[1] = hpos;
+ y[0] = y[1] = vpos;
+
+ for (i = 1; i < N; i++) {
+ x[i+1] += x[i];
+ y[i+1] += y[i];
+ } /* End for */
+
+ x[N] = x[N-1];
+ y[N] = y[N-1];
+
+ for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++)
+ fprintf(tf, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]);
+
+ hgoto(x[N]); /* where troff expects to be */
+ vgoto(y[N]);
+
+ resetpos(); /* not sure where the printer is */
+
+} /* End of drawspline */
+
+
+/*****************************************************************************/
+
+
+void
+beginpath(char *buf, int copy)
+ /* buf - whatever followed "x X BeginPath" */
+ /* copy - ignore *buf if FALSE */
+{
+
+/*
+ *
+ * Called from devcntrl() whenever an "x X BeginPath" command is read. It's used
+ * to mark the start of a sequence of drawing commands that should be grouped
+ * together and treated as a single path. By default the drawing procedures in
+ * *drawfile treat each drawing command as a separate object, and usually start
+ * with a newpath (just as a precaution) and end with a stroke. The newpath and
+ * stroke isolate individual drawing commands and make it impossible to deal with
+ * composite objects. "x X BeginPath" can be used to mark the start of drawing
+ * commands that should be grouped together and treated as a single object, and
+ * part of what's done here ensures that the PostScript drawing commands defined
+ * in *drawfile skip the newpath and stroke, until after the next "x X DrawPath"
+ * command. At that point the path that's been built up can be manipulated in
+ * various ways (eg. filled and/or stroked with a different line width).
+ *
+ * String *buf is unnecessary and is only included for compatibility with an early
+ * verion of that's still in use. In that version "x X BeginObject" marked the
+ * start of a graphical object, and whatever followed it was passed along in *buf
+ * and copied to the output file. Color selection is one of the options that's
+ * available in parsebuf(), so if we get here we add *colorfile to the output
+ * file before doing anything important.
+ *
+ */
+
+
+
+ if ( inpath == FALSE ) {
+ endtext();
+ getdraw();
+ getcolor();
+ fprintf(tf, "gsave\n");
+ fprintf(tf, "newpath\n");
+ fprintf(tf, "%d %d m\n", hpos, vpos);
+ fprintf(tf, "/inpath true def\n");
+ if ( copy == TRUE )
+ fprintf(tf, "%s", buf);
+ inpath = TRUE;
+ } /* End if */
+
+} /* End of beginpath */
+
+
+/*****************************************************************************/
+
+
+void
+drawpath(char *buf, int copy)
+{
+
+/*
+ *
+ * Called from devcntrl() whenever an "x X DrawPath" command is read. It marks the
+ * end of the path started by the last "x X BeginPath" command and uses whatever
+ * has been passed along in *buf to manipulate the path (eg. fill and/or stroke
+ * the path). Once that's been done the drawing procedures are restored to their
+ * default behavior in which each drawing command is treated as an isolated path.
+ * The new version (called after "x X DrawPath") has copy set to FALSE, and calls
+ * parsebuf() to figure out what goes in the output file. It's a feeble attempt
+ * to free users and preprocessors (like pic) from having to know PostScript. The
+ * comments in parsebuf() describe what's handled.
+ *
+ * In the early version a path was started with "x X BeginObject" and ended with
+ * "x X EndObject". In both cases *buf was just copied to the output file, and
+ * was expected to be legitimate PostScript that manipulated the current path.
+ * The old escape sequence will be supported for a while (for Ravi), and always
+ * call this routine with copy set to TRUE.
+ *
+ *
+ */
+
+
+ if ( inpath == TRUE ) {
+ if ( copy == TRUE )
+ fprintf(tf, "%s", buf);
+ else parsebuf(buf);
+ fprintf(tf, "grestore\n");
+ fprintf(tf, "/inpath false def\n");
+ reset();
+ inpath = FALSE;
+ } /* End if */
+
+} /* End of drawpath */
+
+
+/*****************************************************************************/
+
+
+static void
+parsebuf(char *buf)
+ /* whatever followed "x X DrawPath" */
+{
+ char *p; /* usually the next token */
+ char *p1; /* for grabbing arguments */
+ char *pend; /* end of the original string (ie. *buf) */
+ int gsavelevel = 0; /* non-zero if we've done a gsave */
+
+/*
+ *
+ * Simple minded attempt at parsing the string that followed an "x X DrawPath"
+ * command. Everything not recognized here is simply ignored - there's absolutely
+ * no error checking and what was originally in buf is clobbered by strtok().
+ * A typical *buf might look like,
+ *
+ * gray .9 fill stroke
+ *
+ * to fill the current path with a gray level of .9 and follow that by stroking the
+ * outline of the path. Since unrecognized tokens are ignored the last example
+ * could also be written as,
+ *
+ * with gray .9 fill then stroke
+ *
+ * The "with" and "then" strings aren't recognized tokens and are simply discarded.
+ * The "stroke", "fill", and "wfill" force out appropriate PostScript code and are
+ * followed by a grestore. In otherwords changes to the grahics state (eg. a gray
+ * level or color) are reset to default values immediately after the stroke, fill,
+ * or wfill tokens. For now "fill" gets invokes PostScript's eofill operator and
+ * "wfill" calls fill (ie. the operator that uses the non-zero winding rule).
+ *
+ * The tokens that cause temporary changes to the graphics state are "gray" (for
+ * setting the gray level), "color" (for selecting a known color from the colordict
+ * dictionary defined in *colorfile), and "line" (for setting the line width). All
+ * three tokens can be extended since strncmp() makes the comparison. For example
+ * the strings "line" and "linewidth" accomplish the same thing. Colors are named
+ * (eg. "red"), but must be appropriately defined in *colorfile. For now all three
+ * tokens must be followed immediately by their single argument. The gray level
+ * (ie. the argument that follows "gray") should be a number between 0 and 1, with
+ * 0 for black and 1 for white.
+ *
+ * To pass straight PostScript through enclose the appropriate commands in double
+ * quotes. Straight PostScript is only bracketed by the outermost gsave/grestore
+ * pair (ie. the one from the initial "x X BeginPath") although that's probably
+ * a mistake. Suspect I may have to change the double quote delimiters.
+ *
+ */
+
+
+ pend = buf + strlen(buf);
+ p = strtok(buf, " \n");
+
+ while ( p != NULL ) {
+ if ( gsavelevel == 0 ) {
+ fprintf(tf, "gsave\n");
+ gsavelevel++;
+ } /* End if */
+ if ( strcmp(p, "stroke") == 0 ) {
+ fprintf(tf, "closepath stroke\ngrestore\n");
+ gsavelevel--;
+ } else if ( strcmp(p, "openstroke") == 0 ) {
+ fprintf(tf, "stroke\ngrestore\n");
+ gsavelevel--;
+ } else if ( strcmp(p, "fill") == 0 ) {
+ fprintf(tf, "eofill\ngrestore\n");
+ gsavelevel--;
+ } else if ( strcmp(p, "wfill") == 0 ) {
+ fprintf(tf, "fill\ngrestore\n");
+ gsavelevel--;
+ } else if ( strcmp(p, "sfill") == 0 ) {
+ fprintf(tf, "eofill\ngrestore\ngsave\nstroke\ngrestore\n");
+ gsavelevel--;
+ } else if ( strncmp(p, "gray", strlen("gray")) == 0 ) {
+ p1 = strtok(NULL, " \n");
+ fprintf(tf, "%s setgray\n", p1);
+ } else if ( strncmp(p, "color", strlen("color")) == 0 ) {
+ p1 = strtok(NULL, " \n");
+ fprintf(tf, "/%s setcolor\n", p1);
+ } else if ( strncmp(p, "line", strlen("line")) == 0 ) {
+ p1 = strtok(NULL, " \n");
+ fprintf(tf, "%s resolution mul 2 div setlinewidth\n", p1);
+ } else if ( strncmp(p, "reverse", strlen("reverse")) == 0 )
+ fprintf(tf, "reversepath\n");
+ else if ( *p == '"' ) {
+ for ( ; gsavelevel > 0; gsavelevel-- )
+ fprintf(tf, "grestore\n");
+ if ( (p1 = p + strlen(p)) < pend )
+ *p1 = ' ';
+ p = strtok(p, "\"\n");
+ fprintf(tf, "%s\n", p);
+ } /* End else */
+ p = strtok(NULL, " \n");
+ } /* End while */
+
+ for ( ; gsavelevel > 0; gsavelevel-- )
+ fprintf(tf, "grestore\n");
+
+} /* End of parsebuf */
+
+
+/*****************************************************************************/
+
+static void
+getbaseline(void)
+{
+
+/*
+ *
+ * Responsible for making sure the PostScript procedures needed for printing text
+ * along an arbitrary baseline are downloaded from *baselinefile. Done at most
+ * once per job, and only if the the stuff is really used.
+ *
+ */
+
+
+ if ( gotbaseline == FALSE && access(baselinefile, 04) == 0 )
+ doglobal(baselinefile);
+
+ if ( tf == stdout )
+ gotbaseline = TRUE;
+
+} /* End of getbaseline */
+
+
+/*****************************************************************************/
+
+
+void
+newbaseline(char *buf)
+ /* whatever followed "x X NewBaseline" */
+{
+ char *p; /* for eliminating white space etc. */
+
+
+/*
+ *
+ * Called from devcntrl() whenever an "x X NewBaseline" command is recognized. We
+ * assume whatever is in *buf is a set of parametric equations that describe the
+ * new baseline. Equations for x(t), y(t), dx/dt, and dy/dt must be written in
+ * PostScript, bracketed by { and } characters, and supplied in exactly that order.
+ * In particular the equation for x must come first in *buf and it ends up as the
+ * last one on the stack, while the equation for dy/dt comes last (in *buf) and
+ * ends up on the top of the PostScript stack. For example if *buf is given by,
+ *
+ * {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg}
+ *
+ * text will be printed along the curve y = cos(x).
+ *
+ * Angles given in radians must be converted to degrees for the PostScript trig
+ * functions, and things are scaled so that 1 unit maps into 1 inch. In the last
+ * example the cosine curve that describes the baseline has an amplitude of 1 inch.
+ * As another example of this rather confusing syntax if *buf is,
+ *
+ * {} {} {pop 1} {pop 1}
+ *
+ * the baseline will be the 45 degree line y = x.
+ *
+ * When any of the four functions is used they're called with a single number on
+ * the stack that's equal to the current value of the parameter t. The coordinate
+ * system axes run parallel to the PostScript coordinate system that's currently
+ * being used.
+ *
+ */
+
+
+ for ( p = buf; *p; p++ ) /* eliminate trailing '\n' */
+ if ( *p == '\n' ) {
+ *p = '\0';
+ break;
+ } /* End if */
+
+ for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ;
+
+ if ( *p != '\0' ) { /* something's there */
+ endtext();
+ getbaseline();
+ fprintf(tf, "mark resolution %s newbaseline\n", p);
+ t_sf();
+ resetpos();
+ } /* End if */
+
+} /* End of newbaseline */
+
+
+/*****************************************************************************/
+
+void
+drawtext(char *buf)
+ /* whatever followed "x X DrawText */
+{
+ char *p; /* for eliminating white space etc. */
+
+
+/*
+ *
+ * Called from devcntrl() whenever an "x X DrawText command is recognized. *buf
+ * should contain three arguments in the following order. First comes the text we
+ * want to print along the current baseline. Right now the string should be given
+ * as a PostScript string using characters '(' and ')' as the delimiters. Next in
+ * *buf comes a justification mode that can be the words left, right, or center.
+ * Last comes a number that represents the starting value of the parameter t that's
+ * given as the argument to the parametric equations that describe the current
+ * baseline. For example if *buf is given by,
+ *
+ * (hello world) left .5
+ *
+ * hello world will be printed along the path described by the current baseline
+ * and left justified at whatever (x(.5), y(.5)) happens to be. Usually will be
+ * preceeded by an "x X NewBaseline" call that defines the current baseline. The
+ * origin of the coordinate system used by the parametric equations will be the
+ * current point.
+ *
+ */
+
+
+ for ( p = buf; *p; p++ ) /* eliminate trailing '\n' */
+ if ( *p == '\n' ) {
+ *p = '\0';
+ break;
+ } /* End if */
+
+ for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ;
+
+ if ( *p != '\0' ) { /* something's there */
+ endtext();
+ getbaseline();
+ xymove(hpos, vpos);
+ fprintf(tf, "mark %s drawfunnytext\n", p);
+ resetpos();
+ } /* End if */
+
+} /* End of drawtext */
+
+
+/*****************************************************************************/
+
+void
+settext(char *buf)
+{
+ char *p;
+
+
+/*
+ *
+ * Does whatever is needed to ensure any text that follows will be set along the
+ * curve described by the PostScript procedures listed in *buf. If *buf doesn't
+ * contain anything useful (eg. just a newline) things are restored to whatever
+ * they originally were. Doesn't work well if we try to start in the middle of a
+ * line of text.
+ *
+ * The parametric equations needed are,
+ *
+ * x = f(t)
+ * y = g(t)
+ * dx/dt = f'(t)
+ * dy/dt = g'(t)
+ *
+ * and must be given as proper PostScript procedures. The equation for x must come
+ * first (ie. it ends up on the bottom of the stack) and the equation for dy/dt
+ * must be given last (ie. it ends up on top of the stack). For example if *buf
+ * is given by,
+ *
+ * {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg}
+ *
+ * text will be set along the curve y=cos(x).
+ *
+ */
+
+
+ endtext();
+ getbaseline();
+
+ for ( p = buf; *p && *p == ' '; p++ ) ;
+
+ if ( *p && *p != '\n' ) {
+ encoding = maxencoding + 2;
+ fprintf(tf, "mark resolution %s newbaseline\n", buf);
+ } else encoding = realencoding;
+
+ fprintf(tf, "%d setdecoding\n", encoding);
+ resetpos();
+
+} /* End of settext */
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/pictures.c b/usr/src/cmd/lp/filter/postscript/dpost/pictures.c
new file mode 100644
index 0000000000..023bc014b5
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/pictures.c
@@ -0,0 +1,325 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * PostScript picture inclusion routines. Support for managing in-line pictures
+ * has been added, and works in combination with the simple picpack pre-processor
+ * that's supplied with this package. An in-line picture begins with a special
+ * device control command that looks like,
+ *
+ * x X InlinPicture name size
+ *
+ * where name is the pathname of the original picture file and size is the number
+ * of bytes in the picture, which begins immediately on the next line. When dpost
+ * encounters the InlinePicture device control command inlinepic() is called and
+ * that routine appends the string name and the integer size to a temporary file
+ * (fp_pic) and then adds the next size bytes read from the current input file to
+ * file fp_pic. All in-line pictures are saved in fp_pic and located later using
+ * the name string and picture file size that separate pictures saved in fp_pic.
+ *
+ * When a picture request (ie. an "x X PI" command) is encountered picopen() is
+ * called and it first looks for the picture file in fp_pic. If it's found there
+ * the entire picture (ie. size bytes) is copied from fp_pic to a new temp file
+ * and that temp file is used as the picture file. If there's nothing in fp_pic
+ * or if the lookup failed the original route is taken.
+ *
+ * Support for in-line pictures is an attempt to address requirements, expressed
+ * by several orginazations, of being able to store a document as a single file
+ * (usually troff input) that can then be sent through dpost and ultimately to
+ * a PostScript printer. The mechanism may help some users, but the are obvious
+ * disadvantages to this approach, and the original mechanism is the recommended
+ * approach! Perhaps the most important problem is that troff output, with in-line
+ * pictures included, doesn't fit the device independent language accepted by
+ * important post-processors (like proff) and that means you won't be able to
+ * reliably preview a packed file on your 5620 (or whatever).
+ *
+ */
+
+
+#include <stdio.h>
+
+#include "comments.h" /* PostScript file structuring comments */
+#include "gen.h" /* general purpose definitions */
+#include "path.h" /* just for TEMPDIR definition */
+
+
+FILE *fp_pic = NULL; /* in-line pictures go here */
+FILE *picopen();
+
+extern int res, hpos, vpos;
+extern int picflag;
+extern FILE *tf;
+
+static void piccopy(FILE *, FILE *, long);
+
+/*****************************************************************************/
+
+
+void
+picture(char *buf)
+ /* stuff following 'x X PI' command */
+{
+ int poffset; /* page offset */
+ int indent; /* indent */
+ int length; /* line length */
+ int totrap; /* distance to next trap */
+ char name[100]; /* picture file and page string */
+ char hwo[40], *p; /* height, width and offset strings */
+ char flags[20]; /* miscellaneous stuff */
+ int page = 1; /* page number pulled from name[] */
+ double frame[4]; /* height, width, y, and x offsets from hwo[] */
+ char units; /* scale indicator for frame dimensions */
+ int whiteout = 0; /* white out the box? */
+ int outline = 0; /* draw a box around the picture? */
+ int scaleboth = 0; /* scale both dimensions? */
+ double adjx = 0.5; /* left-right adjustment */
+ double adjy = 0.5; /* top-bottom adjustment */
+ double rot = 0; /* rotation in clockwise degrees */
+ FILE *fp_in; /* for *name */
+ int i; /* loop index */
+
+ char *strchr();
+
+
+/*
+ *
+ * Called from devcntrl() after an 'x X PI' command is found. The syntax of that
+ * command is:
+ *
+ * x X PI:args
+ *
+ * with args separated by colons and given by:
+ *
+ * poffset
+ * indent
+ * length
+ * totrap
+ * file[(page)]
+ * height[,width[,yoffset[,xoffset]]]
+ * [flags]
+ *
+ * poffset, indent, length, and totrap are given in machine units. height, width,
+ * and offset refer to the picture frame in inches, unless they're followed by
+ * the u scale indicator. flags is a string that provides a little bit of control
+ * over the placement of the picture in the frame. Rotation of the picture, in
+ * clockwise degrees, is set by the a flag. If it's not followed by an angle
+ * the current rotation angle is incremented by 90 degrees, otherwise the angle
+ * is set by the number that immediately follows the a.
+ *
+ */
+
+
+ if ( picflag == OFF ) /* skip it */
+ return;
+
+ endtext();
+
+ flags[0] = '\0'; /* just to be safe */
+ if ( sscanf(buf, "%d:%d:%d:%d:%[^:]:%[^:]:%[^:]", &poffset, &indent,
+ &length, &totrap, name, hwo, flags) < 6 ) {
+ error(NON_FATAL, "too few arguments to specify picture");
+ return;
+ } /* End if */
+
+ if ( sscanf(name, "%*[^(](%d", &page) == 1 ) /* grab the page number */
+ strtok(name, "("); /* and separate it from the name */
+
+ if ( (fp_in = picopen(name)) == NULL ) {
+ error(NON_FATAL, "can't open picture file %s", name);
+ return;
+ } /* End if */
+
+ frame[0] = frame[1] = -1; /* default frame height, width */
+ frame[2] = frame[3] = 0; /* and y and x offsets */
+
+ for ( i = 0, p = hwo-1; i < 4 && p != NULL; i++, p = strchr(p, ',') )
+ if ( sscanf(++p, "%lf%c", &frame[i], &units) == 2 )
+ if ( units == 'i' || units == ',' || units == '\0' )
+ frame[i] *= res;
+
+ if ( frame[0] <= 0 ) /* check what we got for height */
+ frame[0] = totrap;
+
+ if ( frame[1] <= 0 ) /* and width - check too big?? */
+ frame[1] = length - indent;
+
+ frame[3] += poffset + indent; /* real x offset */
+
+ for ( i = 0; flags[i]; i++ )
+ switch ( flags[i] ) {
+ case 'c': adjx = adjy = 0.5; break; /* move to the center */
+ case 'l': adjx = 0; break; /* left */
+ case 'r': adjx = 1; break; /* right */
+ case 't': adjy = 1; break; /* top */
+ case 'b': adjy = 0; break; /* or bottom justify */
+ case 'o': outline = 1; break; /* outline the picture */
+ case 'w': whiteout = 1; break; /* white out the box */
+ case 's': scaleboth = 1; break; /* scale both dimensions */
+ case 'a': if ( sscanf(&flags[i+1], "%lf", &rot) != 1 )
+ rot += 90;
+ } /* End switch */
+
+ fprintf(tf, "cleartomark restore\n");
+
+ ps_include(fp_in, tf, page, whiteout, outline, scaleboth,
+ frame[3]+frame[1]/2, -vpos-frame[2]-frame[0]/2, frame[1], frame[0], adjx, adjy, -rot);
+
+ fprintf(tf, "save mark\n");
+ xymove(hpos, vpos);
+ t_sf();
+
+ fclose(fp_in);
+
+} /* End of picture */
+
+
+/*****************************************************************************/
+
+
+FILE *
+picopen(char *path)
+ /* picture file pathname */
+{
+ char name[100]; /* pathnames */
+ long total; /* and sizes - from *fp_pic */
+ char *tname; /* pathname */
+ FILE *fp; /* and pointer for the new temp file */
+
+
+/*
+ *
+ * Responsible for finding and opening the next picture file. If we've accumulated
+ * any in-line pictures fp_pic won't be NULL and we'll look there first. If *path
+ * is found in *fp_pic we create another temp file, open it for update, unlink it,
+ * copy in the picture, seek back to the start of the new temp file, and return
+ * the file pointer to the caller. If fp_pic is NULL or the lookup fails we just
+ * open file *path and return the resulting file pointer to the caller.
+ *
+ */
+
+
+ if ( fp_pic != NULL ) {
+ fseek(fp_pic, 0L, 0);
+ while ( fscanf(fp_pic, "%s %ld\n", name, &total) != EOF ) {
+ if ( strcmp(path, name) == 0 ) {
+ if ( (tname = tempnam(TEMPDIR, "dpost")) == NULL )
+ error(FATAL, "can't generate temp file name");
+ if ( (fp = fopen(tname, "w+")) == NULL )
+ error(FATAL, "can't open %s", tname);
+ unlink(tname);
+ free(tname);
+ piccopy(fp_pic, fp, total);
+ fseek(fp, 0L, 0);
+ return(fp);
+ } /* End if */
+ fseek(fp_pic, total, 1);
+ } /* End while */
+ } /* End if */
+
+ return(fopen(path, "r"));
+
+} /* End of picopen */
+
+
+/*****************************************************************************/
+
+
+void
+inlinepic(FILE *fp, char *buf)
+ /* fp - current input file */
+ /* buf - whatever followed "x X InlinePicture" */
+{
+ char *tname; /* temp file pathname - for *fp_pic */
+ char name[100]; /* picture file pathname */
+ long total; /* and size - both from *buf */
+
+
+/*
+ *
+ * Adds an in-line picture file to the end of temporary file *fp_pic. All pictures
+ * grabbed from the input file are saved in the same temp file. Each is preceeded
+ * by a one line header that includes the original picture file pathname and the
+ * size of the picture in bytes. The in-line picture file is opened for update,
+ * left open, and unlinked so it disappears when we do.
+ *
+ */
+
+
+ if ( fp_pic == NULL ) {
+ if ( (tname = tempnam(TEMPDIR, "dpost")) == NULL )
+ error(FATAL, "can't generate in-line picture file name");
+ if ( (fp_pic = fopen(tname, "w+")) == NULL )
+ error(FATAL, "can't open in-line picture file %s", tname);
+ unlink(tname);
+ } /* End if */
+
+ if ( sscanf(buf, "%s %ld", name, &total) != 2 )
+ error(FATAL, "in-line picture error");
+
+ fseek(fp_pic, 0L, 2);
+ fprintf(fp_pic, "%s %ld\n", name, total);
+ getc(fp);
+ fflush(fp_pic);
+ piccopy(fp, fp_pic, total);
+ ungetc('\n', fp);
+
+} /* End of inlinepic */
+
+
+/*****************************************************************************/
+
+
+static void
+piccopy(FILE *fp_in, FILE *fp_out, long total)
+ /* fp_in - input */
+ /* fp_out - and output file pointers */
+ /* total - number of bytes to be copied */
+{
+ long i; /* loop index */
+
+
+/*
+ *
+ * Copies total bytes from file fp_in to fp_out. Used to append picture files to
+ * *fp_pic and then copy them to yet another temporary file immediately before
+ * they're used (in picture()).
+ *
+ */
+
+
+ for ( i = 0; i < total; i++ )
+ if ( putc(getc(fp_in), fp_out) == EOF )
+ error(FATAL, "error copying in-line picture file");
+ fflush(fp_out);
+
+} /* End of piccopy */
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/ps_include.awk b/usr/src/cmd/lp/filter/postscript/dpost/ps_include.awk
new file mode 100644
index 0000000000..fe51c946e0
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/ps_include.awk
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+/^->/ {
+ if(ndef)
+ printf("\t0\n};\n\n")
+ printf("static char *%s[] = {\n", $2)
+ ndef++
+ next
+}
+/^#/ {next}
+$0 != "" {printf("\t\"%s\",\n", $0); next}
+END {printf("\t0\n};\n")}
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/ps_include.c b/usr/src/cmd/lp/filter/postscript/dpost/ps_include.c
new file mode 100644
index 0000000000..1cd79abe63
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/ps_include.c
@@ -0,0 +1,204 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ *
+ * Picture inclusion code for PostScript printers.
+ *
+ */
+
+
+#include <stdio.h>
+#include "ps_include.h"
+
+
+#define var(x) fprintf(fout, "/%s %g def\n", #x, x)
+#define has(word) (strncmp(buf, word, strlen(word)) == 0)
+#define grab(n) ((Section *)(nglobal \
+ ? realloc((char *)global, n * sizeof (Section)) \
+ : calloc(n, sizeof (Section))))
+
+
+char buf[512];
+typedef struct {
+ long start;
+ long end;
+} Section;
+
+extern char *calloc(), *realloc();
+
+static void print(FILE *, char **);
+static void copy(FILE *, FILE *, Section *);
+
+
+/*
+ * fin, fout - input and output files
+ * page_no physical page number from *fin
+ * whiteout - erase picture area
+ * outline - draw a box around it and
+ * scaleboth - scale both dimensions - if not zero
+ * cx, cy - center of the picture and
+ * sx, sy - its size - in current coordinates
+ * ax, ay - left-right, up-down adjustment
+ * rot - rotation - in clockwise degrees
+ */
+void
+ps_include(FILE *fin, FILE *fout, int page_no, int whiteout,
+ int outline, int scaleboth, double cx, double cy,
+ double sx, double sy, double ax, double ay, double rot)
+{
+ /* found the page when non zero */
+ int foundpage = 0;
+ /* number of global defs so far */
+ int nglobal = 0;
+ /* and the number we've got room for */
+ int maxglobal = 0;
+ /* prologue, page, and trailer offsets */
+ Section prolog, page, trailer;
+ /* offsets for all global definitions */
+ Section *global;
+ /* lower left and */
+ double llx, lly;
+ /* upper right corners - default coords */
+ double urx, ury;
+ /* mostly for the var() macro */
+ double w = whiteout != 0;
+ double o = outline != 0;
+ double s = scaleboth != 0;
+ int i;
+
+
+ /*
+ *
+ * Reads a PostScript file (*fin), and uses structuring comments to
+ * locate the prologue, trailer, global definitions, and the requested
+ * page. After the whole file is scanned, the special ps_include
+ * PostScript definitions are copied to *fout, followed by the
+ * prologue, global definitions, the requested page, and the
+ * trailer. Before returning the initial environment (saved in
+ * PS_head) is restored.
+ *
+ * By default we assume the picture is 8.5 by 11 inches, but the
+ * BoundingBox comment, if found, takes precedence.
+ *
+ */
+
+ /* default BoundingBox - 8.5x11 inches */
+ llx = lly = 0;
+ urx = 72 * 8.5;
+ ury = 72 * 11.0;
+
+ /* section boundaries and bounding box */
+
+ prolog.start = prolog.end = 0;
+ page.start = page.end = 0;
+ trailer.start = 0;
+ fseek(fin, 0L, 0);
+
+ while (fgets(buf, sizeof (buf), fin) != NULL)
+ if (!has("%%"))
+ continue;
+ else if (has("%%Page: ")) {
+ if (!foundpage)
+ page.start = ftell(fin);
+ sscanf(buf, "%*s %*s %d", &i);
+ if (i == page_no)
+ foundpage = 1;
+ else if (foundpage && page.end <= page.start)
+ page.end = ftell(fin);
+ } else if (has("%%EndPage: ")) {
+ sscanf(buf, "%*s %*s %d", &i);
+ if (i == page_no) {
+ foundpage = 1;
+ page.end = ftell(fin);
+ }
+ if (!foundpage)
+ page.start = ftell(fin);
+ } else if (has("%%BoundingBox:"))
+ sscanf(buf, "%%%%BoundingBox: %lf %lf %lf %lf",
+ &llx, &lly, &urx, &ury);
+ else if (has("%%EndProlog") || has("%%EndSetup") ||
+ has("%%EndDocumentSetup"))
+ prolog.end = page.start = ftell(fin);
+ else if (has("%%Trailer"))
+ trailer.start = ftell(fin);
+ else if (has("%%BeginGlobal")) {
+ if (page.end <= page.start) {
+ if (nglobal >= maxglobal) {
+ maxglobal += 20;
+ global = grab(maxglobal);
+ }
+ global[nglobal].start = ftell(fin);
+ }
+ } else if (has("%%EndGlobal"))
+ if (page.end <= page.start)
+ global[nglobal++].end = ftell(fin);
+
+ fseek(fin, 0L, 2);
+ if (trailer.start == 0)
+ trailer.start = ftell(fin);
+ trailer.end = ftell(fin);
+
+ if (page.end <= page.start)
+ page.end = trailer.start;
+
+ /* all output here */
+ print(fout, PS_head);
+ var(llx); var(lly); var(urx); var(ury); var(w); var(o); var(s);
+ var(cx); var(cy); var(sx); var(sy); var(ax); var(ay); var(rot);
+ print(fout, PS_setup);
+ copy(fin, fout, &prolog);
+ for (i = 0; i < nglobal; i++)
+ copy(fin, fout, &global[i]);
+ copy(fin, fout, &page);
+ copy(fin, fout, &trailer);
+ print(fout, PS_tail);
+
+ if (nglobal)
+ free(global);
+
+}
+
+static void
+print(FILE *fout, char **s)
+{
+ while (*s)
+ fprintf(fout, "%s\n", *s++);
+}
+
+static void
+copy(FILE *fin, FILE *fout, Section *s)
+{
+ if (s->end <= s->start)
+ return;
+ fseek(fin, s->start, 0);
+ while (ftell(fin) < s->end && fgets(buf, sizeof (buf), fin) != NULL)
+ if (buf[0] != '%')
+ fprintf(fout, "%s", buf);
+}
diff --git a/usr/src/cmd/lp/filter/postscript/dpost/ps_include.ps b/usr/src/cmd/lp/filter/postscript/dpost/ps_include.ps
new file mode 100644
index 0000000000..70dfdc6990
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/dpost/ps_include.ps
@@ -0,0 +1,139 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+-> PS_head
+
+%ps_include: begin
+save
+/ed {exch def} def
+
+# redefine dangerous operators
+{} /showpage ed
+{} /copypage ed
+{} /erasepage ed
+{} /letter ed
+
+# computations are done in the context of a new dictionary
+36 dict dup /PS-include-dict-dw ed begin
+
+# context holds the save object created earlier
+/context ed
+
+# save and clear the operand stack
+count array astore /o-stack ed
+
+# the following variables are now expected:
+# llx,lly,urx,ury bounding box of picture to be included
+# w nonzero if space should be painted white to start
+# o nonzero if space should be outlined
+# s nonzero if both dimensions should be scaled
+# cx,cy center of page space in current coordinates
+# sx,sy size of page space in current coordinates
+# ax,ay left-right, up-down adjustment of picture in page space
+# rot rotation of picture in page space
+%ps_include: variables begin
+
+
+
+-> PS_setup
+
+%ps_include: variables end
+
+# some routines:
+# - BBOX llx lly urx ury put bounding box on stack
+# llx lly urx ury BOXPATH - make a path with given box corners
+# dx dy LEN length compute length of positionless vector
+# a b MIN min compute minimum of two numbers
+# a b MAX max compute maximum of two numbers
+# x y NICE x y move to pixel boundaries in default coords
+{llx lly urx ury} /bbox ed
+{newpath 2 index exch 2 index exch dup 6 index exch
+ moveto 3 {lineto} repeat closepath} /boxpath ed
+{dup mul exch dup mul add sqrt} /len ed
+{2 copy gt {exch} if pop} /min ed
+{2 copy lt {exch} if pop} /max ed
+{transform round exch round exch A itransform} /nice ed
+
+# A is the transformation from default to current coordinates
+{6 array} /n ed
+n defaultmatrix n currentmatrix n invertmatrix n concatmatrix /A ed
+
+# Sx,Sy and Cx,Cy are dimensions and size of bounding box in current coordinates
+urx llx sub 0 A dtransform len /Sx ed
+0 ury lly sub A dtransform len /Sy ed
+llx urx add 2 div lly ury add 2 div A transform /Cy ed /Cx ed
+
+# H and W are height and width of rotated box in current coordinates
+rot dup sin abs /S ed cos abs /C ed
+Sx S mul Sy C mul add /H ed
+Sx C mul Sy S mul add /W ed
+
+# Scalex and Scaley are the required horizontal and vertical scaling factors
+sy H div /Scaley ed
+sx W div /Scalex ed
+
+# Preserve aspect ratio if we're not scaling both dimensions (ie. s is 0)
+s 0 eq {Scalex Scaley min dup /Scalex ed /Scaley ed} if
+
+# add to cx,cy the shift needed within the page space
+sx Scalex W mul sub 0 max ax 0.5 sub mul cx add /cx ed
+sy Scaley H mul sub 0 max ay 0.5 sub mul cy add /cy ed
+
+# the actual rotation needed is rot less the current rotation
+urx llx sub 0 A dtransform exch atan rot exch sub /rot ed
+
+# set up the coordinate system
+n currentmatrix initgraphics setmatrix
+cx cy translate
+Scalex Scaley scale
+rot rotate
+Cx neg Cy neg translate
+A concat
+
+# set the clipping region, and conditionally whiteout and outline
+bbox boxpath clip newpath
+w 0 ne {gsave bbox boxpath 1 setgray fill grestore} if
+
+# pop local dictionary from the dict stack
+end
+
+# now begins the actual material extracted from the file
+gsave
+%ps_include: inclusion begin
+
+
+
+-> PS_tail
+
+%ps_include: inclusion end
+grestore
+
+# within the context of the local dictionary ...
+PS-include-dict-dw begin
+
+o 0 ne {gsave A defaultmatrix /A ed llx lly nice urx ury nice
+ initgraphics 0.1 setlinewidth boxpath stroke grestore} if
+
+# ... restore the operand stack and the save context
+clear o-stack aload pop
+context end restore
+%ps_include: end
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/Makefile b/usr/src/cmd/lp/filter/postscript/filtdesc/Makefile
new file mode 100644
index 0000000000..6c9e6d4c1b
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/Makefile
@@ -0,0 +1,62 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/filtdesc/Makefile
+#
+
+include ../../../Makefile.lp
+
+ROOTETCLPFD= $(ROOTETCLP)/fd
+
+FILES= catv.fd \
+ download.fd \
+ dpost.fd \
+ postio.fd \
+ postior.fd \
+ postprint.fd \
+ postreverse.fd \
+ postpages.fd \
+ pr.fd
+
+ROOTFILES = $(FILES:%=$(ROOTETCLPFD)/%)
+
+TXTS = README
+
+FILEMODE = 644
+
+.KEEP_STATE:
+
+all: $(TXTS) $(FILES)
+
+install: all $(ROOTETCLPFD) $(ROOTFILES)
+
+$(ROOTETCLPFD) :
+ $(INS.dir)
+
+$(ROOTETCLPFD)/% : %
+ $(INS.file)
+
+clean clobber strip lint catalog:
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/README b/usr/src/cmd/lp/filter/postscript/filtdesc/README
new file mode 100644
index 0000000000..9e42cf455d
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/README
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+This directory contains a set of input files for the lpfilter command
+that will install the PostScript filters under lp.
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/catv.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/catv.fd
new file mode 100644
index 0000000000..bf26c5bff4
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/catv.fd
@@ -0,0 +1,34 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+Input types: simple,postscript
+Output types: simple
+Printer types: any
+Printers: any
+Filter type: slow
+Command: /usr/bin/cat
+Options: MODES catv_filter = -v
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/download.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/download.fd
new file mode 100644
index 0000000000..1225be8d9c
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/download.fd
@@ -0,0 +1,30 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Input types: postscript
+Output types: postdown
+Printer types: PS,PSR,PS-b,PS-r,PS-br
+Printers: any
+Filter type: fast
+Command: /usr/lib/lp/postscript/download
+Options: PRINTER * = -p*
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/dpost.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/dpost.fd
new file mode 100644
index 0000000000..179d7f2eeb
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/dpost.fd
@@ -0,0 +1,39 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Input types: troff
+Output types: postscript
+Printer types: any
+Printers: any
+Filter type: slow
+Command: /usr/lib/lp/postscript/dpost
+Options: PAGES * = -o*
+Options: COPIES * = -c*
+Options: LENGTH * = -l*
+Options: MODES group = -n2
+Options: MODES group\=\([2-9]\) = -n\1
+Options: MODES portrait = -pp
+Options: MODES landscape = -pl
+Options: MODES x\=\(\-*[\.0-9]*\) = -x\1
+Options: MODES y\=\(\-*[\.0-9]*\) = -y\1
+Options: MODES magnify\=\([\.0-9]*\) = -m\1
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/postio.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/postio.fd
new file mode 100644
index 0000000000..d6a3dabba2
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/postio.fd
@@ -0,0 +1,29 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Input types: postdown
+Output types: PS
+Printer types: PS
+Printers: any
+Filter type: fast
+Command: /usr/lib/lp/postscript/postio 2>>$ERRFILE
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/postior.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/postior.fd
new file mode 100644
index 0000000000..2ccded24e5
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/postior.fd
@@ -0,0 +1,29 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Input types: postdown
+Output types: PS
+Printer types: PSR
+Printers: any
+Filter type: fast
+Command: /usr/lib/lp/postscript/postreverse | /usr/lib/lp/postscript/postio 2>>$ERRFILE
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/postpages.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/postpages.fd
new file mode 100644
index 0000000000..bc86038ceb
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/postpages.fd
@@ -0,0 +1,34 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+Input types: postscript
+Output types: postscript
+Printer types: any
+Printers: any
+Filter type: slow
+Command: /usr/lib/lp/postscript/postreverse -r
+Options: PAGES * = -o*
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/postprint.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/postprint.fd
new file mode 100644
index 0000000000..83d8c74b9b
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/postprint.fd
@@ -0,0 +1,43 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+
+Input types: simple
+Output types: postscript
+Printer types: any
+Printers: any
+Filter type: slow
+Command: /usr/lib/lp/postscript/postprint
+Options: PAGES * = -o*
+Options: LENGTH * = -l*
+Options: MODES group = -n2
+Options: MODES group\=\([2-9]\) = -n\1
+Options: MODES portrait = -pp
+Options: MODES landscape = -pl
+Options: MODES x\=\(\-*[\.0-9]*\) = -x\1
+Options: MODES y\=\(\-*[\.0-9]*\) = -y\1
+Options: MODES magnify\=\([\.0-9]*\) = -m\1
+Options: MODES catv_filter = -I
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/postreverse.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/postreverse.fd
new file mode 100644
index 0000000000..f00257e288
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/postreverse.fd
@@ -0,0 +1,30 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Input types: postscript,post
+Output types: postscript
+Printer types: any
+Printers: any
+Filter type: slow
+Command: /usr/lib/lp/postscript/postreverse
+Options: PAGES * = -o*
diff --git a/usr/src/cmd/lp/filter/postscript/filtdesc/pr.fd b/usr/src/cmd/lp/filter/postscript/filtdesc/pr.fd
new file mode 100644
index 0000000000..385fdb3dc0
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/filtdesc/pr.fd
@@ -0,0 +1,36 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+Input types: pr
+Output types: simple
+Printer types: any
+Printers: any
+Filter type: slow
+Command: /usr/bin/pr
+Options: MODES prtitle\=\(\'.*\'\) = -h \1
+Options: MODES width\=\(.*\) = -w\1
+Options: MODES indent\=\(.*\) = -o\1
diff --git a/usr/src/cmd/lp/filter/postscript/font/Makefile b/usr/src/cmd/lp/filter/postscript/font/Makefile
new file mode 100644
index 0000000000..27496b4f75
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/Makefile
@@ -0,0 +1,91 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/font/Makefile
+#
+
+include ../../../Makefile.lp
+
+PROG = makedev
+
+SRCS = makedev.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+SUBDIRS = devpost
+
+COMMONDIR = ../common
+ROOTLIBFONT = $(ROOTLIB)/font
+ROOTLIBFONTPROG = $(PROG:%=$(ROOTLIBFONT)/%)
+
+CPPFLAGS = -I$(COMMONDIR) $(CPPFLAGS.master)
+
+POFILE = lp_filter_postscript_font.po
+
+NATIVEDIR = native
+NATIVEPROG = $(NATIVEDIR)/$(PROG)
+$(NATIVEPROG) := CC=$(NATIVECC)
+$(NATIVEPROG) := LDLIBS=
+$(NATIVEPROG) := CPPFLAGS.master=
+
+.KEEP_STATE:
+
+all : $(PROG) $(NATIVEPROG) $(SUBDIRS)
+
+install : $(PROG) $(ROOTLIBFONTPROG) $(SUBDIRS)
+
+clean : $(SUBDIRS)
+ $(RM) $(OBJS)
+
+clobber : $(SUBDIRS) clean
+ $(RM) $(PROG) $(NATIVEPROG) $(CLOBBERFILES)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint:
+ $(LINT.c) $(SRCS)
+
+include ../Makefile.msg
+
+$(NATIVEPROG) : $(NATIVEDIR) $(SRCS)
+ $(LINK.c) -o $@ $(SRCS) $(LDLIBS)
+
+$(NATIVEDIR) :
+ -@mkdir -p $@
+
+$(ROOTLIBFONT)/%: %
+ $(INS.file)
+
+$(PROG) : $(SRCS)
+ $(LINK.c) -o $@ $(SRCS) $(LDLIBS)
+ $(POST_PROCESS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/lp/filter/postscript/font/README b/usr/src/cmd/lp/filter/postscript/font/README
new file mode 100644
index 0000000000..d5a5a865bc
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/README
@@ -0,0 +1,139 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+The devpost directory includes width tables for the entire LaserWriter Plus font
+set (and a few others). The width tables assume a resolution of 720 dpi (which
+isn't expected to match your printer's resolution) and by default are installed
+in /usr/lib/font/devpost. You can point troff there using the -Tpost option, while
+dpost goes there automatically. The width tables were generated on a PostScript
+printer using postio (with the -t option) and the files that you'll find in
+directory ../buildtables.
+
+The mapping from troff's one or two character font names to PostScript fonts is
+handled by definitions made near the start of file ../postscript/dpost.ps. troff
+characters not available in PostScript fonts are constructed using the files in
+./devpost/charlib. Characters that are assigned a code (ie. number in the fourth
+column) less than 32 are looked up (by dpost) in the charlib directory. A code
+of 1 implies the character definition comes in one piece, while anything else
+means the character may come in two pieces. The first part is downloaded once,
+while the second part (ie. the one that ends in .map) must be included every
+time the character is printed.
+
+Adding a new font file (for troff and dpost) can be time consuming, but isn't
+difficult. The steps you'll need to follow are outlined below:
+
+ 1: Pick a one or two character font name for troff and dpost - no longer a
+ trivial task! To find out what two character font names are taken type,
+
+ cd devpost
+ ls -l ? ??
+
+ Any unused one or two character font name can be chosen. I've tried to choose
+ two character font names with the first character representing the font family
+ (eg. K for Bookman) and second (upper or lower case R, I, B, or X) indicating
+ the style.
+
+ 2: Choose a unique internal name (ie. integer between 1 and 255). To find out
+ what internal names (ie. numbers) are already taken type,
+
+ cd devpost
+ grep internalname ? ?? | sort -n +1 -2
+
+ Any number not already used can be chosen. Consecutive numbering starting at
+ a fixed offset (like 128) might be a useful approach.
+
+ 3: Build the width tables and install the ASCII files in ./devpost. Width tables
+ can be built by hand or you can use postio (with the -t option) and the stuff
+ in directory ../buildtables and have the printer generate the tables. Widths
+ (ie. numbers in column 2) are point size 10 widths assuming a resolution of
+ 720 dpi. As an example if you wanted to find the width of character A in
+ Times-Roman you could send the following to a PostScript printer,
+
+ /Times-Roman findfont 100 scalefont setfont
+ (A) stringwidth pop ==
+
+ The fourth column in the width tables is the character code field and is only
+ used by dpost. It must be the code assigned to the character in the PostScript
+ font. For simple characters (like an a) it's just the ASCII code. Characters
+ that are assigned codes less than 32 (typically 1 or 2) are special and are
+ built up using files in devpost/charlib.
+
+ 4: Any new special character names you've added to the width table must appear in
+ the charset portion of file devpost/DESC.
+
+ 5: Add a mapping definition to ../postscript/dpost.ps. For example if you've
+ built a width table for font XR and the PostScript name is /ExtraFont-Roman
+ then add,
+
+ /XR /ExtraFont-Roman def
+
+ to the dpost prologue.
+
+ 6: If you're system uses PDQs you'll need to build new PDQ font files. I've
+ included the PDQ version of makedev and font.mk includes a target called PDQ
+ that works on MHCC systems. Typing,
+
+ make -f font.mk PDQ
+
+ should work, provided you can execute the PDQFRONT program. The new binary
+ PDQ files initially go in directory PDQ/devpost and from there are installed
+ in /usr/lib/font/PDQ/devpost. If you don't know what PDQs are skip this stuff.
+
+ 7: Build and install the new binary font files and dpost prologue by typing,
+
+ cd ..
+ make TARGETS='font postscript' install
+
+ Actually the install (as written above) installs everything in directory
+ ../postscript. Since all you need is the new version of dpost.ps the following
+ might be safer,
+
+ cd ..
+ make TARGETS=font install
+ cd postscript
+ cp dpost.ps /usr/lib/postscript/dpost.ps
+
+The devpostaps directory is new and the binary tables won't be built or installed
+unless you do it by hand. The tables are an attempt to make Linotronic output look
+something like APS-5 output, and won't be useful to most people. The only real
+application is for simple (perhaps one or two page) updates to larger documents
+that have already been formatted and printed on the APS-5. The following commands
+build and install the devpostaps tables,
+
+ make -f font.mk makedev
+ cd devpostaps
+ ../makedev DESC ? ??
+ mkdir /usr/lib/font/devpostaps
+ cp *.out /usr/lib/font/devpostaps
+ cd charlib
+ mkdir /usr/lib/font/devpostaps/charlib
+ cp * /usr/lib/font/devpostaps/charlib
+
+The tables should only be used by dpost - troff files should be formatted with
+the -Taps option. In addition dpost must use level 2 encoding. A command line
+that forces dpost to do the best it can with APS files would be,
+
+ dpost -e2 -Tpostaps -C/usr/lib/postscript/aps.ps file >file.ps
+
+where aps.ps is additional PostScript code (pulled in using the -C option) that
+tunes the Courier, Times, and Helvetica fonts so they look more like APS fonts.
+
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/AB b/usr/src/cmd/lp/filter/postscript/font/devpost/AB
new file mode 100644
index 0000000000..b838a54749
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/AB
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# AvantGarde-Demi
+name AB
+internalname 27
+ligatures fi fl 0
+charset
+! 28 2 33
+$ 56 2 36
+% 86 2 37
+& 68 2 38
+' 28 2 39
+( 38 3 40
+) 38 3 41
+* 44 2 42
++ 60 0 43
+, 28 1 44
+hy 42 0 45
+- "
+. 28 0 46
+/ 46 3 47
+0 56 2 48
+1 56 2 49
+2 56 2 50
+3 56 2 51
+4 56 2 52
+5 56 2 53
+6 56 2 54
+7 56 2 55
+8 56 2 56
+9 56 2 57
+: 28 0 58
+; 28 1 59
+= 60 0 61
+? 56 2 63
+A 74 2 65
+B 58 2 66
+C 78 2 67
+D 70 2 68
+E 52 2 69
+F 48 2 70
+G 84 2 71
+H 68 2 72
+I 28 2 73
+J 48 2 74
+K 62 2 75
+L 44 2 76
+M 90 2 77
+N 74 2 78
+O 84 2 79
+P 56 2 80
+Q 84 2 81
+R 58 2 82
+S 52 2 83
+T 42 2 84
+U 64 2 85
+V 70 2 86
+W 90 2 87
+X 68 2 88
+Y 62 2 89
+Z 50 2 90
+[ 32 3 91
+] 32 3 93
+` 28 2 96
+a 66 0 97
+b 66 2 98
+c 64 0 99
+d 66 2 100
+e 64 0 101
+f 28 2 102
+g 66 1 103
+h 60 2 104
+i 24 2 105
+j 26 3 106
+k 58 2 107
+l 24 2 108
+m 94 0 109
+n 60 0 110
+o 64 0 111
+p 66 1 112
+q 66 1 113
+r 32 0 114
+s 44 0 115
+t 30 2 116
+u 60 0 117
+v 56 0 118
+w 80 0 119
+x 56 0 120
+y 58 1 121
+z 46 0 122
+ct 56 2 162
+fi 52 2 174
+fl 52 2 175
+dg 56 3 178
+bu 60 0 183
+de 36 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 48 2 170
+'' 48 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/AB.name b/usr/src/cmd/lp/filter/postscript/font/devpost/AB.name
new file mode 100644
index 0000000000..66cbce00a8
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/AB.name
@@ -0,0 +1 @@
+AvantGarde-Demi
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/AI b/usr/src/cmd/lp/filter/postscript/font/devpost/AI
new file mode 100644
index 0000000000..b7872c4f59
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/AI
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# AvantGarde-BookOblique
+name AI
+internalname 26
+ligatures fi fl 0
+charset
+! 29 2 33
+$ 55 2 36
+% 77 2 37
+& 76 2 38
+' 35 2 39
+( 37 3 40
+) 37 3 41
+* 42 2 42
++ 61 0 43
+, 28 0 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 44 3 47
+0 55 2 48
+1 55 2 49
+2 55 2 50
+3 55 2 51
+4 55 2 52
+5 55 2 53
+6 55 2 54
+7 55 2 55
+8 55 2 56
+9 55 2 57
+: 28 0 58
+; 28 0 59
+= 61 0 61
+? 59 2 63
+A 74 2 65
+B 57 2 66
+C 81 2 67
+D 74 2 68
+E 54 2 69
+F 49 2 70
+G 87 2 71
+H 68 2 72
+I 23 2 73
+J 48 2 74
+K 59 2 75
+L 46 2 76
+M 92 2 77
+N 74 2 78
+O 87 2 79
+P 59 2 80
+Q 87 2 81
+R 61 2 82
+S 50 2 83
+T 43 2 84
+U 66 2 85
+V 70 2 86
+W 96 2 87
+X 61 2 88
+Y 59 2 89
+Z 48 2 90
+[ 35 3 91
+] 35 3 93
+` 35 2 96
+a 68 0 97
+b 68 2 98
+c 65 0 99
+d 69 2 100
+e 65 0 101
+f 31 2 102
+g 67 1 103
+h 61 2 104
+i 20 2 105
+j 20 3 106
+k 50 2 107
+l 20 2 108
+m 94 0 109
+n 61 0 110
+o 66 0 111
+p 68 1 112
+q 68 1 113
+r 30 0 114
+s 39 0 115
+t 34 2 116
+u 61 0 117
+v 55 0 118
+w 83 0 119
+x 48 0 120
+y 54 1 121
+z 42 0 122
+ct 55 2 162
+fi 49 2 174
+fl 49 2 175
+dg 55 3 178
+bu 61 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/AI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/AI.name
new file mode 100644
index 0000000000..042c47d36d
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/AI.name
@@ -0,0 +1 @@
+AvantGarde-BookOblique
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/AR b/usr/src/cmd/lp/filter/postscript/font/devpost/AR
new file mode 100644
index 0000000000..9263876201
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/AR
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# AvantGarde-Book
+name AR
+internalname 25
+ligatures fi fl 0
+charset
+! 29 2 33
+$ 55 2 36
+% 77 2 37
+& 76 2 38
+' 35 2 39
+( 37 3 40
+) 37 3 41
+* 42 2 42
++ 61 0 43
+, 28 0 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 44 3 47
+0 55 2 48
+1 55 2 49
+2 55 2 50
+3 55 2 51
+4 55 2 52
+5 55 2 53
+6 55 2 54
+7 55 2 55
+8 55 2 56
+9 55 2 57
+: 28 0 58
+; 28 0 59
+= 61 0 61
+? 59 2 63
+A 74 2 65
+B 57 2 66
+C 81 2 67
+D 74 2 68
+E 54 2 69
+F 49 2 70
+G 87 2 71
+H 68 2 72
+I 23 2 73
+J 48 2 74
+K 59 2 75
+L 46 2 76
+M 92 2 77
+N 74 2 78
+O 87 2 79
+P 59 2 80
+Q 87 2 81
+R 61 2 82
+S 50 2 83
+T 43 2 84
+U 66 2 85
+V 70 2 86
+W 96 2 87
+X 61 2 88
+Y 59 2 89
+Z 48 2 90
+[ 35 3 91
+] 35 3 93
+` 35 2 96
+a 68 0 97
+b 68 2 98
+c 65 0 99
+d 69 2 100
+e 65 0 101
+f 31 2 102
+g 67 1 103
+h 61 2 104
+i 20 2 105
+j 20 3 106
+k 50 2 107
+l 20 2 108
+m 94 0 109
+n 61 0 110
+o 66 0 111
+p 68 1 112
+q 68 1 113
+r 30 0 114
+s 39 0 115
+t 34 2 116
+u 61 0 117
+v 55 0 118
+w 83 0 119
+x 48 0 120
+y 54 1 121
+z 42 0 122
+ct 55 2 162
+fi 49 2 174
+fl 49 2 175
+dg 55 3 178
+bu 61 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/AR.name b/usr/src/cmd/lp/filter/postscript/font/devpost/AR.name
new file mode 100644
index 0000000000..8e691047db
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/AR.name
@@ -0,0 +1 @@
+AvantGarde-Book
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/AX b/usr/src/cmd/lp/filter/postscript/font/devpost/AX
new file mode 100644
index 0000000000..c756805d33
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/AX
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# AvantGarde-DemiOblique
+name AX
+internalname 28
+ligatures fi fl 0
+charset
+! 28 2 33
+$ 56 2 36
+% 86 2 37
+& 68 2 38
+' 28 2 39
+( 38 3 40
+) 38 3 41
+* 44 2 42
++ 60 0 43
+, 28 1 44
+hy 42 0 45
+- "
+. 28 0 46
+/ 46 3 47
+0 56 2 48
+1 56 2 49
+2 56 2 50
+3 56 2 51
+4 56 2 52
+5 56 2 53
+6 56 2 54
+7 56 2 55
+8 56 2 56
+9 56 2 57
+: 28 0 58
+; 28 1 59
+= 60 0 61
+? 56 2 63
+A 74 2 65
+B 58 2 66
+C 78 2 67
+D 70 2 68
+E 52 2 69
+F 48 2 70
+G 84 2 71
+H 68 2 72
+I 28 2 73
+J 48 2 74
+K 62 2 75
+L 44 2 76
+M 90 2 77
+N 74 2 78
+O 84 2 79
+P 56 2 80
+Q 84 2 81
+R 58 2 82
+S 52 2 83
+T 42 2 84
+U 64 2 85
+V 70 2 86
+W 90 2 87
+X 68 2 88
+Y 62 2 89
+Z 50 2 90
+[ 32 3 91
+] 32 3 93
+` 28 2 96
+a 66 0 97
+b 66 2 98
+c 64 0 99
+d 66 2 100
+e 64 0 101
+f 28 2 102
+g 66 1 103
+h 60 2 104
+i 24 2 105
+j 26 3 106
+k 58 2 107
+l 24 2 108
+m 94 0 109
+n 60 0 110
+o 64 0 111
+p 66 1 112
+q 66 1 113
+r 32 0 114
+s 44 0 115
+t 30 2 116
+u 60 0 117
+v 56 0 118
+w 80 0 119
+x 56 0 120
+y 58 1 121
+z 46 0 122
+ct 56 2 162
+fi 52 2 174
+fl 52 2 175
+dg 56 3 178
+bu 60 0 183
+de 36 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 48 2 170
+'' 48 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/AX.name b/usr/src/cmd/lp/filter/postscript/font/devpost/AX.name
new file mode 100644
index 0000000000..4cff429625
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/AX.name
@@ -0,0 +1 @@
+AvantGarde-DemiOblique
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/B b/usr/src/cmd/lp/filter/postscript/font/devpost/B
new file mode 100644
index 0000000000..1959f183b7
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/B
@@ -0,0 +1,134 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Times-Bold
+name B
+internalname 3
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 50 3 36
+% 100 2 37
+& 83 2 38
+' 33 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 57 0 43
+, 25 1 44
+hy 33 0 45
+- "
+. 25 0 46
+/ 28 2 47
+0 50 2 48
+1 50 2 49
+2 50 2 50
+3 50 2 51
+4 50 2 52
+5 50 2 53
+6 50 2 54
+7 50 2 55
+8 50 2 56
+9 50 2 57
+: 33 0 58
+; 33 1 59
+= 57 0 61
+? 50 2 63
+A 72 2 65
+B 67 2 66
+C 72 2 67
+D 72 2 68
+E 67 2 69
+F 61 2 70
+G 78 2 71
+H 78 2 72
+I 39 2 73
+J 50 2 74
+K 78 2 75
+L 67 2 76
+M 94 2 77
+N 72 2 78
+O 78 2 79
+P 61 2 80
+Q 78 3 81
+R 72 2 82
+S 56 2 83
+T 67 2 84
+U 72 2 85
+V 72 2 86
+W 100 2 87
+X 72 2 88
+Y 72 2 89
+Z 67 2 90
+[ 33 3 91
+] 33 3 93
+` 33 2 96
+a 50 0 97
+b 56 2 98
+c 44 0 99
+d 56 2 100
+e 44 0 101
+f 33 2 102
+g 50 1 103
+h 56 2 104
+i 28 2 105
+j 33 3 106
+k 56 2 107
+l 28 2 108
+m 83 0 109
+n 56 0 110
+o 50 0 111
+p 56 1 112
+q 56 1 113
+r 44 0 114
+s 39 0 115
+t 33 2 116
+u 56 0 117
+v 50 0 118
+w 72 0 119
+x 50 0 120
+y 50 1 121
+z 44 0 122
+ct 50 3 162
+fi 56 2 174
+fl 56 2 175
+ff 60 2 1
+Fi 84 2 1
+Fl 84 2 1
+dg 50 3 178
+bu 35 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+sq 50 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/B.name b/usr/src/cmd/lp/filter/postscript/font/devpost/B.name
new file mode 100644
index 0000000000..0eff771010
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/B.name
@@ -0,0 +1 @@
+Times-Bold
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/BI b/usr/src/cmd/lp/filter/postscript/font/devpost/BI
new file mode 100644
index 0000000000..f5c5d99daa
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/BI
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Times-BoldItalic
+name BI
+internalname 4
+ligatures fi fl 0
+charset
+! 39 2 33
+$ 50 2 36
+% 83 2 37
+& 78 2 38
+' 33 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 57 0 43
+, 25 1 44
+hy 33 0 45
+- "
+. 25 0 46
+/ 28 2 47
+0 50 2 48
+1 50 2 49
+2 50 2 50
+3 50 2 51
+4 50 2 52
+5 50 2 53
+6 50 2 54
+7 50 2 55
+8 50 2 56
+9 50 2 57
+: 33 0 58
+; 33 1 59
+= 57 0 61
+? 50 2 63
+A 67 2 65
+B 67 2 66
+C 67 2 67
+D 72 2 68
+E 67 2 69
+F 67 2 70
+G 72 2 71
+H 78 2 72
+I 39 2 73
+J 50 2 74
+K 67 2 75
+L 61 2 76
+M 89 2 77
+N 72 2 78
+O 72 2 79
+P 61 2 80
+Q 72 3 81
+R 67 2 82
+S 56 2 83
+T 61 2 84
+U 72 2 85
+V 67 2 86
+W 89 2 87
+X 67 2 88
+Y 61 2 89
+Z 61 2 90
+[ 33 3 91
+] 33 3 93
+` 33 2 96
+a 50 0 97
+b 50 2 98
+c 44 0 99
+d 50 2 100
+e 44 0 101
+f 33 3 102
+g 50 1 103
+h 56 2 104
+i 28 2 105
+j 28 3 106
+k 50 2 107
+l 28 2 108
+m 78 0 109
+n 56 0 110
+o 50 0 111
+p 50 1 112
+q 50 1 113
+r 39 0 114
+s 39 0 115
+t 28 2 116
+u 56 0 117
+v 44 0 118
+w 67 0 119
+x 50 0 120
+y 44 1 121
+z 39 0 122
+ct 50 3 162
+fi 56 3 174
+fl 56 3 175
+dg 50 3 178
+bu 35 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/BI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/BI.name
new file mode 100644
index 0000000000..3aed601b14
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/BI.name
@@ -0,0 +1 @@
+Times-BoldItalic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CB b/usr/src/cmd/lp/filter/postscript/font/devpost/CB
new file mode 100644
index 0000000000..1dd2c34050
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CB
@@ -0,0 +1,134 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Courier-Bold
+name CB
+internalname 7
+spacewidth 60
+charset
+! 60 2 33
+" 60 2 34
+# 60 2 35
+$ 60 2 36
+% 60 2 37
+& 60 2 38
+' 60 2 39
+( 60 3 40
+) 60 3 41
+* 60 2 42
++ 60 0 43
+, 60 1 44
+hy 60 0 45
+- "
+. 60 0 46
+/ 60 2 47
+0 60 2 48
+1 60 2 49
+2 60 2 50
+3 60 2 51
+4 60 2 52
+5 60 2 53
+6 60 2 54
+7 60 2 55
+8 60 2 56
+9 60 2 57
+: 60 0 58
+; 60 1 59
+< 60 2 60
+= 60 0 61
+> 60 2 62
+? 60 2 63
+@ 60 2 64
+A 60 2 65
+B 60 2 66
+C 60 2 67
+D 60 2 68
+E 60 2 69
+F 60 2 70
+G 60 2 71
+H 60 2 72
+I 60 2 73
+J 60 2 74
+K 60 2 75
+L 60 2 76
+M 60 2 77
+N 60 2 78
+O 60 2 79
+P 60 2 80
+Q 60 3 81
+R 60 2 82
+S 60 2 83
+T 60 2 84
+U 60 2 85
+V 60 2 86
+W 60 2 87
+X 60 2 88
+Y 60 2 89
+Z 60 2 90
+[ 60 3 91
+\ 60 3 92
+] 60 3 93
+^ 60 2 94
+_ 60 1 95
+` 60 2 96
+a 60 0 97
+b 60 2 98
+c 60 0 99
+d 60 2 100
+e 60 0 101
+f 60 2 102
+g 60 1 103
+h 60 2 104
+i 60 2 105
+j 60 3 106
+k 60 2 107
+l 60 2 108
+m 60 0 109
+n 60 0 110
+o 60 0 111
+p 60 1 112
+q 60 1 113
+r 60 0 114
+s 60 0 115
+t 60 2 116
+u 60 0 117
+v 60 0 118
+w 60 0 119
+x 60 0 120
+y 60 1 121
+z 60 0 122
+{ 60 3 123
+| 60 3 124
+} 60 3 125
+~ 60 0 126
+ct 60 2 162
+\- 60 0 177
+en "
+dg 60 3 178
+bu 60 0 183
+de 60 2 202
+em 60 0 208
+14 60 2 1
+34 60 2 1
+12 60 2 1
+`` 60 2 170
+'' 60 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CB.name b/usr/src/cmd/lp/filter/postscript/font/devpost/CB.name
new file mode 100644
index 0000000000..e29f392a7e
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CB.name
@@ -0,0 +1 @@
+Courier-Bold
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CI b/usr/src/cmd/lp/filter/postscript/font/devpost/CI
new file mode 100644
index 0000000000..3b8ad8b379
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CI
@@ -0,0 +1,142 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Courier-Oblique
+name CI
+internalname 6
+spacewidth 60
+charset
+! 60 2 33
+" 60 2 34
+# 60 2 35
+$ 60 2 36
+% 60 2 37
+& 60 2 38
+' 60 2 39
+( 60 3 40
+) 60 3 41
+* 60 2 42
++ 60 0 43
+, 60 1 44
+hy 60 0 45
+- "
+. 60 0 46
+/ 60 2 47
+0 60 2 48
+1 60 2 49
+2 60 2 50
+3 60 2 51
+4 60 2 52
+5 60 2 53
+6 60 2 54
+7 60 2 55
+8 60 2 56
+9 60 2 57
+: 60 0 58
+; 60 1 59
+< 60 2 60
+= 60 0 61
+> 60 2 62
+? 60 2 63
+@ 60 2 64
+A 60 2 65
+B 60 2 66
+C 60 2 67
+D 60 2 68
+E 60 2 69
+F 60 2 70
+G 60 2 71
+H 60 2 72
+I 60 2 73
+J 60 2 74
+K 60 2 75
+L 60 2 76
+M 60 2 77
+N 60 2 78
+O 60 2 79
+P 60 2 80
+Q 60 3 81
+R 60 2 82
+S 60 2 83
+T 60 2 84
+U 60 2 85
+V 60 2 86
+W 60 2 87
+X 60 2 88
+Y 60 2 89
+Z 60 2 90
+[ 60 3 91
+\ 60 3 92
+] 60 3 93
+^ 60 2 94
+_ 60 1 95
+` 60 2 96
+a 60 0 97
+b 60 2 98
+c 60 0 99
+d 60 2 100
+e 60 0 101
+f 60 2 102
+g 60 1 103
+h 60 2 104
+i 60 2 105
+j 60 3 106
+k 60 2 107
+l 60 2 108
+m 60 0 109
+n 60 0 110
+o 60 0 111
+p 60 1 112
+q 60 1 113
+r 60 0 114
+s 60 0 115
+t 60 2 116
+u 60 0 117
+v 60 0 118
+w 60 0 119
+x 60 0 120
+y 60 1 121
+z 60 0 122
+{ 60 3 123
+| 60 3 124
+} 60 3 125
+~ 60 0 126
+ct 60 2 162
+\- 60 0 177
+en "
+dg 60 3 178
+bu 60 0 183
+de 60 2 202
+em 60 0 208
+14 60 2 1
+34 60 2 1
+12 60 2 1
+`` 60 2 170
+'' 60 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/CI.name
new file mode 100644
index 0000000000..96620c5d3b
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CI.name
@@ -0,0 +1 @@
+Courier-Oblique
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CO b/usr/src/cmd/lp/filter/postscript/font/devpost/CO
new file mode 100644
index 0000000000..f6a1c8c64e
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CO
@@ -0,0 +1,134 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Courier
+name CW
+internalname 5
+spacewidth 60
+charset
+! 60 2 33
+" 60 2 34
+# 60 2 35
+$ 60 2 36
+% 60 2 37
+& 60 2 38
+' 60 2 39
+( 60 3 40
+) 60 3 41
+* 60 2 42
++ 60 0 43
+, 60 1 44
+hy 60 0 45
+- "
+. 60 0 46
+/ 60 2 47
+0 60 2 48
+1 60 2 49
+2 60 2 50
+3 60 2 51
+4 60 2 52
+5 60 2 53
+6 60 2 54
+7 60 2 55
+8 60 2 56
+9 60 2 57
+: 60 0 58
+; 60 1 59
+< 60 2 60
+= 60 0 61
+> 60 2 62
+? 60 2 63
+@ 60 2 64
+A 60 2 65
+B 60 2 66
+C 60 2 67
+D 60 2 68
+E 60 2 69
+F 60 2 70
+G 60 2 71
+H 60 2 72
+I 60 2 73
+J 60 2 74
+K 60 2 75
+L 60 2 76
+M 60 2 77
+N 60 2 78
+O 60 2 79
+P 60 2 80
+Q 60 3 81
+R 60 2 82
+S 60 2 83
+T 60 2 84
+U 60 2 85
+V 60 2 86
+W 60 2 87
+X 60 2 88
+Y 60 2 89
+Z 60 2 90
+[ 60 3 91
+\ 60 3 92
+] 60 3 93
+^ 60 2 94
+_ 60 1 95
+` 60 2 96
+a 60 0 97
+b 60 2 98
+c 60 0 99
+d 60 2 100
+e 60 0 101
+f 60 2 102
+g 60 1 103
+h 60 2 104
+i 60 2 105
+j 60 3 106
+k 60 2 107
+l 60 2 108
+m 60 0 109
+n 60 0 110
+o 60 0 111
+p 60 1 112
+q 60 1 113
+r 60 0 114
+s 60 0 115
+t 60 2 116
+u 60 0 117
+v 60 0 118
+w 60 0 119
+x 60 0 120
+y 60 1 121
+z 60 0 122
+{ 60 3 123
+| 60 3 124
+} 60 3 125
+~ 60 0 126
+ct 60 2 162
+\- 60 0 177
+en "
+dg 60 3 178
+bu 60 0 183
+de 60 2 202
+em 60 0 208
+14 60 2 1
+34 60 2 1
+12 60 2 1
+`` 60 2 170
+'' 60 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CO.name b/usr/src/cmd/lp/filter/postscript/font/devpost/CO.name
new file mode 100644
index 0000000000..75f4fae71e
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CO.name
@@ -0,0 +1 @@
+Courier
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CW b/usr/src/cmd/lp/filter/postscript/font/devpost/CW
new file mode 100644
index 0000000000..64016b9270
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CW
@@ -0,0 +1,142 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Courier
+name CW
+internalname 5
+spacewidth 60
+charset
+! 60 2 33
+" 60 2 34
+# 60 2 35
+$ 60 2 36
+% 60 2 37
+& 60 2 38
+' 60 2 39
+( 60 3 40
+) 60 3 41
+* 60 2 42
++ 60 0 43
+, 60 1 44
+hy 60 0 45
+- "
+. 60 0 46
+/ 60 2 47
+0 60 2 48
+1 60 2 49
+2 60 2 50
+3 60 2 51
+4 60 2 52
+5 60 2 53
+6 60 2 54
+7 60 2 55
+8 60 2 56
+9 60 2 57
+: 60 0 58
+; 60 1 59
+< 60 2 60
+= 60 0 61
+> 60 2 62
+? 60 2 63
+@ 60 2 64
+A 60 2 65
+B 60 2 66
+C 60 2 67
+D 60 2 68
+E 60 2 69
+F 60 2 70
+G 60 2 71
+H 60 2 72
+I 60 2 73
+J 60 2 74
+K 60 2 75
+L 60 2 76
+M 60 2 77
+N 60 2 78
+O 60 2 79
+P 60 2 80
+Q 60 3 81
+R 60 2 82
+S 60 2 83
+T 60 2 84
+U 60 2 85
+V 60 2 86
+W 60 2 87
+X 60 2 88
+Y 60 2 89
+Z 60 2 90
+[ 60 3 91
+\ 60 3 92
+] 60 3 93
+^ 60 2 94
+_ 60 1 95
+` 60 2 96
+a 60 0 97
+b 60 2 98
+c 60 0 99
+d 60 2 100
+e 60 0 101
+f 60 2 102
+g 60 1 103
+h 60 2 104
+i 60 2 105
+j 60 3 106
+k 60 2 107
+l 60 2 108
+m 60 0 109
+n 60 0 110
+o 60 0 111
+p 60 1 112
+q 60 1 113
+r 60 0 114
+s 60 0 115
+t 60 2 116
+u 60 0 117
+v 60 0 118
+w 60 0 119
+x 60 0 120
+y 60 1 121
+z 60 0 122
+{ 60 3 123
+| 60 3 124
+} 60 3 125
+~ 60 0 126
+ct 60 2 162
+\- 60 0 177
+en "
+dg 60 3 178
+bu 60 0 183
+de 60 2 202
+em 60 0 208
+14 60 2 1
+34 60 2 1
+12 60 2 1
+`` 60 2 170
+'' 60 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CW.name b/usr/src/cmd/lp/filter/postscript/font/devpost/CW.name
new file mode 100644
index 0000000000..75f4fae71e
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CW.name
@@ -0,0 +1 @@
+Courier
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CX b/usr/src/cmd/lp/filter/postscript/font/devpost/CX
new file mode 100644
index 0000000000..b804583461
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CX
@@ -0,0 +1,142 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Courier-BoldOblique
+name CX
+internalname 8
+spacewidth 60
+charset
+! 60 2 33
+" 60 2 34
+# 60 2 35
+$ 60 2 36
+% 60 2 37
+& 60 2 38
+' 60 2 39
+( 60 3 40
+) 60 3 41
+* 60 2 42
++ 60 0 43
+, 60 1 44
+hy 60 0 45
+- "
+. 60 0 46
+/ 60 2 47
+0 60 2 48
+1 60 2 49
+2 60 2 50
+3 60 2 51
+4 60 2 52
+5 60 2 53
+6 60 2 54
+7 60 2 55
+8 60 2 56
+9 60 2 57
+: 60 0 58
+; 60 1 59
+< 60 2 60
+= 60 0 61
+> 60 2 62
+? 60 2 63
+@ 60 2 64
+A 60 2 65
+B 60 2 66
+C 60 2 67
+D 60 2 68
+E 60 2 69
+F 60 2 70
+G 60 2 71
+H 60 2 72
+I 60 2 73
+J 60 2 74
+K 60 2 75
+L 60 2 76
+M 60 2 77
+N 60 2 78
+O 60 2 79
+P 60 2 80
+Q 60 3 81
+R 60 2 82
+S 60 2 83
+T 60 2 84
+U 60 2 85
+V 60 2 86
+W 60 2 87
+X 60 2 88
+Y 60 2 89
+Z 60 2 90
+[ 60 3 91
+\ 60 3 92
+] 60 3 93
+^ 60 2 94
+_ 60 1 95
+` 60 2 96
+a 60 0 97
+b 60 2 98
+c 60 0 99
+d 60 2 100
+e 60 0 101
+f 60 2 102
+g 60 1 103
+h 60 2 104
+i 60 2 105
+j 60 3 106
+k 60 2 107
+l 60 2 108
+m 60 0 109
+n 60 0 110
+o 60 0 111
+p 60 1 112
+q 60 1 113
+r 60 0 114
+s 60 0 115
+t 60 2 116
+u 60 0 117
+v 60 0 118
+w 60 0 119
+x 60 0 120
+y 60 1 121
+z 60 0 122
+{ 60 3 123
+| 60 3 124
+} 60 3 125
+~ 60 0 126
+ct 60 2 162
+\- 60 0 177
+en "
+dg 60 3 178
+bu 60 0 183
+de 60 2 202
+em 60 0 208
+14 60 2 1
+34 60 2 1
+12 60 2 1
+`` 60 2 170
+'' 60 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/CX.name b/usr/src/cmd/lp/filter/postscript/font/devpost/CX.name
new file mode 100644
index 0000000000..cbd4f3d606
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/CX.name
@@ -0,0 +1 @@
+Courier-BoldOblique
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/DESC b/usr/src/cmd/lp/filter/postscript/font/devpost/DESC
new file mode 100644
index 0000000000..0472a8f612
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/DESC
@@ -0,0 +1,57 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Description file for Postscript printers. The resolution and unitwidth have
+# been selected to match, in a sense, PostScript's default coordinate system
+# and the widths given in Adobe's Font manual.
+#
+# Right now biggestfont shouldn't be set larger than 219.
+#
+
+fonts 10 R I B BI CW H HB HX S1 S
+sizes 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+24 25 26 27 28 29 30 31 32 33 34 35 36 38 40 44 48 54 60 72 0
+res 720
+hor 1
+vert 1
+unitwidth 10
+biggestfont 200
+charset
+hy ct fi fl ff Fi Fl dg em 14 34 12 \- en \' aa
+\` ga ru sc dd -> \e br Sl ps cs cy as os =. ld
+rd le ge pp -+
+sq bx ci fa te ** pl mi \< eq \> ~= *A *B *X *D
+*E *F *G *Y *I *K *L *M *N *O *P *R *H *S *T *U
+*W *C *Q *Z ul \_ rn *a *b *x *d *e *f *g *y *i
+*k *l *m *n *o *p *h *r *s *t *u *w *c *q *z \{
+\| \} ap fm <= sl if <- ua da de +- >= mu pt pd
+bu di != == ~~ al Ox O+ es ca cu sp ip sb ib mo
+gr rg co tm sr no \^ or lc lf lt lk lb bv is rc
+rf rt rk rb ts lh rh LV LH Lb L1 LA `` '' ob vr
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/DESC.big b/usr/src/cmd/lp/filter/postscript/font/devpost/DESC.big
new file mode 100644
index 0000000000..4c5d91e054
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/DESC.big
@@ -0,0 +1,48 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Description file for Postscript printers. The resolution and unitwidth have
+# been selected to match, in a sense, PostScript's default coordinate system
+# and the widths given in Adobe's Font manual.
+#
+# Right now biggestfont shouldn't be set larger than 219.
+#
+
+fonts 10 R I B BI CW H HB HX S1 S
+sizes 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+24 25 26 27 28 29 30 31 32 33 34 35 36 38 40 44 48 54 60 72 0
+res 720
+hor 1
+vert 1
+unitwidth 10
+biggestfont 200
+charset
+hy ct fi fl ff Fi Fl dg em 14 34 12 \- en \' aa
+\` ga ru sc dd -> \e br Sl ps cs cy as os =. ld
+rd le ge pp -+
+sq bx ci fa te ** pl mi \< eq \> ~= *A *B *X *D
+*E *F *G *Y *I *K *L *M *N *O *P *R *H *S *T *U *W
+*C *Q *Z ul \_ rn *a *b *x *d *e *f *g *y *i *k
+*l *m *n *o *p *h *r *s *t *u *w *c *q *z \{ \|
+\} ap fm <= sl if <- ua da de +- >= mu pt pd bu
+di != == ~~ al Ox O+ es ca cu sp ip sb ib mo gr
+rg co tm sr no \^ or lc lf lt lk lb bv is rc rf
+rt rk rb ts lh rh LV LH Lb L1 LA `` ''
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/DESC.small b/usr/src/cmd/lp/filter/postscript/font/devpost/DESC.small
new file mode 100644
index 0000000000..3c68c4e766
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/DESC.small
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# A DESC file that can be used with the new version of makedev to produce smaller
+# DESC.out files. May help if you're running troff on a PC with a small address
+# space. biggestfont is set to the size of the CW font, and will accomodate all
+# font files except S and ZD. If you use this version ZD will only be mountable
+# in font position 0 using \f(ZD. To use it replace DESC by DESC.small before
+# building the binary font files. Also included a version of the S font file,
+# S.small, that has all unnamed characters (ie. ones named by ---) removed. Using
+# it will further decrease the size of DESC.out - but may not be necessary.
+#
+
+fonts 10 R I B BI CW H HB HX S1 S
+sizes 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
+24 25 26 27 28 29 30 31 32 33 34 35 36 38 40 44 48 54 60 72 0
+res 720
+hor 1
+vert 1
+unitwidth 10
+biggestfont 106
+charset
+hy ct fi fl ff Fi Fl dg em 14 34 12 \- en \' aa
+\` ga ru sc dd -> \e br Sl ps cs cy as os =. ld
+rd le ge pp -+
+sq bx ci fa te ** pl mi \< eq \> ~= *A *B *X *D
+*E *F *G *Y *I *K *L *M *N *O *P *R *H *S *T *U *W
+*C *Q *Z ul \_ rn *a *b *x *d *e *f *g *y *i *k
+*l *m *n *o *p *h *r *s *t *u *w *c *q *z \{ \|
+\} ap fm <= sl if <- ua da de +- >= mu pt pd bu
+di != == ~~ al Ox O+ es ca cu sp ip sb ib mo gr
+rg co tm sr no \^ or lc lf lt lk lb bv is rc rf
+rt rk rb ts lh rh LV LH Lb L1 LA `` ''
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/GR b/usr/src/cmd/lp/filter/postscript/font/devpost/GR
new file mode 100644
index 0000000000..919f70bda4
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/GR
@@ -0,0 +1,83 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Greek
+name GR
+internalname 33
+special
+charset
+*a 63 0 97
+*b 55 3 98
+*g 41 1 103
+*d 49 2 100
+*e 44 0 101
+*z 49 3 122
+*y 60 1 104
+*h 52 2 113
+*i 33 0 105
+*k 55 0 107
+*l 55 2 108
+*m 58 1 109
+*n 52 0 110
+*c 49 3 120
+*o 55 0 111
+*p 55 0 112
+*r 55 1 114
+*s 60 0 115
+*t 44 0 116
+*u 58 0 117
+*f 52 3 102
+*x 55 1 99
+*q 69 1 121
+*w 69 0 119
+*A 72 2 65
+*B 67 2 66
+*G 60 2 71
+*D 61 2 68
+*E 61 2 69
+*Z 61 2 90
+*Y 72 2 72
+*H 74 2 81
+*R 56 2 82
+*I 33 2 73
+*K 72 2 75
+*L 69 2 76
+*M 89 2 77
+*N 72 2 78
+*C 65 2 88
+*O 72 2 79
+*P 77 2 80
+*S 59 2 83
+*T 61 2 84
+*U 69 2 85
+*F 76 2 70
+*X 72 2 67
+*Q 80 2 89
+*W 77 2 87
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/GR.name b/usr/src/cmd/lp/filter/postscript/font/devpost/GR.name
new file mode 100644
index 0000000000..c5fe836342
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/GR.name
@@ -0,0 +1 @@
+Symbol
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/H b/usr/src/cmd/lp/filter/postscript/font/devpost/H
new file mode 100644
index 0000000000..1aef144198
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/H
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Helvetica
+name H
+internalname 9
+ligatures fi fl 0
+charset
+! 28 2 33
+$ 56 3 36
+% 89 2 37
+& 67 2 38
+' 22 2 39
+( 33 3 40
+) 33 3 41
+* 39 2 42
++ 58 0 43
+, 28 1 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 28 2 47
+0 56 2 48
+1 56 2 49
+2 56 2 50
+3 56 2 51
+4 56 2 52
+5 56 2 53
+6 56 2 54
+7 56 2 55
+8 56 2 56
+9 56 2 57
+: 28 0 58
+; 28 1 59
+= 58 0 61
+? 56 2 63
+A 67 2 65
+B 67 2 66
+C 72 2 67
+D 72 2 68
+E 67 2 69
+F 61 2 70
+G 78 2 71
+H 72 2 72
+I 28 2 73
+J 50 2 74
+K 67 2 75
+L 56 2 76
+M 83 2 77
+N 72 2 78
+O 78 2 79
+P 67 2 80
+Q 78 2 81
+R 72 2 82
+S 67 2 83
+T 61 2 84
+U 72 2 85
+V 67 2 86
+W 94 2 87
+X 67 2 88
+Y 67 2 89
+Z 61 2 90
+[ 28 3 91
+] 28 3 93
+` 22 2 96
+a 56 0 97
+b 56 2 98
+c 50 0 99
+d 56 2 100
+e 56 0 101
+f 28 2 102
+g 56 1 103
+h 56 2 104
+i 22 2 105
+j 22 3 106
+k 50 2 107
+l 22 2 108
+m 83 0 109
+n 56 0 110
+o 56 0 111
+p 56 1 112
+q 56 1 113
+r 33 0 114
+s 50 0 115
+t 28 2 116
+u 56 0 117
+v 50 0 118
+w 72 0 119
+x 50 0 120
+y 50 1 121
+z 50 0 122
+ct 56 3 162
+fi 50 2 174
+fl 50 2 175
+dg 56 3 178
+bu 35 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 33 2 170
+'' 33 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/H.name b/usr/src/cmd/lp/filter/postscript/font/devpost/H.name
new file mode 100644
index 0000000000..c2ed429f59
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/H.name
@@ -0,0 +1 @@
+Helvetica
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/HB b/usr/src/cmd/lp/filter/postscript/font/devpost/HB
new file mode 100644
index 0000000000..f6758640c6
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/HB
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Helvetica-Bold
+name HB
+internalname 11
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 56 3 36
+% 89 2 37
+& 72 2 38
+' 28 2 39
+( 33 3 40
+) 33 3 41
+* 39 2 42
++ 58 0 43
+, 28 1 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 28 2 47
+0 56 2 48
+1 56 2 49
+2 56 2 50
+3 56 2 51
+4 56 2 52
+5 56 2 53
+6 56 2 54
+7 56 2 55
+8 56 2 56
+9 56 2 57
+: 33 0 58
+; 33 1 59
+= 58 0 61
+? 61 2 63
+A 72 2 65
+B 72 2 66
+C 72 2 67
+D 72 2 68
+E 67 2 69
+F 61 2 70
+G 78 2 71
+H 72 2 72
+I 28 2 73
+J 56 2 74
+K 72 2 75
+L 61 2 76
+M 83 2 77
+N 72 2 78
+O 78 2 79
+P 67 2 80
+Q 78 2 81
+R 72 2 82
+S 67 2 83
+T 61 2 84
+U 72 2 85
+V 67 2 86
+W 94 2 87
+X 67 2 88
+Y 67 2 89
+Z 61 2 90
+[ 33 3 91
+] 33 3 93
+` 28 2 96
+a 56 0 97
+b 61 2 98
+c 56 0 99
+d 61 2 100
+e 56 0 101
+f 33 2 102
+g 61 1 103
+h 61 2 104
+i 28 2 105
+j 28 3 106
+k 56 2 107
+l 28 2 108
+m 89 0 109
+n 61 0 110
+o 61 0 111
+p 61 1 112
+q 61 1 113
+r 39 0 114
+s 56 0 115
+t 33 2 116
+u 61 0 117
+v 56 0 118
+w 78 0 119
+x 56 0 120
+y 56 1 121
+z 50 0 122
+ct 56 3 162
+fi 61 2 174
+fl 61 2 175
+dg 56 3 178
+bu 35 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/HB.name b/usr/src/cmd/lp/filter/postscript/font/devpost/HB.name
new file mode 100644
index 0000000000..b6fcae93c0
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/HB.name
@@ -0,0 +1 @@
+Helvetica-Bold
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/HI b/usr/src/cmd/lp/filter/postscript/font/devpost/HI
new file mode 100644
index 0000000000..fe5d467043
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/HI
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Helvetica-Oblique
+name HI
+internalname 10
+ligatures fi fl 0
+charset
+! 28 2 33
+$ 56 3 36
+% 89 2 37
+& 67 2 38
+' 22 2 39
+( 33 3 40
+) 33 3 41
+* 39 2 42
++ 58 0 43
+, 28 1 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 28 2 47
+0 56 2 48
+1 56 2 49
+2 56 2 50
+3 56 2 51
+4 56 2 52
+5 56 2 53
+6 56 2 54
+7 56 2 55
+8 56 2 56
+9 56 2 57
+: 28 0 58
+; 28 1 59
+= 58 0 61
+? 56 2 63
+A 67 2 65
+B 67 2 66
+C 72 2 67
+D 72 2 68
+E 67 2 69
+F 61 2 70
+G 78 2 71
+H 72 2 72
+I 28 2 73
+J 50 2 74
+K 67 2 75
+L 56 2 76
+M 83 2 77
+N 72 2 78
+O 78 2 79
+P 67 2 80
+Q 78 2 81
+R 72 2 82
+S 67 2 83
+T 61 2 84
+U 72 2 85
+V 67 2 86
+W 94 2 87
+X 67 2 88
+Y 67 2 89
+Z 61 2 90
+[ 28 3 91
+] 28 3 93
+` 22 2 96
+a 56 0 97
+b 56 2 98
+c 50 0 99
+d 56 2 100
+e 56 0 101
+f 28 2 102
+g 56 1 103
+h 56 2 104
+i 22 2 105
+j 22 3 106
+k 50 2 107
+l 22 2 108
+m 83 0 109
+n 56 0 110
+o 56 0 111
+p 56 1 112
+q 56 1 113
+r 33 0 114
+s 50 0 115
+t 28 2 116
+u 56 0 117
+v 50 0 118
+w 72 0 119
+x 50 0 120
+y 50 1 121
+z 50 0 122
+ct 56 3 162
+fi 50 2 174
+fl 50 2 175
+dg 56 3 178
+bu 35 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 33 2 170
+'' 33 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/HI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/HI.name
new file mode 100644
index 0000000000..1082d54ec2
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/HI.name
@@ -0,0 +1 @@
+Helvetica-Oblique
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/HX b/usr/src/cmd/lp/filter/postscript/font/devpost/HX
new file mode 100644
index 0000000000..857b910acb
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/HX
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Helvetica-BoldOblique
+name HX
+internalname 12
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 56 3 36
+% 89 2 37
+& 72 2 38
+' 28 2 39
+( 33 3 40
+) 33 3 41
+* 39 2 42
++ 58 0 43
+, 28 1 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 28 2 47
+0 56 2 48
+1 56 2 49
+2 56 2 50
+3 56 2 51
+4 56 2 52
+5 56 2 53
+6 56 2 54
+7 56 2 55
+8 56 2 56
+9 56 2 57
+: 33 0 58
+; 33 1 59
+= 58 0 61
+? 61 2 63
+A 72 2 65
+B 72 2 66
+C 72 2 67
+D 72 2 68
+E 67 2 69
+F 61 2 70
+G 78 2 71
+H 72 2 72
+I 28 2 73
+J 56 2 74
+K 72 2 75
+L 61 2 76
+M 83 2 77
+N 72 2 78
+O 78 2 79
+P 67 2 80
+Q 78 2 81
+R 72 2 82
+S 67 2 83
+T 61 2 84
+U 72 2 85
+V 67 2 86
+W 94 2 87
+X 67 2 88
+Y 67 2 89
+Z 61 2 90
+[ 33 3 91
+] 33 3 93
+` 28 2 96
+a 56 0 97
+b 61 2 98
+c 56 0 99
+d 61 2 100
+e 56 0 101
+f 33 2 102
+g 61 1 103
+h 61 2 104
+i 28 2 105
+j 28 3 106
+k 56 2 107
+l 28 2 108
+m 89 0 109
+n 61 0 110
+o 61 0 111
+p 61 1 112
+q 61 1 113
+r 39 0 114
+s 56 0 115
+t 33 2 116
+u 61 0 117
+v 56 0 118
+w 78 0 119
+x 56 0 120
+y 56 1 121
+z 50 0 122
+ct 56 3 162
+fi 61 2 174
+fl 61 2 175
+dg 56 3 178
+bu 35 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/HX.name b/usr/src/cmd/lp/filter/postscript/font/devpost/HX.name
new file mode 100644
index 0000000000..41e8c82f18
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/HX.name
@@ -0,0 +1 @@
+Helvetica-BoldOblique
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Hb b/usr/src/cmd/lp/filter/postscript/font/devpost/Hb
new file mode 100644
index 0000000000..ad7b7636c0
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Hb
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Helvetica-Narrow-Bold
+name Hb
+internalname 19
+ligatures fi fl 0
+charset
+! 27 2 33
+$ 46 3 36
+% 73 2 37
+& 59 2 38
+' 23 2 39
+( 27 3 40
+) 27 3 41
+* 32 2 42
++ 48 0 43
+, 23 1 44
+hy 27 0 45
+- "
+. 23 0 46
+/ 23 2 47
+0 46 2 48
+1 46 2 49
+2 46 2 50
+3 46 2 51
+4 46 2 52
+5 46 2 53
+6 46 2 54
+7 46 2 55
+8 46 2 56
+9 46 2 57
+: 27 0 58
+; 27 1 59
+= 48 0 61
+? 50 2 63
+A 59 2 65
+B 59 2 66
+C 59 2 67
+D 59 2 68
+E 55 2 69
+F 50 2 70
+G 64 2 71
+H 59 2 72
+I 23 2 73
+J 46 2 74
+K 59 2 75
+L 50 2 76
+M 68 2 77
+N 59 2 78
+O 64 2 79
+P 55 2 80
+Q 64 2 81
+R 59 2 82
+S 55 2 83
+T 50 2 84
+U 59 2 85
+V 55 2 86
+W 77 2 87
+X 55 2 88
+Y 55 2 89
+Z 50 2 90
+[ 27 3 91
+] 27 3 93
+` 23 2 96
+a 46 0 97
+b 50 2 98
+c 46 0 99
+d 50 2 100
+e 46 0 101
+f 27 2 102
+g 50 1 103
+h 50 2 104
+i 23 2 105
+j 23 3 106
+k 46 2 107
+l 23 2 108
+m 73 0 109
+n 50 0 110
+o 50 0 111
+p 50 1 112
+q 50 1 113
+r 32 0 114
+s 46 0 115
+t 27 2 116
+u 50 0 117
+v 46 0 118
+w 64 0 119
+x 46 0 120
+y 46 1 121
+z 41 0 122
+ct 46 3 162
+fi 50 2 174
+fl 50 2 175
+dg 46 3 178
+bu 29 0 183
+de 27 2 202
+em 82 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 41 2 170
+'' 41 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Hb.name b/usr/src/cmd/lp/filter/postscript/font/devpost/Hb.name
new file mode 100644
index 0000000000..c13a099737
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Hb.name
@@ -0,0 +1 @@
+Helvetica-Narrow-Bold
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Hi b/usr/src/cmd/lp/filter/postscript/font/devpost/Hi
new file mode 100644
index 0000000000..f8261bd80f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Hi
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Helvetica-Narrow-Oblique
+name Hi
+internalname 18
+ligatures fi fl 0
+charset
+! 23 2 33
+$ 46 3 36
+% 73 2 37
+& 55 2 38
+' 18 2 39
+( 27 3 40
+) 27 3 41
+* 32 2 42
++ 48 0 43
+, 23 1 44
+hy 27 0 45
+- "
+. 23 0 46
+/ 23 2 47
+0 46 2 48
+1 46 2 49
+2 46 2 50
+3 46 2 51
+4 46 2 52
+5 46 2 53
+6 46 2 54
+7 46 2 55
+8 46 2 56
+9 46 2 57
+: 23 0 58
+; 23 1 59
+= 48 0 61
+? 46 2 63
+A 55 2 65
+B 55 2 66
+C 59 2 67
+D 59 2 68
+E 55 2 69
+F 50 2 70
+G 64 2 71
+H 59 2 72
+I 23 2 73
+J 41 2 74
+K 55 2 75
+L 46 2 76
+M 68 2 77
+N 59 2 78
+O 64 2 79
+P 55 2 80
+Q 64 2 81
+R 59 2 82
+S 55 2 83
+T 50 2 84
+U 59 2 85
+V 55 2 86
+W 77 2 87
+X 55 2 88
+Y 55 2 89
+Z 50 2 90
+[ 23 3 91
+] 23 3 93
+` 18 2 96
+a 46 0 97
+b 46 2 98
+c 41 0 99
+d 46 2 100
+e 46 0 101
+f 23 2 102
+g 46 1 103
+h 46 2 104
+i 18 2 105
+j 18 3 106
+k 41 2 107
+l 18 2 108
+m 68 0 109
+n 46 0 110
+o 46 0 111
+p 46 1 112
+q 46 1 113
+r 27 0 114
+s 41 0 115
+t 23 2 116
+u 46 0 117
+v 41 0 118
+w 59 0 119
+x 41 0 120
+y 41 1 121
+z 41 0 122
+ct 46 3 162
+fi 41 2 174
+fl 41 2 175
+dg 46 3 178
+bu 29 0 183
+de 27 2 202
+em 82 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 27 2 170
+'' 27 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Hi.name b/usr/src/cmd/lp/filter/postscript/font/devpost/Hi.name
new file mode 100644
index 0000000000..5702536b08
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Hi.name
@@ -0,0 +1 @@
+Helvetica-Narrow-Oblique
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Hr b/usr/src/cmd/lp/filter/postscript/font/devpost/Hr
new file mode 100644
index 0000000000..a67afe0f41
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Hr
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Helvetica-Narrow
+name Hr
+internalname 17
+ligatures fi fl 0
+charset
+! 23 2 33
+$ 46 3 36
+% 73 2 37
+& 55 2 38
+' 18 2 39
+( 27 3 40
+) 27 3 41
+* 32 2 42
++ 48 0 43
+, 23 1 44
+hy 27 0 45
+- "
+. 23 0 46
+/ 23 2 47
+0 46 2 48
+1 46 2 49
+2 46 2 50
+3 46 2 51
+4 46 2 52
+5 46 2 53
+6 46 2 54
+7 46 2 55
+8 46 2 56
+9 46 2 57
+: 23 0 58
+; 23 1 59
+= 48 0 61
+? 46 2 63
+A 55 2 65
+B 55 2 66
+C 59 2 67
+D 59 2 68
+E 55 2 69
+F 50 2 70
+G 64 2 71
+H 59 2 72
+I 23 2 73
+J 41 2 74
+K 55 2 75
+L 46 2 76
+M 68 2 77
+N 59 2 78
+O 64 2 79
+P 55 2 80
+Q 64 2 81
+R 59 2 82
+S 55 2 83
+T 50 2 84
+U 59 2 85
+V 55 2 86
+W 77 2 87
+X 55 2 88
+Y 55 2 89
+Z 50 2 90
+[ 23 3 91
+] 23 3 93
+` 18 2 96
+a 46 0 97
+b 46 2 98
+c 41 0 99
+d 46 2 100
+e 46 0 101
+f 23 2 102
+g 46 1 103
+h 46 2 104
+i 18 2 105
+j 18 3 106
+k 41 2 107
+l 18 2 108
+m 68 0 109
+n 46 0 110
+o 46 0 111
+p 46 1 112
+q 46 1 113
+r 27 0 114
+s 41 0 115
+t 23 2 116
+u 46 0 117
+v 41 0 118
+w 59 0 119
+x 41 0 120
+y 41 1 121
+z 41 0 122
+ct 46 3 162
+fi 41 2 174
+fl 41 2 175
+dg 46 3 178
+bu 29 0 183
+de 27 2 202
+em 82 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 27 2 170
+'' 27 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Hr.name b/usr/src/cmd/lp/filter/postscript/font/devpost/Hr.name
new file mode 100644
index 0000000000..73a487bb4a
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Hr.name
@@ -0,0 +1 @@
+Helvetica-Narrow
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Hx b/usr/src/cmd/lp/filter/postscript/font/devpost/Hx
new file mode 100644
index 0000000000..daf3bbde92
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Hx
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Helvetica-Narrow-BoldOblique
+name Hx
+internalname 20
+ligatures fi fl 0
+charset
+! 27 2 33
+$ 46 3 36
+% 73 2 37
+& 59 2 38
+' 23 2 39
+( 27 3 40
+) 27 3 41
+* 32 2 42
++ 48 0 43
+, 23 1 44
+hy 27 0 45
+- "
+. 23 0 46
+/ 23 2 47
+0 46 2 48
+1 46 2 49
+2 46 2 50
+3 46 2 51
+4 46 2 52
+5 46 2 53
+6 46 2 54
+7 46 2 55
+8 46 2 56
+9 46 2 57
+: 27 0 58
+; 27 1 59
+= 48 0 61
+? 50 2 63
+A 59 2 65
+B 59 2 66
+C 59 2 67
+D 59 2 68
+E 55 2 69
+F 50 2 70
+G 64 2 71
+H 59 2 72
+I 23 2 73
+J 46 2 74
+K 59 2 75
+L 50 2 76
+M 68 2 77
+N 59 2 78
+O 64 2 79
+P 55 2 80
+Q 64 2 81
+R 59 2 82
+S 55 2 83
+T 50 2 84
+U 59 2 85
+V 55 2 86
+W 77 2 87
+X 55 2 88
+Y 55 2 89
+Z 50 2 90
+[ 27 3 91
+] 27 3 93
+` 23 2 96
+a 46 0 97
+b 50 2 98
+c 46 0 99
+d 50 2 100
+e 46 0 101
+f 27 2 102
+g 50 1 103
+h 50 2 104
+i 23 2 105
+j 23 3 106
+k 46 2 107
+l 23 2 108
+m 73 0 109
+n 50 0 110
+o 50 0 111
+p 50 1 112
+q 50 1 113
+r 32 0 114
+s 46 0 115
+t 27 2 116
+u 50 0 117
+v 46 0 118
+w 64 0 119
+x 46 0 120
+y 46 1 121
+z 41 0 122
+ct 46 3 162
+fi 50 2 174
+fl 50 2 175
+dg 46 3 178
+bu 29 0 183
+de 27 2 202
+em 82 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 41 2 170
+'' 41 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Hx.name b/usr/src/cmd/lp/filter/postscript/font/devpost/Hx.name
new file mode 100644
index 0000000000..bcb1cd265f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Hx.name
@@ -0,0 +1 @@
+Helvetica-Narrow-BoldOblique
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/I b/usr/src/cmd/lp/filter/postscript/font/devpost/I
new file mode 100644
index 0000000000..ce4d027019
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/I
@@ -0,0 +1,134 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Times-Italic
+name I
+internalname 2
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 50 2 36
+% 83 2 37
+& 78 2 38
+' 33 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 68 0 43
+, 25 1 44
+hy 33 0 45
+- "
+. 25 0 46
+/ 28 2 47
+0 50 2 48
+1 50 2 49
+2 50 2 50
+3 50 2 51
+4 50 2 52
+5 50 2 53
+6 50 2 54
+7 50 2 55
+8 50 2 56
+9 50 2 57
+: 33 0 58
+; 33 1 59
+= 68 0 61
+? 50 2 63
+A 61 2 65
+B 61 2 66
+C 67 2 67
+D 72 2 68
+E 61 2 69
+F 61 2 70
+G 72 2 71
+H 72 2 72
+I 33 2 73
+J 44 2 74
+K 67 2 75
+L 56 2 76
+M 83 2 77
+N 67 2 78
+O 72 2 79
+P 61 2 80
+Q 72 3 81
+R 61 2 82
+S 50 2 83
+T 56 2 84
+U 72 2 85
+V 61 2 86
+W 83 2 87
+X 61 2 88
+Y 56 2 89
+Z 56 2 90
+[ 39 3 91
+] 39 3 93
+` 33 2 96
+a 50 0 97
+b 50 2 98
+c 44 0 99
+d 50 2 100
+e 44 0 101
+f 28 3 102
+g 50 1 103
+h 50 2 104
+i 28 2 105
+j 28 3 106
+k 44 2 107
+l 28 2 108
+m 72 0 109
+n 50 0 110
+o 50 0 111
+p 50 1 112
+q 50 1 113
+r 39 0 114
+s 39 0 115
+t 28 0 116
+u 50 0 117
+v 44 0 118
+w 67 0 119
+x 44 0 120
+y 44 1 121
+z 39 0 122
+ct 50 3 162
+fi 50 3 174
+fl 50 3 175
+ff 50 2 1
+Fi 72 2 1
+Fl 72 2 1
+dg 50 2 178
+bu 35 0 183
+de 33 2 202
+em 89 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+sq 50 2 1
+`` 56 2 170
+'' 56 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/I.name b/usr/src/cmd/lp/filter/postscript/font/devpost/I.name
new file mode 100644
index 0000000000..df19d08bda
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/I.name
@@ -0,0 +1 @@
+Times-Italic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/KB b/usr/src/cmd/lp/filter/postscript/font/devpost/KB
new file mode 100644
index 0000000000..1aef8be74f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/KB
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Bookman-Demi
+name KB
+internalname 23
+ligatures fi fl 0
+charset
+! 36 2 33
+$ 66 3 36
+% 94 2 37
+& 80 2 38
+' 32 2 39
+( 32 3 40
+) 32 3 41
+* 46 2 42
++ 60 0 43
+, 34 1 44
+hy 36 0 45
+- "
+. 34 0 46
+/ 60 3 47
+0 66 2 48
+1 66 2 49
+2 66 2 50
+3 66 2 51
+4 66 2 52
+5 66 2 53
+6 66 2 54
+7 66 2 55
+8 66 2 56
+9 66 2 57
+: 34 0 58
+; 34 1 59
+= 60 0 61
+? 66 2 63
+A 72 2 65
+B 72 2 66
+C 74 2 67
+D 78 2 68
+E 72 2 69
+F 68 2 70
+G 78 2 71
+H 82 2 72
+I 40 2 73
+J 64 2 74
+K 80 2 75
+L 64 2 76
+M 94 2 77
+N 74 2 78
+O 80 2 79
+P 66 2 80
+Q 80 3 81
+R 78 2 82
+S 66 2 83
+T 70 2 84
+U 74 2 85
+V 72 2 86
+W 94 2 87
+X 78 2 88
+Y 70 2 89
+Z 64 2 90
+[ 30 3 91
+] 30 3 93
+` 32 2 96
+a 58 0 97
+b 60 2 98
+c 58 0 99
+d 64 2 100
+e 58 0 101
+f 38 2 102
+g 58 3 103
+h 68 2 104
+i 36 2 105
+j 34 3 106
+k 66 2 107
+l 34 2 108
+m 100 0 109
+n 68 0 110
+o 62 0 111
+p 64 1 112
+q 62 1 113
+r 46 0 114
+s 52 0 115
+t 46 2 116
+u 66 0 117
+v 60 0 118
+w 80 0 119
+x 60 0 120
+y 62 1 121
+z 56 0 122
+ct 66 2 162
+fi 74 2 174
+fl 74 2 175
+dg 44 3 178
+bu 46 0 183
+de 34 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 54 2 170
+'' 54 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/KB.name b/usr/src/cmd/lp/filter/postscript/font/devpost/KB.name
new file mode 100644
index 0000000000..8b408b1708
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/KB.name
@@ -0,0 +1 @@
+Bookman-Demi
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/KI b/usr/src/cmd/lp/filter/postscript/font/devpost/KI
new file mode 100644
index 0000000000..2264ef1c30
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/KI
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Bookman-LightItalic
+name KI
+internalname 22
+ligatures fi fl 0
+charset
+! 32 2 33
+$ 62 2 36
+% 80 2 37
+& 82 2 38
+' 28 2 39
+( 28 3 40
+) 28 3 41
+* 44 2 42
++ 60 0 43
+, 30 1 44
+hy 32 0 45
+- "
+. 30 0 46
+/ 60 3 47
+0 62 2 48
+1 62 2 49
+2 62 2 50
+3 62 2 51
+4 62 2 52
+5 62 2 53
+6 62 2 54
+7 62 2 55
+8 62 2 56
+9 62 2 57
+: 30 0 58
+; 30 1 59
+= 60 0 61
+? 54 2 63
+A 70 2 65
+B 72 2 66
+C 72 2 67
+D 74 2 68
+E 68 2 69
+F 62 2 70
+G 76 2 71
+H 80 2 72
+I 32 2 73
+J 56 2 74
+K 72 2 75
+L 58 2 76
+M 86 2 77
+N 72 2 78
+O 76 2 79
+P 60 2 80
+Q 78 3 81
+R 70 2 82
+S 64 2 83
+T 60 2 84
+U 72 2 85
+V 68 2 86
+W 96 2 87
+X 70 2 88
+Y 66 2 89
+Z 58 2 90
+[ 26 3 91
+] 26 3 93
+` 28 2 96
+a 62 0 97
+b 60 2 98
+c 48 0 99
+d 64 2 100
+e 54 0 101
+f 34 3 102
+g 56 1 103
+h 62 2 104
+i 28 2 105
+j 28 3 106
+k 60 2 107
+l 28 2 108
+m 88 0 109
+n 62 0 110
+o 54 0 111
+p 60 1 112
+q 56 1 113
+r 40 0 114
+s 54 0 115
+t 34 2 116
+u 62 0 117
+v 54 0 118
+w 88 0 119
+x 54 0 120
+y 60 1 121
+z 52 0 122
+ct 62 2 162
+fi 64 3 174
+fl 66 3 175
+dg 62 3 178
+bu 46 0 183
+de 30 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 44 2 170
+'' 44 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/KI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/KI.name
new file mode 100644
index 0000000000..d00e32f28b
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/KI.name
@@ -0,0 +1 @@
+Bookman-LightItalic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/KR b/usr/src/cmd/lp/filter/postscript/font/devpost/KR
new file mode 100644
index 0000000000..59303d06ac
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/KR
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Bookman-Light
+name KR
+internalname 21
+ligatures fi fl 0
+charset
+! 30 2 33
+$ 62 2 36
+% 90 2 37
+& 80 2 38
+' 22 2 39
+( 30 3 40
+) 30 3 41
+* 44 2 42
++ 60 0 43
+, 32 1 44
+hy 40 0 45
+- "
+. 32 0 46
+/ 60 3 47
+0 62 2 48
+1 62 2 49
+2 62 2 50
+3 62 2 51
+4 62 2 52
+5 62 2 53
+6 62 2 54
+7 62 2 55
+8 62 2 56
+9 62 2 57
+: 32 0 58
+; 32 1 59
+= 60 0 61
+? 54 2 63
+A 68 2 65
+B 74 2 66
+C 74 2 67
+D 80 2 68
+E 72 2 69
+F 64 2 70
+G 80 2 71
+H 80 2 72
+I 34 2 73
+J 60 2 74
+K 72 2 75
+L 60 2 76
+M 92 2 77
+N 74 2 78
+O 80 2 79
+P 62 2 80
+Q 82 3 81
+R 72 2 82
+S 66 2 83
+T 62 2 84
+U 78 2 85
+V 70 2 86
+W 96 2 87
+X 72 2 88
+Y 64 2 89
+Z 64 2 90
+[ 30 3 91
+] 30 3 93
+` 22 2 96
+a 58 0 97
+b 62 2 98
+c 52 0 99
+d 62 2 100
+e 52 0 101
+f 32 2 102
+g 54 3 103
+h 66 2 104
+i 30 2 105
+j 30 3 106
+k 62 2 107
+l 30 2 108
+m 94 0 109
+n 66 0 110
+o 56 0 111
+p 62 1 112
+q 58 1 113
+r 44 0 114
+s 52 0 115
+t 38 2 116
+u 68 0 117
+v 52 0 118
+w 78 0 119
+x 56 0 120
+y 54 1 121
+z 48 0 122
+ct 62 2 162
+fi 62 2 174
+fl 62 2 175
+dg 54 3 178
+bu 46 0 183
+de 32 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 40 2 170
+'' 40 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/KR.name b/usr/src/cmd/lp/filter/postscript/font/devpost/KR.name
new file mode 100644
index 0000000000..f9eef0ca61
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/KR.name
@@ -0,0 +1 @@
+Bookman-Light
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/KX b/usr/src/cmd/lp/filter/postscript/font/devpost/KX
new file mode 100644
index 0000000000..da20dbdf73
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/KX
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Bookman-DemiItalic
+name KX
+internalname 24
+ligatures fi fl 0
+charset
+! 32 2 33
+$ 68 3 36
+% 88 2 37
+& 98 2 38
+' 32 2 39
+( 26 3 40
+) 26 3 41
+* 46 2 42
++ 60 0 43
+, 34 1 44
+hy 28 0 45
+- "
+. 34 0 46
+/ 36 2 47
+0 68 2 48
+1 68 2 49
+2 68 2 50
+3 68 2 51
+4 68 2 52
+5 68 2 53
+6 68 2 54
+7 68 2 55
+8 68 2 56
+9 68 2 57
+: 34 0 58
+; 34 1 59
+= 60 0 61
+? 62 2 63
+A 72 2 65
+B 72 2 66
+C 70 2 67
+D 76 2 68
+E 72 2 69
+F 66 2 70
+G 76 2 71
+H 80 2 72
+I 38 2 73
+J 62 2 74
+K 78 2 75
+L 64 2 76
+M 86 2 77
+N 74 2 78
+O 76 2 79
+P 64 2 80
+Q 76 3 81
+R 74 2 82
+S 70 2 83
+T 70 2 84
+U 74 2 85
+V 66 2 86
+W 100 2 87
+X 74 2 88
+Y 66 2 89
+Z 68 2 90
+[ 26 3 91
+] 26 3 93
+` 32 2 96
+a 68 0 97
+b 60 2 98
+c 56 0 99
+d 68 2 100
+e 56 0 101
+f 42 3 102
+g 62 1 103
+h 70 2 104
+i 38 2 105
+j 32 3 106
+k 70 2 107
+l 38 2 108
+m 96 0 109
+n 68 0 110
+o 60 0 111
+p 66 1 112
+q 62 1 113
+r 50 0 114
+s 54 0 115
+t 44 2 116
+u 68 0 117
+v 54 0 118
+w 86 0 119
+x 62 0 120
+y 60 1 121
+z 56 0 122
+ct 68 2 162
+fi 82 3 174
+fl 82 3 175
+dg 42 3 178
+bu 36 0 183
+de 36 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 52 2 170
+'' 52 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/KX.name b/usr/src/cmd/lp/filter/postscript/font/devpost/KX.name
new file mode 100644
index 0000000000..591feecdc8
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/KX.name
@@ -0,0 +1 @@
+Bookman-DemiItalic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/LINKFILE b/usr/src/cmd/lp/filter/postscript/font/devpost/LINKFILE
new file mode 100644
index 0000000000..e70c33ad16
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/LINKFILE
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# This file is used to link any missing .out files to appropriate existing
+# .out files.
+#
+
+rm -f G.out
+ln H.out G.out
+
+rm -f GI.out
+ln HI.out GI.out
+
+rm -f HM.out
+ln H.out HM.out
+
+rm -f HK.out
+ln H.out HK.out
+
+rm -f HL.out
+ln H.out HL.out
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/Makefile b/usr/src/cmd/lp/filter/postscript/font/devpost/Makefile
new file mode 100644
index 0000000000..fffb603bf0
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/Makefile
@@ -0,0 +1,98 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1989 by Sun Microsystems, Inc.
+#
+# cmd/lp/filter/postscript/font/devpost/Makefile
+#
+
+include ../../../../Makefile.lp
+
+FONTFILES = AB AI AR AX BI CB CI CO \
+ CW CX GR HB HI HX Hb Hi \
+ Hr Hx KB KI KR KX NB NI \
+ NR NX PA PB PI PX S1 VB \
+ VI VR VX ZD ZI B H I \
+ R S
+FONTLNK1 = G HM HK HL
+FONTLNK2 = GI
+DESCFILE = DESC
+TXTS = DESC.big DESC.small S.big S.small LINKFILE
+
+FONTNAMES = $(FONTFILES:%=%.name)
+FONTLNK1OUTS = $(FONTLNK1:%=%.out)
+FONTLNK2OUTS = $(FONTLNK2:%=%.out)
+FONTOUTS = $(FONTFILES:%=%.out) $(DESCFILE:%=%.out)
+
+SUBDIRS = charlib
+
+NATIVEMAKEDEV = ../native/makedev
+
+ROOTLIBFONT = $(ROOT)/usr/lib/font
+ROOTDEVPOST = $(ROOTLIBFONT)/devpost
+
+ROOTFONTFILES = $(FONTFILES:%=$(ROOTDEVPOST)/%) \
+ $(ROOTDEVPOST)/$(DESCFILE)
+ROOTFONTNAMES = $(FONTNAMES:%=$(ROOTDEVPOST)/%)
+ROOTFONTOUTS = $(FONTOUTS:%=$(ROOTDEVPOST)/%) \
+ $(FONTLNK1OUTS:%=$(ROOTDEVPOST)/%) \
+ $(FONTLNK2OUTS:%=$(ROOTDEVPOST)/%)
+
+FILEMODE = 0444
+
+.KEEP_STATE:
+
+all : $(TXTS) $(FONTOUTS) $(FONTNAMES) $(SUBDIRS)
+
+install: $(TXTS) $(FONTOUTS) $(FONTNAMES) \
+ $(ROOTDEVPOST) $(ROOTFONTFILES) $(ROOTFONTNAMES) \
+ $(ROOTFONTOUTS) $(SUBDIRS)
+
+$(FONTOUTS) : $$(@:%.out=%) $(NATIVEMAKEDEV)
+ @$(RM) $@; $(NATIVEMAKEDEV) $(@:%.out=%)
+
+$(ROOTDEVPOST) :
+ $(INS.dir)
+
+$(NATIVEMAKEDEV) :
+ @cd ..; $(MAKE) native/makedev
+
+$(FONTLNK1OUTS) : H.out
+ @$(RM) $@; $(LN) H.out $@
+
+$(FONTLNK2OUTS) : HI.out
+ @$(RM) $@; $(LN) HI.out $@
+
+$(ROOTDEVPOST)/% : %
+ $(INS.file)
+
+clean strip lint : $(SUBDIRS)
+
+clobber: $(SUBDIRS)
+ $(RM) $(FONTOUTS) $(FONTLNK1OUTS) $(FONTLNK2OUTS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/NB b/usr/src/cmd/lp/filter/postscript/font/devpost/NB
new file mode 100644
index 0000000000..63e9e27684
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/NB
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# NewCenturySchlbk-Bold
+name NB
+internalname 31
+ligatures fi fl 0
+charset
+! 30 2 33
+$ 57 3 36
+% 83 2 37
+& 85 2 38
+' 24 2 39
+( 39 3 40
+) 39 3 41
+* 50 2 42
++ 61 0 43
+, 28 1 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 28 2 47
+0 57 2 48
+1 57 2 49
+2 57 2 50
+3 57 2 51
+4 57 2 52
+5 57 2 53
+6 57 2 54
+7 57 2 55
+8 57 2 56
+9 57 2 57
+: 28 0 58
+; 28 1 59
+= 61 0 61
+? 50 2 63
+A 76 2 65
+B 78 2 66
+C 78 2 67
+D 83 2 68
+E 76 2 69
+F 72 2 70
+G 83 2 71
+H 87 2 72
+I 44 2 73
+J 65 2 74
+K 81 2 75
+L 72 2 76
+M 98 2 77
+N 83 2 78
+O 83 2 79
+P 76 2 80
+Q 83 3 81
+R 81 2 82
+S 67 2 83
+T 72 2 84
+U 83 2 85
+V 76 2 86
+W 98 2 87
+X 72 2 88
+Y 72 2 89
+Z 67 2 90
+[ 39 3 91
+] 39 3 93
+` 24 2 96
+a 61 0 97
+b 65 2 98
+c 56 0 99
+d 67 2 100
+e 57 0 101
+f 39 2 102
+g 61 1 103
+h 69 2 104
+i 37 2 105
+j 35 3 106
+k 67 2 107
+l 35 2 108
+m 96 0 109
+n 69 0 110
+o 61 0 111
+p 67 1 112
+q 65 1 113
+r 52 0 114
+s 50 0 115
+t 43 2 116
+u 69 0 117
+v 61 0 118
+w 89 0 119
+x 61 0 120
+y 61 1 121
+z 54 0 122
+ct 57 3 162
+fi 69 2 174
+fl 69 2 175
+dg 50 2 178
+bu 61 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 48 2 170
+'' 48 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/NB.name b/usr/src/cmd/lp/filter/postscript/font/devpost/NB.name
new file mode 100644
index 0000000000..3caf245522
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/NB.name
@@ -0,0 +1 @@
+NewCenturySchlbk-Bold
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/NI b/usr/src/cmd/lp/filter/postscript/font/devpost/NI
new file mode 100644
index 0000000000..8c5e8c9512
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/NI
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# NewCenturySchlbk-Italic
+name NI
+internalname 30
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 56 3 36
+% 83 2 37
+& 85 2 38
+' 20 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 61 0 43
+, 28 1 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 61 2 47
+0 56 2 48
+1 56 2 49
+2 56 2 50
+3 56 2 51
+4 56 2 52
+5 56 2 53
+6 56 2 54
+7 56 2 55
+8 56 2 56
+9 56 2 57
+: 28 0 58
+; 28 1 59
+= 61 0 61
+? 44 2 63
+A 70 2 65
+B 72 2 66
+C 72 2 67
+D 78 2 68
+E 72 2 69
+F 67 2 70
+G 78 2 71
+H 83 2 72
+I 41 2 73
+J 61 2 74
+K 74 2 75
+L 67 2 76
+M 94 2 77
+N 81 2 78
+O 78 2 79
+P 67 2 80
+Q 78 3 81
+R 74 2 82
+S 67 2 83
+T 69 2 84
+U 81 2 85
+V 70 2 86
+W 93 2 87
+X 70 2 88
+Y 69 2 89
+Z 67 2 90
+[ 33 3 91
+] 33 3 93
+` 20 2 96
+a 57 0 97
+b 56 2 98
+c 44 0 99
+d 61 2 100
+e 44 0 101
+f 33 3 102
+g 54 1 103
+h 61 2 104
+i 33 2 105
+j 32 3 106
+k 56 2 107
+l 33 2 108
+m 89 0 109
+n 61 0 110
+o 50 0 111
+p 57 1 112
+q 56 1 113
+r 44 0 114
+s 44 0 115
+t 35 2 116
+u 61 0 117
+v 52 0 118
+w 78 0 119
+x 50 0 120
+y 50 1 121
+z 46 0 122
+ct 56 3 162
+fi 61 3 174
+fl 61 3 175
+dg 50 3 178
+bu 61 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 39 2 170
+'' 39 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/NI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/NI.name
new file mode 100644
index 0000000000..2874e8afbe
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/NI.name
@@ -0,0 +1 @@
+NewCenturySchlbk-Italic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/NR b/usr/src/cmd/lp/filter/postscript/font/devpost/NR
new file mode 100644
index 0000000000..f5d795f0c9
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/NR
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# NewCenturySchlbk-Roman
+name NR
+internalname 29
+ligatures fi fl 0
+charset
+! 30 2 33
+$ 56 3 36
+% 83 2 37
+& 81 2 38
+' 20 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 61 0 43
+, 28 1 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 28 2 47
+0 56 2 48
+1 56 2 49
+2 56 2 50
+3 56 2 51
+4 56 2 52
+5 56 2 53
+6 56 2 54
+7 56 2 55
+8 56 2 56
+9 56 2 57
+: 28 0 58
+; 28 1 59
+= 61 0 61
+? 44 2 63
+A 72 2 65
+B 72 2 66
+C 72 2 67
+D 78 2 68
+E 72 2 69
+F 67 2 70
+G 78 2 71
+H 83 2 72
+I 41 2 73
+J 56 2 74
+K 78 2 75
+L 67 2 76
+M 94 2 77
+N 81 2 78
+O 78 2 79
+P 67 2 80
+Q 78 3 81
+R 72 2 82
+S 63 2 83
+T 67 2 84
+U 81 2 85
+V 72 2 86
+W 98 2 87
+X 70 2 88
+Y 70 2 89
+Z 61 2 90
+[ 33 3 91
+] 33 3 93
+` 20 2 96
+a 56 0 97
+b 56 2 98
+c 44 0 99
+d 57 2 100
+e 50 0 101
+f 33 2 102
+g 54 1 103
+h 61 2 104
+i 32 2 105
+j 30 3 106
+k 59 2 107
+l 32 2 108
+m 89 0 109
+n 61 0 110
+o 50 0 111
+p 57 1 112
+q 56 1 113
+r 44 0 114
+s 46 0 115
+t 39 2 116
+u 61 0 117
+v 54 0 118
+w 78 0 119
+x 54 0 120
+y 54 1 121
+z 48 0 122
+ct 56 3 162
+fi 61 2 174
+fl 61 2 175
+dg 50 3 178
+bu 61 2 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 39 2 170
+'' 39 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/NR.name b/usr/src/cmd/lp/filter/postscript/font/devpost/NR.name
new file mode 100644
index 0000000000..82ea91140f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/NR.name
@@ -0,0 +1 @@
+NewCenturySchlbk-Roman
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/NX b/usr/src/cmd/lp/filter/postscript/font/devpost/NX
new file mode 100644
index 0000000000..e7750c0fa0
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/NX
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# NewCenturySchlbk-BoldItalic
+name NX
+internalname 32
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 57 3 36
+% 89 2 37
+& 89 2 38
+' 26 2 39
+( 41 3 40
+) 41 3 41
+* 50 2 42
++ 61 0 43
+, 29 1 44
+hy 33 0 45
+- "
+. 29 0 46
+/ 28 2 47
+0 57 2 48
+1 57 2 49
+2 57 2 50
+3 57 2 51
+4 57 2 52
+5 57 2 53
+6 57 2 54
+7 57 2 55
+8 57 2 56
+9 57 2 57
+: 29 0 58
+; 29 1 59
+= 61 0 61
+? 48 2 63
+A 74 2 65
+B 76 2 66
+C 76 2 67
+D 83 2 68
+E 74 2 69
+F 70 2 70
+G 81 2 71
+H 87 2 72
+I 44 2 73
+J 67 2 74
+K 78 2 75
+L 70 2 76
+M 94 2 77
+N 85 2 78
+O 83 2 79
+P 74 2 80
+Q 83 3 81
+R 80 2 82
+S 69 2 83
+T 72 2 84
+U 83 2 85
+V 74 2 86
+W 94 2 87
+X 74 2 88
+Y 70 2 89
+Z 70 2 90
+[ 41 3 91
+] 41 3 93
+` 26 2 96
+a 67 0 97
+b 61 2 98
+c 54 0 99
+d 67 2 100
+e 52 0 101
+f 39 3 102
+g 61 1 103
+h 69 2 104
+i 39 2 105
+j 37 3 106
+k 65 2 107
+l 39 2 108
+m 94 0 109
+n 69 0 110
+o 57 0 111
+p 65 1 112
+q 63 1 113
+r 52 0 114
+s 48 0 115
+t 41 2 116
+u 69 0 117
+v 56 0 118
+w 83 0 119
+x 57 0 120
+y 52 1 121
+z 52 0 122
+ct 57 3 162
+fi 69 3 174
+fl 69 3 175
+dg 50 3 178
+bu 61 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 48 2 170
+'' 48 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/NX.name b/usr/src/cmd/lp/filter/postscript/font/devpost/NX.name
new file mode 100644
index 0000000000..cce962696f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/NX.name
@@ -0,0 +1 @@
+NewCenturySchlbk-BoldItalic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/PA b/usr/src/cmd/lp/filter/postscript/font/devpost/PA
new file mode 100644
index 0000000000..80ed449f66
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/PA
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Palatino-Roman
+name PA
+internalname 13
+ligatures fi fl 0
+charset
+! 28 2 33
+$ 50 2 36
+% 84 2 37
+& 78 2 38
+' 28 2 39
+( 33 2 40
+) 33 2 41
+* 39 2 42
++ 61 0 43
+, 25 1 44
+hy 33 0 45
+- "
+. 25 0 46
+/ 61 2 47
+0 50 2 48
+1 50 2 49
+2 50 2 50
+3 50 2 51
+4 50 2 52
+5 50 2 53
+6 50 2 54
+7 50 2 55
+8 50 2 56
+9 50 2 57
+: 25 0 58
+; 25 1 59
+= 61 0 61
+? 44 2 63
+A 78 2 65
+B 61 2 66
+C 71 2 67
+D 77 2 68
+E 61 2 69
+F 56 2 70
+G 76 2 71
+H 83 2 72
+I 34 2 73
+J 33 3 74
+K 73 2 75
+L 61 2 76
+M 95 2 77
+N 83 2 78
+O 79 2 79
+P 60 2 80
+Q 79 3 81
+R 67 2 82
+S 53 2 83
+T 61 2 84
+U 78 2 85
+V 72 2 86
+W 100 2 87
+X 67 2 88
+Y 67 2 89
+Z 67 2 90
+[ 33 2 91
+] 33 2 93
+` 28 2 96
+a 50 0 97
+b 55 2 98
+c 44 0 99
+d 61 2 100
+e 48 0 101
+f 33 2 102
+g 56 1 103
+h 58 2 104
+i 29 2 105
+j 23 3 106
+k 56 2 107
+l 29 2 108
+m 88 0 109
+n 58 0 110
+o 55 0 111
+p 60 1 112
+q 56 1 113
+r 40 0 114
+s 42 0 115
+t 33 2 116
+u 60 0 117
+v 56 0 118
+w 83 0 119
+x 52 0 120
+y 56 1 121
+z 50 0 122
+ct 50 0 162
+fi 61 2 174
+fl 61 2 175
+dg 50 2 178
+bu 61 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/PA.name b/usr/src/cmd/lp/filter/postscript/font/devpost/PA.name
new file mode 100644
index 0000000000..b5b49c8bfe
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/PA.name
@@ -0,0 +1 @@
+Palatino-Roman
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/PB b/usr/src/cmd/lp/filter/postscript/font/devpost/PB
new file mode 100644
index 0000000000..82d7ca2b7f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/PB
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Palatino-Bold
+name PB
+internalname 15
+ligatures fi fl 0
+charset
+! 28 2 33
+$ 50 2 36
+% 89 2 37
+& 83 2 38
+' 28 2 39
+( 33 2 40
+) 33 2 41
+* 44 2 42
++ 61 0 43
+, 25 1 44
+hy 33 0 45
+- "
+. 25 0 46
+/ 30 2 47
+0 50 2 48
+1 50 2 49
+2 50 2 50
+3 50 2 51
+4 50 2 52
+5 50 2 53
+6 50 2 54
+7 50 2 55
+8 50 2 56
+9 50 2 57
+: 25 0 58
+; 25 1 59
+= 61 0 61
+? 44 2 63
+A 78 2 65
+B 67 2 66
+C 72 2 67
+D 83 2 68
+E 61 2 69
+F 56 2 70
+G 83 2 71
+H 83 2 72
+I 39 2 73
+J 39 3 74
+K 78 2 75
+L 61 2 76
+M 100 2 77
+N 83 2 78
+O 83 2 79
+P 61 2 80
+Q 83 3 81
+R 72 2 82
+S 61 2 83
+T 67 2 84
+U 78 2 85
+V 78 2 86
+W 100 2 87
+X 67 2 88
+Y 67 2 89
+Z 67 2 90
+[ 33 2 91
+] 33 2 93
+` 28 2 96
+a 50 0 97
+b 61 2 98
+c 44 0 99
+d 61 2 100
+e 50 0 101
+f 39 2 102
+g 56 1 103
+h 61 2 104
+i 33 2 105
+j 33 3 106
+k 61 2 107
+l 33 2 108
+m 89 0 109
+n 61 0 110
+o 56 0 111
+p 61 1 112
+q 61 1 113
+r 39 0 114
+s 44 0 115
+t 33 2 116
+u 61 0 117
+v 56 0 118
+w 83 0 119
+x 50 0 120
+y 56 1 121
+z 50 0 122
+ct 50 0 162
+fi 61 2 174
+fl 61 2 175
+dg 50 2 178
+bu 61 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/PB.name b/usr/src/cmd/lp/filter/postscript/font/devpost/PB.name
new file mode 100644
index 0000000000..63a4fa8374
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/PB.name
@@ -0,0 +1 @@
+Palatino-Bold
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/PI b/usr/src/cmd/lp/filter/postscript/font/devpost/PI
new file mode 100644
index 0000000000..4150f9b063
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/PI
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Palatino-Italic
+name PI
+internalname 14
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 50 2 36
+% 89 2 37
+& 78 2 38
+' 28 2 39
+( 33 2 40
+) 33 2 41
+* 39 2 42
++ 61 0 43
+, 25 1 44
+hy 33 0 45
+- "
+. 25 0 46
+/ 30 3 47
+0 50 2 48
+1 50 2 49
+2 50 2 50
+3 50 2 51
+4 50 2 52
+5 50 2 53
+6 50 2 54
+7 50 2 55
+8 50 2 56
+9 50 2 57
+: 25 0 58
+; 25 1 59
+= 61 0 61
+? 50 2 63
+A 72 2 65
+B 61 2 66
+C 67 2 67
+D 78 2 68
+E 61 2 69
+F 56 2 70
+G 72 2 71
+H 78 2 72
+I 33 2 73
+J 33 3 74
+K 67 2 75
+L 56 2 76
+M 94 2 77
+N 78 2 78
+O 78 2 79
+P 61 2 80
+Q 78 3 81
+R 67 2 82
+S 56 2 83
+T 61 2 84
+U 78 2 85
+V 72 2 86
+W 94 2 87
+X 72 2 88
+Y 67 2 89
+Z 67 2 90
+[ 33 2 91
+] 33 2 93
+` 28 2 96
+a 44 0 97
+b 46 2 98
+c 41 0 99
+d 50 2 100
+e 39 0 101
+f 28 3 102
+g 50 1 103
+h 50 2 104
+i 28 2 105
+j 28 3 106
+k 44 2 107
+l 28 2 108
+m 78 0 109
+n 56 0 110
+o 44 0 111
+p 50 1 112
+q 46 1 113
+r 39 0 114
+s 39 0 115
+t 33 2 116
+u 56 0 117
+v 50 0 118
+w 72 0 119
+x 50 0 120
+y 50 1 121
+z 44 0 122
+ct 50 0 162
+fi 53 3 174
+fl 54 3 175
+dg 50 2 178
+bu 50 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/PI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/PI.name
new file mode 100644
index 0000000000..f6e9f5ee5d
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/PI.name
@@ -0,0 +1 @@
+Palatino-Italic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/PX b/usr/src/cmd/lp/filter/postscript/font/devpost/PX
new file mode 100644
index 0000000000..9dd7927160
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/PX
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Palatino-BoldItalic
+name PX
+internalname 16
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 50 2 36
+% 89 2 37
+& 83 2 38
+' 28 2 39
+( 33 2 40
+) 33 2 41
+* 44 2 42
++ 61 0 43
+, 25 1 44
+hy 39 0 45
+- "
+. 25 0 46
+/ 32 2 47
+0 50 2 48
+1 50 2 49
+2 50 2 50
+3 50 2 51
+4 50 2 52
+5 50 2 53
+6 50 2 54
+7 50 2 55
+8 50 2 56
+9 50 2 57
+: 25 0 58
+; 25 1 59
+= 61 0 61
+? 44 2 63
+A 72 2 65
+B 67 2 66
+C 69 2 67
+D 78 2 68
+E 61 2 69
+F 56 2 70
+G 78 2 71
+H 78 2 72
+I 39 2 73
+J 39 3 74
+K 72 2 75
+L 61 2 76
+M 94 2 77
+N 78 2 78
+O 83 2 79
+P 67 2 80
+Q 83 3 81
+R 72 2 82
+S 56 2 83
+T 61 2 84
+U 78 2 85
+V 67 2 86
+W 100 2 87
+X 72 2 88
+Y 61 2 89
+Z 67 2 90
+[ 33 2 91
+] 33 2 93
+` 28 2 96
+a 56 0 97
+b 54 2 98
+c 44 0 99
+d 56 2 100
+e 44 0 101
+f 33 3 102
+g 50 1 103
+h 56 2 104
+i 33 2 105
+j 33 3 106
+k 56 2 107
+l 33 2 108
+m 83 0 109
+n 56 0 110
+o 56 0 111
+p 56 1 112
+q 54 1 113
+r 39 0 114
+s 44 0 115
+t 39 2 116
+u 56 0 117
+v 56 0 118
+w 83 0 119
+x 50 0 120
+y 56 1 121
+z 50 0 122
+ct 50 0 162
+fi 61 3 174
+fl 61 3 175
+dg 56 2 178
+bu 61 0 183
+de 56 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 50 2 170
+'' 50 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/PX.name b/usr/src/cmd/lp/filter/postscript/font/devpost/PX.name
new file mode 100644
index 0000000000..bbca096271
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/PX.name
@@ -0,0 +1 @@
+Palatino-BoldItalic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/R b/usr/src/cmd/lp/filter/postscript/font/devpost/R
new file mode 100644
index 0000000000..585879eb07
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/R
@@ -0,0 +1,134 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Times-Roman
+name R
+internalname 1
+ligatures fi fl 0
+charset
+! 33 2 33
+$ 50 2 36
+% 83 2 37
+& 78 2 38
+' 33 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 56 0 43
+, 25 1 44
+hy 33 0 45
+- "
+. 25 0 46
+/ 28 2 47
+0 50 2 48
+1 50 2 49
+2 50 2 50
+3 50 2 51
+4 50 2 52
+5 50 2 53
+6 50 2 54
+7 50 2 55
+8 50 2 56
+9 50 2 57
+: 28 0 58
+; 28 1 59
+= 56 0 61
+? 44 2 63
+A 72 2 65
+B 67 2 66
+C 67 2 67
+D 72 2 68
+E 61 2 69
+F 56 2 70
+G 72 2 71
+H 72 2 72
+I 33 2 73
+J 39 2 74
+K 72 2 75
+L 61 2 76
+M 89 2 77
+N 72 2 78
+O 72 2 79
+P 56 2 80
+Q 72 3 81
+R 67 2 82
+S 56 2 83
+T 61 2 84
+U 72 2 85
+V 72 2 86
+W 94 2 87
+X 72 2 88
+Y 72 2 89
+Z 61 2 90
+[ 33 3 91
+] 33 3 93
+` 33 2 96
+a 44 0 97
+b 50 2 98
+c 44 0 99
+d 50 2 100
+e 44 0 101
+f 33 2 102
+g 50 1 103
+h 50 2 104
+i 28 2 105
+j 28 3 106
+k 50 2 107
+l 28 2 108
+m 78 0 109
+n 50 0 110
+o 50 0 111
+p 50 1 112
+q 50 1 113
+r 33 0 114
+s 39 0 115
+t 28 2 116
+u 50 0 117
+v 50 0 118
+w 72 0 119
+x 50 0 120
+y 50 1 121
+z 44 0 122
+ct 50 3 162
+fi 56 2 174
+fl 56 2 175
+ff 60 2 1
+Fi 84 2 1
+Fl 84 2 1
+dg 50 3 178
+bu 35 0 183
+de 33 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+sq 50 2 1
+`` 44 2 170
+'' 44 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/R.name b/usr/src/cmd/lp/filter/postscript/font/devpost/R.name
new file mode 100644
index 0000000000..1a9e5453e1
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/R.name
@@ -0,0 +1 @@
+Times-Roman
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/S b/usr/src/cmd/lp/filter/postscript/font/devpost/S
new file mode 100644
index 0000000000..0837c0b2f5
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/S
@@ -0,0 +1,236 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Symbol
+name S
+internalname 33
+special
+charset
+bx 50 2 1
+ci 75 0 1
+sq 50 2 1
+~= 55 0 1
+L1 110 1 2
+LA 110 1 2
+LV 110 3 2
+LH 210 1 2
+Lb "
+lh 100 0 2
+rh 100 0 2
+--- 25 0 32
+--- 33 2 33
+fa 71 2 34
+--- 50 2 35
+te 55 2 36
+--- 83 2 37
+--- 78 2 38
+--- 44 0 39
+--- 33 3 40
+--- 33 3 41
+** 50 0 42
+pl 55 0 43
+--- 25 1 44
+mi 55 0 45
+--- 25 0 46
+--- 28 2 47
+--- 50 2 48
+--- 50 2 49
+--- 50 2 50
+--- 50 2 51
+--- 50 2 52
+--- 50 2 53
+--- 50 2 54
+--- 50 2 55
+--- 50 2 56
+--- 50 2 57
+--- 28 0 58
+--- 28 1 59
+< 55 0 60
+eq 55 0 61
+> 55 0 62
+--- 44 2 63
+*A 72 2 65
+*B 67 2 66
+*X 72 2 67
+*D 61 2 68
+*E 61 2 69
+*F 76 2 70
+*G 60 2 71
+*Y 72 2 72
+*I 33 2 73
+--- 63 2 74
+*K 72 2 75
+*L 69 2 76
+*M 89 2 77
+*N 72 2 78
+*O 72 2 79
+*P 77 2 80
+*H 74 2 81
+*R 56 2 82
+*S 59 2 83
+*T 61 2 84
+*U 69 2 85
+--- 44 1 86
+ts 44 1 86
+*W 77 2 87
+*C 65 2 88
+*Q 80 2 89
+*Z 61 2 90
+--- 33 3 91
+--- 86 0 92
+--- 33 3 93
+--- 66 2 94
+ul 50 1 95
+_ "
+rn 50 2 96
+*a 63 0 97
+*b 55 3 98
+*x 55 1 99
+*d 49 2 100
+*e 44 0 101
+*f 52 3 102
+*g 41 1 103
+*y 60 1 104
+*i 33 0 105
+--- 60 1 106
+*k 55 0 107
+*l 55 2 108
+*m 58 1 109
+*n 52 0 110
+*o 55 0 111
+*p 55 0 112
+*h 52 2 113
+*r 55 1 114
+*s 60 0 115
+*t 44 0 116
+*u 58 0 117
+--- 71 2 118
+*w 69 0 119
+*c 49 3 120
+*q 69 1 121
+*z 49 3 122
+{ 48 3 123
+or 20 3 124
+} 48 3 125
+ap 55 0 126
+--- 62 2 161
+fm 25 2 162
+<= 55 2 163
+sl 17 2 164
+if 73 0 165
+--- 50 3 166
+--- 75 0 167
+--- 75 0 168
+--- 75 0 169
+--- 75 0 170
+--- 104 0 171
+<- 99 0 172
+ua 60 2 173
+-> 99 0 174
+da 60 2 175
+de 40 2 176
++- 55 2 177
+--- 41 2 178
+>= 55 2 179
+mu 55 0 180
+pt 71 0 181
+pd 49 2 182
+bu 46 0 183
+di 55 0 184
+!= 55 0 185
+== 55 0 186
+~~ 55 0 187
+--- 100 0 188
+--- 60 3 189
+--- 100 0 190
+--- 66 2 191
+al 82 2 192
+--- 69 2 193
+--- 80 2 194
+--- 99 3 195
+Ox 77 2 196
+O+ 77 2 197
+es 82 2 198
+ca 77 0 199
+cu 77 0 200
+sp 71 0 201
+ip 71 1 202
+--- 71 0 203
+sb 71 0 204
+ib 71 1 205
+mo 71 0 206
+--- 71 0 207
+--- 77 2 208
+gr 71 2 209
+rg 79 2 210
+co 79 2 211
+tm 89 2 212
+--- 82 2 213
+sr 55 2 214
+--- 25 0 215
+no 71 0 216
+^ 60 0 217
+or 60 0 218
+--- 104 0 219
+--- 99 0 220
+--- 60 2 221
+--- 99 0 222
+--- 60 2 223
+--- 49 2 224
+--- 33 3 225
+--- 79 2 226
+--- 79 2 227
+--- 79 2 228
+--- 71 2 229
+--- 38 3 230
+br 0 3 231
+--- 38 3 232
+lc 50 2 233
+vr 0 2 234
+lf 50 2 235
+lt 49 2 236
+lk 49 2 237
+lb 49 2 238
+bv 49 2 239
+--- 25 0 240
+--- 33 3 241
+is 50 3 242
+--- 69 2 243
+--- 69 2 244
+--- 69 2 245
+--- 38 3 246
+--- 38 2 247
+--- 38 3 248
+rc 38 2 249
+| 50 3 250
+rf 38 2 251
+rt 49 2 252
+rk 49 2 253
+rb 49 2 254
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/S.big b/usr/src/cmd/lp/filter/postscript/font/devpost/S.big
new file mode 100644
index 0000000000..7ded493934
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/S.big
@@ -0,0 +1,228 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Symbol
+#
+name S
+internalname 33
+special
+charset
+bx 50 2 1
+ci 75 0 1
+sq 50 2 1
+~= 55 0 1
+L1 110 1 2
+LA 110 1 2
+LV 110 3 2
+LH 210 1 2
+Lb "
+lh 100 0 2
+rh 100 0 2
+--- 25 0 32
+--- 33 2 33
+fa 71 2 34
+--- 50 2 35
+te 55 2 36
+--- 83 2 37
+--- 78 2 38
+--- 44 0 39
+--- 33 3 40
+--- 33 3 41
+** 50 0 42
+pl 55 0 43
+--- 25 1 44
+mi 55 0 45
+--- 25 0 46
+--- 28 2 47
+--- 50 2 48
+--- 50 2 49
+--- 50 2 50
+--- 50 2 51
+--- 50 2 52
+--- 50 2 53
+--- 50 2 54
+--- 50 2 55
+--- 50 2 56
+--- 50 2 57
+--- 28 0 58
+--- 28 1 59
+< 55 0 60
+eq 55 0 61
+> 55 0 62
+--- 44 2 63
+*A 72 2 65
+*B 67 2 66
+*X 72 2 67
+*D 61 2 68
+*E 61 2 69
+*F 76 2 70
+*G 60 2 71
+*Y 72 2 72
+*I 33 2 73
+--- 63 2 74
+*K 72 2 75
+*L 69 2 76
+*M 89 2 77
+*N 72 2 78
+*O 72 2 79
+*P 77 2 80
+*H 74 2 81
+*R 56 2 82
+*S 59 2 83
+*T 61 2 84
+*U 69 2 85
+--- 44 1 86
+ts 44 1 86
+*W 77 2 87
+*C 65 2 88
+*Q 80 2 89
+*Z 61 2 90
+--- 33 3 91
+--- 86 0 92
+--- 33 3 93
+--- 66 2 94
+ul 50 1 95
+_ "
+rn 50 2 96
+*a 63 0 97
+*b 55 3 98
+*x 55 1 99
+*d 49 2 100
+*e 44 0 101
+*f 52 3 102
+*g 41 1 103
+*y 60 1 104
+*i 33 0 105
+--- 60 1 106
+*k 55 0 107
+*l 55 2 108
+*m 58 1 109
+*n 52 0 110
+*o 55 0 111
+*p 55 0 112
+*h 52 2 113
+*r 55 1 114
+*s 60 0 115
+*t 44 0 116
+*u 58 0 117
+--- 71 2 118
+*w 69 0 119
+*c 49 3 120
+*q 69 1 121
+*z 49 3 122
+{ 48 3 123
+or 20 3 124
+} 48 3 125
+ap 55 0 126
+--- 62 2 161
+fm 25 2 162
+<= 55 2 163
+sl 17 2 164
+if 73 0 165
+--- 50 3 166
+--- 75 0 167
+--- 75 0 168
+--- 75 0 169
+--- 75 0 170
+--- 104 0 171
+<- 99 0 172
+ua 60 2 173
+-> 99 0 174
+da 60 2 175
+de 40 2 176
++- 55 2 177
+--- 41 2 178
+>= 55 2 179
+mu 55 0 180
+pt 71 0 181
+pd 49 2 182
+bu 46 0 183
+di 55 0 184
+!= 55 0 185
+== 55 0 186
+~~ 55 0 187
+--- 100 0 188
+--- 60 3 189
+--- 100 0 190
+--- 66 2 191
+al 82 2 192
+--- 69 2 193
+--- 80 2 194
+--- 99 3 195
+Ox 77 2 196
+O+ 77 2 197
+es 82 2 198
+ca 77 0 199
+cu 77 0 200
+sp 71 0 201
+ip 71 1 202
+--- 71 0 203
+sb 71 0 204
+ib 71 1 205
+mo 71 0 206
+--- 71 0 207
+--- 77 2 208
+gr 71 2 209
+rg 79 2 210
+co 79 2 211
+tm 89 2 212
+--- 82 2 213
+sr 55 2 214
+--- 25 0 215
+no 71 0 216
+^ 60 0 217
+or 60 0 218
+--- 104 0 219
+--- 99 0 220
+--- 60 2 221
+--- 99 0 222
+--- 60 2 223
+--- 49 2 224
+--- 33 3 225
+--- 79 2 226
+--- 79 2 227
+--- 79 2 228
+--- 71 2 229
+--- 38 3 230
+br 0 3 231
+--- 38 3 232
+lc 50 2 233
+vr 0 2 234
+lf 50 2 235
+lt 49 2 236
+lk 49 2 237
+lb 49 2 238
+bv 49 2 239
+--- 25 0 240
+--- 33 3 241
+is 50 3 242
+--- 69 2 243
+--- 69 2 244
+--- 69 2 245
+--- 38 3 246
+--- 38 2 247
+--- 38 3 248
+rc 38 2 249
+| 50 3 250
+rf 38 2 251
+rt 49 2 252
+rk 49 2 253
+rb 49 2 254
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/S.name b/usr/src/cmd/lp/filter/postscript/font/devpost/S.name
new file mode 100644
index 0000000000..c5fe836342
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/S.name
@@ -0,0 +1 @@
+Symbol
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/S.small b/usr/src/cmd/lp/filter/postscript/font/devpost/S.small
new file mode 100644
index 0000000000..d002a7aa17
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/S.small
@@ -0,0 +1,155 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Symbol
+#
+name S
+internalname 33
+special
+charset
+bx 50 2 1
+ci 75 0 1
+sq 50 2 1
+~= 55 0 1
+L1 110 1 2
+LA 110 1 2
+LV 110 3 2
+LH 210 1 2
+Lb "
+lh 100 0 2
+rh 100 0 2
+fa 71 2 34
+te 55 2 36
+** 50 0 42
+pl 55 0 43
+mi 55 0 45
+< 55 0 60
+eq 55 0 61
+> 55 0 62
+*A 72 2 65
+*B 67 2 66
+*X 72 2 67
+*D 61 2 68
+*E 61 2 69
+*F 76 2 70
+*G 60 2 71
+*Y 72 2 72
+*I 33 2 73
+*K 72 2 75
+*L 69 2 76
+*M 89 2 77
+*N 72 2 78
+*O 72 2 79
+*P 77 2 80
+*H 74 2 81
+*R 56 2 82
+*S 59 2 83
+*T 61 2 84
+*U 69 2 85
+ts 44 1 86
+*W 77 2 87
+*C 65 2 88
+*Q 80 2 89
+*Z 61 2 90
+ul 50 1 95
+_ "
+rn 50 2 96
+*a 63 0 97
+*b 55 3 98
+*x 55 1 99
+*d 49 2 100
+*e 44 0 101
+*f 52 3 102
+*g 41 1 103
+*y 60 1 104
+*i 33 0 105
+*k 55 0 107
+*l 55 2 108
+*m 58 1 109
+*n 52 0 110
+*o 55 0 111
+*p 55 0 112
+*h 52 2 113
+*r 55 1 114
+*s 60 0 115
+*t 44 0 116
+*u 58 0 117
+*w 69 0 119
+*c 49 3 120
+*q 69 1 121
+*z 49 3 122
+{ 48 3 123
+or 20 3 124
+} 48 3 125
+ap 55 0 126
+fm 25 2 162
+<= 55 2 163
+sl 17 2 164
+if 73 0 165
+<- 99 0 172
+ua 60 2 173
+-> 99 0 174
+da 60 2 175
+de 40 2 176
++- 55 2 177
+>= 55 2 179
+mu 55 0 180
+pt 71 0 181
+pd 49 2 182
+bu 46 0 183
+di 55 0 184
+!= 55 0 185
+== 55 0 186
+~~ 55 0 187
+al 82 2 192
+Ox 77 2 196
+O+ 77 2 197
+es 82 2 198
+ca 77 0 199
+cu 77 0 200
+sp 71 0 201
+ip 71 1 202
+sb 71 0 204
+ib 71 1 205
+mo 71 0 206
+gr 71 2 209
+rg 79 2 210
+co 79 2 211
+tm 89 2 212
+sr 55 2 214
+no 71 0 216
+^ 60 0 217
+or 60 0 218
+br 0 3 231
+lc 50 2 233
+vr 0 2 234
+lf 50 2 235
+lt 49 2 236
+lk 49 2 237
+lb 49 2 238
+bv 49 2 239
+is 50 3 242
+rc 38 2 249
+| 50 3 250
+rf 38 2 251
+rt 49 2 252
+rk 49 2 253
+rb 49 2 254
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/S1 b/usr/src/cmd/lp/filter/postscript/font/devpost/S1
new file mode 100644
index 0000000000..ac624b6f46
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/S1
@@ -0,0 +1,62 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+# Times-Roman special font
+name S1
+internalname 1
+special
+charset
+" 41 2 34
+# 50 2 35
+< 56 0 60
+> 56 0 62
+@ 92 3 64
+\ 28 2 92
+or 20 2 124
+^ 33 2 195
+~ 33 2 196
+\' 33 2 194
+aa "
+\` 33 2 193
+ga "
+ru 50 0 95
+\- 65 0 177
+en "
+sc 50 3 167
+dg 50 3 178
+dd 50 3 179
+ct 50 3 162
+14 75 2 1
+34 75 2 1
+12 75 2 1
+Sl 50 2 1
+ob 38 0 1
+`` 44 2 170
+'' 44 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/S1.name b/usr/src/cmd/lp/filter/postscript/font/devpost/S1.name
new file mode 100644
index 0000000000..1a9e5453e1
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/S1.name
@@ -0,0 +1 @@
+Times-Roman
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/VB b/usr/src/cmd/lp/filter/postscript/font/devpost/VB
new file mode 100644
index 0000000000..eaf054c416
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/VB
@@ -0,0 +1,126 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Varitimes#Bold
+name VB
+internalname 1
+special
+charset
+! 28 2 33
+$ 53 3 36
+% 83 2 37
+& 77 2 38
+' 28 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 77 0 43
+, 28 1 44
+hy 33 0 45
+- "
+. 28 0 46
+/ 33 2 47
+0 53 2 48
+1 53 2 49
+2 53 2 50
+3 53 2 51
+4 53 2 52
+5 53 2 53
+6 53 2 54
+7 53 2 55
+8 53 2 56
+9 53 2 57
+: 28 0 58
+; 28 1 59
+= 77 0 61
+? 47 2 63
+A 72 2 65
+B 64 2 66
+C 72 2 67
+D 72 2 68
+E 66 2 69
+F 61 2 70
+G 75 2 71
+H 77 2 72
+I 39 2 73
+J 50 2 74
+K 77 2 75
+L 64 2 76
+M 94 2 77
+N 75 2 78
+O 77 2 79
+P 64 2 80
+Q 77 3 81
+R 72 2 82
+S 55 2 83
+T 66 2 84
+U 75 2 85
+V 72 2 86
+W 100 2 87
+X 69 2 88
+Y 72 2 89
+Z 64 2 90
+[ 33 3 91
+] 33 3 93
+` 28 2 96
+a 50 0 97
+b 55 2 98
+c 44 0 99
+d 55 2 100
+e 44 0 101
+f 36 2 102
+g 50 1 103
+h 55 2 104
+i 28 2 105
+j 30 3 106
+k 55 2 107
+l 28 2 108
+m 83 0 109
+n 55 0 110
+o 50 0 111
+p 55 1 112
+q 55 1 113
+r 44 0 114
+s 39 0 115
+t 33 2 116
+u 55 0 117
+v 47 0 118
+w 69 0 119
+x 50 0 120
+y 47 1 121
+z 44 0 122
+ct 53 3 162
+fi 55 2 174
+fl 55 2 175
+ff 60 2 1
+Fi 84 2 1
+Fl 84 2 1
+dg 53 3 178
+bu 41 0 183
+de 50 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+sq 50 2 1
+`` 44 2 170
+'' 44 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/VB.name b/usr/src/cmd/lp/filter/postscript/font/devpost/VB.name
new file mode 100644
index 0000000000..7ce3b11ae1
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/VB.name
@@ -0,0 +1 @@
+Varitimes#Bold
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/VI b/usr/src/cmd/lp/filter/postscript/font/devpost/VI
new file mode 100644
index 0000000000..24e6d80335
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/VI
@@ -0,0 +1,126 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Varitimes#Italic
+name VI
+internalname 1
+special
+charset
+! 25 2 33
+$ 55 2 36
+% 89 2 37
+& 75 2 38
+' 25 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 77 0 43
+, 22 1 44
+hy 39 0 45
+- "
+. 22 0 46
+/ 33 2 47
+0 55 2 48
+1 55 2 49
+2 55 2 50
+3 55 2 51
+4 55 2 52
+5 55 2 53
+6 55 2 54
+7 55 2 55
+8 55 2 56
+9 55 2 57
+: 22 0 58
+; 22 1 59
+= 77 0 61
+? 44 2 63
+A 69 2 65
+B 64 2 66
+C 69 2 67
+D 75 2 68
+E 61 2 69
+F 58 2 70
+G 75 2 71
+H 75 2 72
+I 33 2 73
+J 41 2 74
+K 64 2 75
+L 58 2 76
+M 86 2 77
+N 72 2 78
+O 75 2 79
+P 58 2 80
+Q 75 3 81
+R 61 2 82
+S 53 2 83
+T 61 2 84
+U 75 2 85
+V 69 2 86
+W 89 2 87
+X 69 2 88
+Y 64 2 89
+Z 66 2 90
+[ 33 3 91
+] 33 3 93
+` 25 2 96
+a 53 0 97
+b 53 2 98
+c 44 0 99
+d 53 2 100
+e 41 0 101
+f 33 3 102
+g 44 1 103
+h 53 2 104
+i 25 2 105
+j 25 3 106
+k 47 2 107
+l 25 2 108
+m 77 0 109
+n 53 0 110
+o 53 0 111
+p 53 1 112
+q 53 1 113
+r 36 0 114
+s 36 0 115
+t 28 0 116
+u 53 0 117
+v 44 0 118
+w 72 0 119
+x 47 0 120
+y 47 1 121
+z 39 0 122
+ct 50 3 162
+fi 55 3 174
+fl 55 3 175
+ff 60 2 1
+Fi 84 2 1
+Fl 84 2 1
+dg 53 2 178
+bu 41 0 183
+de 50 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+sq 50 2 1
+`` 44 2 170
+'' 44 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/VI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/VI.name
new file mode 100644
index 0000000000..4562893d5c
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/VI.name
@@ -0,0 +1 @@
+Varitimes#Italic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/VR b/usr/src/cmd/lp/filter/postscript/font/devpost/VR
new file mode 100644
index 0000000000..a9d2371263
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/VR
@@ -0,0 +1,126 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Varitimes#Roman
+name VR
+internalname 1
+special
+charset
+! 25 2 33
+$ 55 2 36
+% 83 2 37
+& 77 2 38
+' 25 2 39
+( 33 3 40
+) 33 3 41
+* 50 2 42
++ 77 0 43
+, 22 1 44
+hy 39 0 45
+- "
+. 22 0 46
+/ 39 2 47
+0 55 2 48
+1 55 2 49
+2 55 2 50
+3 55 2 51
+4 55 2 52
+5 55 2 53
+6 55 2 54
+7 55 2 55
+8 55 2 56
+9 55 2 57
+: 22 0 58
+; 22 1 59
+= 77 0 61
+? 47 2 63
+A 75 2 65
+B 64 2 66
+C 75 2 67
+D 77 2 68
+E 66 2 69
+F 61 2 70
+G 77 2 71
+H 75 2 72
+I 33 2 73
+J 39 2 74
+K 75 2 75
+L 64 2 76
+M 91 2 77
+N 75 2 78
+O 77 2 79
+P 61 2 80
+Q 77 3 81
+R 69 2 82
+S 53 2 83
+T 66 2 84
+U 75 2 85
+V 72 2 86
+W 100 2 87
+X 75 2 88
+Y 72 2 89
+Z 64 2 90
+[ 33 3 91
+] 33 3 93
+` 25 2 96
+a 50 0 97
+b 53 2 98
+c 47 0 99
+d 53 2 100
+e 47 0 101
+f 33 2 102
+g 53 1 103
+h 53 2 104
+i 28 2 105
+j 28 3 106
+k 55 2 107
+l 28 2 108
+m 83 0 109
+n 53 0 110
+o 53 0 111
+p 53 1 112
+q 53 1 113
+r 36 0 114
+s 39 0 115
+t 30 2 116
+u 53 0 117
+v 50 0 118
+w 75 0 119
+x 50 0 120
+y 50 1 121
+z 47 0 122
+ct 53 3 162
+fi 58 2 174
+fl 58 2 175
+ff 60 2 1
+Fi 84 2 1
+Fl 84 2 1
+dg 53 3 178
+bu 41 0 183
+de 50 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+sq 50 2 1
+`` 44 2 170
+'' 44 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/VR.name b/usr/src/cmd/lp/filter/postscript/font/devpost/VR.name
new file mode 100644
index 0000000000..ce7ab7c8ee
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/VR.name
@@ -0,0 +1 @@
+Varitimes#Roman
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/VX b/usr/src/cmd/lp/filter/postscript/font/devpost/VX
new file mode 100644
index 0000000000..59283ea1d9
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/VX
@@ -0,0 +1,126 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Varitimes#BoldItalic
+name VX
+internalname 1
+special
+charset
+! 28 2 33
+$ 55 2 36
+% 91 2 37
+& 75 2 38
+' 28 2 39
+( 33 3 40
+) 33 3 41
+* 55 2 42
++ 77 0 43
+, 28 1 44
+hy 39 0 45
+- "
+. 28 1 46
+/ 22 2 47
+0 53 2 48
+1 53 2 49
+2 53 2 50
+3 53 2 51
+4 53 2 52
+5 53 2 53
+6 53 2 54
+7 53 2 55
+8 53 2 56
+9 53 2 57
+: 28 0 58
+; 28 1 59
+= 77 0 61
+? 44 2 63
+A 66 2 65
+B 69 2 66
+C 69 2 67
+D 77 2 68
+E 69 2 69
+F 66 2 70
+G 77 2 71
+H 80 2 72
+I 39 2 73
+J 50 2 74
+K 69 2 75
+L 64 2 76
+M 94 2 77
+N 75 2 78
+O 75 2 79
+P 64 2 80
+Q 75 3 81
+R 72 2 82
+S 58 2 83
+T 66 2 84
+U 77 2 85
+V 69 2 86
+W 91 2 87
+X 66 2 88
+Y 61 2 89
+Z 64 2 90
+[ 33 3 91
+] 33 3 93
+` 28 2 96
+a 53 0 97
+b 53 2 98
+c 44 0 99
+d 53 2 100
+e 44 0 101
+f 33 3 102
+g 50 1 103
+h 55 2 104
+i 30 2 105
+j 33 3 106
+k 53 2 107
+l 30 2 108
+m 80 0 109
+n 55 0 110
+o 50 0 111
+p 53 1 112
+q 53 1 113
+r 41 0 114
+s 39 0 115
+t 33 2 116
+u 55 0 117
+v 44 0 118
+w 66 0 119
+x 50 0 120
+y 44 1 121
+z 44 0 122
+ct 44 3 162
+fi 61 3 174
+fl 61 3 175
+ff 60 2 1
+Fi 84 2 1
+Fl 84 2 1
+dg 50 3 178
+bu 41 0 183
+de 30 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+sq 50 2 1
+`` 44 2 170
+'' 44 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/VX.name b/usr/src/cmd/lp/filter/postscript/font/devpost/VX.name
new file mode 100644
index 0000000000..6beb074533
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/VX.name
@@ -0,0 +1 @@
+Varitimes#BoldItalic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/ZD b/usr/src/cmd/lp/filter/postscript/font/devpost/ZD
new file mode 100644
index 0000000000..57834daf39
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/ZD
@@ -0,0 +1,214 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ZapfDingbats
+name ZD
+internalname 36
+ligatures fi fl 0
+charset
+! 97 2 33
+" 96 2 34
+# 97 2 35
+$ 98 3 36
+% 72 2 37
+& 79 3 38
+' 79 3 39
+( 79 3 40
+) 69 2 41
+* 96 2 42
++ 94 2 43
+, 55 3 44
+- 86 2 45
+. 91 2 46
+/ 93 2 47
+0 91 2 48
+1 94 2 49
+2 97 2 50
+3 76 3 51
+4 85 3 52
+5 76 2 53
+6 76 2 54
+7 57 3 55
+8 68 3 56
+9 76 2 57
+: 76 2 58
+; 76 2 59
+< 75 3 60
+= 49 2 61
+> 55 2 62
+? 54 3 63
+@ 58 2 64
+A 69 3 65
+B 79 3 66
+C 79 3 67
+D 79 3 68
+E 79 3 69
+F 79 3 70
+G 79 3 71
+H 82 3 72
+I 82 3 73
+J 79 3 74
+K 84 3 75
+L 82 3 76
+M 83 3 77
+N 82 3 78
+O 83 3 79
+P 92 3 80
+Q 74 2 81
+R 72 2 82
+S 75 2 83
+T 79 3 84
+U 79 3 85
+V 69 3 86
+W 78 3 87
+X 77 3 88
+Y 79 3 89
+Z 76 2 90
+[ 71 3 91
+\ 71 3 92
+] 68 3 93
+^ 70 3 94
+_ 83 3 95
+` 81 3 96
+a 79 3 97
+b 79 3 98
+c 71 3 99
+d 69 2 100
+e 70 2 101
+f 69 2 102
+g 79 3 103
+h 79 3 104
+i 71 3 105
+j 79 3 106
+k 78 3 107
+l 79 3 108
+m 87 3 109
+n 76 2 110
+o 76 2 111
+p 76 2 112
+q 76 3 113
+r 76 3 114
+s 89 2 115
+t 89 3 116
+u 79 3 117
+v 78 3 118
+w 44 3 119
+x 14 2 120
+y 28 2 121
+z 41 2 122
+{ 39 2 123
+| 39 2 124
+} 67 2 125
+~ 67 2 126
+hy 73 3 161
+em 54 3 162
+de 54 3 163
+\- 91 2 164
+en 67 3 165
+ff 76 3 166
+fi 76 2 167
+fl 78 2 168
+Fi 60 3 169
+Fl 69 3 170
+fm 63 3 171
+ru 79 3 172
+dg 79 3 173
+bu 79 3 174
+14 79 3 175
+34 79 3 176
+12 79 3 177
+ct 79 3 178
+rg 79 3 179
+sq 79 3 180
+sl 79 3 181
+ul 79 3 182
+or 79 3 183
+no 79 3 184
+-> 79 3 185
+<- 79 3 186
+da 79 3 187
+lh 79 3 188
+ua 79 3 189
+\e 79 3 190
+\' 79 3 191
+aa 79 3 192
+\` 79 3 193
+ga 79 3 194
+pl 79 3 195
+mi 79 3 196
+mu 79 3 197
+di 79 3 198
+eq 79 3 199
+== 79 3 200
+>= 79 3 201
+<= 79 3 202
+!= 79 3 203
++- 79 3 204
+-+ 79 3 205
+ap 79 3 206
+~= 79 3 207
+gr 79 3 208
+is 79 3 209
+pd 79 3 210
+if 79 3 211
+sr 89 2 212
+rn 84 2 213
+sb 102 2 214
+sp 46 3 215
+cu 75 2 216
+ca 92 2 217
+ib 75 2 218
+ip 92 2 219
+mo 93 2 220
+es 93 2 221
+sc 93 2 222
+dd 83 2 223
+lc 87 2 224
+rc 83 2 225
+lf 92 2 226
+rf 92 2 227
+bv 92 2 228
+** 93 2 229
+br 93 2 230
+ci 46 3 231
+ts 88 2 232
+co 84 2 233
+lt 84 2 234
+rt 87 2 235
+lb 87 2 236
+rb 70 2 237
+lk 70 2 238
+rk 87 2 239
+rh 87 2 241
+tm 76 2 242
+Sl 95 2 243
+ps 77 2 244
+cs 86 2 245
+cy 77 2 246
+as 89 3 247
+os 97 2 248
+=. 89 3 249
+ld 83 2 250
+rd 87 2 251
+le 93 2 252
+ge 97 2 253
+pp 92 2 254
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/ZD.name b/usr/src/cmd/lp/filter/postscript/font/devpost/ZD.name
new file mode 100644
index 0000000000..b70c41eb04
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/ZD.name
@@ -0,0 +1 @@
+ZapfDingbats
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/ZI b/usr/src/cmd/lp/filter/postscript/font/devpost/ZI
new file mode 100644
index 0000000000..48820a3188
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/ZI
@@ -0,0 +1,122 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# ZapfChancery-MediumItalic
+name ZI
+internalname 37
+ligatures fi fl 0
+charset
+! 28 2 33
+$ 44 3 36
+% 68 2 37
+& 78 2 38
+' 24 2 39
+( 26 3 40
+) 22 3 41
+* 42 2 42
++ 52 0 43
+, 22 0 44
+hy 28 0 45
+- "
+. 22 0 46
+/ 34 3 47
+0 44 2 48
+1 44 2 49
+2 44 2 50
+3 44 2 51
+4 44 2 52
+5 44 2 53
+6 44 2 54
+7 44 2 55
+8 44 2 56
+9 44 2 57
+: 26 0 58
+; 24 0 59
+= 52 0 61
+? 38 2 63
+A 62 2 65
+B 60 2 66
+C 52 2 67
+D 70 2 68
+E 62 2 69
+F 58 2 70
+G 62 3 71
+H 68 2 72
+I 38 2 73
+J 40 2 74
+K 66 3 75
+L 58 2 76
+M 84 2 77
+N 70 3 78
+O 60 2 79
+P 54 2 80
+Q 60 3 81
+R 60 3 82
+S 46 2 83
+T 50 2 84
+U 74 2 85
+V 64 2 86
+W 88 2 87
+X 56 2 88
+Y 56 3 89
+Z 62 2 90
+[ 24 3 91
+] 32 3 93
+` 24 2 96
+a 42 0 97
+b 42 2 98
+c 34 0 99
+d 44 2 100
+e 34 0 101
+f 32 3 102
+g 40 1 103
+h 44 2 104
+i 24 2 105
+j 22 3 106
+k 44 3 107
+l 24 2 108
+m 62 0 109
+n 46 0 110
+o 40 0 111
+p 44 1 112
+q 40 3 113
+r 30 0 114
+s 32 0 115
+t 32 2 116
+u 46 0 117
+v 44 0 118
+w 68 0 119
+x 42 1 120
+y 40 1 121
+z 44 0 122
+ct 44 2 162
+fi 52 3 174
+fl 52 3 175
+dg 46 3 178
+bu 60 2 183
+de 30 2 202
+em 100 0 208
+14 75 2 1
+34 75 2 1
+12 75 2 1
+`` 34 2 170
+'' 36 2 186
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/ZI.name b/usr/src/cmd/lp/filter/postscript/font/devpost/ZI.name
new file mode 100644
index 0000000000..f995af1403
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/ZI.name
@@ -0,0 +1 @@
+ZapfChancery-MediumItalic
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/12 b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/12
new file mode 100644
index 0000000000..69e8cf28d1
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/12
@@ -0,0 +1,40 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/12 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_12 {
+ pop
+ /optsize ptsize def
+ /osize size def
+ /ofont font def
+
+ optsize 2 div dup R exch R f
+ 0 size 2 mul 3 div dup neg exch 0 exch rmoveto
+
+ (1) show
+ rmoveto
+ optsize R f
+ (\244) show
+ f
+ (2) show
+
+ optsize ofont f
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/14 b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/14
new file mode 100644
index 0000000000..f2c643e984
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/14
@@ -0,0 +1,40 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/14 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_14 {
+ pop
+ /optsize ptsize def
+ /osize size def
+ /ofont font def
+
+ optsize 2 div dup R exch R f
+ 0 size 2 mul 3 div dup neg exch 0 exch rmoveto
+
+ (1) show
+ rmoveto
+ optsize R f
+ (\244) show
+ f
+ (4) show
+
+ optsize ofont f
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/34 b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/34
new file mode 100644
index 0000000000..991b800a88
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/34
@@ -0,0 +1,40 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/34 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_34 {
+ pop
+ /optsize ptsize def
+ /osize size def
+ /ofont font def
+
+ optsize 2 div dup R exch R f
+ 0 size 2 mul 3 div dup neg exch 0 exch rmoveto
+
+ (3) show
+ rmoveto
+ optsize R f
+ (\244) show
+ f
+ (4) show
+
+ optsize ofont f
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/BRACKETS_NOTE b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/BRACKETS_NOTE
new file mode 100644
index 0000000000..c120e3d83a
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/BRACKETS_NOTE
@@ -0,0 +1,58 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+ lc, rc, lf, and rf contain PostScript code that can be used to build the top
+ and bottom bracket pieces used by eqn. The files are only used if the character
+ code field in the S font file for lc, rc, lf, and rf is set to 1. A code larger
+ than 32 means a character from Adobe's Symbol font will be used. Think the real
+ solution is to change eqn so large brackets and braces are built differently.
+
+ There were some serious collisions with eqn's bracket building algorithm and
+ Adobe's Symbol font. eqn extends all the pieces with the \(bv character, while
+ the bracket and brace pieces available in Adobe's Symbol are all quite different
+ and are designed to work with their own extenders. The reference points are
+ different, but worse still the thickness of brackets and braces don't match.
+ Anyway using a single extender (the way eqn does) can't ever work with the
+ bracket and brace characters available in Adobe's Symbol font.
+
+ The lc, rc, lf, and rf files are a very complicated attempt to get around the
+ problem. Each builds the troff character by using the \(bv character from the
+ Symbol font and then draws a small horizontal line at either the top or bottom
+ of the \(bv. Using \(bv for the vertical part guarantees things will stack
+ properly, but getting to the precise top or bottom of the \(bv (down to the
+ pixel level on all devices and in all sizes) proved to be very difficult. In
+ fact you would think that determining the bounding box of \(bv would be enough
+ to let you draw a good bracket piece that matched up nicely with the extender.
+ Not quite, at least I didn't find that it was possible to do a good job drawing
+ the pieces from the \(bv bounding box. Think roundoff errors introduced by the
+ CTM caused the trouble, although I expect there's more to it.
+
+ Clipping a rectangular region 2 pixels smaller in height than the bounding box
+ of the \(bv character, and using the corners of that box to locate the top and
+ bottom of the bv for the horizontal extender solved the problems I originally
+ had with the precise placement of the horizontal rule. Anyway that's what the
+ clipping and idtransform are for. The initgraphics stuff is an attempt to fit
+ a tight bounding box around the \(bv character independent of the rotation of
+ our coordinate system. pathbbox only returns what we want if the coordinate
+ system has been rotated by a multiple of 90 degrees.
+
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Fi b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Fi
new file mode 100644
index 0000000000..78f7b710d5
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Fi
@@ -0,0 +1,26 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/Fi 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_Fi {
+ pop
+ size .05 mul neg 0 (ffi) ashow
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Fl b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Fl
new file mode 100644
index 0000000000..5106155229
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Fl
@@ -0,0 +1,26 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/Fl 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_Fl {
+ pop
+ size .05 mul neg 0 (ffl) ashow
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/L1 b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/L1
new file mode 100644
index 0000000000..9650fddac4
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/L1
@@ -0,0 +1,34 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/L1 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_L1 {
+ pop
+ /picstr 40 string def
+ gsave
+ currentpoint translate
+ .533 72 mul size mul 36 div
+ .5 72 mul size mul 36 div
+ scale
+ 160 150 1 [160 0 0 -150 0 150]
+ {currentfile picstr readhexstring pop} image
+ grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/L1.map b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/L1.map
new file mode 100644
index 0000000000..0847af4559
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/L1.map
@@ -0,0 +1,150 @@
+FFFFFFFFFFFFFFFFFF0007FFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF00000007FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFE0000000007FFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF00000000000FFFFFFFFFFFFFFF
+FFFFFFFFFFFFF8000000000001FFFFFFFFFFFFFF
+FFFFFFFFFFFFE00000000000003FFFFFFFFFFFFF
+FFFFFFFFFFFF000000000000000FFFFFFFFFFFFF
+FFFFFFFFFFFC0000000000000003FFFFFFFFFFFF
+FFFFFFFFFFF000000000000000007FFFFFFFFFFF
+FFFFFFFFFFC000000000000000003FFFFFFFFFFF
+FFFFFFFFFF8FFFFFFF00000000000FFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFF0000000007FFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFC00000000003FFFFFFFF
+FFFFFFF81FFFFFFFFFC0000000000001FFFFFFFF
+FFFFFFF0000000000000000000000000FFFFFFFF
+FFFFFFE00000000000000000000000007FFFFFFF
+FFFFFFC00000000000000000000000003FFFFFFF
+FFFFFF800000000000000000000000001FFFFFFF
+FFFFFF000000000000000000000000000FFFFFFF
+FFFFFE0007FFFFFFFF8000000000000007FFFFFF
+FFFFFE7FFFFFFFFFFFFFFE000000000003FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF0000000003FFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFE000000001FFFFF
+FFFFFFFFFFFFFFFFFFFFFFFF80000000001FFFFF
+FFFF01FFFFFFFFFFFFFFFFC000000000000FFFFF
+FFFE00000000000000000000000000000007FFFF
+FFFE00000000000000000000000000000007FFFF
+FFFC00000000000000000000000000000003FFFF
+FFFC00000000000000000000000000000003FFFF
+FFF800000000000000000000000000000001FFFF
+FFF800000000000000000000000000000000FFFF
+FFF80FFFFFFFFFFFFFFFFFE0000000000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFE0000000000FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFC00000001FFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFC0000000001FFF
+FF87FFFFFFFFFFFFFFFFFFFFC000000000000FFF
+FF000000007FFFFFFFFFFC000000000000000FFF
+FF000000000000000000000000000000000007FF
+FF000000000000000000000000000000000007FF
+FE000000000000000000000000000000000007FF
+FE000000000000000000000000000000000003FF
+FE000000000000000000000000000000000003FF
+FE0007FFFFFFFFFFFFFFFFC000000000000003FF
+FC0FFFFFFFFFFFFFFFFFFFFFFC000000000003FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFC000000003FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFC00000001FF
+FFFFFFFFFFFFFFFFFFFFFFFFFF800000000001FF
+F8FFFFFFFFFFFFFFFFFFFFFF80000000000000FF
+F8000FFFFFFFFFFFFFFFFF0000000000000000FF
+F8000000000000000000000000000000000000FF
+F0000000000000000000000000000000000000FF
+F0000000000000000000000000000000000000FF
+F0000000000000000000000000000000000000FF
+F00000000000000000000000000000000000007F
+F00000007FFFFFFFFFFFE000000000000000007F
+F000FFFFFFFFFFFFFFFFFFFF000000000000007F
+F07FFFFFFFFFFFFFFFFFFFFFFFC000000000007F
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFF0000000000007F
+F007FFFFFFFFFFFFFFFFFFFC000000000000007F
+F00003FFFFFFFFFFFFFFF000000000000000007F
+F00000000000000000000000000000000000007F
+F00000000000000000000000000000000000007F
+F0000000000000000000000000000000000000FF
+F0000000000000000000000000000000000000FF
+F8000000000000000000000000000000000000FF
+F8000000000000000000000000000000000000FF
+F80003FFFFFFFFFFFFFFF80000000000000000FF
+F80FFFFFFFFFFFFFFFFFFFFFC0000000000000FF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFE00000000000003FF
+FC003FFFFFFFFFFFFFFE000000000000000003FF
+FE000000FFFFFFFFC800000000000000000003FF
+FE000000000000000000000000000000000003FF
+FE000000000000000000000000000000000003FF
+FE000000000000000000000000000000000003FF
+FF000000000000000000000000000000000007FF
+FF000000000000000000000000000000000007FF
+FF000000000000000000000000000000000007FF
+FF80000000000000000000000000000000000FFF
+FF8000000007FF80000000000000000000000FFF
+FFC00007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFC07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF03FFFFFFFFFFFFFFFC0000000000000007FFF
+FFF0000007FFFFFE000000000000000000007FFF
+FFF800000000000000000000000000000000FFFF
+FFF800000000000000000000000000000000FFFF
+FFF800000000000000000000000000000000FFFF
+FFFC00000000000000000000000000000001FFFF
+FFFE00000000000000000000000000000003FFFF
+FFFE00000000000000000000000000000003FFFF
+FFFF00000000000000000000000000000007FFFF
+FFFF0000000000000000000000000000000FFFFF
+FFFF8000000000000000000000000000000FFFFF
+FFFFC000003FFFE00000000000000000001FFFFF
+FFFFE007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFC0000000000000000000000000001FFFFFF
+FFFFFE0000000000000000000000000003FFFFFF
+FFFFFF0000000000000000000000000003FFFFFF
+FFFFFF0000000000000000000000000007FFFFFF
+FFFFFF800000000000000000000000000FFFFFFF
+FFFFFFC00000000000000000000000001FFFFFFF
+FFFFFFE00000000000000000000000003FFFFFFF
+FFFFFFF00000000000000000000000007FFFFFFF
+FFFFFFFC000000000000000000000000FFFFFFFF
+FFFFFFFE000000000000000000000003FFFFFFFF
+FFFFFFFF000000000000000000000007FFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF00000000000000000003FFFFFFFFFF
+FFFFFFFFFF8000000000000000000FFFFFFFFFFF
+FFFFFFFFFFE000000000000000001FFFFFFFFFFF
+FFFFFFFFFFF000000000000000007FFFFFFFFFFF
+FFFFFFFFFFFC0000000000000001FFFFFFFFFFFF
+FFFFFFFFFFFF0000000000000007FFFFFFFFFFFF
+FFFFFFFFFFFFE00000000000003FFFFFFFFFFFFF
+FFFFFFFFFFFFF8000000000000FFFFFFFFFFFFFF
+FFFFFFFFFFFFFF000000000007FFFFFFFFFFFFFF
+FFFFFFFFFFFFFFF0000000007FFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFF00000007FFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFE0007FFFFFFFFFFFFFFFFFF
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/LH b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/LH
new file mode 100644
index 0000000000..740d2c58ab
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/LH
@@ -0,0 +1,23 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/LH 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_LH {pop} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/LH.map b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/LH.map
new file mode 100644
index 0000000000..b2aa627216
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/LH.map
@@ -0,0 +1,871 @@
+gsave
+/M {moveto} def
+/L {lineto} def
+
+currentpoint translate
+0 360 translate
+2.4 2.4 scale
+ptsize 36 div dup neg scale
+
+68 1 M
+68 1 L
+60 2 L
+55 3 L
+52 4 L
+49 5 L
+47 6 L
+44 7 L
+42 8 L
+40 9 L
+38 10 L
+37 11 L
+39 11 L
+53 10 L
+68 11 L
+76 12 L
+112 12 L
+111 11 L
+109 10 L
+108 9 L
+105 8 L
+103 7 L
+101 6 L
+98 5 L
+95 4 L
+92 3 L
+88 2 L
+80 1 L
+closepath
+84 17 M
+84 17 L
+78 18 L
+70 19 L
+50 20 L
+30 19 L
+25 19 L
+24 20 L
+23 21 L
+22 22 L
+21 23 L
+20 24 L
+19 25 L
+19 26 L
+20 26 L
+32 25 L
+50 24 L
+69 25 L
+83 26 L
+92 27 L
+129 27 L
+129 26 L
+128 25 L
+127 24 L
+126 23 L
+125 22 L
+124 21 L
+123 20 L
+122 19 L
+121 18 L
+119 17 L
+closepath
+99 32 M
+99 32 L
+93 33 L
+86 34 L
+52 35 L
+18 34 L
+12 34 L
+11 35 L
+11 36 L
+10 37 L
+10 38 L
+9 39 L
+9 40 L
+9 41 L
+15 41 L
+51 40 L
+87 41 L
+99 42 L
+139 42 L
+139 41 L
+139 40 L
+138 39 L
+137 38 L
+137 37 L
+136 36 L
+136 35 L
+135 34 L
+134 33 L
+134 32 L
+closepath
+110 47 M
+110 47 L
+102 48 L
+94 49 L
+82 50 L
+59 51 L
+36 50 L
+8 49 L
+5 49 L
+4 50 L
+4 51 L
+4 52 L
+3 53 L
+3 54 L
+3 55 L
+3 56 L
+2 57 L
+7 57 L
+16 56 L
+51 55 L
+86 56 L
+98 57 L
+110 58 L
+145 58 L
+145 57 L
+145 56 L
+145 55 L
+145 54 L
+144 53 L
+144 52 L
+144 51 L
+143 50 L
+143 49 L
+142 48 L
+142 47 L
+closepath
+178 49 M
+178 49 L
+178 50 L
+177 51 L
+177 52 L
+177 53 L
+176 54 L
+176 55 L
+176 56 L
+175 57 L
+175 58 L
+175 59 L
+174 60 L
+174 61 L
+174 62 L
+173 63 L
+173 64 L
+173 65 L
+172 66 L
+172 67 L
+172 68 L
+171 69 L
+171 70 L
+171 71 L
+170 72 L
+170 73 L
+170 74 L
+169 75 L
+169 76 L
+169 77 L
+168 78 L
+168 79 L
+168 80 L
+167 81 L
+167 82 L
+167 83 L
+166 84 L
+166 85 L
+166 86 L
+165 87 L
+165 88 L
+165 89 L
+164 90 L
+164 91 L
+164 92 L
+163 93 L
+163 94 L
+163 95 L
+162 96 L
+162 97 L
+162 98 L
+161 99 L
+161 100 L
+161 101 L
+160 102 L
+174 102 L
+174 101 L
+175 100 L
+175 99 L
+175 98 L
+176 97 L
+176 96 L
+176 95 L
+177 94 L
+185 93 L
+194 94 L
+194 95 L
+195 96 L
+195 97 L
+195 98 L
+195 99 L
+196 100 L
+196 101 L
+196 102 L
+210 102 L
+209 101 L
+209 100 L
+209 99 L
+208 98 L
+208 97 L
+208 96 L
+208 95 L
+207 94 L
+207 93 L
+207 92 L
+206 91 L
+206 90 L
+206 89 L
+205 88 L
+205 87 L
+205 86 L
+204 85 L
+204 84 L
+204 83 L
+203 82 L
+203 81 L
+203 80 L
+202 79 L
+202 78 L
+202 77 L
+202 76 L
+201 75 L
+201 74 L
+201 73 L
+200 72 L
+200 71 L
+200 70 L
+199 69 L
+199 68 L
+199 67 L
+198 66 L
+198 65 L
+198 64 L
+197 63 L
+197 62 L
+197 61 L
+197 60 L
+196 59 L
+196 58 L
+196 57 L
+195 56 L
+195 55 L
+195 54 L
+194 53 L
+194 52 L
+194 51 L
+193 50 L
+193 49 L
+closepath
+200 49 M
+200 49 L
+200 50 L
+200 51 L
+200 52 L
+200 53 L
+200 54 L
+200 55 L
+200 56 L
+200 57 L
+200 58 L
+200 59 L
+200 60 L
+214 61 L
+214 62 L
+214 63 L
+214 64 L
+214 65 L
+214 66 L
+214 67 L
+214 68 L
+214 69 L
+214 70 L
+214 71 L
+214 72 L
+214 73 L
+214 74 L
+214 75 L
+214 76 L
+214 77 L
+214 78 L
+214 79 L
+214 80 L
+214 81 L
+214 82 L
+214 83 L
+214 84 L
+214 85 L
+214 86 L
+214 87 L
+214 88 L
+214 89 L
+214 90 L
+214 91 L
+214 92 L
+214 93 L
+214 94 L
+214 95 L
+214 96 L
+214 97 L
+214 98 L
+214 99 L
+214 100 L
+214 101 L
+214 102 L
+228 102 L
+228 101 L
+228 100 L
+228 99 L
+228 98 L
+228 97 L
+228 96 L
+228 95 L
+228 94 L
+228 93 L
+228 92 L
+228 91 L
+228 90 L
+228 89 L
+228 88 L
+228 87 L
+228 86 L
+228 85 L
+228 84 L
+228 83 L
+228 82 L
+228 81 L
+228 80 L
+228 79 L
+228 78 L
+228 77 L
+228 76 L
+228 75 L
+228 74 L
+228 73 L
+228 72 L
+228 71 L
+228 70 L
+228 69 L
+228 68 L
+228 67 L
+228 66 L
+228 65 L
+228 64 L
+228 63 L
+228 62 L
+228 61 L
+241 60 L
+241 59 L
+241 58 L
+241 57 L
+241 56 L
+241 55 L
+241 54 L
+241 53 L
+241 52 L
+241 51 L
+241 50 L
+241 49 L
+closepath
+266 49 M
+266 49 L
+266 50 L
+266 51 L
+266 52 L
+266 53 L
+266 54 L
+266 55 L
+266 56 L
+266 57 L
+266 58 L
+266 59 L
+266 60 L
+280 61 L
+280 62 L
+280 63 L
+280 64 L
+280 65 L
+280 66 L
+280 67 L
+280 68 L
+280 69 L
+280 70 L
+280 71 L
+280 72 L
+280 73 L
+280 74 L
+280 75 L
+280 76 L
+280 77 L
+280 78 L
+280 79 L
+280 80 L
+280 81 L
+280 82 L
+280 83 L
+280 84 L
+280 85 L
+280 86 L
+280 87 L
+280 88 L
+280 89 L
+280 90 L
+280 91 L
+280 92 L
+280 93 L
+280 94 L
+280 95 L
+280 96 L
+280 97 L
+280 98 L
+280 99 L
+280 100 L
+280 101 L
+280 102 L
+294 102 L
+294 101 L
+294 100 L
+294 99 L
+294 98 L
+294 97 L
+294 96 L
+294 95 L
+294 94 L
+294 93 L
+294 92 L
+294 91 L
+294 90 L
+294 89 L
+294 88 L
+294 87 L
+294 86 L
+294 85 L
+294 84 L
+294 83 L
+294 82 L
+294 81 L
+294 80 L
+294 79 L
+294 78 L
+294 77 L
+294 76 L
+294 75 L
+294 74 L
+294 73 L
+294 72 L
+294 71 L
+294 70 L
+294 69 L
+294 68 L
+294 67 L
+294 66 L
+294 65 L
+294 64 L
+294 63 L
+294 62 L
+294 61 L
+308 60 L
+308 59 L
+308 58 L
+308 57 L
+308 56 L
+308 55 L
+308 54 L
+308 53 L
+308 52 L
+308 51 L
+308 50 L
+308 49 L
+closepath
+251 59 M
+251 59 L
+245 60 L
+243 61 L
+241 62 L
+240 63 L
+239 64 L
+239 65 L
+238 66 L
+238 67 L
+237 68 L
+237 69 L
+237 70 L
+237 71 L
+237 72 L
+238 73 L
+238 74 L
+238 75 L
+239 76 L
+239 77 L
+240 78 L
+239 79 L
+238 80 L
+237 81 L
+237 82 L
+237 83 L
+236 84 L
+236 85 L
+235 86 L
+235 87 L
+235 88 L
+235 89 L
+235 90 L
+235 91 L
+235 92 L
+236 93 L
+236 94 L
+237 95 L
+237 96 L
+238 97 L
+239 98 L
+240 99 L
+241 100 L
+243 101 L
+245 102 L
+249 103 L
+259 103 L
+262 102 L
+265 101 L
+267 100 L
+270 101 L
+272 102 L
+276 102 L
+276 101 L
+276 100 L
+276 99 L
+276 98 L
+276 97 L
+276 96 L
+276 95 L
+276 94 L
+276 93 L
+273 92 L
+273 91 L
+274 90 L
+274 89 L
+274 88 L
+274 87 L
+274 86 L
+274 85 L
+274 84 L
+274 83 L
+274 82 L
+274 81 L
+274 80 L
+274 79 L
+274 78 L
+274 77 L
+274 76 L
+264 75 L
+264 74 L
+264 73 L
+264 72 L
+264 71 L
+264 70 L
+264 69 L
+264 68 L
+264 67 L
+263 66 L
+263 65 L
+263 64 L
+262 63 L
+261 62 L
+260 61 L
+258 60 L
+253 59 L
+closepath
+114 62 M
+114 62 L
+101 63 L
+93 64 L
+84 65 L
+49 66 L
+15 65 L
+3 64 L
+1 64 L
+1 65 L
+1 66 L
+0 67 L
+0 68 L
+0 69 L
+0 70 L
+0 71 L
+0 72 L
+0 73 L
+4 73 L
+11 72 L
+28 71 L
+53 70 L
+79 71 L
+92 72 L
+102 73 L
+148 73 L
+148 72 L
+148 71 L
+148 70 L
+147 69 L
+147 68 L
+147 67 L
+147 66 L
+147 65 L
+147 64 L
+146 63 L
+146 62 L
+closepath
+185 68 M
+185 68 L
+186 67 L
+187 68 L
+187 69 L
+187 70 L
+188 71 L
+188 72 L
+188 73 L
+188 74 L
+189 75 L
+189 76 L
+189 77 L
+189 78 L
+190 79 L
+190 80 L
+190 81 L
+185 82 L
+181 81 L
+181 80 L
+181 79 L
+182 78 L
+182 77 L
+182 76 L
+183 75 L
+183 74 L
+183 73 L
+184 72 L
+184 71 L
+184 70 L
+184 69 L
+closepath
+250 68 M
+250 68 L
+251 67 L
+253 68 L
+254 69 L
+254 70 L
+254 71 L
+254 72 L
+254 73 L
+254 74 L
+254 75 L
+252 76 L
+251 75 L
+250 74 L
+249 73 L
+249 72 L
+249 71 L
+249 70 L
+249 69 L
+closepath
+254 77 M
+254 77 L
+259 76 L
+264 77 L
+264 78 L
+264 79 L
+264 80 L
+264 81 L
+264 82 L
+264 83 L
+264 84 L
+263 85 L
+262 84 L
+261 83 L
+260 82 L
+258 81 L
+257 80 L
+256 79 L
+255 78 L
+closepath
+100 78 M
+100 78 L
+90 79 L
+80 80 L
+48 81 L
+17 80 L
+8 79 L
+0 79 L
+0 80 L
+0 81 L
+0 82 L
+0 83 L
+0 84 L
+1 85 L
+1 86 L
+1 87 L
+1 88 L
+7 88 L
+17 87 L
+49 86 L
+81 87 L
+94 88 L
+147 88 L
+147 87 L
+147 86 L
+147 85 L
+147 84 L
+147 83 L
+148 82 L
+148 81 L
+148 80 L
+148 79 L
+148 78 L
+closepath
+246 86 M
+246 86 L
+247 85 L
+249 86 L
+250 87 L
+252 88 L
+253 89 L
+254 90 L
+255 91 L
+255 92 L
+252 93 L
+250 92 L
+248 91 L
+247 90 L
+247 89 L
+246 88 L
+246 87 L
+closepath
+91 93 M
+91 93 L
+75 94 L
+65 95 L
+64 96 L
+63 95 L
+62 95 L
+44 96 L
+27 95 L
+13 94 L
+2 94 L
+3 95 L
+3 96 L
+3 97 L
+3 98 L
+4 99 L
+4 100 L
+4 101 L
+5 102 L
+5 103 L
+6 104 L
+6 105 L
+12 105 L
+24 104 L
+40 103 L
+46 102 L
+53 103 L
+143 103 L
+143 102 L
+144 101 L
+144 100 L
+144 99 L
+145 98 L
+145 97 L
+145 96 L
+145 95 L
+145 94 L
+145 93 L
+closepath
+8 108 M
+8 108 L
+8 109 L
+9 110 L
+9 111 L
+9 112 L
+10 113 L
+11 114 L
+11 115 L
+12 116 L
+12 117 L
+13 118 L
+14 119 L
+15 120 L
+24 120 L
+37 119 L
+46 118 L
+55 119 L
+134 119 L
+135 118 L
+135 117 L
+136 116 L
+137 115 L
+137 114 L
+138 113 L
+139 112 L
+139 111 L
+139 110 L
+140 109 L
+140 108 L
+78 108 L
+59 109 L
+45 110 L
+32 109 L
+13 108 L
+closepath
+18 124 M
+18 124 L
+19 125 L
+20 126 L
+20 127 L
+21 128 L
+22 129 L
+23 130 L
+24 131 L
+26 132 L
+27 133 L
+28 134 L
+120 134 L
+121 133 L
+123 132 L
+124 131 L
+125 130 L
+126 129 L
+127 128 L
+128 127 L
+129 126 L
+129 125 L
+130 124 L
+closepath
+36 139 M
+36 139 L
+37 140 L
+39 141 L
+40 142 L
+42 143 L
+44 144 L
+47 145 L
+49 146 L
+52 147 L
+56 148 L
+60 149 L
+67 150 L
+80 150 L
+88 149 L
+92 148 L
+96 147 L
+99 146 L
+101 145 L
+104 144 L
+106 143 L
+108 142 L
+110 141 L
+111 140 L
+113 139 L
+closepath
+fill
+grestore
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Lb b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Lb
new file mode 100644
index 0000000000..054da5a132
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Lb
@@ -0,0 +1,34 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/Lb 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_Lb {
+ pop
+ /picstr 78 string def
+ gsave
+ currentpoint translate
+ 1.03 72 mul size mul 36 div
+ .5 72 mul size mul 36 div
+ scale
+ 309 150 1 [309 0 0 -150 0 150]
+ {currentfile picstr readhexstring pop} image
+ grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Lb.map b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Lb.map
new file mode 100644
index 0000000000..e467b45798
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Lb.map
@@ -0,0 +1,150 @@
+FFFFFFFFFFFFFFFFF0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFF00000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFE0000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFF00000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF8000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFE00000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFF000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFC0000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFC000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFF8FFFFFFF00000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFF0000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFC00000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF81FFFFFFFFFC0000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF0000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFE00000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFC00000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF800000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFE0007FFFFFFFF8000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFE7FFFFFFFFFFFFFFE000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFF0000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFE000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFF80000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF01FFFFFFFFFFFFFFFFC000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFE00000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFE00000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFC00000000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFC00000000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF80FFFFFFFFFFFFFFFFFE0000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFE0000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFC00000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFC0000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+F87FFFFFFFFFFFFFFFFFFFFC000000000000FFFFFFFFC0003F00000000003FFFFFC00000000007
+F000000007FFFFFFFFFFC000000000000000FFFFFFFFC0003F00000000003FFFFFC00000000007
+F000000000000000000000000000000000007FFFFFFF80001F00000000003FFFFFC00000000007
+F000000000000000000000000000000000007FFFFFFF80001F00000000003FFFFFC00000000007
+E000000000000000000000000000000000007FFFFFFF80001F00000000003FFFFFC00000000007
+E000000000000000000000000000000000003FFFFFFF00000F00000000003FFFFFC00000000007
+E000000000000000000000000000000000003FFFFFFF00000F00000000003FFFFFC00000000007
+E0007FFFFFFFFFFFFFFFFC000000000000003FFFFFFF00000F00000000003FFFFFC00000000007
+C0FFFFFFFFFFFFFFFFFFFFFFC000000000003FFFFFFE00000700000000003FFFFFC00000000007
+FFFFFFFFFFFFFFFFFFFFFFFFFFFC000000003FFFFFFE00000700000000003FFFFFC00000000007
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000700000000003FE3FFC00000000007
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000003000000000038001FC00000000007
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000003FFFC0007FFE00007FFFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFC00000001FFFFFFC000003FFFC0007FF800003FFFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFF800000000001FFFFFF8000003FFFC0007FF000001FFFF0001FFFF
+8FFFFFFFFFFFFFFFFFFFFFF80000000000000FFFFFF8000001FFFC0007FE000000FFFF0001FFFF
+8000FFFFFFFFFFFFFFFFF0000000000000000FFFFFF8000001FFFC0007FE000000FFFF0001FFFF
+8000000000000000000000000000000000000FFFFFF0000001FFFC0007FC000000FFFF0001FFFF
+0000000000000000000000000000000000000FFFFFF0000000FFFC0007FC0000007FFF0001FFFF
+0000000000000000000000000000000000000FFFFFF0002000FFFC0007F80018007FFF0001FFFF
+0000000000000000000000000000000000000FFFFFE0006000FFFC0007F8003C007FFF0001FFFF
+00000000000000000000000000000000000007FFFFE00060007FFC0007F8003C007FFF0001FFFF
+00000007FFFFFFFFFFFE000000000000000007FFFFE00070007FFC0007F8003C007FFF0001FFFF
+000FFFFFFFFFFFFFFFFFFFF000000000000007FFFFC00070007FFC0007F8003C007FFF0001FFFF
+07FFFFFFFFFFFFFFFFFFFFFFFC000000000007FFFFC000F0003FFC0007FC003C007FFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000F0003FFC0007FC001C007FFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000F8003FFC0007FC000C007FFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8001F8001FFC0007FE000000001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8001F8001FFC0007FE0001FF001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFF0000000000007FFFF0001F8001FFC0007FF0000FF001F0001FFFF
+007FFFFFFFFFFFFFFFFFFFC000000000000007FFFF0003FC001FFC0007FE00007F001F0001FFFF
+00003FFFFFFFFFFFFFFF000000000000000007FFFF0003FC000FFC0007FC00003F001F0001FFFF
+00000000000000000000000000000000000007FFFE0003FC000FFC0007F800001F001F0001FFFF
+00000000000000000000000000000000000007FFFE000000000FFC0007F8000007001F0001FFFF
+0000000000000000000000000000000000000FFFFE0000000007FC0007F8000003001F0001FFFF
+0000000000000000000000000000000000000FFFFC0000000007FC0007F0000001001F0001FFFF
+8000000000000000000000000000000000000FFFFC0000000007FC0007F0000000001F0001FFFF
+8000000000000000000000000000000000000FFFFC0000000003FC0007E0018000001F0001FFFF
+80003FFFFFFFFFFFFFFF80000000000000000FFFF80000000003FC0007E001C000001F0001FFFF
+80FFFFFFFFFFFFFFFFFFFFFC0000000000000FFFF80000000003FC0007E001F000001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000001FC0007E000F800001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000001FC0007E000FC00001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000001FC0007E0007E00003F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000FC0007E0001E00003F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFE00000000000003FFFE00000000000FC0007F000000000070001FFFF
+C003FFFFFFFFFFFFFFE000000000000000003FFFE0003FFFC000FC0007F000000000070001FFFF
+E000000FFFFFFFFC800000000000000000003FFFE0007FFFC0007C0007F800000000070001FFFF
+E000000000000000000000000000000000003FFFC0007FFFE0007C0007F800000000070001FFFF
+E000000000000000000000000000000000003FFFC0007FFFE0007C0007FC00000000070001FFFF
+E000000000000000000000000000000000003FFFC000FFFFE0007C0007FE00000000070001FFFF
+F000000000000000000000000000000000007FFF8000FFFFE0003C0007FF00000000070001FFFF
+F000000000000000000000000000000000007FFF8000FFFFF0003C0007FF80000000070001FFFF
+F000000000000000000000000000000000007FFF8001FFFFF0003C0007FFE000003C070001FFFF
+F80000000000000000000000000000000000FFFF0001FFFFF0001C0007FFF80001FF070001FFFF
+F8000000007FF80000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFF800FFFFFFFFFFFFF
+FC00007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FC07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF03FFFFFFFFFFFFFFFC0000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF0000007FFFFFE000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFC00000000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFE00000000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFE00000000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF00000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF0000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF8000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFC000003FFFE00000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFE007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFC0000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFE0000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF0000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF0000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF800000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFC00000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFE00000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF00000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFC000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFE000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFF000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFF00000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFF8000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFE000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFC0000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFF0000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFE00000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF8000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFF000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF0000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFF00000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFE0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Makefile b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Makefile
new file mode 100644
index 0000000000..0cedf220dd
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Makefile
@@ -0,0 +1,62 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/font/devpost/charlib/Makefile
+#
+
+include ../../../../../Makefile.lp
+
+CHARFILES = 12 14 34 Fi Fl L1 LH Lb \
+ OLD_LH Sl bx ci ff lc lf lh \
+ ob rc rf rh sq
+MAPFILES = L1.map LH.map Lb.map OLD_LH.map
+TXTS = BRACKETS_NOTE README
+FILES = $(CHARFILES) $(MAPFILES) $(TXTS)
+
+ROOTCHARLIB = $(ROOT)/usr/lib/font/devpost/charlib
+
+ROOTFILES = $(FILES:%=$(ROOTCHARLIB)/%)
+
+FILEMODE = 0444
+
+.KEEP_STATE:
+
+all: $(FILES)
+
+# because of its name, the file ~= is a special case
+#
+install: all $(ROOTCHARLIB) $(ROOTFILES)
+ $(RM) $(ROOTCHARLIB)/~=
+ $(INS) -m $(FILEMODE) -f $(ROOTCHARLIB) ~=
+ $(RM) $(ROOTCHARLIB)/'~'
+ $(LN) $(ROOTCHARLIB)/~= $(ROOTCHARLIB)/'~'
+
+$(ROOTCHARLIB):
+ $(INS.dir)
+
+$(ROOTCHARLIB)/% : %
+ $(INS.file)
+
+clean clobber strip lint :
+
+FRC:
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/OLD_LH b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/OLD_LH
new file mode 100644
index 0000000000..3feb59c636
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/OLD_LH
@@ -0,0 +1,34 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/OLD_LH 1.1"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_LH {
+ pop
+ /picstr 78 string def
+ gsave
+ currentpoint translate
+ 1.03 72 mul size mul 36 div
+ .5 72 mul size mul 36 div
+ scale
+ 309 150 1 [309 0 0 -150 0 150]
+ {currentfile picstr readhexstring pop} image
+ grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/OLD_LH.map b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/OLD_LH.map
new file mode 100644
index 0000000000..e467b45798
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/OLD_LH.map
@@ -0,0 +1,150 @@
+FFFFFFFFFFFFFFFFF0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFF00000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFE0000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFF00000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF8000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFE00000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFF000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFC0000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFC000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFF8FFFFFFF00000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFF0000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFF000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFC00000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF81FFFFFFFFFC0000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF0000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFE00000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFC00000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF800000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFE0007FFFFFFFF8000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFE7FFFFFFFFFFFFFFE000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFF0000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFE000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFF80000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF01FFFFFFFFFFFFFFFFC000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFE00000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFE00000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFC00000000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFC00000000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF80FFFFFFFFFFFFFFFFFE0000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFE0000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFC00000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFC0000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+F87FFFFFFFFFFFFFFFFFFFFC000000000000FFFFFFFFC0003F00000000003FFFFFC00000000007
+F000000007FFFFFFFFFFC000000000000000FFFFFFFFC0003F00000000003FFFFFC00000000007
+F000000000000000000000000000000000007FFFFFFF80001F00000000003FFFFFC00000000007
+F000000000000000000000000000000000007FFFFFFF80001F00000000003FFFFFC00000000007
+E000000000000000000000000000000000007FFFFFFF80001F00000000003FFFFFC00000000007
+E000000000000000000000000000000000003FFFFFFF00000F00000000003FFFFFC00000000007
+E000000000000000000000000000000000003FFFFFFF00000F00000000003FFFFFC00000000007
+E0007FFFFFFFFFFFFFFFFC000000000000003FFFFFFF00000F00000000003FFFFFC00000000007
+C0FFFFFFFFFFFFFFFFFFFFFFC000000000003FFFFFFE00000700000000003FFFFFC00000000007
+FFFFFFFFFFFFFFFFFFFFFFFFFFFC000000003FFFFFFE00000700000000003FFFFFC00000000007
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE00000700000000003FE3FFC00000000007
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000003000000000038001FC00000000007
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000003FFFC0007FFE00007FFFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFC00000001FFFFFFC000003FFFC0007FF800003FFFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFF800000000001FFFFFF8000003FFFC0007FF000001FFFF0001FFFF
+8FFFFFFFFFFFFFFFFFFFFFF80000000000000FFFFFF8000001FFFC0007FE000000FFFF0001FFFF
+8000FFFFFFFFFFFFFFFFF0000000000000000FFFFFF8000001FFFC0007FE000000FFFF0001FFFF
+8000000000000000000000000000000000000FFFFFF0000001FFFC0007FC000000FFFF0001FFFF
+0000000000000000000000000000000000000FFFFFF0000000FFFC0007FC0000007FFF0001FFFF
+0000000000000000000000000000000000000FFFFFF0002000FFFC0007F80018007FFF0001FFFF
+0000000000000000000000000000000000000FFFFFE0006000FFFC0007F8003C007FFF0001FFFF
+00000000000000000000000000000000000007FFFFE00060007FFC0007F8003C007FFF0001FFFF
+00000007FFFFFFFFFFFE000000000000000007FFFFE00070007FFC0007F8003C007FFF0001FFFF
+000FFFFFFFFFFFFFFFFFFFF000000000000007FFFFC00070007FFC0007F8003C007FFF0001FFFF
+07FFFFFFFFFFFFFFFFFFFFFFFC000000000007FFFFC000F0003FFC0007FC003C007FFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC000F0003FFC0007FC001C007FFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000F8003FFC0007FC000C007FFF0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8001F8001FFC0007FE000000001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8001F8001FFC0007FE0001FF001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFF0000000000007FFFF0001F8001FFC0007FF0000FF001F0001FFFF
+007FFFFFFFFFFFFFFFFFFFC000000000000007FFFF0003FC001FFC0007FE00007F001F0001FFFF
+00003FFFFFFFFFFFFFFF000000000000000007FFFF0003FC000FFC0007FC00003F001F0001FFFF
+00000000000000000000000000000000000007FFFE0003FC000FFC0007F800001F001F0001FFFF
+00000000000000000000000000000000000007FFFE000000000FFC0007F8000007001F0001FFFF
+0000000000000000000000000000000000000FFFFE0000000007FC0007F8000003001F0001FFFF
+0000000000000000000000000000000000000FFFFC0000000007FC0007F0000001001F0001FFFF
+8000000000000000000000000000000000000FFFFC0000000007FC0007F0000000001F0001FFFF
+8000000000000000000000000000000000000FFFFC0000000003FC0007E0018000001F0001FFFF
+80003FFFFFFFFFFFFFFF80000000000000000FFFF80000000003FC0007E001C000001F0001FFFF
+80FFFFFFFFFFFFFFFFFFFFFC0000000000000FFFF80000000003FC0007E001F000001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000001FC0007E000F800001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000001FC0007E000FC00001F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000001FC0007E0007E00003F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000FC0007E0001E00003F0001FFFF
+FFFFFFFFFFFFFFFFFFFFFFE00000000000003FFFE00000000000FC0007F000000000070001FFFF
+C003FFFFFFFFFFFFFFE000000000000000003FFFE0003FFFC000FC0007F000000000070001FFFF
+E000000FFFFFFFFC800000000000000000003FFFE0007FFFC0007C0007F800000000070001FFFF
+E000000000000000000000000000000000003FFFC0007FFFE0007C0007F800000000070001FFFF
+E000000000000000000000000000000000003FFFC0007FFFE0007C0007FC00000000070001FFFF
+E000000000000000000000000000000000003FFFC000FFFFE0007C0007FE00000000070001FFFF
+F000000000000000000000000000000000007FFF8000FFFFE0003C0007FF00000000070001FFFF
+F000000000000000000000000000000000007FFF8000FFFFF0003C0007FF80000000070001FFFF
+F000000000000000000000000000000000007FFF8001FFFFF0003C0007FFE000003C070001FFFF
+F80000000000000000000000000000000000FFFF0001FFFFF0001C0007FFF80001FF070001FFFF
+F8000000007FF80000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFF800FFFFFFFFFFFFF
+FC00007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FC07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF03FFFFFFFFFFFFFFFC0000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF0000007FFFFFE000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FF800000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFC00000000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFE00000000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFE00000000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF00000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF0000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFF8000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFC000003FFFE00000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFE007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFC0000000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFE0000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF0000000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF0000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFF800000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFC00000000000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFE00000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFF00000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFC000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFE000000000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFF000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFF00000000000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFF8000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFE000000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFF000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFC0000000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFF0000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFE00000000000003FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFF8000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFF000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFF0000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFF00000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+FFFFFFFFFFFFFFFFE0007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/README b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/README
new file mode 100644
index 0000000000..f8a31f9254
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/README
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# University Copyright- Copyright (c) 1982, 1986, 1988
+# The Regents of the University of California
+# All Rights Reserved
+#
+# University Acknowledgment- Portions of this document are derived from
+# software developed by the University of California, Berkeley, and its
+# contributors.
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+Postscript definitions of some special troff characters. For now each file
+is named by its two character troff name and is copied to the output file,
+as is, when the character is first used. Each procedure is called with a
+single argument, namely the width of the character. The name of the PostScript
+procedure that builds the character must begin with the prefix build_ and
+end with the character's name.
+
+The following variables are defined in dpost.ps and may help when you're building
+a new character:
+
+ font name of the current font
+ ptsize and the point size
+ size Postscript is using this size - it's scaled up from ptsize
+
+
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Sl b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Sl
new file mode 100644
index 0000000000..b05f0e8540
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/Sl
@@ -0,0 +1,126 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/Sl 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_Sl {
+pop
+gsave
+size .0022 mul dup scale
+currentpoint translate
+14 93 moveto
+14 96 lineto
+29 110 lineto
+44 121 lineto
+54 127 lineto
+55 132 lineto
+57 146 lineto
+59 157 lineto
+62 171 lineto
+66 186 lineto
+70 199 lineto
+75 213 lineto
+81 228 lineto
+88 243 lineto
+96 257 lineto
+106 272 lineto
+118 287 lineto
+133 300 lineto
+148 307 lineto
+163 308 lineto
+178 304 lineto
+191 293 lineto
+197 281 lineto
+198 277 lineto
+198 260 lineto
+194 246 lineto
+187 231 lineto
+179 217 lineto
+168 202 lineto
+155 187 lineto
+141 172 lineto
+126 158 lineto
+111 146 lineto
+96 136 lineto
+94 131 lineto
+93 123 lineto
+92 112 lineto
+91 103 lineto
+90 93 lineto
+89 81 lineto
+89 40 lineto
+92 28 lineto
+97 18 lineto
+108 10 lineto
+122 10 lineto
+134 18 lineto
+145 33 lineto
+152 48 lineto
+158 62 lineto
+168 58 lineto
+168 59 lineto
+163 45 lineto
+157 31 lineto
+148 16 lineto
+133 3 lineto
+118 -1 lineto
+103 0 lineto
+88 5 lineto
+73 18 lineto
+64 31 lineto
+58 46 lineto
+55 59 lineto
+53 73 lineto
+52 111 lineto
+37 101 lineto
+22 86 lineto
+14 93 lineto
+
+97 152 moveto
+97 153 lineto
+99 166 lineto
+101 178 lineto
+103 190 lineto
+106 205 lineto
+109 218 lineto
+113 232 lineto
+118 246 lineto
+124 261 lineto
+132 275 lineto
+144 290 lineto
+157 298 lineto
+171 298 lineto
+181 291 lineto
+186 283 lineto
+187 279 lineto
+187 264 lineto
+186 260 lineto
+181 246 lineto
+174 233 lineto
+165 218 lineto
+155 204 lineto
+142 190 lineto
+127 175 lineto
+112 162 lineto
+97 152 lineto
+
+eofill
+grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/bx b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/bx
new file mode 100644
index 0000000000..0ec7bf411e
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/bx
@@ -0,0 +1,34 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/bx 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_bx {
+ pop
+ size 2 div /side exch def
+ currentpoint
+ newpath
+ moveto
+ 0 side rlineto
+ side 0 rlineto
+ 0 side neg rlineto
+ closepath
+ fill
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ci b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ci
new file mode 100644
index 0000000000..dba95d10b9
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ci
@@ -0,0 +1,30 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/ci 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_ci {
+ pop
+ size 3 mul 8 div /rad exch def
+ currentpoint
+ newpath
+ rad add exch rad add exch rad 0 360 arc
+ stroke
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ff b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ff
new file mode 100644
index 0000000000..fea5a53e70
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ff
@@ -0,0 +1,26 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/ff 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_ff {
+ pop
+ size .05 mul neg 0 (ff) ashow
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lc b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lc
new file mode 100644
index 0000000000..3f34ba0d3a
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lc
@@ -0,0 +1,58 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/lc 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% This stuff has gotten terribly complicated - sorry.
+%
+
+currentdict /bvbbox known not {/bvbbox [0 0 0 0 0 0 0] def} if
+
+/build_lc {
+ pop
+ gsave
+ currentpoint translate newpath
+ bvbbox 6 get size ne {
+ gsave
+ initgraphics
+ scaling scaling scale
+ 0 0 moveto
+ (\357) false charpath flattenpath pathbbox 0 0 size bvbbox astore pop
+ 0 1 idtransform dup mul exch dup mul add sqrt dup
+ bvbbox 1 get add bvbbox 1 3 -1 roll put
+ bvbbox 3 get exch sub bvbbox 3 3 -1 roll put
+ bvbbox 2 get bvbbox 0 get sub bvbbox 4 3 -1 roll put
+ bvbbox 2 get bvbbox 0 get add 2 div bvbbox 5 3 -1 roll put
+ grestore
+ } if
+ bvbbox 0 get bvbbox 1 get moveto
+ bvbbox 0 get bvbbox 3 get lineto
+ bvbbox 5 get bvbbox 4 get 8 mul add dup bvbbox 3 get lineto
+ bvbbox 1 get lineto closepath clip newpath
+ 0 0 moveto (\357) show
+ bvbbox 5 get bvbbox 3 get moveto
+ bvbbox 4 get dup dup
+ 8 mul 0 rlineto
+ 0 exch neg rlineto
+ 8 mul neg 0 rlineto
+ closepath clip eofill
+ grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lf b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lf
new file mode 100644
index 0000000000..b99ab46001
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lf
@@ -0,0 +1,58 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/lf 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% This stuff has gotten terribly complicated - sorry.
+%
+
+currentdict /bvbbox known not {/bvbbox [0 0 0 0 0 0 0] def} if
+
+/build_lf {
+ pop
+ gsave
+ currentpoint translate newpath
+ bvbbox 6 get size ne {
+ gsave
+ initgraphics
+ scaling scaling scale
+ 0 0 moveto
+ (\357) false charpath flattenpath pathbbox 0 0 size bvbbox astore pop
+ 0 1 idtransform dup mul exch dup mul add sqrt dup
+ bvbbox 1 get add bvbbox 1 3 -1 roll put
+ bvbbox 3 get exch sub bvbbox 3 3 -1 roll put
+ bvbbox 2 get bvbbox 0 get sub bvbbox 4 3 -1 roll put
+ bvbbox 2 get bvbbox 0 get add 2 div bvbbox 5 3 -1 roll put
+ grestore
+ } if
+ bvbbox 0 get bvbbox 1 get moveto
+ bvbbox 0 get bvbbox 3 get lineto
+ bvbbox 5 get bvbbox 4 get 8 mul add dup bvbbox 3 get lineto
+ bvbbox 1 get lineto closepath clip newpath
+ 0 0 moveto (\357) show
+ bvbbox 5 get bvbbox 1 get moveto
+ bvbbox 4 get dup dup
+ 8 mul 0 rlineto
+ 0 exch rlineto
+ 8 mul neg 0 rlineto
+ closepath clip eofill
+ grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lh b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lh
new file mode 100644
index 0000000000..59d43b4033
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/lh
@@ -0,0 +1,188 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/lh 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_lh {
+pop
+gsave
+size .0022 mul dup scale
+currentpoint translate
+
+16 177 moveto
+16 188 lineto
+21 193 lineto
+30 193 lineto
+34 189 lineto
+36 183 lineto
+36 180 lineto
+34 174 lineto
+27 170 lineto
+19 172 lineto
+16 177 lineto
+stroke
+
+38 194 moveto
+38 196 lineto
+53 199 lineto
+68 201 lineto
+83 202 lineto
+98 203 lineto
+113 204 lineto
+128 204 lineto
+143 205 lineto
+158 205 lineto
+173 205 lineto
+188 204 lineto
+203 203 lineto
+218 202 lineto
+233 200 lineto
+248 198 lineto
+263 196 lineto
+278 194 lineto
+293 190 lineto
+308 186 lineto
+323 181 lineto
+338 176 lineto
+353 168 lineto
+361 162 lineto
+364 153 lineto
+366 138 lineto
+367 126 lineto
+368 106 lineto
+369 80 lineto
+369 74 lineto
+368 60 lineto
+367 54 lineto
+362 43 lineto
+348 34 lineto
+333 28 lineto
+318 25 lineto
+303 26 lineto
+288 29 lineto
+273 31 lineto
+258 32 lineto
+243 32 lineto
+228 30 lineto
+213 27 lineto
+198 24 lineto
+183 23 lineto
+168 23 lineto
+153 27 lineto
+148 34 lineto
+148 47 lineto
+153 54 lineto
+168 58 lineto
+183 58 lineto
+198 58 lineto
+213 59 lineto
+226 60 lineto
+228 62 lineto
+228 67 lineto
+223 71 lineto
+208 71 lineto
+193 70 lineto
+178 70 lineto
+163 70 lineto
+148 70 lineto
+133 71 lineto
+123 76 lineto
+120 84 lineto
+120 91 lineto
+122 98 lineto
+129 104 lineto
+144 106 lineto
+159 107 lineto
+174 107 lineto
+189 107 lineto
+202 108 lineto
+204 110 lineto
+204 117 lineto
+201 119 lineto
+186 119 lineto
+171 119 lineto
+156 119 lineto
+141 119 lineto
+126 119 lineto
+111 121 lineto
+103 128 lineto
+101 137 lineto
+101 142 lineto
+103 150 lineto
+111 158 lineto
+126 161 lineto
+141 161 lineto
+156 162 lineto
+171 163 lineto
+186 163 lineto
+191 165 lineto
+192 167 lineto
+192 171 lineto
+190 174 lineto
+176 175 lineto
+161 175 lineto
+146 175 lineto
+131 174 lineto
+116 174 lineto
+101 174 lineto
+86 173 lineto
+71 172 lineto
+56 171 lineto
+41 171 lineto
+41 174 lineto
+43 178 lineto
+43 187 lineto
+38 194 lineto
+stroke
+
+373 169 moveto
+373 176 lineto
+375 182 lineto
+386 190 lineto
+401 193 lineto
+408 191 lineto
+411 185 lineto
+412 181 lineto
+414 167 lineto
+415 158 lineto
+416 144 lineto
+417 128 lineto
+418 110 lineto
+418 60 lineto
+417 45 lineto
+415 37 lineto
+409 34 lineto
+394 31 lineto
+381 35 lineto
+379 42 lineto
+379 52 lineto
+380 67 lineto
+380 77 lineto
+379 77 lineto
+378 106 lineto
+377 121 lineto
+376 133 lineto
+375 147 lineto
+374 158 lineto
+373 169 lineto
+
+stroke
+grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ob b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ob
new file mode 100644
index 0000000000..c53491c351
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/ob
@@ -0,0 +1,30 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/ob 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_ob {
+ pop
+ size 3 mul 16 div /rad exch def
+ currentpoint
+ newpath
+ rad add exch rad add exch rad 0 360 arc
+ stroke
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rc b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rc
new file mode 100644
index 0000000000..9e34612524
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rc
@@ -0,0 +1,58 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/rc 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% This stuff has gotten terribly complicated - sorry.
+%
+
+currentdict /bvbbox known not {/bvbbox [0 0 0 0 0 0 0] def} if
+
+/build_rc {
+ pop
+ gsave
+ currentpoint translate newpath
+ bvbbox 6 get size ne {
+ gsave
+ initgraphics
+ scaling scaling scale
+ 0 0 moveto
+ (\357) false charpath flattenpath pathbbox 0 0 size bvbbox astore pop
+ 0 1 idtransform dup mul exch dup mul add sqrt dup
+ bvbbox 1 get add bvbbox 1 3 -1 roll put
+ bvbbox 3 get exch sub bvbbox 3 3 -1 roll put
+ bvbbox 2 get bvbbox 0 get sub bvbbox 4 3 -1 roll put
+ bvbbox 2 get bvbbox 0 get add 2 div bvbbox 5 3 -1 roll put
+ grestore
+ } if
+ bvbbox 2 get bvbbox 1 get moveto
+ bvbbox 2 get bvbbox 3 get lineto
+ bvbbox 5 get bvbbox 4 get 8 mul sub dup bvbbox 3 get lineto
+ bvbbox 1 get lineto closepath clip newpath
+ 0 0 moveto (\357) show
+ bvbbox 5 get bvbbox 3 get moveto
+ bvbbox 4 get dup dup
+ 8 mul neg 0 rlineto
+ 0 exch neg rlineto
+ 8 mul 0 rlineto
+ closepath clip eofill
+ grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rf b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rf
new file mode 100644
index 0000000000..17de01d417
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rf
@@ -0,0 +1,58 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/rf 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% This stuff has gotten terribly complicated - sorry.
+%
+
+currentdict /bvbbox known not {/bvbbox [0 0 0 0 0 0 0] def} if
+
+/build_rf {
+ pop
+ gsave
+ currentpoint translate newpath
+ bvbbox 6 get size ne {
+ gsave
+ initgraphics
+ scaling scaling scale
+ 0 0 moveto
+ (\357) false charpath flattenpath pathbbox 0 0 size bvbbox astore pop
+ 0 1 idtransform dup mul exch dup mul add sqrt dup
+ bvbbox 1 get add bvbbox 1 3 -1 roll put
+ bvbbox 3 get exch sub bvbbox 3 3 -1 roll put
+ bvbbox 2 get bvbbox 0 get sub bvbbox 4 3 -1 roll put
+ bvbbox 2 get bvbbox 0 get add 2 div bvbbox 5 3 -1 roll put
+ grestore
+ } if
+ bvbbox 2 get bvbbox 1 get moveto
+ bvbbox 2 get bvbbox 3 get lineto
+ bvbbox 5 get bvbbox 4 get 8 mul sub dup bvbbox 3 get lineto
+ bvbbox 1 get lineto closepath clip newpath
+ 0 0 moveto (\357) show
+ bvbbox 5 get bvbbox 1 get moveto
+ bvbbox 4 get dup dup
+ 8 mul neg 0 rlineto
+ 0 exch rlineto
+ 8 mul 0 rlineto
+ closepath clip eofill
+ grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rh b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rh
new file mode 100644
index 0000000000..5a929ef4ae
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/rh
@@ -0,0 +1,179 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/rh 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_rh {
+pop
+gsave
+size .0022 mul dup scale
+currentpoint translate
+
+15 66 moveto
+15 86 lineto
+16 131 lineto
+17 146 lineto
+18 158 lineto
+19 167 lineto
+21 181 lineto
+24 190 lineto
+34 193 lineto
+49 189 lineto
+58 182 lineto
+60 177 lineto
+60 166 lineto
+59 156 lineto
+58 143 lineto
+57 130 lineto
+56 117 lineto
+55 102 lineto
+54 42 lineto
+53 39 lineto
+49 35 lineto
+34 34 lineto
+19 39 lineto
+16 47 lineto
+15 66 lineto
+stroke
+
+65 60 moveto
+65 111 lineto
+66 127 lineto
+67 139 lineto
+69 153 lineto
+72 163 lineto
+83 171 lineto
+98 177 lineto
+113 182 lineto
+128 187 lineto
+143 190 lineto
+158 194 lineto
+173 196 lineto
+188 199 lineto
+203 201 lineto
+218 203 lineto
+233 205 lineto
+248 205 lineto
+263 206 lineto
+278 206 lineto
+293 206 lineto
+308 206 lineto
+323 206 lineto
+338 205 lineto
+353 203 lineto
+368 202 lineto
+383 200 lineto
+394 197 lineto
+389 190 lineto
+389 180 lineto
+391 176 lineto
+391 173 lineto
+380 173 lineto
+365 173 lineto
+350 174 lineto
+335 175 lineto
+320 176 lineto
+305 176 lineto
+290 176 lineto
+275 177 lineto
+260 177 lineto
+245 177 lineto
+240 173 lineto
+240 170 lineto
+245 165 lineto
+260 164 lineto
+275 164 lineto
+290 164 lineto
+305 163 lineto
+320 160 lineto
+327 155 lineto
+330 149 lineto
+330 134 lineto
+328 129 lineto
+323 124 lineto
+309 121 lineto
+294 121 lineto
+279 121 lineto
+264 121 lineto
+249 121 lineto
+234 121 lineto
+228 118 lineto
+228 112 lineto
+234 109 lineto
+249 109 lineto
+264 109 lineto
+279 108 lineto
+294 108 lineto
+306 104 lineto
+311 97 lineto
+312 91 lineto
+312 88 lineto
+311 82 lineto
+305 74 lineto
+290 72 lineto
+275 72 lineto
+260 72 lineto
+245 73 lineto
+230 73 lineto
+215 73 lineto
+205 70 lineto
+205 63 lineto
+217 60 lineto
+232 60 lineto
+247 60 lineto
+262 60 lineto
+277 57 lineto
+283 52 lineto
+285 44 lineto
+285 41 lineto
+284 35 lineto
+280 30 lineto
+268 26 lineto
+253 25 lineto
+238 26 lineto
+223 28 lineto
+208 31 lineto
+193 33 lineto
+178 34 lineto
+163 33 lineto
+148 31 lineto
+133 28 lineto
+118 27 lineto
+103 28 lineto
+88 34 lineto
+73 43 lineto
+67 52 lineto
+65 60 lineto
+stroke
+
+396 180 moveto
+396 188 lineto
+399 194 lineto
+410 196 lineto
+416 190 lineto
+416 180 lineto
+415 177 lineto
+411 173 lineto
+400 173 lineto
+396 180 lineto
+stroke
+
+grestore
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/sq b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/sq
new file mode 100644
index 0000000000..ed03e8baa7
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/sq
@@ -0,0 +1,34 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/sq 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_sq {
+ pop
+ size 2 div /side exch def
+ currentpoint
+ newpath
+ moveto
+ 0 side rlineto
+ side 0 rlineto
+ 0 side neg rlineto
+ closepath
+ font B eq {fill} {stroke} ifelse
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/~= b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/~=
new file mode 100644
index 0000000000..7b7a4d6c57
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/devpost/charlib/~=
@@ -0,0 +1,26 @@
+%ident "@(#)lp:filter/postscript/font/devpost/charlib/~= 1.2"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+/build_~= {
+ pop
+ (\176) stringwidth pop neg size -.15 mul (\176\055) ashow
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/font/makedev.c b/usr/src/cmd/lp/filter/postscript/font/makedev.c
new file mode 100644
index 0000000000..5e9212e71a
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/font/makedev.c
@@ -0,0 +1,353 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* Note added 9/25/83
+ Setting the parameter biggestfont in the DESC file
+ to be at least as big as the number of characters
+ in the largest font for a particular device
+ eliminates the "font X too big for position Y"
+ message from troff.
+ Thanks to Dave Stephens, WECo.
+*/
+/*
+ makedev:
+ read text info about a particular device
+ (e.g., cat, 202, aps5) from file, convert
+ it into internal (binary) form suitable for
+ fast reading by troff initialization (ptinit()).
+
+ Usage:
+
+ makedev DESC [ F ... ]
+ uses DESC to create a description file
+ using the information therein.
+ It creates the file DESC.out.
+
+ makedev F ...
+ makes the font tables for fonts F only,
+ creates files F.out.
+
+ DESC.out contains:
+ dev structure with fundamental sizes
+ list of sizes (nsizes+1) terminated by 0, as short's
+ indices of char names (nchtab * sizeof(short))
+ char names as hy\0em\0... (lchname)
+ nfonts occurrences of
+ widths (nwidth)
+ kerning (nwidth) [ascender+descender only so far]
+ codes (nwidth) to drive actual typesetter
+ fitab (nchtab+128-32)
+ each of these is an array of char.
+
+ dev.filesize contains the number of bytes
+ in the file, excluding the dev part itself.
+
+ F.out contains the font header, width, kern, codes, and fitab.
+ Width, kern and codes are parallel arrays.
+ (Which suggests that they ought to be together?)
+ Later, we might allow for codes which are actually
+ sequences of formatting info so characters can be drawn.
+*/
+
+#include "stdio.h"
+#include "dev.h"
+
+#define BYTEMASK 0377
+#define skipline(f) while(getc(f) != '\n')
+
+struct dev dev;
+struct Font font;
+
+#define NSIZE 100 /* maximum number of sizes */
+short size[NSIZE];
+#define NCH 256 /* max number of characters with funny names */
+char chname[5*NCH]; /* character names, including \0 for each */
+short chtab[NCH]; /* index of character in chname */
+
+#define NFITAB (NCH + 128-32) /* includes ascii chars, but not non-graphics */
+char fitab[NFITAB]; /* font index table: position of char i on this font. */
+ /* zero if not there */
+
+#define FSIZE 254 /* size of a physical font (e.g., 102 for cat) */
+char width[FSIZE]; /* width table for a physical font */
+char kern[FSIZE]; /* ascender+descender info */
+char code[FSIZE]; /* actual device codes for a physical font */
+#define BIGGESTFONT FSIZE /* biggest font if no size in DESC */
+ /* MUST be < 256 */
+
+#define NFONT 50 /* max number of default fonts */
+char fname[NFONT][10]; /* temp space to hold default font names */
+
+int fflag = 0; /* on if font table to be written */
+int fdout; /* output file descriptor */
+char *fout = "DESC.out";
+
+static int dofont(char *);
+static int getlig(FILE *);
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fin;
+ char cmd[100], *p;
+ int i, totfont, v;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: makedev [DESC] [fonts]\n");
+ exit(1);
+ }
+ if ((fin = fopen("DESC", "r")) == NULL) {
+ fprintf(stderr, "makedev: can't open DESC file\n");
+ exit(1);
+ }
+ while (fscanf(fin, "%s", cmd) != EOF) {
+ if (cmd[0] == '#') /* comment */
+ skipline(fin);
+ else if (strcmp(cmd, "res") == 0) {
+ fscanf(fin, "%hd", &dev.res);
+ } else if (strcmp(cmd, "hor") == 0) {
+ fscanf(fin, "%hd", &dev.hor);
+ } else if (strcmp(cmd, "vert") == 0) {
+ fscanf(fin, "%hd", &dev.vert);
+ } else if (strcmp(cmd, "unitwidth") == 0) {
+ fscanf(fin, "%hd", &dev.unitwidth);
+ } else if (strcmp(cmd, "sizescale") == 0) {
+ fscanf(fin, "%hd", &dev.sizescale);
+ } else if (strcmp(cmd, "paperwidth") == 0) {
+ fscanf(fin, "%hd", &dev.paperwidth);
+ } else if (strcmp(cmd, "paperlength") == 0) {
+ fscanf(fin, "%hd", &dev.paperlength);
+ } else if (strcmp(cmd, "biggestfont") == 0) {
+ fscanf(fin, "%hd", &dev.biggestfont);
+ } else if (strcmp(cmd, "spare2") == 0) {
+ fscanf(fin, "%hd", &dev.spare2);
+ } else if (strcmp(cmd, "sizes") == 0) {
+ dev.nsizes = 0;
+ while (fscanf(fin, "%d", &v) != EOF && v != 0)
+ size[dev.nsizes++] = v;
+ size[dev.nsizes] = 0; /* need an extra 0 at the end */
+ } else if (strcmp(cmd, "fonts") == 0) {
+ fscanf(fin, "%hd", &dev.nfonts);
+ for (i = 0; i < dev.nfonts; i++)
+ fscanf(fin, "%s", fname[i]);
+ } else if (strcmp(cmd, "charset") == 0) {
+ short pchname;
+
+ p = chname;
+ pchname = 0;
+ dev.nchtab = 0;
+ while (fscanf(fin, "%s", p) != EOF) {
+ chtab[dev.nchtab++] = pchname;
+ while (*p++) /* skip to end of name */
+ pchname++;
+ pchname++;
+ }
+ dev.lchname = pchname;
+ chtab[dev.nchtab++] = 0; /* terminate properly */
+ } else
+ fprintf(stderr, "makedev: unknown command %s\n", cmd);
+ }
+ if (argc > 1 && strcmp(argv[1], "DESC") == 0) {
+ fdout = creat(fout, 0666);
+ if (fdout < 0) {
+ fprintf(stderr, "makedev: can't open %s\n", fout);
+ exit(1);
+ }
+ write(fdout, &dev, sizeof(struct dev));
+ write(fdout, size, (dev.nsizes+1) * sizeof(size[0])); /* we need a 0 on the end */
+ write(fdout, chtab, dev.nchtab * sizeof(chtab[0]));
+ write(fdout, chname, dev.lchname);
+ totfont = 0;
+ for (i = 0; i < dev.nfonts; i++) {
+ totfont += dofont(fname[i]);
+ write(fdout, &font, sizeof(struct Font));
+ write(fdout, width, font.nwfont & BYTEMASK);
+ write(fdout, kern, font.nwfont & BYTEMASK);
+ write(fdout, code, font.nwfont & BYTEMASK);
+ write(fdout, fitab, dev.nchtab+128-32);
+ }
+ lseek(fdout, 0L, 0); /* back to beginning to install proper size */
+ dev.filesize = /* excluding dev struct itself */
+ (dev.nsizes+1) * sizeof(size[0])
+ + dev.nchtab * sizeof(chtab[0])
+ + dev.lchname * sizeof(char)
+ + totfont * sizeof(char);
+ write(fdout, &dev, sizeof(struct dev));
+ close(fdout);
+ argc--;
+ argv++;
+ }
+ for (i = 1; i < argc; i++)
+ dofont(argv[i]);
+ return (0);
+}
+
+static int
+dofont(char *name) /* create fitab and width tab for font */
+{
+ FILE *fin;
+ int fdout;
+ int i, nw, spacewidth, n, v;
+ char buf[100], ch[10], s1[10], s2[10], s3[10], cmd[30];
+
+ if ((fin = fopen(name, "r")) == NULL) {
+ fprintf(stderr, "makedev: can't open font %s\n", name);
+ exit(2);
+ }
+ sprintf(cmd, "%s.out", name);
+ fdout = creat(cmd, 0666);
+ if (fdout < 0) {
+ fprintf(stderr, "makedev: can't open %s\n", fout);
+ exit(1);
+ }
+ for (i = 0; i < NFITAB; i++)
+ fitab[i] = 0;
+ for (i = 0; i < FSIZE; i++)
+ width[i] = kern[i] = code[i] = 0;
+ font.specfont = font.ligfont = spacewidth = 0;
+ while (fscanf(fin, "%s", cmd) != EOF) {
+ if (cmd[0] == '#')
+ skipline(fin);
+ else if (strcmp(cmd, "name") == 0)
+ fscanf(fin, "%s", font.namefont);
+ else if (strcmp(cmd, "internalname") == 0)
+ fscanf(fin, "%s", font.intname);
+ else if (strcmp(cmd, "special") == 0)
+ font.specfont = 1;
+ else if (strcmp(cmd, "spare1") == 0)
+ fscanf(fin, "%1s", &font.spare1);
+ else if (strcmp(cmd, "ligatures") == 0) {
+ font.ligfont = getlig(fin);
+ } else if (strcmp(cmd, "spacewidth") == 0) {
+ fscanf(fin, "%d", &spacewidth);
+ width[0] = spacewidth; /* width of space on this font */
+ } else if (strcmp(cmd, "charset") == 0) {
+ skipline(fin);
+ nw = 0;
+ /* widths are origin 1 so fitab==0 can mean "not there" */
+ while (fgets(buf, 100, fin) != NULL) {
+ sscanf(buf, "%s %s %s %s", ch, s1, s2, s3);
+ if (s1[0] != '"') { /* it's a genuine new character */
+ nw++;
+ width[nw] = atoi(s1);
+ kern[nw] = atoi(s2);
+ /* temporarily, pick up one byte as code */
+ if (s3[0] == '0')
+ sscanf(s3, "%o", &i);
+ else
+ sscanf(s3, "%d", &i);
+ code[nw] = i;
+ }
+ /* otherwise it's a synonym for previous character,
+ * so leave previous values intact
+ */
+ if (strlen(ch) == 1) /* it's ascii */
+ fitab[ch[0] - 32] = nw; /* fitab origin omits non-graphics */
+ else if (strcmp(ch, "---") != 0) { /* it has a 2-char name */
+ for (i = 0; i < dev.nchtab; i++)
+ if (strcmp(&chname[chtab[i]], ch) == 0) {
+ fitab[i + 128-32] = nw; /* starts after the ascii */
+ break;
+ }
+ if (i >= dev.nchtab)
+ fprintf(stderr, "makedev: font %s: %s not in charset\n", name, ch);
+ }
+ }
+ nw++;
+ if (dev.biggestfont > 0)
+ n = dev.biggestfont + 1;
+ else
+ n = BIGGESTFONT;
+ /*
+ * Make files at least as big as biggestfont. Larger fonts
+ * may only fit in postion 0.
+ */
+ if ( nw > n ) {
+ n = nw;
+ fprintf(stderr, "makedev: warning font %s may only fit in position 0\n", font.namefont);
+ }
+ if (n >= NCH) {
+ fprintf(stderr, "makedev: font has %d characters, too big\n", n);
+ exit(2);
+ }
+ font.nwfont = n;
+ }
+ }
+ if (spacewidth == 0)
+ width[0] = dev.res * dev.unitwidth / 72 / 3; /* should be rounded */
+ fclose(fin);
+
+ write(fdout, &font, sizeof(struct Font));
+ write(fdout, width, font.nwfont & BYTEMASK);
+ write(fdout, kern, font.nwfont & BYTEMASK);
+ write(fdout, code, font.nwfont & BYTEMASK);
+ write(fdout, fitab, dev.nchtab+128-32);
+ close(fdout);
+ v = sizeof(struct Font) + 3 * n + dev.nchtab + 128-32;
+ fprintf(stderr, "%3s: %3d chars, width %3d, size %3d\n",
+ font.namefont, nw, width[0], v);
+ return (v);
+}
+
+static int
+getlig(FILE *fin) /* pick up ligature list */
+{
+ int lig;
+ char temp[100];
+
+ lig = 0;
+ while (fscanf(fin, "%s", temp) != EOF && strcmp(temp, "0") != 0) {
+ if (strcmp(temp, "fi") == 0)
+ lig |= LFI;
+ else if (strcmp(temp, "fl") == 0)
+ lig |= LFL;
+ else if (strcmp(temp, "ff") == 0)
+ lig |= LFF;
+ else if (strcmp(temp, "ffi") == 0)
+ lig |= LFFI;
+ else if (strcmp(temp, "ffl") == 0)
+ lig |= LFFL;
+ else
+ fprintf(stderr, "illegal ligature %s\n", temp);
+ }
+ skipline(fin);
+ return (lig);
+}
diff --git a/usr/src/cmd/lp/filter/postscript/postcomm/Makefile b/usr/src/cmd/lp/filter/postscript/postcomm/Makefile
new file mode 100644
index 0000000000..0e8985d2e5
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postcomm/Makefile
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/postcomm/Makefile
+#
+
+include ../../../Makefile.lp
+
+PROG= postcomm
+
+SRCS= postcomm.c
+
+OBJS= $(SRCS:.c=.o)
+
+
+COMMONDIR = ../common
+CPPFLAGS = -I. -I$(COMMONDIR) $(CPPFLAGS.master)
+
+POFILE = lp_filter_postscript_postcomm.po
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all .WAIT $(ROOTLIBLPPOSTPROG)
+
+clean:
+ $(RM) $(OBJS)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint: lint_PROG
+
+include ../../../../Makefile.targ
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/filter/postscript/postcomm/postcomm.c b/usr/src/cmd/lp/filter/postscript/postcomm/postcomm.c
new file mode 100644
index 0000000000..dde1e97e9f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postcomm/postcomm.c
@@ -0,0 +1,717 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * A simple program that can be used to filter jobs for PostScript
+ * printers. It's a cleaned up version of usg_iox, that I assume was
+ * written by Richard Flood. The most important addition includes some
+ * simple processing of printer status reports, usually obtained when
+ * \024 is sent to the printer. The returned status lines look like:
+ *
+ *
+ * %%[ status: idle; source serial 25 ]%%
+ * %%[ status: waiting; source serial 25 ]%%
+ * %%[ status: initializing; source serial 25 ]%%
+ * %%[ status: busy; source serial 25 ]%%
+ * %%[ status: printing; source serial 25 ]%%
+ * %%[ status: PrinterError: out of paper; source serial 25 ]%%
+ * %%[ status: PrinterError: no paper tray; source serial 25 ]%%
+ *
+ *
+ * although the list isn't meant to be complete.
+ *
+ * Other changes to the original program include the addition of
+ * options that let you select the tty line, baud rate, and printer
+ * log file. The program seems to work reasonably well, at least for
+ * our QMS PS-800 printer, but could still use some work.
+ *
+ * There were a couple of serious mistakes in the first few versions of
+ * postcomm. Both were made in setting up flow control in routine
+ * initialize(). Setting the IXANY flag in c_iflag was wrong, and
+ * often caused problems when the printer transmitted a spontaneous
+ * status report, which always happens when the paper runs out.
+ * Things were kludged up to get around the problems, but they were
+ * never exactly right, and probably could never be guaranteed to work
+ * 100%.
+ *
+ * The other mistake was setting the IXOFF flag, again in c_iflag.
+ * Although I never saw deadlock in the original versions of postcomm,
+ * it could happen. Apparently the IXANY and IXOFF flags combined to
+ * make that an unlikely event. Anyway both flags should normally be
+ * turned off to ensure reliable transmission of jobs.
+ *
+ * The implications of only setting IXON are obvious. Job transmission
+ * should be reliable, but data returned by the printer over the tty
+ * line may get lost. That won't cause problems in postcomm, but there
+ * may be occasions when you want to run a job and recover data
+ * generated by the printer. The -t option sets the IXOFF, IXANY, and
+ * IXON flags in c_iflag and causes send() to be far more careful about
+ * when data is sent to the printer. In addition anything not
+ * recognized as a status report is written on stdout. It seems to
+ * work reasonably well, but it's slow and may hang or have flow
+ * control problems. Only use the -t option when it's absolutely
+ * necessary. A small block size, like 512, should also help.
+ *
+ * Using two processes, one for reads and the other for writes, may
+ * eventually be needed. For now postcomm seems to do a good job
+ * transmitting data, and the -t option is probably acceptable for
+ * those few jobs that need to recover data from the printer.
+ *
+ * A typical command line might be:
+ *
+ * postcomm -L log -t <file1 > device
+ *
+ * where -L selects the printer log file and -t sends data from the
+ * printer out to the printer. If you don't choose a log file stderr
+ * will be used and the information mailed or written to you.
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+
+
+# define OFF 0
+# define ON 1
+# define TRUE 1
+# define FALSE 0
+# define FATAL 1
+# define NON_FATAL 0
+
+#include "postcomm.h" /* some special definitions */
+
+
+char *prog_name = "postcomm"; /* just for error messages */
+
+int debug = OFF; /* debug flag */
+int ignore = OFF; /* what's done for FATAL errors */
+
+
+char *block = NULL; /* input file buffer */
+int blocksize = BLOCKSIZE; /* and its size in bytes */
+int head = 0; /* block[head] is the next character */
+int tail = 0; /* one past the last byte in block[] */
+
+char mesg[BUFSIZE]; /* exactly what came back on ttyi */
+char sbuf[BUFSIZE]; /* for parsing the message */
+int next = 0; /* next character goes in sbuf[next] */
+Status status[] = STATUS; /* for converting status strings */
+
+int stopbits = 1; /* number of stop bits */
+int tostdout = FALSE; /* non-status stuff goes to stdout? */
+int curfile = 0; /* only needed when tostdout is TRUE */
+
+char *postbegin = POSTBEGIN; /* preceeds all the input files */
+
+int ttyi; /* input */
+int ttyo = 2; /* and output file descriptors */
+
+FILE *fp_log = stderr; /* log file for data from the printer */
+
+
+
+static void filter(void);
+static int getstatus(int);
+static void initialize(void);
+static void options(int, char *[]);
+static int readblock(int);
+static int readline(void);
+static void reset(void);
+static int writeblock(void);
+
+void
+logit(char *mesg, ...)
+{
+
+/*
+ *
+ * Simple routine that's used to write a message to the log file.
+ *
+ */
+
+
+ if (mesg != NULL)
+ {
+ va_list ap;
+
+ va_start(ap, mesg);
+ vfprintf(fp_log, mesg, ap);
+ va_end(ap);
+ fflush(fp_log);
+ }
+
+} /* End of logit */
+
+
+
+
+
+void
+error(int kind, char *mesg, ...)
+{
+
+
+/*
+ *
+ * Called when we've run into some kind of program error. First *mesg is
+ * printed using the control string arguments a?. Then if kind is FATAL
+ * and we're not ignoring errors the program will be terminated.
+ *
+ * If mesg is NULL or *mesg is the NULL string nothing will be printed.
+ *
+ */
+
+
+ if ( mesg != NULL && *mesg != '\0' ) {
+ va_list ap;
+
+ fprintf(fp_log, "%s: ", prog_name);
+ va_start(ap, mesg);
+ vfprintf(fp_log, mesg, ap);
+ va_end(ap);
+ putc('\n', fp_log);
+ } /* End if */
+
+ if ( kind == FATAL && ignore == OFF ) {
+ write(ttyo, "\003\004", 2);
+ exit(1);
+ } /* End if */
+
+} /* End of error */
+
+
+
+
+
+int
+main(int argc, char *argv[])
+{
+
+/*
+ *
+ * A simple program that manages input and output for PostScript
+ * printers. If you're sending a PostScript program that will be
+ * returning useful information add the -ot option to the lp(1) command
+ * line. Everything not recognized as a printer status report will go
+ * to stdout. The -ot option should only be used when needed! It's slow
+ * and doesn't use flow control properly, but it's probably the best
+ * that can be done using a single process for reading and writing.
+ */
+
+ prog_name = argv[0]; /* really just for error messages */
+
+ options(argc, argv);
+
+ initialize(); /* Set printer up for printing */
+
+ filter();
+
+ reset(); /* wait 'til it's finished & reset it*/
+
+ return (0); /* everything probably went OK */
+
+} /* End of main */
+
+
+
+
+
+static void
+options(int argc, char *argv[])
+{
+
+
+ int ch; /* return value from getopt() */
+ char *names = "tB:L:P:DI";
+
+ extern char *optarg; /* used by getopt() */
+
+/*
+ *
+ * Reads and processes the command line options. The -t option should
+ * only be used when absolutely necessary. It's slow and doesn't do
+ * flow control properly. Selecting a small block size (eg. 512 or
+ * less) with with the -B option may help when you need the -t option.
+ *
+ */
+
+
+ while ( (ch = getopt(argc, argv, names)) != EOF )
+ {
+ switch ( ch )
+ {
+ case 't': /* non-status stuff goes to stdout */
+ tostdout = TRUE;
+ break;
+
+ case 'B': /* set the job buffer size */
+ if ((blocksize = atoi(optarg)) <= 0)
+ blocksize = BLOCKSIZE;
+ break;
+
+ case 'L': /* printer log file */
+ if ((fp_log = fopen(optarg, "w")) == NULL)
+ {
+ fp_log = stderr;
+ error(NON_FATAL, "can't open log file %s",
+ optarg);
+ } /* End if */
+ break;
+
+ case 'P': /* initial PostScript program */
+ postbegin = optarg;
+ break;
+
+ case 'D': /* debug flag */
+ debug = ON;
+ break;
+
+ case 'I': /* ignore FATAL errors */
+ ignore = ON;
+ break;
+
+ case '?': /* don't understand the option */
+ error(FATAL, "");
+ break;
+
+ default: /* don't know what to do for ch */
+ error(FATAL, "missing case for option %c\n", ch);
+ break;
+
+ } /* End switch */
+
+ } /* End while */
+} /* End of options */
+
+
+
+
+
+static void
+initialize(void)
+{
+ if ((block = malloc(blocksize)) == NULL)
+ error(FATAL, "no memory");
+
+ ttyi = fileno(stdout);
+
+ if ((ttyo = dup(ttyi)) == -1)
+ error(FATAL, "can't dup file descriptor for stdout");
+
+/*
+ *
+ * Makes sure the printer is in the
+ * IDLE state before any real data is sent.
+ *
+ */
+
+
+ logit("printer startup\n");
+
+ while ( 1 )
+ switch (getstatus(1))
+ {
+ case IDLE:
+ if (postbegin != NULL)
+ write(ttyo, postbegin, strlen(postbegin));
+ else
+ write(ttyo, "\n", 1);
+ return;
+
+ case WAITING:
+ case BUSY:
+ case ERROR:
+ write(ttyo, "\003\004", 2);
+ sleep(1);
+ break;
+
+ case FLUSHING:
+ write(ttyo, "\004", 1);
+ sleep(1);
+ break;
+
+ case PRINTERERROR:
+ case INITIALIZING:
+ sleep(15);
+ break;
+
+ case DISCONNECT:
+ /* talk to spooler w/S_FAULT_ALERT */
+ error(FATAL, "printer appears to be offline");
+ break;
+
+ default:
+ sleep(1);
+ break;
+
+ } /* End switch */
+
+} /* End of initialize */
+
+
+
+
+
+static void
+filter(void)
+{
+ static int wflag = 0; /* nonzero if we've written a block */
+ int fd_in = fileno(stdin);
+
+/*
+ *
+ * Responsible for sending the next file to the printer.
+ * Most of the hard stuff is done in getstatus() and readline().
+ * All this routine really does is control what happens for the
+ * different printer states.
+ *
+ */
+
+
+ logit("sending file\n");
+
+ curfile++;
+
+ while (readblock(fd_in))
+ switch (getstatus(0))
+ {
+ case WAITING:
+ writeblock();
+ wflag = 1;
+ break;
+
+ case BUSY:
+ case PRINTING:
+ case PRINTERERROR:
+ if (tostdout == FALSE)
+ {
+ writeblock();
+ wflag = 1;
+ }
+ else
+ sleep(1);
+ break;
+
+ case UNKNOWN:
+ if (tostdout == FALSE)
+ {
+ writeblock();
+ wflag = 1;
+ }
+ break;
+
+ case NOSTATUS:
+ if (tostdout == FALSE)
+ {
+ if (wflag)
+ writeblock();
+ }
+ else
+ sleep(1);
+ break;
+
+ case IDLE:
+ if (wflag)
+ error(FATAL, "printer is idle");
+ write(ttyo, "\n", 1);
+ break;
+
+ case ERROR:
+ fprintf(stderr, "%s", mesg); /* for csw */
+ error(FATAL, "PostScript error");
+ break;
+
+ case FLUSHING:
+ error(FATAL, "PostScript error");
+ break;
+
+ case INITIALIZING:
+ error(FATAL, "printer booting");
+ break;
+
+ case DISCONNECT:
+ error(FATAL, "printer appears to be offline");
+ break;
+
+ } /* End switch */
+
+} /* End of print */
+
+
+
+
+
+static int
+readblock(int fd_in)
+ /* current input file */
+{
+
+/*
+ *
+ * Fills the input buffer with the next block, provided we're all done
+ * with the last one. Blocks from fd_in are stored in array block[].
+ * Head is the index of the next byte in block[] that's supposed to go
+ * to the printer. tail points one past the last byte in the current
+ * block. head is adjusted in writeblock() after each successful
+ * write, while head and tail are reset here each time a new block is
+ * read. Returns the number of bytes left in the current block. Read
+ * errors cause the program to abort.
+ *
+ */
+
+ if (head >= tail)
+ { /* done with the last block */
+ if ((tail = read(fd_in, block, blocksize)) == -1)
+ error(FATAL, "error reading input file");
+ head = 0;
+ }
+
+ return(tail - head);
+
+} /* End of readblock */
+
+
+
+
+
+static int
+writeblock(void)
+{
+ int count; /* bytes successfully written */
+
+/*
+ *
+ * Called from send() when it's OK to send the next block to the
+ * printer. head is adjusted after the write, and the number of bytes
+ * that were successfully written is returned to the caller.
+ *
+ */
+
+
+ if ((count = write(ttyo, &block[head], tail - head)) == -1)
+ error(FATAL, "error writing to stdout");
+ else
+ if (count == 0)
+ error(FATAL, "printer appears to be offline");
+
+ head += count;
+ return(count);
+} /* End of writeblock */
+
+
+
+
+
+static int
+getstatus(int t)
+ /* sleep time after sending '\024' */
+{
+ char *state; /* new printer state - from sbuf[] */
+ int i; /* index of new state in status[] */
+ static int laststate = NOSTATUS;
+ /* last state we found out about */
+
+/*
+ *
+ * Sends a status request to the printer and tries to read the response.
+ * If an entire line is available readline() returns TRUE and the
+ * string in sbuf[] is parsed and converted into an integer code that
+ * represents the printer's state. If readline() returns FALSE,
+ * meaning an entire line wasn't available, NOSTATUS is returned.
+ *
+ */
+
+ if (readline() == TRUE)
+ {
+ state = sbuf;
+
+ if (strncmp(sbuf, "%%[", 3) == 0)
+ {
+ strtok(sbuf, " "); /* skip the leading "%%[ " */
+ if (strcmp(state = strtok(NULL, " :;"), "status") == 0)
+ state = strtok(NULL, " :;");
+ }
+
+ for (i = 0; status[i].state != NULL; i++)
+ if (strcmp(state, status[i].state) == 0)
+ break;
+
+ if (status[i].val != laststate || debug == ON)
+ logit("%s", mesg);
+
+ if (tostdout == TRUE && status[i].val == UNKNOWN && curfile > 0)
+ fprintf(stdout, "%s", mesg);
+
+ return(laststate = status[i].val);
+ } /* End if */
+
+ if ( write(ttyo, "\024", 1) != 1 )
+ error(FATAL, "printer appears to be offline");
+
+ if ( t > 0 )
+ sleep(t);
+
+ return(NOSTATUS);
+
+} /* End of getstatus */
+
+
+
+
+
+static void
+reset(void)
+{
+ int sleeptime = 15; /* for 'out of paper' etc. */
+ int senteof = FALSE;
+
+/*
+ *
+ * We're all done sending the input files, so we'll send an EOF to the
+ * printer and wait until it tells us it's done.
+ *
+ */
+
+
+ logit("waiting for end of job\n");
+
+ while (1)
+ {
+ switch (getstatus(2))
+ {
+ case WAITING:
+ write(ttyo, "\004", 1);
+ senteof = TRUE;
+ sleeptime = 15;
+ break;
+
+ case ENDOFJOB:
+ if (senteof == TRUE)
+ {
+ logit("job complete\n");
+ return;
+ }
+ sleeptime = 15;
+ break;
+
+ case BUSY:
+ case PRINTING:
+ sleeptime = 15;
+ sleep(1);
+ break;
+
+ case PRINTERERROR:
+ sleep(sleeptime++);
+ break;
+
+ case ERROR:
+ fprintf(stderr, "%s", mesg); /* for csw */
+ error(FATAL, "PostScript error");
+ return;
+
+ case FLUSHING:
+ error(FATAL, "PostScript error");
+ return;
+
+ case IDLE:
+ error(FATAL, "printer is idle");
+ return;
+
+ case INITIALIZING:
+ error(FATAL, "printer booting");
+ return;
+
+ case DISCONNECT:
+ error(FATAL, "printer appears to be offline");
+ return;
+
+ default:
+ sleep(1);
+ break;
+
+ } /* End switch */
+
+ if (sleeptime > 60)
+ sleeptime = 60;
+
+ } /* End while */
+
+} /* End of reset */
+
+
+
+
+
+
+
+
+
+static int
+readline(void)
+{
+ char ch; /* next character from ttyi */
+ int n; /* read() return value */
+
+/*
+ *
+ * Reads the printer's tty line up to a newline (or EOF) or until no
+ * more characters are available. As characters are read they're
+ * converted to lower case and put in sbuf[next] until a newline (or
+ * EOF) are found. The string is then terminated with '\0', next is
+ * reset to zero, and TRUE is returned.
+ *
+ */
+
+
+ while ((n = read(ttyi, &ch, 1)) != 0)
+ {
+ if (n < 0)
+ error(FATAL, "error reading stdout");
+ mesg[next] = ch;
+ sbuf[next++] = tolower(ch);
+ if (ch == '\n' || ch == '\004')
+ {
+ mesg[next] = sbuf[next] = '\0';
+ if (ch == '\004')
+ sprintf(sbuf, "%%%%[ status: endofjob ]%%%%\n");
+ next = 0;
+ return(TRUE);
+ } /* End if */
+ } /* End while */
+
+ return(FALSE);
+
+} /* End of readline */
diff --git a/usr/src/cmd/lp/filter/postscript/postcomm/postcomm.h b/usr/src/cmd/lp/filter/postscript/postcomm/postcomm.h
new file mode 100644
index 0000000000..9a26fff546
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postcomm/postcomm.h
@@ -0,0 +1,211 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ *
+ * A few special definitions used by the program that sends jobs to PostScript
+ * printers. Most, if not all the testing, was done on a QMS PS-800 printer.
+ *
+ * POSTBEGIN, if it's not NULL, is some PostScript code that's sent to the
+ * printer before any of the input files. It's not terribly important since the
+ * same thing can be accomplished in other ways, but it is convenient. POSTBEGIN
+ * is initialized so as to disable job timeouts. The string can also be set on
+ * the command line using the -P option.
+ *
+ */
+
+
+#define POSTBEGIN "statusdict /waittimeout 0 put\n"
+
+
+/*
+ *
+ * Status lines returned by the printer usually look like,
+ *
+ *
+ * %%[ status: idle; source serial 25 ]%%
+ * %%[ status: waiting; source serial 25 ]%%
+ * %%[ status: initializing; source serial 25 ]%%
+ * %%[ status: busy; source serial 25 ]%%
+ * %%[ status: printing; source serial 25 ]%%
+ * %%[ status: PrinterError: out of paper; source serial 25 ]%%
+ * %%[ status: PrinterError: no paper tray; source serial 25 ]%%
+ *
+ *
+ * although the list isn't meant to be complete.
+ *
+ * The following constants are used to classify some of the different printer
+ * states. readline() reads status lines from ttyi and converts everything to
+ * lower case. getstatus() interprets the text that readline() stores in sbuf[]
+ * and returns integer codes that classify the printer status. Those codes are
+ * used in routines start(), send(), and done() to figure out what's happening
+ * and what should be done next.
+ *
+ */
+
+
+#define WAITING 0 /* printer wants more data */
+#define BUSY 1 /* processing data already sent */
+#define PRINTING 2 /* printing a page */
+#define IDLE 3 /* ready to start the next job */
+#define ENDOFJOB 4 /* readline() builds this up on EOF */
+#define PRINTERERROR 5 /* PrinterError - eg. out of paper */
+#define ERROR 6 /* some kind of PostScript problem */
+#define FLUSHING 7 /* throwing out the rest of the job */
+#define INITIALIZING 8 /* printer's booting */
+#define DISCONNECT 9 /* from Datakit */
+#define UNKNOWN 10 /* in case we missed anything */
+#define NOSTATUS 11 /* no response from the printer */
+
+
+/*
+ *
+ * An array of type Status is used, in getstatus(), to figure out the printer's
+ * current state. Just helps convert strings representing the current state into
+ * integer codes that other routines use.
+ *
+ */
+
+
+typedef struct {
+
+ char *state; /* printer's current status */
+ int val; /* value returned by getstatus() */
+
+} Status;
+
+
+/*
+ *
+ * STATUS is used to initialize an array of type Status that translates the
+ * ASCII strings returned by the printer into appropriate codes that can be used
+ * later on in the program. State strings should all be entered in lower case.
+ * readline() converts characters to lower before adding them to sbuf[]. If you
+ * add any states, do it in lower case only, and be sure to add the new status
+ * descriptions before the UNKNOWN entry. The lookup in getstatus() terminates
+ * when it finds the printer state or encounters an entry with NULL in the state
+ * field.
+ *
+ */
+
+
+#define STATUS \
+ \
+ { \
+ "waiting", WAITING, \
+ "busy", BUSY, \
+ "printing", PRINTING, \
+ "idle", IDLE, \
+ "endofjob", ENDOFJOB, \
+ "printererror", PRINTERERROR, \
+ "error", ERROR, \
+ "flushing", FLUSHING, \
+ "initializing", INITIALIZING, \
+ "conversation ended.\n", DISCONNECT, \
+ NULL, UNKNOWN \
+ }
+
+
+/*
+ *
+ * The baud rate can be set on the command line using the -b option. If you omit
+ * it BAUDRATE will be used.
+ *
+ */
+
+
+#define BAUDRATE B9600
+
+
+/*
+ *
+ * An array of type Baud is used, in routine getbaud(), to translate ASCII
+ * strings into termio values that represent the requested baud rate.
+ *
+ */
+
+
+typedef struct {
+
+ char *rate; /* string identifying the baud rate */
+ short val; /* and its termio.h value */
+
+} Baud;
+
+
+/*
+ *
+ * BAUDTABLE initializes the array that's used to translate baud rate requests
+ * into termio values. It needs to end with an entry that has NULL assigned to
+ * the rate field.
+ *
+ */
+
+
+#define BAUDTABLE \
+ \
+ { \
+ "9600", B9600, \
+ "B9600", B9600, \
+ "19200", EXTA, \
+ "19.2", EXTA, \
+ "B19200", EXTA, \
+ "EXTA", EXTA, \
+ "1200", B1200, \
+ "B1200", B1200, \
+ "B4800", B4800, \
+ "4800", B4800, \
+ NULL, B9600 \
+ }
+
+
+/*
+ *
+ * A few miscellaneous definitions. BLOCKSIZE is the default size of the buffer
+ * used for reading the input files (changed with the -B option). BUFSIZE is
+ * the size of the character array used to store printer status lines - don't
+ * make it too small!
+ *
+ */
+
+
+#define BLOCKSIZE 1024
+#define BUFSIZE 512
+
+
+/*
+ *
+ * Finally we'll declare a few of the non-integer valued functions used in
+ * postio.c.
+ *
+ */
+
+
+char *malloc();
+char *strtok();
+
+
diff --git a/usr/src/cmd/lp/filter/postscript/postio/Makefile b/usr/src/cmd/lp/filter/postscript/postio/Makefile
new file mode 100644
index 0000000000..5bc75cb6a1
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postio/Makefile
@@ -0,0 +1,71 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/postio/Makefile
+#
+
+include ../../../Makefile.lp
+
+COMMONDIR= ../common
+
+PROG= postio
+
+SRCS= postio.c ifdef.c slowsend.c parallel.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+TXTS= README
+
+ENCODING= 2
+CPPFLAGS = -DDFLTENCODING=$(ENCODING) \
+ -DSYSV \
+ -I. -I$(COMMONDIR) \
+ $(CPPFLAGS.master)
+
+POFILE = lp_filter_postscript_postio.po
+
+.KEEP_STATE:
+
+all: $(TXTS) $(PROG)
+
+install: all $(ROOTLIBLPPOSTPROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clean :
+ $(RM) $(OBJS)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint: lint_SRCS
+
+include ../../../../Makefile.targ
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/filter/postscript/postio/README b/usr/src/cmd/lp/filter/postscript/postio/README
new file mode 100644
index 0000000000..9afc7f95fa
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postio/README
@@ -0,0 +1,75 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+Source code in this directory is for the program that can be used to send files
+to printers that understand PostScript.
+
+I've added code that lets you split the program into separate read and write
+processes (the -R2 option), supports an interactive mode (-i option), suppresses
+status queries while the files are being transmitted to the printer (-q option),
+and runs in a mode that can help if flow control doesn't appear to be working
+properly (-S option). All the options are described in the man page. In addition
+The parsing of lines returned by the printer has been improved and should do a
+decent job with anything that comes its way.
+
+By default the program runs much like the original version - a single process with
+status queries sent every block or two. It's not how to get the best performance,
+but using a single read/write process may be important if you're running lots of
+printers under a single userid. Four things can help improve performance, and all
+can be set by command line options:
+
+ 1: Use separate read and write processes. The -R2 option gets it or if you want
+ it as the default initialize splitme (near line 132 in postio.c) to TRUE before
+ compiling postio.
+
+ 2: Use a large input buffer. The default size is 2048 bytes, but it can be set
+ to whatever you want on the command line using the -B option. If you want a
+ larger default buffer change the definition of BLOCKSIZE (near line 204 in
+ postio.h) before you compile postio.
+
+ 3: Quiet mode prevents the transmission of status requests (ie. ^Ts) while files
+ are being sent to the printer. You can turn off the status query stuff with
+ the -q option or if you want it as the default initialize quiet (near line 122
+ in postio.c) to TRUE before compiling the program.
+
+ 4: Avoid using the -S option. It's real slow and I thought some about leaving it
+ out, but it's needed at a few sites. Seems to help most with printers connected
+ to UTS systems using DACUs and Datakit PVCs.
+
+One possible strategy would be to have the spooler run postio as a single process
+on all small printers (eg. LaserWriters or PS-800s) and use two processes on faster
+printers like the DataProducts 2665 or QMS PS-2400.
+
+A typical command line might look something like,
+
+ postio -l /dev/tty?? -b 9600 -L log file1 file2 file3
+
+where /dev/tty?? is the line that's connected to the printer, 9600 (or B9600) is
+the baud rate, and log is a file used to record printer status. You should always
+use the -l option to select the printer line, and if you don't choose a log file
+everything coming back from the printer goes to stderr. The following command line
+accomplishes the same thing, but runs postio as separate read and write processes,
+
+ postio -R2 -l/dev/tty?? -b9600 -Llog file1 file2 file3
+
+Check the man page for more examples.
+
diff --git a/usr/src/cmd/lp/filter/postscript/postio/ifdef.c b/usr/src/cmd/lp/filter/postscript/postio/ifdef.c
new file mode 100644
index 0000000000..6ca546cb9f
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postio/ifdef.c
@@ -0,0 +1,967 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ *
+ * Conditionally compiled routines for setting up and reading the line. Things
+ * were getting out of hand with all the ifdefs, and even though this defeats
+ * part of the purpose of conditional complilation directives, I think it's easier
+ * to follow this way. Thanks to Alan Buckwalter for the System V DKHOST code.
+ *
+ * postio now can be run as separate read and write processes, but requires that
+ * you write a procedure called resetline() and perhaps modify readline() some.
+ * I've already tested the code on System V and it seems to work. Ninth Edition
+ * and BSD code may be missing.
+ *
+ * By request I've changed the way some of the setupline() procedures (eg. in the
+ * System V implementation) handle things when no line has been given. If line is
+ * NULL the new setupline() procedures try to continue, assuming whoever called
+ * postio connected stdout to the printer. Things will only work if we can read
+ * and write stdout!
+ *
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include "ifdef.h" /* conditional header file inclusion */
+#include "gen.h" /* general purpose definitions */
+
+FILE *fp_ttyi = NULL, *fp_ttyo;
+char *ptr = mesg;
+extern FILE *fp_log;
+
+
+/*****************************************************************************/
+
+
+#ifdef SYSV
+void
+setupline(void)
+{
+ struct termio termio;
+ struct termios termios;
+ char buf[100];
+
+
+/*
+ *
+ * Line initialization for SYSV. For now if no line is given (ie. line == NULL )
+ * we continue on as before using stdout as ttyi and ttyo. Doesn't work when we're
+ * running in interactive mode or forcing stuff that comes back from the printer
+ * to stdout. Both cases are now caught by a test that's been added to routine
+ * initialize(). The change is primarily for the version of lp that's available
+ * with SVR3.2.
+ *
+ */
+
+#ifdef DKHOST
+ if ( line != NULL && *line != '/' ) {
+ if ( strncmp(line, "DK:", 3) == 0 )
+ line += 3;
+ dkhost_connect();
+ } else
+#endif
+
+ if ( line == NULL ) {
+ ttyi = fileno(stdout);
+ }
+ else if ( (ttyi = open(line, O_RDWR)) == -1 )
+ error(FATAL, "can't open %s", line);
+
+ if ( (ttyo = dup(ttyi)) == -1 ) {
+ error(FATAL, "can't dup file descriptor for %s", line);
+ }
+
+ if ( fcntl(ttyi, F_SETFL, O_NDELAY) == -1 ) {
+ error(FATAL, "fcntl error - F_SETFL");
+ }
+
+ if ( ioctl(ttyi, TCGETS, &termios) < 0 ) {
+ if ( ioctl(ttyi, TCGETA, &termio) == -1 ) {
+ error(FATAL, "ioctl error - TCGETA");
+ }
+ stopbits = (stopbits == 1) ? 0 : CSTOPB;
+
+ termio.c_iflag = IXON | IGNCR;
+ termio.c_oflag = 0;
+ termio.c_cflag = HUPCL | CREAD | CS8 | stopbits |
+ ((line != NULL) ? baudrate : (termio.c_cflag & CBAUD));
+ termio.c_lflag = 0;
+ termio.c_cc[VMIN] = termio.c_cc[VTIME] = 0;
+ if ( ioctl(ttyi, TCSETA, &termio) == -1 ) {
+ error(FATAL, "ioctl error - TCSETA");
+ }
+ } else {
+ stopbits = (stopbits == 1) ? 0 : CSTOPB;
+
+ termios.c_iflag = IXON | IGNCR;
+ termios.c_oflag = 0;
+ termios.c_cflag = HUPCL | CREAD | CS8 | stopbits |
+ ((line != NULL) ? baudrate : cfgetospeed(&termios));
+ termios.c_lflag = 0;
+ termios.c_cc[VMIN] = termios.c_cc[VTIME] = 0;
+ if ( ioctl(ttyi, TCSETS, &termios) == -1 ) {
+ error(FATAL, "ioctl error - TCSETS");
+ }
+ }
+
+ if ( ioctl(ttyi, TCFLSH, 2) == -1 ) {
+ error(FATAL, "ioctl error - TCFLSH");
+ }
+ fp_ttyi = fdopen(ttyi, "r");
+
+ if ( line == NULL ) {
+ line = "stdout";
+ }
+
+} /* End of setupline */
+
+
+/*****************************************************************************/
+
+
+int
+resetline(void)
+{
+
+
+ int flags; /* for turning O_NDELAY off */
+ struct termio termio; /* so we can reset flow control */
+
+
+/*
+ *
+ * Only used if we're running the program as separate read and write processes.
+ * Called from split() after the initial connection has been made and returns
+ * TRUE if two processes should work. Don't know if the O_NDELAY stuff is really
+ * needed, but setting c_cc[VMIN] to 1 definitely is. If we leave it be (as a 0)
+ * the read in readline() won't block!
+ *
+ */
+
+
+ if ( (flags = fcntl(ttyi, F_GETFL, 0)) == -1 )
+ error(FATAL, "fcntl error - F_GETFL");
+
+ flags &= ~O_NDELAY;
+
+ if ( fcntl(ttyi, F_SETFL, flags) == -1 )
+ error(FATAL, "fcntl error - F_SETFL");
+
+ if ( ioctl(ttyi, TCGETA, &termio) == -1 )
+ error(FATAL, "ioctl error - TCGETA");
+
+ termio.c_iflag &= ~IXANY;
+ termio.c_iflag |= IXON | IXOFF;
+ termio.c_cc[VMIN] = 1;
+ termio.c_cc[VTIME] = 0;
+
+ if ( ioctl(ttyi, TCSETA, &termio) == -1 )
+ error(FATAL, "ioctl error - TCSETA");
+
+ return(TRUE);
+
+} /* End of resetline */
+
+
+/*****************************************************************************/
+
+
+void
+setupstdin(int mode)
+ /* what to do with stdin settings */
+{
+ struct termio termio;
+
+ static int saved = FALSE;
+ static struct termio oldtermio;
+
+
+/*
+ *
+ * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
+ * stdin. Expect something like raw mode with no echo will be set up. Explicit
+ * code to ensure blocking reads probably isn't needed because blocksize is set
+ * to 1 when we're in interactive mode, but I've included it anyway.
+ *
+ */
+
+
+ if ( interactive == TRUE )
+ switch ( mode ) {
+ case 0:
+ if ( isatty(0) != 1 )
+ error(FATAL, "stdin not a terminal - can't run interactive mode");
+ if ( ioctl(0, TCGETA, &oldtermio) == -1 )
+ error(FATAL, "can't save terminal settings");
+ saved = TRUE;
+ break;
+
+ case 1:
+ termio = oldtermio;
+ termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+ termio.c_cc[VMIN] = 1;
+ termio.c_cc[VTIME] = 0;
+ ioctl(0, TCSETA, &termio);
+ break;
+
+ case 2:
+ if ( saved == TRUE )
+ ioctl(0, TCSETA, &oldtermio);
+ break;
+ } /* End switch */
+
+} /* End of setupstdin */
+
+
+/*****************************************************************************/
+
+
+int
+readline(void)
+{
+
+
+ int n; /* read() return value */
+ int ch; /* for interactive mode */
+
+ static int tries = 0; /* consecutive times read returned 0 */
+
+
+/*
+ *
+ * Reads characters coming back from the printer on ttyi up to a newline (or EOF)
+ * or until no more characters are available. Characters are put in mesg[], the
+ * string is terminated with '\0' when we're done with a line and TRUE is returned
+ * to the caller. If complete line wasn't available FALSE is returned. Interactive
+ * mode should loop here forever, except during start(), echoing characters to
+ * stdout. If it happens to leave FALSE should be returned. The non-blocking read
+ * gets us out until split() is called.
+ *
+ * Some users (apparently just on 3B2 DKHOST systems) have had problems with the
+ * two process implementation that's forced me to kludge things up some. When a
+ * printer (on those systems) is turned off while postio is transmitting files
+ * the write process hangs in writeblock() (postio.c) - it's typically in the
+ * middle of a write() call, while the read() call (below) continually returns 0.
+ * In the original code readline() returned FALSE when read() returned 0 and we
+ * get into a loop that never ends - because the write process is hung. In the
+ * one process implementation having read return 0 is legitimate because the line
+ * is opened for no delay, but with two processes the read() blocks and a return
+ * value of 0 should never occur. From my point of view the real problem is that
+ * the write() call hangs on 3B2 DKHOST systems and apparently doesn't anywhere
+ * else. If the write returned anything less than or equal to 0 writeblock() would
+ * shut things down. The kludge I've implemented counts the number of consecutive
+ * times read() returns a 0 and if it exceeds a limit (100) the read process will
+ * shut things down. In fact one return of 0 from read() when we're in the two
+ * process mode is undoubtedly sufficient and no counting should be necessary!!!
+ * Moving the check to getstatus() should also work and is probably where things
+ * belong.
+ *
+ */
+
+ if ( interactive == FALSE ) {
+ while ( (n = read(ttyi, ptr, 1)) != 0 ) {
+ if ( n < 0 )
+ if ( errno == EINTR )
+ continue;
+ else error(FATAL, "error reading %s", line);
+ tries = 0;
+ if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) {
+ *(ptr+1) = '\0';
+ if ( *ptr == '\004' )
+ strcpy(ptr, "%%[ status: endofjob ]%%\n");
+ ptr = mesg;
+ return(TRUE);
+ } /* End if */
+ ptr++;
+ } /* End while */
+ if ( canread == TRUE && canwrite == FALSE ) /* read process kludge */
+ if ( ++tries > 100 )
+ error(FATAL, "printer appears to be offline - shutting down");
+ return(FALSE);
+ } /* End if */
+
+ if ( canwrite == TRUE ) /* don't block during start() */
+ return(FALSE);
+
+ while ( (ch = getc(fp_ttyi)) != EOF )
+ putc(ch, stdout);
+ return(FALSE);
+
+} /* End of readline */
+#endif
+
+
+/*****************************************************************************/
+
+
+#ifdef V9
+#include <ipc.h>
+
+char tbuf[256]; /* temporary input buffer */
+char *nptr = tbuf; /* next character comes from here */
+char *eptr = tbuf; /* one past the last character in tbuf */
+
+
+setupline()
+
+
+{
+
+
+ struct sgttyb sgtty;
+ struct ttydevb ttydev; /* for setting up the line */
+ static struct tchars tchar = { '\377', /* interrupt */
+ '\377', /* quit */
+ '\021', /* start output */
+ '\023', /* stop output */
+ '\377', /* end-of-file */
+ '\377' /* input delimiter */
+ };
+
+/*
+ *
+ * Line initialization for V9.
+ *
+ */
+
+
+ if ( line == NULL ) {
+ ttyi = ttyo = 1;
+ return;
+ } /* End if */
+
+ if ( strncmp(line, "/cs", 3) == 0 ) {
+ if ((ttyi = ipcopen(line, "")) < 0) {
+ sleep(5); /* wait for Datakit to hangup */
+ if ((ttyi = ipcopen(line, "")) < 0)
+ error(FATAL, "can't ipcopen %s", line);
+ }
+ } else if ( (ttyi = open(line, O_RDWR)) == -1 )
+ error(FATAL, "can't open %s", line);
+
+ if ( (ttyo = dup(ttyi)) == -1 )
+ error(FATAL, "can't dup file descriptor for %s", line);
+
+ if ( ioctl(ttyi, FIOPUSHLD, &tty_ld) == -1 )
+ error(FATAL, "ioctl error - FIOPUSHLD");
+
+ if ( ioctl(ttyi, TIOCGDEV, &ttydev) == -1 )
+ error(FATAL, "ioctl error - TIOCGDEV");
+
+ if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
+ error(FATAL, "ioctl error - TIOCGETP");
+
+ sgtty.sg_flags &= ~ECHO;
+ sgtty.sg_flags &= ~CRMOD;
+ sgtty.sg_flags |= CBREAK;
+ ttydev.ispeed = baudrate;
+ ttydev.ospeed = baudrate;
+
+ if ( ioctl(ttyi, TIOCSDEV, &ttydev) == -1 )
+ error(FATAL, "ioctl error - TIOCSDEV");
+
+ if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
+ error(FATAL, "ioctl error - TIOCSETP");
+
+ if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 )
+ error(FATAL, "ioctl error - TIOCSETC");
+
+ fp_ttyi = fdopen(ttyi, "r");
+
+} /* End of setupline */
+
+
+/*****************************************************************************/
+
+
+resetline()
+
+
+{
+
+
+ struct sgttyb sgtty;
+
+
+/*
+ *
+ * Only used if we're running the program as separate read and write processes.
+ * Called from split() after the initial connection has been made and returns
+ * TRUE if two processes should work. Haven't tested or even compiled the stuff
+ * for separate read and write processes on Ninth Edition systems - no guarantees
+ * even though we return TRUE!
+ *
+ */
+
+
+ if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
+ error(FATAL, "ioctl error - TIOCGETP");
+
+ sgtty.sg_flags |= TANDEM;
+
+ if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
+ error(FATAL, "ioctl error - TIOCSETP");
+
+ return(TRUE);
+
+} /* End of resetline */
+
+
+/*****************************************************************************/
+
+
+setupstdin(mode)
+
+
+ int mode; /* what to do with stdin settings */
+
+
+{
+
+
+ struct sgttyb sgtty;
+
+ static int saved = FALSE;
+ static struct sgttyb oldsgtty;
+
+
+/*
+ *
+ * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
+ * stdin. Expect something like raw mode with no echo will be set up. Need to make
+ * sure interrupt and quit still work - they're the only good way to exit when
+ * we're running interactive mode. I haven't tested or even compiled this code
+ * so there are no guarantees.
+ *
+ */
+
+
+ if ( interactive == TRUE )
+ switch ( mode ) {
+ case 0:
+ if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 )
+ error(FATAL, "can't save terminal settings");
+ saved = TRUE;
+ break;
+
+ case 1:
+ sgtty = oldsgtty;
+ sgtty.sg_flags &= ~ECHO;
+ sgtty.sg_flags |= CBREAK;
+ ioctl(0, TIOCSETP, &sgtty);
+ break;
+
+ case 2:
+ if ( saved == TRUE )
+ ioctl(0, TIOCSETP, &oldsgtty);
+ break;
+ } /* End switch */
+
+} /* End of setupstdin */
+
+
+/*****************************************************************************/
+
+
+readline()
+
+
+{
+
+
+ int n; /* read() return value */
+ int ch; /* for interactive mode */
+
+
+/*
+ *
+ * Reads characters coming back from the printer on ttyi up to a newline (or EOF)
+ * and transfers each line to the mesg[] array. Everything available on ttyi is
+ * initially stored in tbuf[] and a line at a time is transferred from there to
+ * mesg[]. The string in mesg[] is terminated with a '\0' and TRUE is returned to
+ * the caller when we find a newline, EOF, or reach the end of the mesg[] array.
+ * If nothing is available on ttyi we return FALSE if a single process is being
+ * used for reads and writes, while in the two process implementation we force a
+ * one character read. Interactive mode loops here forever, except during start(),
+ * echoing everything that comes back on ttyi to stdout. The performance of a
+ * simple getc/putc loop for interactive mode was unacceptable when run under mux
+ * and has been replaced by more complicated code. When layers wasn't involved
+ * the getc/putc loop worked well.
+ *
+ */
+
+
+ if ( interactive == FALSE ) {
+ while ( 1 ) {
+ while ( nptr < eptr ) { /* grab characters from tbuf */
+ *ptr = *nptr++;
+ if ( *ptr == '\r' ) continue;
+ if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) {
+ *(ptr+1) = '\0';
+ if ( *ptr == '\004' )
+ strcpy(ptr, "%%[ status: endofjob ]%%\n");
+ ptr = mesg;
+ return(TRUE);
+ } /* End if */
+ ++ptr;
+ } /* End for */
+
+ nptr = eptr = tbuf;
+ if ( ioctl(ttyi, FIONREAD, &n) < 0 )
+ if ( errno == EINTR )
+ continue;
+ else error(FATAL, "ioctl error - FIONREAD");
+ if ( n <= 0 )
+ if ( canwrite == TRUE )
+ return(FALSE);
+ n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf)));
+ if ( (n = read(ttyi, tbuf, n)) < 0 )
+ if ( errno == EINTR )
+ continue;
+ else error(FATAL, "error reading line %s", line);
+ else eptr = nptr + n;
+ } /* End while */
+ } /* End if */
+
+ if ( canwrite == TRUE ) /* don't block during start() */
+ return(FALSE);
+
+ while ( 1 ) { /* only interactive mode gets here */
+ if ( ioctl(ttyi, FIONREAD, &n) < 0 )
+ error(FATAL, "ioctl error - FIONREAD");
+ n = ((n < 1) ? 1 : ((n < sizeof(tbuf)) ? n : sizeof(tbuf)));
+ if ( (n = read(ttyi, tbuf, n)) < 0 )
+ error(FATAL, "error reading line %s", line);
+ else if ( n == 0 ) /* should not happen */
+ error(FATAL, "end of file in interactive mode");
+ if ( write(1, tbuf, n) != n )
+ error(FATAL, "error writing to stdout");
+ } /* End while */
+
+ return(FALSE);
+
+} /* End of readline */
+#endif
+
+
+/*****************************************************************************/
+
+
+#ifdef BSD4_2
+setupline()
+
+
+{
+
+
+ struct sgttyb sgtty;
+ static struct tchars tchar = { '\377', /* interrupt */
+ '\377', /* quit */
+ '\021', /* start output */
+ '\023', /* stop output */
+ '\377', /* end-of-file */
+ '\377' /* input delimiter */
+ };
+ long lmodes;
+ int disc = NTTYDISC;
+
+
+/*
+ *
+ * Line initialization for BSD4_2. As in the System V code, if no line is given
+ * (ie. line == NULL) we continue on as before using stdout as ttyi and ttyo.
+ *
+ */
+
+
+ if ( line == NULL )
+ ttyi = fileno(stdout);
+ else if ( (ttyi = open(line, O_RDWR)) == -1 )
+ error(FATAL, "can't open %s", line);
+
+ if ( (ttyo = dup(ttyi)) == -1 )
+ error(FATAL, "can't dup file descriptor for %s", line);
+
+ if (ioctl(ttyi, TIOCSETD, &disc) == -1 )
+ error(FATAL, "ioctl error - TIOCSETD");
+
+ if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
+ error(FATAL, "ioctl error - TIOCGETP");
+
+ if ( ioctl(ttyi, TIOCLGET, &lmodes) == -1 )
+ error(FATAL, "ioctl error - TIOCLGET");
+
+ sgtty.sg_flags &= ~ECHO;
+ sgtty.sg_flags &= ~CRMOD;
+ sgtty.sg_flags |= CBREAK;
+ sgtty.sg_ispeed = baudrate;
+ sgtty.sg_ospeed = baudrate;
+ lmodes |= LDECCTQ;
+
+ if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
+ error(FATAL, "ioctl error - TIOCSETP");
+
+ if ( ioctl(ttyi, TIOCSETC, &tchar) == -1 )
+ error(FATAL, "ioctl error - TIOCSETC");
+
+ if ( ioctl(ttyi, TIOCLSET, &lmodes) == -1 )
+ error(FATAL, "ioctl error - TIOCLSET");
+
+ fp_ttyi = fdopen(ttyi, "r");
+
+} /* End of setupline */
+
+
+/*****************************************************************************/
+
+
+resetline()
+
+
+{
+
+
+ struct sgttyb sgtty;
+
+
+/*
+ *
+ * Only used if we're running the program as separate read and write processes.
+ * Called from split() after the initial connection has been made and returns
+ * TRUE if two processes should work. Haven't tested or even compiled the stuff
+ * for separate read and write processes on Berkeley systems - no guarantees
+ * even though we return TRUE!
+ *
+ */
+
+
+ if ( ioctl(ttyi, TIOCGETP, &sgtty) == -1 )
+ error(FATAL, "ioctl error - TIOCGETP");
+
+ sgtty.sg_flags |= TANDEM;
+
+ if ( ioctl(ttyi, TIOCSETP, &sgtty) == -1 )
+ error(FATAL, "ioctl error - TIOCSETP");
+
+ return(TRUE);
+
+} /* End of resetline */
+
+
+/*****************************************************************************/
+
+
+setupstdin(mode)
+
+
+ int mode; /* what to do with stdin settings */
+
+
+{
+
+
+ struct sgttyb sgtty;
+
+ static int saved = FALSE;
+ static struct sgttyb oldsgtty;
+
+
+/*
+ *
+ * Save (mode = 0), reset (mode = 1), or restore (mode = 2) the tty settings for
+ * stdin. Expect something like raw mode with no echo will be set up. Need to make
+ * sure interrupt and quit still work - they're the only good way to exit when
+ * we're running interactive mode. I haven't tested or even compiled this code
+ * so there are no guarantees.
+ *
+ */
+
+
+ if ( interactive == TRUE )
+ switch ( mode ) {
+ case 0:
+ if ( isatty(0) != 1 )
+ error(FATAL, "stdin not a terminal - can't run interactive mode");
+ if ( ioctl(0, TIOCGETP, &oldsgtty) == -1 )
+ error(FATAL, "can't save terminal settings");
+ saved = TRUE;
+ break;
+
+ case 1:
+ sgtty = oldsgtty;
+ sgtty.sg_flags &= ~ECHO;
+ sgtty.sg_flags |= CBREAK;
+ ioctl(0, TIOCSETP, &sgtty);
+ break;
+
+ case 2:
+ if ( saved == TRUE )
+ ioctl(0, TIOCSETP, &oldsgtty);
+ break;
+ } /* End switch */
+
+} /* End of setupstdin */
+
+
+/*****************************************************************************/
+
+
+readline()
+
+
+{
+
+
+ int n; /* read() return value */
+ int ch; /* for interactive mode */
+
+
+/*
+ *
+ * Reads characters coming back from the printer on ttyo up to a newline (or EOF)
+ * or until no more characters are available. Characters are put in mesg[], the
+ * string is terminated with '\0' when we're done with a line and TRUE is returned
+ * to the caller. If complete line wasn't available FALSE is returned. Interactive
+ * mode should loop here forever, except during start(), echoing characters to
+ * stdout. If it happens to leave FALSE should be returned. Probably should read
+ * everything available on ttyi into a temporary buffer and work from there rather
+ * than reading one character at a time.
+ *
+ */
+
+
+ if ( interactive == FALSE ) {
+ while ( 1 ) {
+ if ( ioctl(ttyi, FIONREAD, &n) < 0 )
+ if ( errno == EINTR )
+ continue;
+ else error(FATAL, "ioctl error - FIONREAD");
+ if ( n <= 0 )
+ if ( canwrite == TRUE )
+ return(FALSE);
+ else n = 1;
+ for ( ; n > 0; n-- ) {
+ /*if ( read(ttyi, ptr, 1) < 0 )*/
+ if ( (*ptr = getc(fp_ttyi)) == EOF )
+ if ( errno == EINTR )
+ continue;
+ else error(FATAL, "error reading %s", line);
+ if ( *ptr == '\r' ) continue;
+ if ( *ptr == '\n' || *ptr == '\004' || ptr >= endmesg ) {
+ *(ptr+1) = '\0';
+ if ( *ptr == '\004' )
+ strcpy(ptr, "%%[ status: endofjob ]%%\n");
+ ptr = mesg;
+ return(TRUE);
+ } /* End if */
+ ++ptr;
+ } /* End for */
+ } /* End while */
+ } /* End if */
+
+ if ( canwrite == TRUE ) /* don't block during start() */
+ return(FALSE);
+
+ while ( (ch = getc(fp_ttyi)) != EOF )
+ putc(ch, stdout);
+ return(FALSE);
+
+} /* End of readline */
+
+
+/*****************************************************************************/
+
+
+/* @(#)strspn.c 1.2 */
+/*LINTLIBRARY*/
+/*
+ * Return the number of characters in the maximum leading segment
+ * of string which consists solely of characters from charset.
+ */
+int
+strspn(string, charset)
+char *string;
+register char *charset;
+{
+ register char *p, *q;
+
+ for(q=string; *q != '\0'; ++q) {
+ for(p=charset; *p != '\0' && *p != *q; ++p)
+ ;
+ if(*p == '\0')
+ break;
+ }
+ return(q-string);
+}
+
+/* @(#)strpbrk.c 1.2 */
+/*LINTLIBRARY*/
+/*
+ * Return ptr to first occurance of any character from `brkset'
+ * in the character string `string'; NULL if none exists.
+ */
+
+char *
+strpbrk(string, brkset)
+register char *string, *brkset;
+{
+ register char *p;
+
+ do {
+ for(p=brkset; *p != '\0' && *p != *string; ++p)
+ ;
+ if(*p != '\0')
+ return(string);
+ }
+ while(*string++);
+ return((char*)0);
+}
+
+/* @(#)strtok.c 1.2 */
+/* 3.0 SID # 1.2 */
+/*LINTLIBRARY*/
+/*
+ * uses strpbrk and strspn to break string into tokens on
+ * sequentially subsequent calls. returns NULL when no
+ * non-separator characters remain.
+ * `subsequent' calls are calls with first argument NULL.
+ */
+
+
+extern int strspn();
+extern char *strpbrk();
+
+char *
+strtok(string, sepset)
+char *string, *sepset;
+{
+ register char *p, *q, *r;
+ static char *savept;
+
+ /*first or subsequent call*/
+ p = (string == (char*)0)? savept: string;
+
+ if(p == 0) /* return if no tokens remaining */
+ return((char*)0);
+
+ q = p + strspn(p, sepset); /* skip leading separators */
+
+ if(*q == '\0') /* return if no tokens remaining */
+ return((char*)0);
+
+ if((r = strpbrk(q, sepset)) == (char*)0) /* move past token */
+ savept = 0; /* indicate this is last token */
+ else {
+ *r = '\0';
+ savept = ++r;
+ }
+ return(q);
+}
+#endif
+
+
+/*****************************************************************************/
+
+
+#ifdef DKHOST
+
+short dkrmode[3] = {DKR_TIME, 0, 0};
+
+dkhost_connect()
+
+
+{
+
+
+ int ofd; /* for saving and restoring stderr */
+ int dfd;
+ int retrytime = 5;
+
+
+/*
+ *
+ * Tries to connect to a Datakit destination. The extra stuff I've added to save
+ * and later restore stderr is primarily for our spooling setup at Murray Hill.
+ * postio is usually called with stderr directed to a file that will be returned
+ * to the user when the job finishes printing. Problems encountered by dkdial(),
+ * like busy messages, go to stderr but don't belong in the user's mail. They'll
+ * be temporarily directed to the log file. After we've connected stderr will be
+ * restored.
+ *
+ */
+
+
+ if ( *line == '\0' )
+ error(FATAL, "incomplete Datakit line");
+
+ if ( fp_log != stderr ) { /* save stderr - redirect dkdial errors */
+ ofd = dup(2);
+ close(2);
+ dup(fileno(fp_log));
+ } /* End if */
+
+ while ( (dfd = ttyi = dkdial(line)) < 0 ) {
+ if ( retrytime < 0 )
+ error(FATAL, "can't connect to %s", line);
+ sleep(retrytime++);
+ if ( retrytime > 60 )
+ retrytime = 60;
+ } /* End while */
+
+ if ( fp_log != stderr ) { /* restore stderr */
+ close(2);
+ dup(ofd);
+ close(ofd);
+ } /* End if */
+
+ if ( ioctl(ttyi, DIOCRMODE, dkrmode) == -1 )
+ error(FATAL, "ioctl error - DIOCRMODE");
+
+ line = dtnamer(dkminor(ttyi));
+
+ if ( (ttyi = open(line, O_RDWR)) == -1 )
+ error(FATAL, "can't open %s", line);
+
+ close(dfd);
+
+} /* End of dkhost_connect */
+#endif
+
+
+/*****************************************************************************/
+
diff --git a/usr/src/cmd/lp/filter/postscript/postio/ifdef.h b/usr/src/cmd/lp/filter/postscript/postio/ifdef.h
new file mode 100644
index 0000000000..d36cc5a5bb
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postio/ifdef.h
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1996 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/*
+ *
+ * Conditional compilation definitions needed in ifdef.c and postio.c.
+ *
+ */
+
+
+#ifdef SYSV
+#include <termio.h>
+#endif
+
+
+#ifdef V9
+#include <sys/filio.h>
+#include <sys/ttyio.h>
+
+extern int tty_ld;
+#endif
+
+
+#ifdef BSD4_2
+#include <sgtty.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#define FD_ZERO(s) (s) = 0
+#define FD_SET(n,s) (s) |= 1 << (n)
+
+extern int errno;
+#endif
+
+
+#ifdef DKHOST
+#include <dk.h>
+#include <sysexits.h>
+
+extern char *dtnamer();
+extern int dkminor();
+#endif
+
+
+/*
+ *
+ * External variable declarations - most (if not all) are defined in postio.c and
+ * needed by the routines in ifdef.c.
+ *
+ */
+
+
+extern char *line; /* printer is on this line */
+extern int ttyi; /* input */
+extern int ttyo; /* and output file descriptors */
+extern FILE *fp_log; /* just for DKHOST stuff */
+
+extern char mesg[]; /* exactly what came back on ttyi */
+extern char *endmesg; /* one in front of last free slot in mesg */
+extern int next; /* next character goes in mesg[next] */
+
+extern short baudrate; /* printer is running at this speed */
+extern int stopbits; /* and expects this many stop bits */
+extern int interactive; /* TRUE for interactive mode */
+
+extern int canread; /* allows reads */
+extern int canwrite; /* and writes if TRUE */
+
diff --git a/usr/src/cmd/lp/filter/postscript/postio/parallel.c b/usr/src/cmd/lp/filter/postscript/postio/parallel.c
new file mode 100644
index 0000000000..a8bca7e41e
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postio/parallel.c
@@ -0,0 +1,386 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+extern char *postbegin;
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioccom.h>
+#include <sys/ioctl.h>
+
+#include <sys/bpp_io.h>
+#include <sys/ecppsys.h>
+#include <sys/prnio.h>
+
+#define PRINTER_IO_ERROR 129
+
+/*
+ * the parameter structure for the parallel port
+ */
+struct ppc_params_t {
+ int flags; /* same as above */
+ int state; /* status of the printer interface */
+ int strobe_w; /* strobe width, in uS */
+ int data_setup; /* data setup time, in uS */
+ int ack_timeout; /* ACK timeout, in secs */
+ int error_timeout; /* PAPER OUT, etc... timeout, in secs */
+ int busy_timeout; /* BUSY timeout, in seconds */
+};
+
+
+
+extern char *block;
+extern int head, tail;
+extern int readblock(int);
+extern FILE *fp_log;
+static void printer_info(char *fmt, ...);
+
+/* These are the routines avaliable to others for use */
+int is_a_parallel_bpp(int);
+int bpp_state(int);
+int parallel_comm(int, int());
+int get_ecpp_status(int);
+int is_a_prnio(int);
+int prnio_state(int);
+
+#define PRINTER_ERROR_PAPER_OUT 1
+#define PRINTER_ERROR_OFFLINE 2
+#define PRINTER_ERROR_BUSY 3
+#define PRINTER_ERROR_ERROR 4
+#define PRINTER_ERROR_CABLE_POWER 5
+#define PRINTER_ERROR_UNKNOWN 6
+#define PRINTER_ERROR_TIMEOUT 7
+
+/****************************************************************************/
+
+/**
+ * for BPP PARALLEL interfaces
+ **/
+
+int is_a_parallel_bpp(int fd)
+{
+ if (ioctl(fd, BPPIOC_TESTIO) == 0 || errno == EIO)
+ return(1);
+ return(0);
+}
+
+
+#if defined(DEBUG) && defined(NOTDEF)
+char *BppState(int state)
+{
+ static char buf[BUFSIZ];
+
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "State (0x%.4x) - (%s%s%s%s)\n", state,
+ ((state & BPP_SLCT_ERR) ? "offline " : ""),
+ ((state & BPP_BUSY_ERR) ? "busy " : ""),
+ ((state & BPP_PE_ERR) ? "paper " : ""),
+ ((state & BPP_ERR_ERR) ? "error " : ""));
+
+ return(buf);
+}
+#endif
+
+int bpp_state(int fd)
+{
+ if (ioctl(fd, BPPIOC_TESTIO)) {
+ struct bpp_error_status bpp_stat;
+ int state;
+
+ if (ioctl(fd, BPPIOC_GETERR, &bpp_stat) < 0)
+ exit(PRINTER_IO_ERROR);
+ state = bpp_stat.pin_status;
+
+#if defined(DEBUG) && defined(NOTDEF)
+ logit("%s", BppState(state));
+#endif
+
+ if (state == (BPP_PE_ERR | BPP_ERR_ERR | BPP_SLCT_ERR)) {
+ /* paper is out */
+ return(PRINTER_ERROR_PAPER_OUT);
+ } else if (state & BPP_BUSY_ERR) {
+ /* printer is busy */
+ return(PRINTER_ERROR_BUSY);
+ } else if (state & BPP_SLCT_ERR) {
+ /* printer is offline */
+ return(PRINTER_ERROR_OFFLINE);
+ } else if (state & BPP_ERR_ERR) {
+ /* printer is errored */
+ return(PRINTER_ERROR_ERROR);
+ } else if (state == BPP_PE_ERR) {
+ /* printer is off/unplugged */
+ return(PRINTER_ERROR_CABLE_POWER);
+ } else if (state) {
+ return(PRINTER_ERROR_UNKNOWN);
+ } else
+ return(0);
+ }
+ return(0);
+}
+
+int
+get_ecpp_status(int fd)
+{
+ int state;
+ struct ecpp_transfer_parms transfer_parms;
+
+
+ if (ioctl(fd, ECPPIOC_GETPARMS, &transfer_parms) == -1) {
+ return(-1);
+ }
+
+ state = transfer_parms.mode;
+ /*
+ * We don't know what all printers will return in
+ * nibble mode, therefore if we support nibble mode we will
+ * force the printer to be in CENTRONICS mode.
+ */
+
+ if (state != ECPP_CENTRONICS) {
+ transfer_parms.mode = ECPP_CENTRONICS;
+ if (ioctl(fd, ECPPIOC_SETPARMS, &transfer_parms) == -1) {
+ return(-1);
+ } else {
+ state = ECPP_CENTRONICS;
+ }
+ }
+
+ return(state);
+}
+
+/**
+ * For prnio(7I) - generic printer interface
+ **/
+int is_a_prnio(int fd)
+{
+ uint_t cap;
+
+ /* check if device supports prnio */
+ if (ioctl(fd, PRNIOC_GET_IFCAP, &cap) == -1) {
+ return (0);
+ }
+ /* we will use 1284 status if available */
+ if ((cap & PRN_1284_STATUS) == 0) {
+ /* some devices may only support 1284 status in unidir. mode */
+ if (cap & PRN_BIDI) {
+ cap &= ~PRN_BIDI;
+ (void) ioctl(fd, PRNIOC_SET_IFCAP, &cap);
+ }
+ }
+ return (1);
+}
+
+int prnio_state(int fd)
+{
+ uint_t status;
+ uchar_t pins;
+
+ if ((ioctl(fd, PRNIOC_GET_STATUS, &status) == 0) &&
+ (status & PRN_READY)) {
+ return(0);
+ }
+
+ if (ioctl(fd, PRNIOC_GET_1284_STATUS, &pins) != 0) {
+ return(PRINTER_ERROR_UNKNOWN);
+ }
+
+ if ((pins & ~PRN_1284_BUSY) == PRN_1284_PE) {
+ /* paper is out */
+ return(PRINTER_ERROR_PAPER_OUT);
+ } else if (pins == (PRN_1284_PE | PRN_1284_SELECT |
+ PRN_1284_NOFAULT | PRN_1284_BUSY)) {
+ /* printer is off/unplugged */
+ return(PRINTER_ERROR_CABLE_POWER);
+ } else if ((pins & PRN_1284_SELECT) == 0) {
+ /* printer is offline */
+ return(PRINTER_ERROR_OFFLINE);
+ } else if ((pins & PRN_1284_NOFAULT) == 0) {
+ /* printer is errored */
+ return(PRINTER_ERROR_ERROR);
+ } else if (pins & PRN_1284_PE) {
+ /* paper is out */
+ return(PRINTER_ERROR_PAPER_OUT);
+ } else if (pins ^ (PRN_1284_SELECT | PRN_1284_NOFAULT)) {
+ return(PRINTER_ERROR_UNKNOWN);
+ }
+ return(0);
+}
+
+/**
+ * Common routines
+ **/
+
+/*ARGSUSED0*/
+static void
+ByeByeParallel(int sig)
+{
+ /* try to shove out the EOT */
+ (void) write(1, "\004", 1);
+ exit(0);
+}
+
+
+/*ARGSUSED0*/
+static void
+printer_info(char *fmt, ...)
+{
+ char mesg[BUFSIZ];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsprintf(mesg, fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr,
+ "%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
+ mesg);
+ fflush(stderr);
+ fsync(2);
+
+ if (fp_log != stderr) {
+ fprintf(fp_log,
+ "%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
+ mesg);
+ fflush(fp_log);
+ }
+}
+
+static void
+printer_error(int error)
+{
+ switch (error) {
+ case -1:
+ printer_info("ioctl(): %s", strerror(errno));
+ break;
+ case PRINTER_ERROR_PAPER_OUT:
+ printer_info("out of paper");
+ break;
+ case PRINTER_ERROR_OFFLINE:
+ printer_info("offline");
+ break;
+ case PRINTER_ERROR_BUSY:
+ printer_info("busy");
+ break;
+ case PRINTER_ERROR_ERROR:
+ printer_info("printer error");
+ break;
+ case PRINTER_ERROR_CABLE_POWER:
+ printer_info("printer powered off or disconnected");
+ break;
+ case PRINTER_ERROR_UNKNOWN:
+ printer_info("unknown error");
+ break;
+ case PRINTER_ERROR_TIMEOUT:
+ printer_info("communications timeout");
+ break;
+ default:
+ printer_info("get_status() failed");
+ }
+}
+
+
+static void
+wait_state(int fd, int get_state())
+{
+ int state;
+ int was_faulted = 0;
+
+ while (state = get_state(fd)) {
+ was_faulted=1;
+ printer_error(state);
+ sleep(15);
+ }
+
+ if (was_faulted) {
+ fprintf(stderr, "%%%%[ status: idle ]%%%%\n");
+ fflush(stderr);
+ fsync(2);
+ if (fp_log != stderr) {
+ fprintf(fp_log, "%%%%[ status: idle ]%%%%\n");
+ fflush(fp_log);
+ }
+ }
+}
+
+
+int
+parallel_comm(int fd, int get_state())
+{
+ int actual; /* number of bytes successfully written */
+ int count = 0;
+
+ (void) signal(SIGTERM, ByeByeParallel);
+ (void) signal(SIGQUIT, ByeByeParallel);
+ (void) signal(SIGHUP, ByeByeParallel);
+ (void) signal(SIGINT, ByeByeParallel);
+ (void) signal(SIGALRM, SIG_IGN);
+
+ /* is the device ready? */
+
+ /* bracket job with EOT */
+ wait_state(fd, get_state);
+ (void) write(fd, "\004", 1);
+
+/* write(fd, postbegin, strlen(postbegin)); */
+
+ while (readblock(fileno(stdin)) > 0) {
+ wait_state(fd, get_state);
+ alarm(120);
+ if ((actual = write(fd, block + head, tail - head)) == -1) {
+ alarm(0);
+ if (errno == EINTR) {
+ printer_error(PRINTER_ERROR_TIMEOUT);
+ sleep(30);
+ continue;
+ } else {
+ printer_info("I/O Error during write(): %s",
+ strerror(errno));
+ exit(2);
+ }
+ }
+ alarm(0);
+ if (actual >= 0)
+ head += actual;
+
+#if defined(DEBUG) && defined(NOTDEF)
+ logit("Writing (%d) at 0x%x actual: %d, %s\n", count++, head,
+ actual, (actual < 1 ? strerror(errno) : ""));
+#endif
+ }
+
+ /* write the final EOT */
+ wait_state(fd, get_state);
+ (void) write(fd, "\004", 1);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/filter/postscript/postio/postio.c b/usr/src/cmd/lp/filter/postscript/postio/postio.c
new file mode 100644
index 0000000000..c1a1ab01dd
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postio/postio.c
@@ -0,0 +1,1246 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * postio - RS-232 serial interface for PostScript printers
+ *
+ * A simple program that manages input and output for PostScript printers. Much
+ * has been added and changed from early versions of the program, but the basic
+ * philosophy is still the same. Don't send real data until we're certain we've
+ * connected to a PostScript printer that's in the idle state and try to hold
+ * the connection until the job is completely done. It's more work than you
+ * might expect is necessary, but should provide a reasonably reliable spooler
+ * interface that can return error indications to the caller via the program's
+ * exit status.
+ *
+ * I've added code that will let you split the program into separate read/write
+ * processes. Although it's not the default it should be useful if you have a
+ * file that will be returning useful data from the printer. The two process
+ * stuff was laid down on top of the single process code and both methods still
+ * work. The implementation isn't as good as it could be, but didn't require
+ * many changes to the original program (despite the fact that there are now
+ * many differences).
+ *
+ * By default the program still runs as a single process. The -R2 option forces
+ * separate read and write processes after the intial connection is made. If you
+ * want that as the default initialize splitme (below) to TRUE. In addition the
+ * -t option that's used to force stuff not recognized as status reports to
+ * stdout also tries to run as two processes (by setting splitme to TRUE). It
+ * will only work if the required code (ie. resetline() in ifdef.c) has been
+ * implemented for your Unix system. I've only tested the System V code.
+ *
+ * Code needed to support interactive mode has also been added, although again
+ * it's not as efficient as it could be. It depends on the system dependent
+ * procedures resetline() and setupstdin() (file ifdef.c) and for now is only
+ * guaranteed to work on System V. Can be requested using the -i option.
+ *
+ * Quiet mode (-q option) is also new, but was needed for some printers
+ * connected to RADIAN. If you're running in quiet mode no status requests will
+ * be sent to the printer while files are being transmitted (ie. in send()).
+ *
+ * The program expects to receive printer status lines that look like,
+ *
+ * %%[ status: idle; source: serial 25 ]%%
+ * %%[ status: waiting; source: serial 25 ]%%
+ * %%[ status: initializing; source: serial 25 ]%%
+ * %%[ status: busy; source: serial 25 ]%%
+ * %%[ status: printing; source: serial 25 ]%%
+ * %%[ status: PrinterError: out of paper; source: serial 25 ]%%
+ * %%[ status: PrinterError: no paper tray; source: serial 25 ]%%
+ *
+ * although this list isn't complete. Sending a '\024' (control T) character
+ * forces the return of a status report. PostScript errors detected on the
+ * printer result in the immediate transmission of special error messages that
+ * look like,
+ *
+ * %%[ Error: undefined; OffendingCommand: xxx ]%%
+ * %%[ Flushing: rest of job (to end-of-file) will be ignored ]%%
+ *
+ * although we only use the Error and Flushing keywords. Finally conditions,
+ * like being out of paper, result in other messages being sent back from the
+ * printer over the communications line. Typical PrinterError messages look
+ * like,
+ *
+ * %%[ PrinterError: out of paper; source: serial 25 ]%%
+ * %%[ PrinterError: paper jam; source: serial 25 ]%%
+ *
+ * although we only use the PrinterError keyword rather than trying to recognize
+ * all possible printer errors.
+ *
+ * The implications of using one process and only flow controlling data going to
+ * the printer are obvious. Job transmission should be reliable, but there can
+ * be data loss in stuff sent back from the printer. Usually that only caused
+ * problems with jobs designed to run on the printer and return useful data
+ * back over the communications line. If that's the kind of job you're sending
+ * call postio with the -t option. That should force the program to split into
+ * separate read and write processes and everything not bracketed by "%%[ "
+ * and " ]%%" strings goes to stdout. In otherwords the data you're expecting
+ * should be separated from the status stuff that goes to the log file (or
+ * stderr). The -R2 option does almost the same thing (ie. separate read and
+ * write processes), but everything that comes back from the printer goes to
+ * the log file (stderr by default) and you'll have to separate your data from
+ * any printer messages.
+ *
+ * A typical command line might be,
+ *
+ * postio -l /dev/tty01 -b 9600 -L log file1 file2
+ *
+ * where -l selects the line, -b sets the baud rate, and -L selects the printer
+ * log file. Since there's no default line, at least not right now, you'll
+ * always need to use the -l option, and if you don't choose a log file stderr
+ * will be used. If you have a program that will be returning data the command
+ * line might look like,
+ *
+ * postio -t -l/dev/tty01 -b9600 -Llog file >results
+ *
+ * Status stuff goes to file log while the data you're expecting back from the
+ * printer gets put in file results.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioccom.h>
+#include <sys/ioctl.h>
+#include <sys/bpp_io.h>
+#include <sys/ecppsys.h>
+
+#include "ifdef.h" /* conditional compilation stuff */
+#include "gen.h" /* general purpose definitions */
+#include "postio.h" /* some special definitions */
+
+static char **argv; /* global so everyone can use them */
+static int argc;
+static char *prog_name = ""; /* really just for error messages */
+static int x_stat = 0; /* program exit status */
+static int debug = OFF; /* debug flag */
+static int ignore = OFF; /* what's done for FATAL errors */
+static Baud baudtable[] = BAUDTABLE; /* converts strings to termio values */
+static int quiet = FALSE; /* no status queries in send if TRUE */
+char *postbegin = POSTBEGIN; /* preceeds all the input files */
+static int useslowsend = FALSE; /* not recommended! */
+static int splitme = FALSE; /* into READ & WRITE procs if TRUE */
+static int whatami = READWRITE; /* a READ or WRITE process - or both */
+static int otherpid = -1; /* who gets signals if greater than 1 */
+static int joinsig = SIGTRAP; /* reader gets when writing is done */
+static int writedone = FALSE; /* and then sets this to TRUE */
+static char sbuf[MESGSIZE]; /* for parsing the message */
+static char *mesgptr = NULL; /* printer msg starts here in mesg[] */
+static Status status[] = STATUS; /* for converting status strings */
+static int nostatus = NOSTATUS; /* default getstatus() return value */
+static int tostdout = FALSE; /* non-status stuff goes to stdout? */
+static int currentstate = NOTCONNECTED; /* START, SEND, or DONE */
+
+char *line = NULL; /* printer is on this tty line */
+short baudrate = BAUDRATE; /* and running at this baud rate */
+int stopbits = 1; /* number of stop bits */
+int interactive = FALSE; /* interactive mode */
+char *block = NULL; /* input file buffer */
+int blocksize = BLOCKSIZE; /* and its size in bytes */
+int head = 0; /* block[head] is the next character */
+int tail = 0; /* one past the last byte in block[] */
+int canread = TRUE; /* allow reads */
+int canwrite = TRUE; /* and writes if TRUE */
+char mesg[MESGSIZE]; /* exactly what came back on ttyi */
+char *endmesg = NULL; /* end for readline() in mesg[] */
+int ttyi = 0; /* input */
+int ttyo = 2; /* and output file descriptors */
+FILE *fp_log = stderr; /* log file for stuff from printer */
+
+static void init_signals(void);
+static void interrupt(int);
+static void options(void);
+static void initialize(void);
+static void initialize_parallel(void);
+static void start(void);
+static void split(void);
+static void arguments(void);
+static void send(int, char *);
+static void done(void);
+static void cleanup(void);
+static void clearline(void);
+void logit(char *, ...);
+static void quit(int sig);
+static void Rest(int t);
+static int parsemesg(void);
+static int sendsignal(int);
+static int writeblock(void);
+static int Write(int, char *, int);
+static short getbaud(char *);
+static char *find(char *, char *);
+
+void error(int, char *, ...);
+int getstatus(int);
+int readblock(int);
+
+
+/* from parallel.c for parallel interfaces */
+extern int is_a_parallel_bpp(int);
+extern int bpp_state(int);
+extern int is_a_prnio(int);
+extern int prnio_state(int);
+extern int parallel_comm(int, int()); /* arg is bpp_state */
+
+/* from ifdef.c for serial interfaces */
+extern void setupline(void);
+extern void setupstdin(int);
+extern void slowsend(int);
+extern int resetline(void);
+extern int readline(void);
+
+/*
+ * A simple program that manages input and output for PostScript printers.
+ * Can run as a single process or as separate read/write processes. What's
+ * done depends on the value assigned to splitme when split() is called.
+ */
+
+int nop(int fd) { return(0); }
+
+
+int
+main(int agc, char *agv[])
+{
+ argc = agc;
+ argv = agv;
+ prog_name = argv[0]; /* really just for error messages */
+
+ /* is this a serial or parallel port? */
+
+ init_signals(); /* sets up interrupt handling */
+ options(); /* get command line options */
+
+ setbuf(stderr, NULL); /* unbuffer io for stderr */
+
+
+ if (line) {
+ close(1);
+ open(line, O_RDWR);
+
+ }
+
+ if (is_a_prnio(1)) {
+ initialize_parallel();
+ x_stat = parallel_comm(1, prnio_state);
+ } else if (is_a_parallel_bpp(1) ||
+ (get_ecpp_status(1) == ECPP_CENTRONICS)) {
+ initialize_parallel();
+ x_stat = parallel_comm(1, bpp_state);
+ } else if (isatty(1)) {
+ initialize(); /* must be done after options() */
+ start(); /* make sure the printer is ready */
+ split(); /* into read/write processes - maybe */
+ arguments(); /* then send each input file */
+ done(); /* wait until the printer is finished */
+ cleanup(); /* make sure the write process stops */
+ } else {
+ initialize_parallel();
+ x_stat = parallel_comm(1, nop);
+ }
+
+
+ return (x_stat); /* everything probably went OK */
+}
+
+
+/*
+ * Makes sure we handle interrupts. The proper way to kill the program, if
+ * necessary, is to do a kill -15. That forces a call to interrupt(), which in
+ * turn tries to reset the printer and then exits with a non-zero status. If the
+ * program is running as two processes, sending SIGTERM to either the parent or
+ * child should clean things up.
+ */
+
+static void
+init_signals(void)
+{
+ if (signal(SIGINT, interrupt) == SIG_IGN) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ } else {
+ signal(SIGHUP, interrupt);
+ signal(SIGQUIT, interrupt);
+ }
+
+ signal(SIGTERM, interrupt);
+
+}
+
+
+/*
+ * Reads and processes the command line options. The -R2, -t, and -i options all
+ * force separate read and write processes by eventually setting splitme to TRUE
+ * (check initialize()). The -S option is not recommended and should only be
+ * used as a last resort!
+ */
+
+static void
+options(void)
+{
+ int ch; /* return value from getopt() */
+ char *optnames = "b:il:qs:tB:L:P:R:SDI";
+
+ extern char *optarg; /* used by getopt() */
+ extern int optind;
+
+ while ((ch = getopt(argc, argv, optnames)) != EOF) {
+
+ switch (ch) {
+
+ case 'b': /* baud rate string */
+ baudrate = getbaud(optarg);
+ break;
+
+ case 'i': /* interactive mode */
+ interactive = TRUE;
+ break;
+
+ case 'l': /* printer line */
+ line = optarg;
+ break;
+
+ case 'q': /* no status queries - for RADIAN? */
+ quiet = TRUE;
+ break;
+
+ case 's': /* use 2 stop bits - for UNISON? */
+ if ((stopbits = atoi(optarg)) < 1 || stopbits > 2)
+ stopbits = 1;
+ break;
+
+ case 't': /* non-status stuff goes to stdout */
+ tostdout = TRUE;
+ break;
+
+ case 'B': /* set the job buffer size */
+ if ((blocksize = atoi(optarg)) <= 0)
+ blocksize = BLOCKSIZE;
+ break;
+
+ case 'L': /* printer log file */
+ if ((fp_log = fopen(optarg, "w")) == NULL) {
+ fp_log = stderr;
+ error(NON_FATAL, "can't open log file %s", optarg);
+ } /* End if */
+ break;
+
+ case 'P': /* initial PostScript code */
+ postbegin = optarg;
+ break;
+
+ case 'R': /* run as one or two processes */
+ if (atoi(optarg) == 2)
+ splitme = TRUE;
+ else splitme = FALSE;
+ break;
+
+ case 'S': /* slow and kludged up vers. of send */
+ useslowsend = TRUE;
+ break;
+
+ case 'D': /* debug flag */
+ debug = ON;
+ break;
+
+ case 'I': /* ignore FATAL errors */
+ ignore = ON;
+ break;
+
+ case '?': /* don't understand the option */
+ error(FATAL, "");
+ break;
+
+ default: /* don't know what to do for ch */
+ error(FATAL, "missing case for option %c\n", ch);
+ break;
+
+ } /* End switch */
+
+ } /* End while */
+
+ argc -= optind; /* get ready for non-option args */
+ argv += optind;
+
+}
+
+
+/*
+ * Called from options() to convert a baud rate string into an appropriate
+ * termio value. *rate is looked up in baudtable[] and if it's found, the
+ * corresponding value is returned to the caller.
+ */
+
+static short
+getbaud(char *rate) /* string representing the baud rate */
+{
+ int i; /* for looking through baudtable[] */
+
+ for (i = 0; baudtable[i].rate != NULL; i++)
+ if (strcmp(rate, baudtable[i].rate) == 0)
+ return (baudtable[i].val);
+
+ error(FATAL, "don't recognize baud rate %s", rate);
+ /*NOTREACHED*/
+ return (0);
+
+}
+
+
+/*
+ * Initialization, a few checks, and a call to setupline() (file ifdef.c) to
+ * open and configure the communications line. Settings for interactive mode
+ * always take precedence. The setupstdin() call with an argument of 0 saves
+ * the current terminal settings if interactive mode has been requested -
+ * otherwise nothing's done. Unbuffering stdout (via the setbuf() call) isn't
+ * really needed on System V since it's flushed whenever terminal input is
+ * requested. It's more efficient if we buffer the stdout (on System V) but
+ * safer (for other versions of Unix) if we include the setbuf() call.
+ */
+
+static void
+initialize(void)
+{
+ whatami = READWRITE; /* always run start() as one process */
+ canread = canwrite = TRUE;
+
+ if (line == NULL) /* kludge for lp - they use -t option */
+ tostdout = FALSE;
+
+ if (tostdout == TRUE) /* force separate read/write procs */
+ splitme = TRUE;
+
+ if (interactive == TRUE) { /* interactive mode settings win */
+ quiet = FALSE;
+ tostdout = FALSE;
+ splitme = TRUE;
+ blocksize = 1;
+ postbegin = NULL;
+ useslowsend = FALSE;
+ nostatus = INTERACTIVE;
+ setbuf(stdout, NULL);
+ }
+
+ if (useslowsend == TRUE) { /* last resort only - not recommended */
+ quiet = FALSE;
+ splitme = FALSE;
+ if (blocksize > 1024) /* don't send too much all at once */
+ blocksize = 1024;
+ }
+
+ if (line == NULL && (interactive == TRUE || tostdout == TRUE))
+ error(FATAL, "a printer line must be supplied - use the -l option");
+
+ if ((block = malloc(blocksize)) == NULL)
+ error(FATAL, "no memory");
+
+ endmesg = mesg + sizeof mesg - 2; /* one byte from last pos. in mesg */
+
+ setupline(); /* configure the communications line */
+ setupstdin(0); /* save current stdin term settings */
+
+}
+
+static void
+initialize_parallel(void)
+{
+ if ((block = malloc(blocksize)) == NULL)
+ error(FATAL, "no memory");
+}
+
+
+/*
+ * Tries to put the printer in the IDLE state before anything important is sent.
+ * Run as a single process no matter what has been assigned to splitme. Separate
+ * read and write processes, if requested, will be created after we're done
+ * here.
+ */
+
+static void
+start(void)
+{
+ int longwait = 0;
+
+ logit("printer startup\n");
+
+ currentstate = START;
+ clearline();
+
+ for (;;)
+ switch (getstatus(1)) {
+
+ case IDLE:
+ case INTERACTIVE:
+ if (postbegin != NULL && *postbegin != '\0')
+ Write(ttyo, postbegin, strlen(postbegin));
+ clearline();
+ return;
+
+ case BUSY:
+ Write(ttyo, "\003", 1);
+ Rest(1);
+ break;
+
+ /* 03/24/95 - bob golden
+ * The HP LJ3 starts in waiting mode and needs the EOF to move
+ * from waiting to idle. To see what would happen, code was added
+ * to send the INTR on waiting and later changed to INTR/EOF.
+ * The INTR by itself had no effect. The INTR/EOF put the
+ * the printer in a busy status loop from which the only
+ * recovery was to reset the printer. Until further testing
+ * testing is done, do not send an INTR to a HPLJ3 in waiting
+ * state. WAITING moved to a separate case to eliminate the
+ * INTR write.
+ */
+ case WAITING:
+ Write(ttyo, "\004", 1);
+ Rest(1);
+ break;
+
+ /* 03/24/95 - bob golden
+ * The HP LJ3 seems to process INTR at later times. All the
+ * longwaits are increaased to reduce the number of INTRs sent.
+ */
+ case ERROR:
+ case FLUSHING:
+ Write(ttyo, "\004", 1);
+ if (longwait++ == 5) {
+ Write(ttyo, "\003", 1);
+ Rest(5);
+ longwait = 0;
+ }
+ Rest(1);
+ break;
+
+ case PRINTERERROR:
+ Rest(15);
+ break;
+
+ case DISCONNECT:
+ error(FATAL, "Disconnected - printer may be offline");
+ break;
+
+ /* 03/24/95 - bob golden
+ * The ENDJOB case has been removed. The HP LJ3 echoes all EOFs
+ * sent so the ENDJOB has no real meaning.
+ */
+ case UNKNOWN:
+ clearline();
+ break;
+
+ default:
+ Rest(1);
+ break;
+
+ } /* End switch */
+
+} /* End of start */
+
+
+/*
+ *
+ * If splitme is TRUE we fork a process, make the parent handle reading, and let
+ * the child take care of writing. resetline() (file ifdef.c) contains all the
+ * system dependent code needed to reset the communications line for separate
+ * read and write processes. For now it's expected to return TRUE or FALSE and
+ * that value controls whether we try the fork. I've only tested the two process
+ * stuff for System V. Other versions of resetline() may just be dummy
+ * procedures that always return FALSE. If the fork() failed previous versions
+ * continued as a single process, although the implementation wasn't quite
+ * right, but I've now decided to quit. The main reason is a Datakit channel
+ * may be configured to flow control data in both directions, and if we run
+ * postio over that channel as a single process we likely will end up in
+ * deadlock.
+ */
+
+static void
+split(void)
+{
+ int pid;
+
+ if (splitme == TRUE)
+ if (resetline() == TRUE) {
+ pid = getpid();
+ signal(joinsig, interrupt);
+ if ((otherpid = fork()) == -1)
+ error(FATAL, "can't fork");
+ else if (otherpid == 0) {
+ whatami = WRITE;
+ nostatus = WRITEPROCESS;
+ otherpid = pid;
+ setupstdin(1);
+ } else
+ whatami = READ;
+ } else if (interactive == TRUE || tostdout == TRUE)
+ error(FATAL,
+ "can't create two process - check resetline()");
+ else
+ error(NON_FATAL,
+ "running as a single process - check resetline()");
+
+ canread = (whatami & READ) ? TRUE : FALSE;
+ canwrite = (whatami & WRITE) ? TRUE : FALSE;
+}
+
+
+/*
+ * Makes sure all the non-option command line arguments are processed. If there
+ * aren't any arguments left when we get here we'll send stdin. Input files are
+ * only read and sent to the printer if canwrite is TRUE. Checking it here means
+ * we won't have to do it in send(). If interactive mode is TRUE we'll stay here
+ * forever sending stdin when we run out of files - exit with a break. Actually
+ * the loop is bogus and used at most once when we're in interactive mode
+ * because stdin is in a pseudo raw mode and the read() in readblock() should
+ * never see the end of file.
+ */
+
+static void
+arguments(void)
+{
+ int fd_in; /* next input file */
+
+ if (canwrite == TRUE)
+ do /* loop is for interactive mode */
+ if (argc < 1)
+ send(fileno(stdin), "pipe.end");
+ else {
+ while (argc > 0) {
+ if ((fd_in = open(*argv, O_RDONLY)) == -1)
+ error(FATAL, "can't open %s", *argv);
+ send(fd_in, *argv);
+ close(fd_in);
+ argc--;
+ argv++;
+ }
+ }
+ while (interactive == TRUE);
+}
+
+/*
+ * Sends file *name to the printer. There's nothing left here that depends on
+ * sending and receiving status reports, although it can be reassuring to know
+ * the printer is responding and processing our job. Only the writer gets here
+ * in the two process implementation, and in that case split() has reset
+ * nostatus to WRITEPROCESS and that's what getstatus() always returns. For
+ * now we accept the IDLE state and ENDOFJOB as legitimate and ignore the
+ * INITIALIZING state.
+ *
+ * fd_in next input file
+ * name it's pathname
+ */
+
+static void
+send(int fd_in, char *name)
+{
+ if (interactive == FALSE)
+ logit("sending file %s\n", name);
+
+ currentstate = SEND;
+
+ if (useslowsend == TRUE) {
+ slowsend(fd_in);
+ return;
+ }
+
+ while (readblock(fd_in))
+
+ switch (getstatus(0)) {
+
+ case IDLE:
+ case BUSY:
+ case WAITING:
+ case PRINTING:
+ case ENDOFJOB:
+ case PRINTERERROR:
+ case UNKNOWN:
+ case NOSTATUS:
+ case WRITEPROCESS:
+ case INTERACTIVE:
+ writeblock();
+ break;
+
+ case ERROR:
+ fprintf(stderr, "%s", mesg); /* for csw */
+ error(USER_FATAL, "PostScript Error");
+ break;
+
+ case FLUSHING:
+ error(USER_FATAL, "Flushing Job");
+ break;
+
+ case DISCONNECT:
+ error(FATAL, "Disconnected - printer may be offline");
+ break;
+
+ }
+
+}
+
+
+/*
+ * Tries to stay connected to the printer until we're reasonably sure the job is
+ * complete. It's the only way we can recover error messages or data generated
+ * by the PostScript program and returned over the communication line. Actually
+ * doing it correctly for all possible PostScript jobs is more difficult that it
+ * might seem. For example if we've sent several jobs, each with their own EOF
+ * mark, then waiting for ENDOFJOB won't guarantee all the jobs have completed.
+ * Even waiting for IDLE isn't good enough. Checking for the WAITING state after
+ * all the files have been sent and then sending an EOF may be the best
+ * approach, but even that won't work all the time - we could miss it or might
+ * not get there. Even sending our own special PostScript job after all the
+ * input files has it's own different set of problems, but probably could work
+ * (perhaps by printing a fake status message or just not timing out). Anyway
+ * it's probably not worth the trouble so for now we'll quit if writedone is
+ * TRUE and we get ENDOFJOB or IDLE.
+ *
+ * If we're running separate read and write processes the reader gets here after
+ * after split() while the writer goes to send() and only gets here after all
+ * the input files have been transmitted. When they're both here the writer
+ * sends the reader signal joinsig and that forces writedone to TRUE in the
+ * reader. At that point the reader can begin looking for an indication of the
+ * end of the job. The writer hangs around until the reader kills it (usually
+ * in cleanup()) sending occasional status requests.
+ */
+
+static void
+done(void)
+{
+ int sleeptime = 15; /* for 'out of paper' etc. */
+ int longwait = 0;
+
+ if (canwrite == TRUE)
+ logit("waiting for end of job\n");
+
+ currentstate = DONE;
+ writedone = (whatami == READWRITE) ? TRUE : FALSE;
+
+ for (;;) {
+
+ switch (getstatus(1)) {
+ case WRITEPROCESS:
+ if (writedone == FALSE) {
+ sendsignal(joinsig);
+ Write(ttyo, "\004", 1);
+ writedone = TRUE;
+ sleeptime = 1;
+ }
+ Rest(sleeptime++);
+ break;
+
+ /* 03/24/95 - bob golden
+ * For the HP LJ3 INTR sent while in the waiting state have
+ * either had no effect or put the printer into a unrecoverable
+ * loop. Further testing may reveal this to not be the case
+ * but for now, remove the send INTR.
+ */
+ case WAITING:
+ Write(ttyo, "\004", 1);
+ Rest(1);
+ sleeptime = 15;
+ break;
+
+ /* 03/24/95 - bob golden
+ * ENDOFJOB case removed here. The HP LJ 3 echoes all EOFs sent so
+ * the ENDOFJOB case is meaningless.
+ */
+ case IDLE:
+ if (writedone == TRUE) {
+ logit("job complete\n");
+ return;
+ }
+ break;
+
+ /* 03/24/95 - bob golden
+ * During print data transmission, the HP LJ3 stays in
+ * status busy. So give it a rest.
+ *
+ */
+ case BUSY:
+ case PRINTING:
+ Rest(1);
+ sleeptime = 15;
+ break;
+
+ case INTERACTIVE:
+ Write(ttyo, "\004", 1);
+ sleeptime = 15;
+ break;
+
+ case PRINTERERROR:
+ Rest(sleeptime++);
+ break;
+
+ case ERROR:
+ Write(ttyo, "\004", 1);
+ fprintf(stderr, "%s", mesg); /* for csw */
+ error(USER_FATAL, "PostScript Error");
+ return;
+
+ case FLUSHING:
+ Write(ttyo, "\004", 1);
+ error(USER_FATAL, "Flushing Job");
+ return;
+
+ case DISCONNECT:
+ error(FATAL, "Disconnected - printer may be offline");
+ return;
+
+ /* 03/24/95 - bob golden
+ * These cases are ignored without a EOF being sent
+ */
+ case ENDOFJOB:
+ case NOSTATUS:
+ Rest(1);
+ break;
+
+ default:
+ Write(ttyo, "\004", 1);
+ Rest(1);
+ break;
+
+ }
+
+ if (sleeptime > 60)
+ sleeptime = 60;
+
+ }
+
+}
+
+
+/*
+ * Only needed if we're running separate read and write processes. Makes sure
+ * the write process is killed after the read process has successfully finished
+ * with all the jobs. sendsignal() returns a -1 if there's nobody to signal so
+ * things work when we're running a single process.
+ */
+
+static void
+cleanup(void)
+{
+ int w;
+
+ while (sendsignal(SIGKILL) != -1 && (w = wait((int *)0)) != otherpid &&
+ w != -1);
+ if ( currentstate != NOTCONNECTED )
+ Write(ttyo, "\004", 1);
+}
+
+
+/*
+ * Fills the input buffer with the next block, provided we're all done with the
+ * last one. Blocks from fd_in are stored in array block[]. head is the index
+ * of the next byte in block[] that's supposed to go to the printer. tail points
+ * one past the last byte in the current block. head is adjusted in writeblock()
+ * after each successful write, while head and tail are reset here each time
+ * a new block is read. Returns the number of bytes left in the current block.
+ * Read errors cause the program to abort. The fake status message that's put
+ * out in quiet mode is only so you can look at the log file and know
+ * something's happening - take it out if you want.
+ */
+
+int
+readblock(int fd_in)
+{
+ static long blocknum = 1;
+
+ if (head >= tail) { /* done with the last block */
+ if ((tail = read(fd_in, block, blocksize)) == -1)
+ error(FATAL, "error reading input file");
+ if (quiet == TRUE && tail > 0) /* put out a fake message? */
+ logit("%%%%[ status: busy; block: %d ]%%%%\n", blocknum++);
+ head = 0;
+ }
+
+ return (tail - head);
+
+}
+
+
+/*
+ * Called from send() when it's OK to send the next block to the printer. head
+ * is adjusted after the write, and the number of bytes that were successfully
+ * written is returned to the caller.
+ */
+
+static int
+writeblock(void)
+{
+ int count; /* bytes successfully written */
+
+ if ((count = write(ttyo, &block[head], tail - head)) == -1)
+ error(FATAL, "error writing to %s", line);
+ else if (count == 0)
+ error(FATAL, "printer appears to be offline");
+
+ head += count;
+ return (count);
+
+}
+
+
+/*
+ * Looks for things coming back from the printer on the communications line,
+ * parses complete lines retrieved by readline(), and returns an integer
+ * representation of the current printer status to the caller. If nothing was
+ * available a status request (control T) is sent to the printer and nostatus
+ * is returned to the caller (provided quiet isn't TRUE). Interactive mode
+ * either never returns from readline() or returns FALSE.
+ */
+
+int
+getstatus(int t) /* sleep time after sending '\024' */
+{
+ int state = nostatus; /* the current state */
+ static int laststate = NOSTATUS; /* last state recognized */
+
+
+ if (canread == TRUE && readline() == TRUE) {
+ state = parsemesg();
+ if (state != laststate || mesgptr != mesg || debug == ON)
+ logit("%s", mesg);
+
+ if (tostdout == TRUE && currentstate != START) {
+ *mesgptr = '\0';
+ fprintf(stdout, "%s", mesg);
+ }
+ return (laststate = state);
+ }
+
+ if ((quiet == FALSE || currentstate != SEND) && interactive == FALSE) {
+ if (Write(ttyo, "\024", 1) != 1)
+ error(FATAL, "printer appears to be offline");
+ if (t > 0) Rest(t);
+ }
+
+ return (nostatus);
+}
+
+
+/*
+ *
+ * Parsing the lines that readline() stores in mesg[] is messy, and what's done
+ * here isn't completely correct nor as fast as it could be. The general format
+ * of lines that come back from the printer (assuming no data loss) is:
+ *
+ * str%%[ key: val; key: val; key: val ]%%\n
+ *
+ * where str can be most anything not containing a newline and printer reports
+ * (eg. status or error messages) are bracketed by "%%[ " and " ]%%" strings and
+ * end with a newline. Usually we'll have the string or printer report but not
+ * both. For most jobs the leading string will be empty, but could be anything
+ * generated on a printer and returned over the communications line using the
+ * PostScript print operator. I'll assume PostScript jobs are well behaved and
+ * never bracket their messages with "%%[ " and " ]%%" strings that delimit
+ * status or error messages.
+ *
+ * Printer reports consist of one or more key/val pairs, and what we're
+ * interested in (status or error indications) may not be the first pair in the
+ * list. In addition we'll sometimes want the value associated with a keyword
+ * (eg. when key = status) and other times we'll want the keyword (eg. when
+ * key = Error or Flushing). The last pair isn't terminated by a semicolon and
+ * a value string often contains many space separated words and it can even
+ * include colons in meaningful places. I've also decided to continue
+ * converting things to lower case before doing the lookup in status[]. The
+ * isupper() test is for Berkeley systems.
+ */
+
+static int
+parsemesg(void)
+{
+ char *e; /* end of printer message in mesg[] */
+ char *key, *val; /* keyword/value strings in sbuf[] */
+ char *p; /* for converting to lower case etc. */
+ int i; /* where *key was found in status[] */
+
+ if (*(mesgptr = find("%%[ ", mesg)) != '\0' &&
+ *(e = find(" ]%%", mesgptr+4)) != '\0') {
+
+ strcpy(sbuf, mesgptr+4); /* don't change mesg[] */
+ sbuf[e-mesgptr-4] = '\0'; /* ignore the trailing " ]%%" */
+
+ for (key = strtok(sbuf, " :"); key != NULL;
+ key = strtok(NULL, " :")) {
+ if ((val = strtok(NULL, ";")) != NULL &&
+ strcmp(key, "status") == 0)
+ key = val;
+
+ for (; *key == ' '; key++); /* skip leading space */
+ for (p = key; *p; p++) /* conv to lower case */
+ if (*p == ':' || *p == ',') {
+ *p = '\0';
+ break;
+ } else if (isupper(*p))
+ *p = tolower(*p);
+
+ for (i = 0; status[i].state != NULL; i++)
+ if (strcmp(status[i].state, key) == 0)
+ return (status[i].val);
+ }
+ } else if (strcmp(mesg, "CONVERSATION ENDED.\n") == 0)
+ return (DISCONNECT);
+
+ return (nostatus);
+}
+
+
+/*
+ * Looks for *str1 in string *str2. Returns a pointer to the start of the
+ * substring if it's found or to the end of string str2 otherwise.
+ */
+
+static char *
+find(char *str1, char *str2)
+{
+ char *s1, *s2; /* can't change str1 or str2 too fast */
+
+ for (; *str2 != '\0'; str2++) {
+ for (s1 = str1, s2 = str2; *s1 != '\0' && *s1 == *s2; s1++, s2++);
+ if (*s1 == '\0')
+ break;
+ }
+
+ return (str2);
+
+}
+
+
+/*
+ * Reads characters from the input line until nothing's left. Don't do
+ * anything if we're currently running separate read and write processes.
+ */
+
+static void
+clearline(void)
+{
+ if (whatami == READWRITE)
+ while (readline() != FALSE);
+
+}
+
+
+/*
+ * Sends signal sig to the other process if we're running as separate read and
+ * write processes. Returns the result of the kill if there's someone else to
+ * signal or -1 if we're running alone.
+ *
+ */
+
+static int
+sendsignal(int sig)
+{
+ if (whatami != READWRITE && otherpid > 1)
+ return (kill(otherpid, sig));
+
+ return (-1);
+}
+
+
+/*
+ * Caught a signal - all except joinsig cause the program to quit. joinsig is
+ * the signal sent by the writer to the reader after all the jobs have been
+ * transmitted. Used to tell the read process when it can start looking for
+ * the end of the job.
+ */
+
+static void
+interrupt(int sig)
+{
+ signal(sig, SIG_IGN);
+
+ if (sig != joinsig) {
+ x_stat |= FATAL;
+ if (canread == TRUE)
+ if (interactive == FALSE)
+ error(NON_FATAL, "signal %d abort", sig);
+ else error(NON_FATAL, "quitting");
+ quit(sig);
+ }
+
+ writedone = TRUE;
+ signal(joinsig, interrupt);
+}
+
+
+/*
+ * Simple routine that's used to write a message to the log file.
+ */
+
+void
+logit(char *mesg, ...)
+{
+ va_list ap;
+
+ va_start(ap, mesg);
+ vfprintf(fp_log, mesg, ap);
+ va_end(ap);
+
+ fflush(fp_log);
+
+}
+
+/*
+ * Called when we've run into some kind of program error. First *mesg is
+ * printed. If kind is FATAL and we're not ignoring errors the program
+ * will be terminated. If mesg is NULL or *mesg is the NULL string nothing
+ * will be printed.
+ */
+
+void
+error(int kind, char *mesg, ...)
+{
+ va_list ap;
+
+ if (mesg != NULL && *mesg != '\0') {
+ fprintf(fp_log, "%s: ", prog_name);
+
+ va_start(ap, mesg);
+ vfprintf(fp_log, mesg, ap);
+ va_end(ap);
+
+ putc('\n', fp_log);
+ }
+
+ x_stat |= kind;
+
+ if (kind != NON_FATAL && ignore == OFF)
+ quit(SIGTERM);
+
+}
+
+
+/*
+ *
+ * Makes sure everything is properly cleaned up if there's a signal or FATAL
+ * error that should cause the program to terminate. The sleep by the write
+ * process is to help give the reset sequence a chance to reach the printer
+ * before we break the connection - primarily for printers connected to Datakit.
+ * There's a very slight chance the reset sequence that's sent to the printer
+ * could get us stuck here. Simplest solution is don't bother to send it -
+ * everything works without it. Flushing ttyo would be better, but means yet
+ * another system dependent procedure in ifdef.c! I'll leave things be for now.
+ */
+
+static void
+quit(int sig)
+{
+ int w;
+
+ signal(sig, SIG_IGN);
+ ignore = ON;
+
+ while (sendsignal(sig) != -1 && (w = wait((int *)0)) != otherpid &&
+ w != -1);
+
+ setupstdin(2);
+
+ if (currentstate != NOTCONNECTED)
+ Write(ttyo, "\003\004", 2);
+ alarm(0); /* prevents sleep() loop on V9 systems */
+ Rest(2);
+
+ exit(x_stat);
+
+}
+
+
+/*
+ * Used to replace sleep() calls. Only needed if we're running the program as
+ * a read and write process and don't want to have the read process sleep. Most
+ * sleeps are in the code because of the non-blocking read used by the single
+ * process implementation. Probably should be a macro.
+ */
+
+static void
+Rest(int t)
+{
+ if (t > 0 && canwrite == TRUE)
+ sleep(t);
+
+}
+
+
+/*
+ * Used to replace some of the read() calls. Only needed if we're running
+ * separate read and write processes. Should only be used to replace read calls
+ * on ttyi. Always returns 0 to the caller if the process doesn't have its
+ * READ flag set. Probably should be a macro.
+ */
+
+#ifdef NEVER
+
+static int
+Read(int fd, char *buf, int n)
+{
+ int count;
+
+ if (canread == TRUE) {
+ if ((count = read(fd, buf, n)) == -1 && errno == EINTR)
+ count = 0;
+ } else count = 0;
+
+ return (count);
+
+}
+
+#endif /* NEVER */
+
+
+/*
+ *
+ * Used to replace some of the write() calls. Again only needed if we're running
+ * separate read and write processes. Should only be used to replace write calls
+ * on ttyo. Always returns n to the caller if the process doesn't have its WRITE
+ * flag set. Should also probably be a macro.
+ *
+ */
+
+static int
+Write(int fd, char *buf, int n)
+{
+ int count;
+
+ if (canwrite == TRUE) {
+ if ((count = write(fd, buf, n)) == -1 && errno == EINTR)
+ count = n;
+ } else count = n;
+
+ return (count);
+}
diff --git a/usr/src/cmd/lp/filter/postscript/postio/postio.h b/usr/src/cmd/lp/filter/postscript/postio/postio.h
new file mode 100644
index 0000000000..d9dbb7ccce
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postio/postio.h
@@ -0,0 +1,251 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#ifndef _POSTIO_POSTIO_H
+#define _POSTIO_POSTIO_H
+
+/*
+ *
+ * Definitions used by the program that sends jobs to PostScript printers.
+ *
+ * POSTBEGIN, if it's not NULL, is some PostScript code that's sent to the
+ * printer before any of the input files. It's not terribly important since
+ * the same thing can be accomplished in other ways, but this approach is
+ * convenient. POSTBEGIN is initialized so as to disable job timeouts. The
+ * string can also be set on the command line using the -P option.
+ *
+ */
+
+#define POSTBEGIN "%!PS\nstatusdict /waittimeout 0 put\n"
+
+/*
+ * The following help determine where postio is when it's running - either
+ * in the START, SEND, or DONE states. Primarily controls what's done in
+ * getstatus().
+ * RADIAN occasionally had problems with two way conversations. Anyway this
+ * stuff can be used to prevent status queries while we're transmitting a
+ * job. Enabled by the -q option.
+ *
+ */
+
+#define NOTCONNECTED 0
+#define START 1
+#define SEND 2
+#define DONE 3
+
+/*
+ * Previous versions of postio only ran as a single process. That was (and
+ * still * is) convenient, but meant we could only flow control one direction.
+ * Data coming back from the printer occasionally got lost, but that didn't
+ * often hurt (except for lost error messages). Anyway I've added code that
+ * lets you split the program into separate read and write processes, thereby
+ * helping to prevent data loss in both directions. It should be particularly
+ * useful when you're sending a job that you expect will be returning useful
+ * data over the communications line.
+ *
+ * The next three definitions control what's done with data on communications
+ * line. The READ flag means the line can be read, while the WRITE flag means
+ * it can be written. When we're running as a single process both flags are
+ * set. I tried to overlay the separate read/write process code on what was
+ * there and working for one process. The implementation isn't as good as it
+ * could be, but should be safe. The single process version still works,
+ * and remains the default.
+ */
+
+#define READ 1
+#define WRITE 2
+#define READWRITE 3
+
+/*
+ * Messages generated on the printer and returned over the communications line
+ * look like,
+ *
+ * %%[ status: idle; source: serial 25 ]%%
+ * %%[ status: waiting; source: serial 25 ]%%
+ * %%[ status: initializing; source: serial 25 ]%%
+ * %%[ status: busy; source: serial 25 ]%%
+ * %%[ status: printing; source: serial 25 ]%%
+ * %%[ status: PrinterError: out of paper; source: serial 25 ]%%
+ * %%[ status: PrinterError: no paper tray; source: serial 25 ]%%
+ *
+ * %%[ PrinterError: out of paper; source: serial 25 ]%%
+ * %%[ PrinterError: no paper tray; source: serial 25 ]%%
+ *
+ * %%[ Error: undefined; OffendingCommand: xxx ]%%
+ * %%[ Flushing: rest of job (to end-of-file) will be ignored ]%%
+ *
+ * although the list isn't meant to be complete.
+ *
+ * The following constants are used to classify the recognized printer states.
+ * readline() reads complete lines from ttyi and stores them in array mesg[].
+ * getstatus() looks for the "%%[ " and " ]%%" delimiters that bracket printer
+ * messages and if found it tries to parse the enclosed message. After the
+ * lookup one of the following numbers is returned as an indication of the
+ * existence or content of the printer message. The return value is used in
+ * start(), send(), and done() to figure out what's happening and what can
+ * be done next.
+ */
+
+#define BUSY 0 /* processing data already sent */
+#define WAITING 1 /* printer wants more data */
+#define PRINTING 2 /* printing a page */
+#define IDLE 3 /* ready to start the next job */
+#define ENDOFJOB 4 /* readline() builds this up on EOF */
+#define PRINTERERROR 5 /* PrinterError - eg. out of paper */
+#define ERROR 6 /* some kind of PostScript error */
+#define FLUSHING 7 /* throwing out the rest of the job */
+#define INITIALIZING 8 /* printer is booting */
+#define DISCONNECT 9 /* from Datakit! */
+#define UNKNOWN 10 /* in case we missed anything */
+#define NOSTATUS 11 /* no response from the printer */
+
+#define WRITEPROCESS 12 /* dummy states for write process */
+#define INTERACTIVE 13 /* and interactive mode */
+
+/*
+ * An array of type Status is used, in getstatus(), to figure out the printer's
+ * current state. Just helps convert strings representing the current state into
+ * integer codes that other routines use.
+ */
+
+typedef struct {
+
+ char *state; /* printer's current status */
+ int val; /* value returned by getstatus() */
+
+} Status;
+
+/*
+ * STATUS is used to initialize an array of type Status that translates the
+ * ASCII strings returned by the printer into appropriate codes that can be
+ * used later on in the program. getstatus() converts characters to lower
+ * case, so if you add any entries make them lower case and put them in
+ * before the UNKNOWN entry.
+ * The lookup terminates when we get a match or when an entry with a NULL state
+ * is found.
+ *
+ */
+
+#define STATUS \
+ \
+ { \
+ "busy", BUSY, \
+ "waiting", WAITING, \
+ "printing", PRINTING, \
+ "idle", IDLE, \
+ "endofjob", ENDOFJOB, \
+ "printererror", PRINTERERROR, \
+ "error", ERROR, \
+ "flushing", FLUSHING, \
+ "initializing", INITIALIZING, \
+ NULL, UNKNOWN \
+ }
+
+/*
+ *
+ * The baud rate can be set on the command line using the -b option. If you omit
+ * it BAUDRATE will be used.
+ *
+ */
+
+#define BAUDRATE B9600
+
+/*
+ *
+ * An array of type Baud is used, in routine getbaud(), to translate ASCII
+ * strings into termio values that represent the requested baud rate.
+ *
+ */
+
+typedef struct {
+
+ char *rate; /* string identifying the baud rate */
+ short val; /* and its termio.h value */
+
+} Baud;
+
+/*
+ *
+ * BAUDTABLE initializes the array that's used to translate baud rate requests
+ * into termio values. It needs to end with an entry that has NULL assigned to
+ * the rate field.
+ *
+ */
+
+#define BAUDTABLE \
+ \
+ { \
+ "9600", B9600, \
+ "B9600", B9600, \
+ "19200", EXTA, \
+ "19.2", EXTA, \
+ "B19200", EXTA, \
+ "EXTA", EXTA, \
+ "1200", B1200, \
+ "B1200", B1200, \
+ "2400", B2400, \
+ "B2400", B2400, \
+ "B4800", B4800, \
+ "4800", B4800, \
+ "38400", EXTB, \
+ "38.4", EXTB, \
+ "B38400", EXTB, \
+ "EXTB", EXTB, \
+ "57600", B57600, \
+ "57.6", B57600, \
+ "76800", B76800, \
+ "76.8", B76800, \
+ "115200", B115200, \
+ "115.2", B115200, \
+ "153600", B153600, \
+ "153.6", B153600, \
+ "230400", B230400, \
+ "230.4", B230400, \
+ "307200", B307200, \
+ "307.2", B307200, \
+ "460800", B460800, \
+ "460.8", B460800, \
+ "921600", B921600, \
+ "921.6", B921600, \
+ NULL, B9600 \
+ }
+
+/*
+ *
+ * A few miscellaneous definitions. BLOCKSIZE is the default size of the buffer
+ * used for reading the input files (changed with the -B option). MESGSIZE is
+ * the size of the character array used to store printer status lines - don't
+ * make it too small!
+ *
+ */
+
+#define BLOCKSIZE 2048
+#define MESGSIZE 512
+
+#endif /* _POSTIO_POSTIO_H */
diff --git a/usr/src/cmd/lp/filter/postscript/postio/slowsend.c b/usr/src/cmd/lp/filter/postscript/postio/slowsend.c
new file mode 100644
index 0000000000..618ebf36a3
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postio/slowsend.c
@@ -0,0 +1,161 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ *
+ * Stuff that slows the transmission of jobs to PostScript printers. ONLY use it
+ * if you appear to be having trouble with flow control. The idea is simple - only
+ * send a significant amount of data when we're certain the printer is in the
+ * WAITING state. Depends on receiving status messages and only works when the
+ * program is run as a single process. What's done should stop printer generated
+ * XOFFs - provided our input buffer (ie. blocksize) is sufficiently small. Was
+ * originally included in the postio.tmp directory, but can now be requested with
+ * the -S option. Considered eliminating this code, but some printers still depend
+ * on it. In particular Datakit connections made using Datakit PVCs and DACUs seem
+ * to have the most problems. Much of the new stuff that was added can't work when
+ * you use this code.
+ *
+ */
+
+
+#include <stdio.h>
+
+#include "gen.h"
+#include "postio.h"
+
+
+extern char *block;
+extern int blocksize;
+extern int head;
+extern int tail;
+extern char *line;
+extern char mesg[];
+extern int ttyo;
+
+static int writeblock(int);
+
+/*****************************************************************************/
+
+
+void
+slowsend(int fd_in)
+ /* next input file */
+{
+
+/*
+ *
+ * A slow version of send() that's very careful about when data is sent to the
+ * printer. Should help prevent overflowing the printer's input buffer, provided
+ * blocksize is sufficiently small (1024 should be safe). It's a totally kludged
+ * up routine that should ONLY be used if you have constant transmission problems.
+ * There's really no way it will be able to drive a printer much faster that about
+ * six pages a minute, even for the simplest jobs. Get it by using the -S option.
+ *
+ */
+
+
+ while ( readblock(fd_in) )
+
+ switch ( getstatus(0) ) {
+
+ case WAITING:
+ writeblock(blocksize);
+ break;
+
+ case BUSY:
+ case IDLE:
+ case PRINTING:
+ writeblock(30);
+ break;
+
+ case NOSTATUS:
+ case UNKNOWN:
+ break;
+
+ case PRINTERERROR:
+ sleep(30);
+ break;
+
+ case ERROR:
+ fprintf(stderr, "%s", mesg); /* for csw */
+ error(FATAL, "PostScript Error");
+ break;
+
+ case FLUSHING:
+ error(FATAL, "Flushing Job");
+ break;
+
+ case DISCONNECT:
+ error(FATAL, "Disconnected - printer may be offline");
+ break;
+
+ default:
+ sleep(2);
+ break;
+
+ } /* End switch */
+
+} /* End of send */
+
+
+/*****************************************************************************/
+
+
+static int
+writeblock(int num)
+ /* most bytes we'll write */
+{
+ int count; /* bytes successfully written */
+
+/*
+ *
+ * Called from send() when it's OK to send the next block to the printer. head
+ * is adjusted after the write, and the number of bytes that were successfully
+ * written is returned to the caller.
+ *
+ */
+
+
+ if ( num > tail - head )
+ num = tail - head;
+
+ if ( (count = write(ttyo, &block[head], num)) == -1 )
+ error(FATAL, "error writing to %s", line);
+ else if ( count == 0 )
+ error(FATAL, "printer appears to be offline");
+
+ head += count;
+ return(count);
+
+} /* End of writeblock */
+
+
+/*****************************************************************************/
+
diff --git a/usr/src/cmd/lp/filter/postscript/postprint/Makefile b/usr/src/cmd/lp/filter/postscript/postprint/Makefile
new file mode 100644
index 0000000000..94c2451fbe
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postprint/Makefile
@@ -0,0 +1,77 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/postprint/Makefile
+#
+
+include ../../../Makefile.lp
+
+PROG= postprint
+
+SRCS= postprint.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+COMMONDIR = ../common
+
+COMMONOBJS = $(COMMONDIR)/request.o \
+ $(COMMONDIR)/glob.o \
+ $(COMMONDIR)/misc.o
+
+TXTS= README
+
+ENCODING = 2
+CPPFLAGS = -DDFLTENCODING=$(ENCODING) \
+ -I. -I$(COMMONDIR) \
+ $(CPPFLAGS.master)
+
+POFILE = lp_filter_postscript_postprint.po
+
+.KEEP_STATE:
+
+all: $(TXTS) $(PROG)
+
+install: all $(ROOTLIBLPPOSTPROG)
+
+$(PROG): $(OBJS) $(COMMONOBJS)
+ $(LINK.c) -o $@ $(OBJS) $(COMMONOBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+$(COMMONOBJS): $$(@:%.o=%.c)
+ cd $(@D); $(MAKE) $(@F)
+
+clean:
+ $(RM) $(OBJS)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint: lint_SRCS
+
+include ../../../../Makefile.targ
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/filter/postscript/postprint/README b/usr/src/cmd/lp/filter/postscript/postprint/README
new file mode 100644
index 0000000000..1d67e506d4
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postprint/README
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Source code for a simple program that translates ASCII files into PostScript. The
+only important change, besides the restructuring that's been applied to all the
+translators, is the addition of the -r option that controls how carriage returns
+are handled. As in previous versions the default behavior is to ignore carriage
+returns. The two other choices are to return to column 1 (-r1 option) or treat
+carriage returns as newlines (-r2 option). You can modify the default behavior by
+changing the initialization of crmode (near line 98) in postprint.c.
+
+Things have been tuned for PostScript printers running at 9600 baud, and may not
+be optimal for fast printers running at higher baud rates. A few simple changes
+here and in ../postscript/postprint.ps could help if throughput seems to be
+lacking:
+
+ 1) Near line 755 in postprint.c change
+
+ fprintf(fp_out, ")%d L\n", stringstart-1);
+
+ to
+
+ fprintf(fp_out, ")%d %d L\n", stringstart-1, stringcount);
+
+ Then change the definition of procedure L in ../postscript/postprint.ps
+ to,
+
+ /L {
+ {charwidth mul currentpoint exch pop show} repeat
+ linespace add dup 0 exch moveto
+ } bind def
+
+ 2) Change the upper limit test near line 694 (procedure spaces()) in postprint.c
+ from 6 to something bigger. Output files will be larger, but will run faster
+ when they get to the printer. Should help if you're running at 19.2KB or
+ higher.
+
+ 3) Adjust the scaling set in procedure setup in ../postscript/postprint.ps so
+ 1 unit corresponds to the line spacing. Then replace 'linespace add' in
+ procedures l and L by '1 sub'. It's a little tricky, but I've tried it and
+ it does work.
+
diff --git a/usr/src/cmd/lp/filter/postscript/postprint/postprint.c b/usr/src/cmd/lp/filter/postscript/postprint/postprint.c
new file mode 100644
index 0000000000..49fe4bb3df
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postprint/postprint.c
@@ -0,0 +1,926 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * postprint - PostScript translator for ASCII files.
+ *
+ * A simple program that translates ASCII files into PostScript. All it really
+ * does is expand tabs and backspaces, handle character quoting, print text lines,
+ * and control when pages are started based on the requested number of lines per
+ * page.
+ *
+ * The PostScript prologue is copied from *prologue before any of the input files
+ * are translated. The program expects that the following procedures are defined
+ * in that file:
+ *
+ * setup
+ *
+ * mark ... setup -
+ *
+ * Handles special initialization stuff that depends on how the program
+ * was called. Expects to find a mark followed by key/value pairs on the
+ * stack. The def operator is applied to each pair up to the mark, then
+ * the default state is set up.
+ *
+ * pagesetup
+ *
+ * page pagesetup -
+ *
+ * Does whatever is needed to set things up for the next page. Expects
+ * to find the current page number on the stack.
+ *
+ * l
+ *
+ * string l -
+ *
+ * Prints string starting in the first column and then goes to the next
+ * line.
+ *
+ * L
+ *
+ * mark string column string column ... L mark
+ *
+ * Prints each string on the stack starting at the horizontal position
+ * selected by column. Used when tabs and spaces can be sufficiently well
+ * compressed to make the printer overhead worthwhile. Always used when
+ * we have to back up.
+ *
+ * done
+ *
+ * done
+ *
+ * Makes sure the last page is printed. Only needed when we're printing
+ * more than one page on each sheet of paper.
+ *
+ * Almost everything has been changed in this version of postprint. The program
+ * is more intelligent, especially about tabs, spaces, and backspacing, and as a
+ * result output files usually print faster. Output files also now conform to
+ * Adobe's file structuring conventions, which is undoubtedly something I should
+ * have done in the first version of the program. If the number of lines per page
+ * is set to 0, which can be done using the -l option, pointsize will be used to
+ * guess a reasonable value. The estimate is based on the values of LINESPP,
+ * POINTSIZE, and pointsize, and assumes LINESPP lines would fit on a page if
+ * we printed in size POINTSIZE. Selecting a point size using the -s option and
+ * adding -l0 to the command line forces the guess to be made.
+ *
+ * Many default values, like the magnification and orientation, are defined in
+ * the prologue, which is where they belong. If they're changed (by options), an
+ * appropriate definition is made after the prologue is added to the output file.
+ * The -P option passes arbitrary PostScript through to the output file. Among
+ * other things it can be used to set (or change) values that can't be accessed by
+ * other options.
+ *
+ */
+
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "comments.h" /* PostScript file structuring comments */
+#include "gen.h" /* general purpose definitions */
+#include "path.h" /* for the prologue */
+#include "ext.h" /* external variable declarations */
+#include "postprint.h" /* a few special definitions */
+
+
+char *optnames = "a:c:e:f:l:m:n:o:p:r:s:t:x:y:A:C:J:L:P:R:DI";
+
+char *prologue = POSTPRINT; /* default PostScript prologue */
+char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
+char *locale = NULL;
+
+int formsperpage = 1; /* page images on each piece of paper */
+int copies = 1; /* and this many copies of each sheet */
+
+int linespp = LINESPP; /* number of lines per page */
+int pointsize = POINTSIZE; /* in this point size */
+int tabstops = TABSTOPS; /* tabs set at these columns */
+int crmode = 0; /* carriage return mode - 0, 1, or 2 */
+
+int col = 1; /* next character goes in this column */
+int line = 1; /* on this line */
+
+int stringcount = 0; /* number of strings on the stack */
+int stringstart = 1; /* column where current one starts */
+
+Fontmap fontmap[] = FONTMAP; /* for translating font names */
+char *fontname = "Courier"; /* use this PostScript font */
+
+int page = 0; /* page we're working on */
+int printed = 0; /* printed this many pages */
+
+FILE *fp_in = stdin; /* read from this file */
+FILE *fp_out = stdout; /* and write stuff here */
+FILE *fp_acct = NULL; /* for accounting data */
+
+static void account(void);
+static void arguments(void);
+static void done(void);
+static void endline(void);
+static void formfeed(void);
+static void header(void);
+static void init_signals(void);
+static void newline(void);
+static void options(void);
+static void oput(int);
+static void redirect(int);
+static void setup(void);
+static void spaces(int);
+static void startline(void);
+static void text(void);
+
+/*****************************************************************************/
+
+
+int
+main(int agc, char *agv[])
+{
+
+/*
+ *
+ * A simple program that translates ASCII files into PostScript. If there's more
+ * than one input file, each begins on a new page.
+ *
+ */
+
+
+ argc = agc; /* other routines may want them */
+ argv = agv;
+
+ prog_name = argv[0]; /* really just for error messages */
+
+ init_signals(); /* sets up interrupt handling */
+ header(); /* PostScript header and prologue */
+ setup(); /* for PostScript */
+ arguments(); /* followed by each input file */
+ done(); /* print the last page etc. */
+ account(); /* job accounting data */
+
+ return (x_stat); /* not much could be wrong */
+
+} /* End of main */
+
+
+/*****************************************************************************/
+
+
+static void
+init_signals(void)
+{
+ void interrupt(); /* signal handler */
+
+/*
+ *
+ * Makes sure we handle interrupts.
+ *
+ */
+
+
+ if ( signal(SIGINT, interrupt) == SIG_IGN ) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ } else {
+ signal(SIGHUP, interrupt);
+ signal(SIGQUIT, interrupt);
+ } /* End else */
+
+ signal(SIGTERM, interrupt);
+
+} /* End of init_signals */
+
+
+/*****************************************************************************/
+
+
+static void
+header(void)
+{
+ int ch; /* return value from getopt() */
+ int old_optind = optind; /* for restoring optind - should be 1 */
+
+/*
+ *
+ * Scans the option list looking for things, like the prologue file, that we need
+ * right away but could be changed from the default. Doing things this way is an
+ * attempt to conform to Adobe's latest file structuring conventions. In particular
+ * they now say there should be nothing executed in the prologue, and they have
+ * added two new comments that delimit global initialization calls. Once we know
+ * where things really are we write out the job header, follow it by the prologue,
+ * and then add the ENDPROLOG and BEGINSETUP comments.
+ *
+ */
+
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF )
+ if ( ch == 'L' )
+ prologue = optarg;
+ else if ( ch == '?' )
+ error(FATAL, "");
+
+ optind = old_optind; /* get ready for option scanning */
+
+ fprintf(stdout, "%s", CONFORMING);
+ fprintf(stdout, "%s %s\n", CREATOR, "%M%");
+ fprintf(stdout, "%s %s\n", VERSION, "%I%");
+ fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
+ fprintf(stdout, "%s %s\n", PAGES, ATEND);
+ fprintf(stdout, "%s", ENDCOMMENTS);
+
+ options(); /* handle the command line options */
+
+ if ( cat(prologue) == FALSE )
+ error(FATAL, "can't read %s", prologue);
+
+ fprintf(stdout, "%s", ENDPROLOG);
+ fprintf(stdout, "%s", BEGINSETUP);
+ fprintf(stdout, "mark\n");
+
+} /* End of header */
+
+
+/*****************************************************************************/
+
+
+static void
+options(void)
+{
+ int ch; /* return value from getopt() */
+ int euro = 0;
+ extern char *getenv(char *);
+
+
+/*
+ *
+ * Reads and processes the command line options. Added the -P option so arbitrary
+ * PostScript code can be passed through. Expect it could be useful for changing
+ * definitions in the prologue for which options have not been defined.
+ *
+ * Although any PostScript font can be used, things will only work well for
+ * constant width fonts.
+ *
+ */
+
+ if (((locale = getenv("LC_MONETARY")) != NULL) ||
+ ((locale = getenv("LANG")) != NULL)) {
+ char *tmp = NULL;
+
+ /* if there is a locale specific prologue, use it as the default */
+ if ((tmp = calloc(1, strlen(POSTPRINT) + strlen(locale) + 2)) != NULL) {
+ sprintf(tmp, "%s-%s", POSTPRINT, locale);
+ if (access(tmp, R_OK) == 0)
+ prologue = tmp;
+ else
+ free(tmp);
+ }
+
+ /* if the locale has 8859-15 or euro in it, add the symbol to font */
+ if ((strstr(locale, "8859-15") != NULL) ||
+ (strstr(locale, "euro") != NULL))
+ euro = 1;
+ }
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
+#if defined(DEBUG)
+ fprintf(stderr, " Opt: %c, arg: %s\n", ch, optarg);
+#endif
+ switch ( ch ) {
+
+ case 'a': /* aspect ratio */
+ fprintf(stdout, "/aspectratio %s def\n", optarg);
+ break;
+
+ case 'c': /* copies */
+ copies = atoi(optarg);
+ fprintf(stdout, "/#copies %s store\n", optarg);
+ break;
+
+ case 'e': /* should we add the euro ? */
+ euro = (strcasecmp(optarg, "on") == 0);
+ break;
+
+ case 'f': /* use this PostScript font */
+ fontname = get_font(optarg);
+ fprintf(stdout, "/font /%s def\n", fontname);
+ break;
+
+ case 'l': /* lines per page */
+ linespp = atoi(optarg);
+ break;
+
+ case 'm': /* magnification */
+ fprintf(stdout, "/magnification %s def\n", optarg);
+ break;
+
+ case 'n': /* forms per page */
+ formsperpage = atoi(optarg);
+
+ if (formsperpage <= 0) {
+ /* set default value */
+ formsperpage = 1;
+ }
+
+ fprintf(stdout, "/formsperpage %d def\n", formsperpage);
+
+ break;
+
+ case 'o': /* output page list */
+ out_list(optarg);
+ break;
+
+ case 'p': /* landscape or portrait mode */
+ if ( *optarg == 'l' )
+ fprintf(stdout, "/landscape true def\n");
+ else fprintf(stdout, "/landscape false def\n");
+ break;
+
+ case 'r': /* carriage return mode */
+ crmode = atoi(optarg);
+ break;
+
+ case 's': /* point size */
+ pointsize = atoi(optarg);
+ fprintf(stdout, "/pointsize %s def\n", optarg);
+ break;
+
+ case 't': /* tabstops */
+ tabstops = atoi(optarg);
+
+ if (tabstops <= 0) {
+ /* set default */
+ tabstops = TABSTOPS;
+ }
+
+ break;
+
+ case 'x': /* shift things horizontally */
+ fprintf(stdout, "/xoffset %s def\n", optarg);
+ break;
+
+ case 'y': /* and vertically on the page */
+ fprintf(stdout, "/yoffset %s def\n", optarg);
+ break;
+
+ case 'A': /* force job accounting */
+ case 'J':
+ if ( (fp_acct = fopen(optarg, "a")) == NULL )
+ error(FATAL, "can't open accounting file %s", optarg);
+ break;
+
+ case 'C': /* copy file straight to output */
+ if ( cat(optarg) == FALSE )
+ error(FATAL, "can't read %s", optarg);
+ break;
+
+ case 'L': /* PostScript prologue file */
+ prologue = optarg;
+ break;
+
+ case 'P': /* PostScript pass through */
+ fprintf(stdout, "%s\n", optarg);
+ break;
+
+ case 'R': /* special global or page level request */
+ saverequest(optarg);
+ break;
+
+ case 'D': /* debug flag */
+ debug = ON;
+ break;
+
+ case 'I': /* ignore FATAL errors */
+ ignore = ON;
+ break;
+
+ case '?': /* don't understand the option */
+ error(FATAL, "");
+ break;
+
+ default: /* don't know what to do for ch */
+ error(FATAL, "missing case for option %c\n", ch);
+ break;
+
+ } /* End switch */
+
+ } /* End while */
+
+ if (euro != 0)
+ fprintf(stdout, "/must-add-euro-to-font true def\n");
+
+ argc -= optind; /* get ready for non-option args */
+ argv += optind;
+
+} /* End of options */
+
+
+/*****************************************************************************/
+
+
+char *get_font(name)
+
+
+ char *name; /* name the user asked for */
+
+
+{
+
+
+ int i; /* for looking through fontmap[] */
+
+
+/*
+ *
+ * Called from options() to map a user's font name into a legal PostScript name.
+ * If the lookup fails *name is returned to the caller. That should let you choose
+ * any PostScript font, although things will only work well for constant width
+ * fonts.
+ *
+ */
+
+
+ for ( i = 0; fontmap[i].name != NULL; i++ )
+ if ( strcmp(name, fontmap[i].name) == 0 )
+ return(fontmap[i].val);
+
+ return(name);
+
+} /* End of get_font */
+
+
+/*****************************************************************************/
+
+
+static void
+setup(void)
+{
+
+/*
+ *
+ * Handles things that must be done after the options are read but before the
+ * input files are processed. linespp (lines per page) can be set using the -l
+ * option. If it's not positive we calculate a reasonable value using the
+ * requested point size - assuming LINESPP lines fit on a page in point size
+ * POINTSIZE.
+ *
+ */
+
+ writerequest(0, stdout); /* global requests eg. manual feed */
+ fprintf(stdout, "setup\n");
+
+ if ( formsperpage > 1 ) {
+ if ( cat(formfile) == FALSE )
+ error(FATAL, "can't read %s", formfile);
+ fprintf(stdout, "%d setupforms\n", formsperpage);
+ } /* End if */
+
+ fprintf(stdout, "%s", ENDSETUP);
+
+ if ( linespp <= 0 )
+ linespp = LINESPP * POINTSIZE / pointsize;
+
+} /* End of setup */
+
+
+/*****************************************************************************/
+
+
+static void
+arguments(void)
+{
+
+/*
+ *
+ * Makes sure all the non-option command line arguments are processed. If we get
+ * here and there aren't any arguments left, or if '-' is one of the input files
+ * we'll translate stdin.
+ *
+ */
+
+ if ( argc < 1 )
+ text();
+ else { /* at least one argument is left */
+ while ( argc > 0 ) {
+ if ( strcmp(*argv, "-") == 0 )
+ fp_in = stdin;
+ else if ( (fp_in = fopen(*argv, "r")) == NULL )
+ error(FATAL, "can't open %s", *argv);
+ text();
+ if ( fp_in != stdin )
+ fclose(fp_in);
+ argc--;
+ argv++;
+ } /* End while */
+ } /* End else */
+
+} /* End of arguments */
+
+
+/*****************************************************************************/
+
+
+static void
+done(void)
+{
+
+/*
+ *
+ * Finished with all the input files, so mark the end of the pages with a TRAILER
+ * comment, make sure the last page prints, and add things like the PAGES comment
+ * that can only be determined after all the input files have been read.
+ *
+ */
+ if (printed % formsperpage != 0) { /* pad to ENDPAGE */
+ while (printed % formsperpage) {
+ printed++;
+
+ fprintf(stdout, "save\n");
+ fprintf(stdout, "mark\n");
+ writerequest(printed, stdout);
+ fprintf(stdout, "%d pagesetup\n", printed);
+
+ fprintf(stdout, "cleartomark\n");
+ fprintf(stdout, "showpage\n");
+ fprintf(stdout, "restore\n");
+ }
+ fprintf(stdout, "%s %d %d\n", ENDPAGE, page, printed);
+ }
+
+ fprintf(stdout, "%s", TRAILER);
+ fprintf(stdout, "done\n");
+ fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
+ fprintf(stdout, "%s %d\n", PAGES, printed);
+
+} /* End of done */
+
+
+/*****************************************************************************/
+
+
+static void
+account(void)
+{
+
+/*
+ *
+ * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is
+ * requested using the -A or -J options.
+ *
+ */
+
+ if ( fp_acct != NULL )
+ fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
+
+} /* End of account */
+
+
+/*****************************************************************************/
+
+
+static void
+text(void)
+{
+ int ch; /* next input character */
+
+/*
+ *
+ * Translates *fp_in into PostScript. All we do here is handle newlines, tabs,
+ * backspaces, and quoting of special characters. All other unprintable characters
+ * are totally ignored. The redirect(-1) call forces the initial output to go to
+ * /dev/null. It's done to force the stuff that formfeed() does at the end of
+ * each page to /dev/null rather than the real output file.
+ *
+ */
+
+
+ redirect(-1); /* get ready for the first page */
+ formfeed(); /* force PAGE comment etc. */
+
+ while ( (ch = getc(fp_in)) != EOF )
+
+ switch ( ch ) {
+
+ case '\n':
+ newline();
+ break;
+
+ case '\t':
+ case '\b':
+ case ' ':
+ spaces(ch);
+ break;
+
+ case '\014':
+ formfeed();
+ break;
+
+ case '\r':
+ if ( crmode == 1 )
+ spaces(ch);
+ else if ( crmode == 2 )
+ newline();
+ break;
+
+ case '(':
+ case ')':
+ case '\\':
+ startline();
+ putc('\\', fp_out);
+
+/*
+ *
+ * Fall through to the default case.
+ *
+ */
+
+ default:
+ if ( isascii(ch) && isprint(ch) )
+ oput(ch);
+ else {
+#define isintlprint(ch) ((ch)&0x80)
+#define isss(ch) 0
+ if (isintlprint(ch) || isss(ch)) {
+ startline();
+ fprintf(fp_out, "\\%03o", 0xFF&ch);
+ col++;
+ }
+ }
+ break;
+
+ } /* End switch */
+
+ formfeed(); /* next file starts on a new page? */
+
+} /* End of text */
+
+
+/*****************************************************************************/
+
+
+static void
+formfeed(void)
+{
+
+/*
+ *
+ * Called whenever we've finished with the last page and want to get ready for the
+ * next one. Also used at the beginning and end of each input file, so we have to
+ * be careful about what's done. The first time through (up to the redirect() call)
+ * output goes to /dev/null.
+ *
+ * Adobe now recommends that the showpage operator occur after the page level
+ * restore so it can be easily redefined to have side-effects in the printer's VM.
+ * Although it seems reasonable I haven't implemented it, because it makes other
+ * things, like selectively setting manual feed or choosing an alternate paper
+ * tray, clumsy - at least on a per page basis.
+ *
+ */
+
+
+ if ( fp_out == stdout ) /* count the last page */
+ printed++;
+
+ endline(); /* print the last line */
+
+ fprintf(fp_out, "cleartomark\n");
+ fprintf(fp_out, "showpage\n");
+ fprintf(fp_out, "restore\n");
+ if (printed % formsperpage == 0)
+ fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
+
+ if ( ungetc(getc(fp_in), fp_in) == EOF )
+ redirect(-1);
+ else redirect(++page);
+
+ if (printed % formsperpage == 0)
+ fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
+ fprintf(fp_out, "save\n");
+ fprintf(fp_out, "mark\n");
+ writerequest(printed+1, fp_out);
+ fprintf(fp_out, "%d pagesetup\n", printed+1);
+
+ line = 1;
+
+} /* End of formfeed */
+
+
+/*****************************************************************************/
+
+
+static void
+newline(void)
+{
+
+/*
+ *
+ * Called when we've read a newline character. The call to startline() ensures
+ * that at least an empty string is on the stack.
+ *
+ */
+
+ startline();
+ endline(); /* print the current line */
+
+ if ( ++line > linespp ) /* done with this page */
+ formfeed();
+
+} /* End of newline */
+
+
+/*****************************************************************************/
+
+
+static void
+spaces(int ch)
+ /* next input character */
+{
+ int endcol; /* ending column */
+ int i; /* final distance - in spaces */
+
+/*
+ *
+ * Counts consecutive spaces, tabs, and backspaces and figures out where the next
+ * string should start. Once that's been done we try to choose an efficient way
+ * to output the required number of spaces. The choice is between using procedure
+ * l with a single string on the stack and L with several string and column pairs.
+ * We usually break even, in terms of the size of the output file, if we need four
+ * consecutive spaces. More means using L decreases the size of the file. For now
+ * if there are less than 6 consecutive spaces we just add them to the current
+ * string, otherwise we end that string, follow it by its starting position, and
+ * begin a new one that starts at endcol. Backspacing is always handled this way.
+ *
+ */
+
+
+ startline(); /* so col makes sense */
+ endcol = col;
+
+ do {
+ if ( ch == ' ' )
+ endcol++;
+ else if ( ch == '\t' )
+ endcol += tabstops - ((endcol - 1) % tabstops);
+ else if ( ch == '\b' )
+ endcol--;
+ else if ( ch == '\r' )
+ endcol = 1;
+ else break;
+ } while ( ch = getc(fp_in) ); /* if ch is 0 we'd quit anyway */
+
+ ungetc(ch, fp_in); /* wasn't a space, tab, or backspace */
+
+ if ( endcol < 1 ) /* can't move past left edge */
+ endcol = 1;
+
+ if ( (i = endcol - col) >= 0 && i < 6 )
+ for ( ; i > 0; i-- )
+ oput((int)' ');
+ else {
+ fprintf(fp_out, ")%d(", stringstart-1);
+ stringcount++;
+ col = stringstart = endcol;
+ } /* End else */
+
+} /* End of spaces */
+
+
+/*****************************************************************************/
+
+
+static void
+startline(void)
+{
+
+/*
+ *
+ * Called whenever we want to be certain we're ready to start pushing characters
+ * into an open string on the stack. If stringcount is positive we've already
+ * started, so there's nothing to do. The first string starts in column 1.
+ *
+ */
+
+
+ if ( stringcount < 1 ) {
+ putc('(', fp_out);
+ stringstart = col = 1;
+ stringcount = 1;
+ } /* End if */
+
+} /* End of startline */
+
+
+/*****************************************************************************/
+
+
+static void
+endline(void)
+{
+
+
+/*
+ *
+ * Generates a call to the PostScript procedure that processes all the text on
+ * the stack - provided stringcount is positive. If one string is on the stack
+ * the fast procedure (ie. l) is used to print the line, otherwise the slower
+ * one that processes string and column pairs is used.
+ *
+ */
+
+
+ if ( stringcount == 1 )
+ fprintf(fp_out, ")l\n");
+ else if ( stringcount > 1 )
+ fprintf(fp_out, ")%d L\n", stringstart-1);
+
+ stringcount = 0;
+
+} /* End of endline */
+
+
+/*****************************************************************************/
+
+
+static void
+oput(int ch)
+ /* next output character */
+{
+
+/*
+ *
+ * Responsible for adding all printing characters from the input file to the
+ * open string on top of the stack. The only other characters that end up in
+ * that string are the quotes required for special characters. Some simple
+ * changes here and in spaces could make line wrapping possible. Doing a good
+ * job would probably force lots of printer dependent stuff into the program,
+ * so I haven't bothered with it. Could also change the prologue, or perhaps
+ * write a different one, that uses kshow instead of show to display strings.
+ *
+ */
+
+
+ startline();
+ putc(ch, fp_out);
+ col++;
+
+} /* End of oput */
+
+
+/*****************************************************************************/
+
+
+static void
+redirect(int pg)
+ /* next page we're printing */
+{
+ static FILE *fp_null = NULL; /* if output is turned off */
+
+/*
+ *
+ * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
+ * otherwise output goes to stdout.
+ *
+ */
+
+
+ if ( pg >= 0 && in_olist(pg) == ON )
+ fp_out = stdout;
+ else if ( (fp_out = fp_null) == NULL )
+ fp_out = fp_null = fopen("/dev/null", "w");
+
+} /* End of redirect */
+
+
+/*****************************************************************************/
+
+
diff --git a/usr/src/cmd/lp/filter/postscript/postprint/postprint.h b/usr/src/cmd/lp/filter/postscript/postprint/postprint.h
new file mode 100644
index 0000000000..fb15ee67af
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postprint/postprint.h
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+/*
+ *
+ * Definitions used by the PostScript translator for ASCII files.
+ *
+ */
+
+#define LINESPP 66
+#define TABSTOPS 8
+#define POINTSIZE 10
+
+/*
+ *
+ * An array of type Fontmap helps convert font names requested by users into
+ * legitimate PostScript names. The array is initialized using FONTMAP, which must
+ * end with an entry that has NULL defined as its name field. The only fonts that
+ * are guaranteed to work well are the constant width fonts.
+ *
+ */
+
+typedef struct {
+
+ char *name; /* user's font name */
+ char *val; /* corresponding PostScript name */
+
+} Fontmap;
+
+#define FONTMAP \
+ \
+ { \
+ "R", "Courier", \
+ "I", "Courier-Oblique", \
+ "B", "Courier-Bold", \
+ "CO", "Courier", \
+ "CI", "Courier-Oblique", \
+ "CB", "Courier-Bold", \
+ "CW", "Courier", \
+ "PO", "Courier", \
+ "courier", "Courier", \
+ "cour", "Courier", \
+ "co", "Courier", \
+ NULL, NULL \
+ }
+
+/*
+ *
+ * Some of the non-integer functions in postprint.c.
+ *
+ */
+
+char *get_font();
+
diff --git a/usr/src/cmd/lp/filter/postscript/postreverse/Makefile b/usr/src/cmd/lp/filter/postscript/postreverse/Makefile
new file mode 100644
index 0000000000..1264a6a574
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postreverse/Makefile
@@ -0,0 +1,66 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1989-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/postreverse/Makefile
+#
+
+include ../../../Makefile.lp
+
+PROG = postreverse
+
+SRCS = postreverse.c
+
+OBJS = $(SRCS:%.c=%.o)
+
+TXTS= README
+
+ENCODING = 2
+CPPFLAGS = -DDFLTENCODING=$(ENCODING) \
+ -I. -I$(COMMONDIR) \
+ $(CPPFLAGS.master)
+
+POFILE = lp_filter_postscript_postreverse.po
+
+.KEEP_STATE :
+
+all : $(TXTS) $(PROG)
+
+$(PROG) : $(OBJS)
+ $(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+install : all $(ROOTLIBLPPOSTPROG)
+
+clean :
+ $(RM) $(OBJS)
+
+strip :
+ $(STRIP) $(PROG)
+
+lint : lint_SRCS
+
+include ../../../../Makefile.targ
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/filter/postscript/postreverse/README b/usr/src/cmd/lp/filter/postscript/postreverse/README
new file mode 100644
index 0000000000..1f94fd272a
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postreverse/README
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+ Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+# ident "%Z%%M% %I% %E% SMI"
+
+SCCS Revision 1.4 of postrevers.[ch] represents a new implementation of
+postreverse that is more memory/swap efficient as well as a much more efficient
+algorithm for parsing the PostScript files. The only requirements for a
+document to be parsed is that it contains DSC Page and Trailer comments. The
+algorithm is documented at the beginning of the code.
diff --git a/usr/src/cmd/lp/filter/postscript/postreverse/postreverse.c b/usr/src/cmd/lp/filter/postscript/postreverse/postreverse.c
new file mode 100644
index 0000000000..72de24d3cd
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postreverse/postreverse.c
@@ -0,0 +1,720 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <errno.h>
+#include "postreverse.h"
+
+/*
+ * This version of postreverse should parse any Adobe DSC conforming
+ * PostScript file and most that are not conforming, but minimally have the
+ * page (%%Page:) and trailer (%%Trailer) comments in them at the begining of
+ * the line.
+ *
+ * If a document cannot be parsed (no page and trailer comments), it is passed
+ * through untouched. If you look through the code you will find that it
+ * doesn't ever look for the PostScript magic (%!). This is because it
+ * assumes that PostScript is sent in. If PostScript is in sent in, it will
+ * still attempt to parse it based on DSC page and trailer comments as if it
+ * were postscript.
+ *
+ * flow goes as follows:
+ * 1) get command line options (including parsing a page
+ * list if supplied)
+ * 2) if no filename is supplied in command line, copy
+ * stdin to temp file.
+ * 3) parse the document:
+ * start from begining looking for a DSC page comment
+ * (that is the header) start from the end looking for
+ * a DSC trailer comment (that is the trailer) start from
+ * the header until the trailer looking for DSC page
+ * comments. Each one signifies a new page.
+ * start from the header until the trailer looking for BSD
+ * global comments. Each one violates page independence and
+ * will be stored so it can be printed after the header and
+ * before any pages.
+ * 4) print the document: if there is no header, trailer, or
+ * pages, print it from start to end unaltered if they all
+ * exist, print the header, pages, and trailer the pages
+ * are compared against a page list before being printed,
+ * and are reversed if the reverse flag has been set.
+ * If global definitions were found in the pages of a
+ * document, they are printed after the header and before
+ * the pages.
+ */
+
+static void *
+nmalloc(size_t size)
+{
+ void *ret = malloc(size);
+
+ if (!ret) {
+ (void) fprintf(stderr,
+ "postreverse : malloc() failed : Out of memory\n");
+ exit(2);
+ }
+ return (ret);
+}
+
+static void *
+nrealloc(void *ptr, size_t size)
+{
+ void *ret = realloc(ptr, size);
+
+ if (!ret) {
+ (void) fprintf(stderr,
+ "postreverse : realloc() failed - Out of memory\n");
+ exit(2);
+ }
+ return (ret);
+}
+
+/*
+ * nstrlen() provides the same functionality as strlen() while also checking
+ * that the pointer does not cross the end of file.
+ *
+ * Returns the number of non-NULL bytes in string argument.
+ */
+
+static size_t
+nstrlen(const char *s, char *bptr)
+{
+ const char *s0 = s;
+
+ while (s < bptr && *s != '\0')
+ s++;
+ return (s - s0);
+}
+
+/*
+ * nstrstr() provides the same functionality as strstr() while also checking
+ * that the pointers do not cross the end of the file.
+ *
+ * nstrstr() locates the first occurrence in the string as1 of the sequence of
+ * characters (excluding the terminating null character) in the string as2.
+ * nstrstr() returns a pointer to the located string, or a null pointer if
+ * the string is not found. If as2 is "", the function returns as1.
+ */
+
+static char *
+nstrstr(const char *as1, const char *as2, char *bptr)
+{
+ const char *s1, *s2;
+ const char *tptr;
+ char c;
+
+ s1 = as1;
+ s2 = as2;
+
+ if (s2 == NULL || *s2 == '\0')
+ return ((char *)s1);
+ c = *s2;
+
+ while (s1 < bptr && *s1)
+ if (*s1++ == c) {
+ tptr = s1;
+ while ((s1 < bptr) &&
+ (c = *++s2) == *s1++ && c);
+ if (c == 0)
+ return ((char *)tptr - 1);
+ s1 = tptr;
+ s2 = as2;
+ c = *s2;
+ }
+ return (NULL);
+}
+
+
+/*
+ * caddr_t strrstr(caddr_t as1, caddr_t as2 char *bptr1)
+ * return the address of the beginning of the last occruence of as2
+ * in as1 or NULL if not found
+ */
+caddr_t
+strrstr(caddr_t s1, caddr_t s2, char *bptr)
+{
+ char *t1, *t2;
+ char c;
+
+
+ t1 = s1 + nstrlen(s1, bptr) - 1;
+ t2 = s2 + nstrlen(s2, bptr) - 1;
+
+ if (t2 == NULL || *t2 == '\0')
+ return ((char *)t1);
+ c = *t2;
+
+ while (s1 <= t1)
+ if (*t1-- == c) {
+ while ((c = *--t2) == *t1-- && t2 > s2);
+ if (t2 <= s2)
+ return ((char *)t1 + 1);
+ t2 = s2 + nstrlen(s2, bptr) - 1;
+ c = *t2;
+ }
+ return (NULL);
+}
+
+/*
+ * Copy stdin to a temp file and return the name
+ */
+char *
+StdinToFile()
+{
+ char *fileName = tmpnam(NULL);
+ int fd;
+ int count;
+ char buf[BUFSIZ];
+
+ if ((fd = open(fileName, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
+ fprintf(stderr, "open(%s): %s\n", fileName,
+ strerror(errno));
+ return (NULL);
+ }
+ while ((count = read(0, buf, sizeof (buf))) > 0)
+ if (write(fd, buf, count) != count) {
+ fprintf(stderr, "write(%d, 0x%x, %d): %s\n", fd, buf,
+ count, strerror(errno));
+ close(fd);
+ unlink(fileName);
+ return (NULL);
+ }
+ return (fileName);
+}
+
+/*
+ * Usage(char *name) - program usage
+ */
+void
+Usage(char *name)
+{
+ fprintf(stderr, "Usage: %s [ -o list ] [ -r ] [ filename ]\n", name);
+ exit(1);
+}
+
+
+/*
+ * int **ParsePageList(char *list)
+ * This will parse as string #,#,#-#,#... into an array of pointers
+ * to integers. This array will contain all numbers in the list including
+ * those int the range #-#. The list returned is NULL terminated.
+ * It uses 2 passes to build the list. pass 1 counts the # of ints and
+ * allocates the space, and pass 2 fills in the list.
+ */
+int **
+ParsePageList(char *list)
+{
+ int **pageList = NULL;
+ int pass = 0;
+
+ if (list == NULL)
+ return (NULL);
+
+ while (pass++ < 2) {
+ char *page;
+ char *tmplist;
+ int size = 0;
+
+ tmplist = strdup(list);
+ page = strtok(tmplist, ",");
+
+ do {
+ int start, end;
+ char *s1 = page, *s2;
+
+ if (s2 = strchr(page, '-')) {
+ *s2++ = NULL;
+ start = atoi(s1);
+ end = atoi(s2);
+ if (end < start) {
+ int tmp = end;
+
+ end = start;
+ start = tmp;
+ }
+ } else
+ start = end = atoi(s1);
+
+ while (start <= end)
+ if (pass == 1)
+ /* count the pages for allocation */
+ size++, start++;
+ else { /* fill in the page list */
+ int *tmp = (int *)nmalloc(sizeof (int));
+ *tmp = start++;
+ pageList[size++] = tmp;
+ }
+ } while (page = strtok(NULL, ","));
+ free(tmplist);
+ if (pass == 1)
+ pageList = (int **)calloc(sizeof (int *), (size + 1));
+ }
+ return (pageList);
+}
+
+
+/*
+ * int PageIsListed(int page, int **pageList)
+ * returns 1 if the pagelist is empty or if the page is in the
+ * NULL terminated pageList. returns 0 if the page is not listed
+ */
+int
+PageIsListed(int page, int **pageList)
+{
+ int count = 0;
+
+ if (!pageList)
+ return (1);
+
+ for (count = 0; pageList[count] != NULL; count++)
+ if (*pageList[count] == page)
+ return (1);
+ return (0);
+}
+
+
+/*
+ * Writes the document Header to the fd
+ */
+int
+WriteDocumentHeader(int fd, DOCUMENT * d)
+{
+ if (d) {
+ HEADER *h = d->header;
+
+ if (h)
+ return (write(fd, h->start, h->size));
+ }
+ errno = EINVAL;
+ return (-1);
+}
+
+/*
+ * Writes the document global block to the fd
+ */
+int
+WriteGlobal(int fd, GLOBAL * g)
+{
+ if (g)
+ return (write(fd, g->start, g->size));
+ errno = EINVAL;
+ return (-1);
+}
+
+/*
+ * Writes the document Trailer to the fd
+ */
+int
+WriteDocumentTrailer(int fd, DOCUMENT * d)
+{
+ if (d) {
+ TRAILER *t = d->trailer;
+
+ if (t)
+ return (write(fd, t->start, t->size));
+ }
+ errno = EINVAL;
+ return (-1);
+}
+
+/*
+ * Writes the document page to the fd
+ */
+int
+WritePage(int fd, PAGE * p, int global, char *bptr)
+{
+ if (p) {
+ caddr_t ptr1;
+
+ if (((ptr1 = nstrstr(p->start, PS_BEGIN_GLOBAL, bptr))
+ != NULL) && (ptr1 < p->start + p->size) &&
+ (global != 0)) {
+ /* BeginGlobal/EndGlobal in the page... */
+ write(fd, p->start, ptr1 - p->start);
+ ptr1 = nstrstr(ptr1, PS_END_GLOBAL, bptr);
+ ptr1 += nstrlen(PS_END_GLOBAL, bptr);
+ return (write(fd, ptr1, (p->size - (ptr1 - p->start))));
+ } else
+ return (write(fd, p->start, p->size));
+ }
+ errno = EINVAL;
+ return (-1);
+}
+
+/*
+ * Writes out the document pages in pageList (or all if NULL) and reverse
+ * the output if reverse == 1
+ */
+void
+WriteDocument(DOCUMENT * document, int reverse, int **pageList)
+{
+ int count = 0;
+ int prnindex;
+
+ if (document->header && document->trailer && document->page) {
+ WriteDocumentHeader(1, document);
+
+ if (document->global != NULL) {
+ while (document->global[count] != NULL) {
+ GLOBAL *global = document->global[count++];
+
+ if (global)
+ WriteGlobal(1, global);
+ }
+ }
+ count = reverse ? (document->pages-1) : 0;
+
+ for (prnindex = 0; prnindex < document->pages; prnindex++) {
+ PAGE *page = document->page[count];
+
+ if (page && PageIsListed(page->number, pageList))
+ WritePage(1, page, document->global != NULL,
+ document->start + document->size);
+
+ count = reverse ? count - 1 : count + 1;
+ }
+
+ WriteDocumentTrailer(1, document);
+ } else {
+ write(1, document->start, document->size);
+ }
+}
+
+/*
+ * get a document header from document and return a pointer to a HEADER
+ * structure.
+ */
+HEADER *
+DocumentHeader(DOCUMENT * document)
+{
+ HEADER *header;
+ caddr_t start;
+
+ header = (HEADER *) nmalloc(sizeof (*header));
+ memset(header, 0, sizeof (*header));
+ if (start = nstrstr(document->start, PS_PAGE,
+ document->start + document->size)) {
+ header->label = "Document Header";
+ header->start = document->start;
+ header->size = (start - document->start + 1);
+ } else {
+ free(header);
+ header = NULL;
+ }
+ return (header);
+}
+
+
+/*
+ * get a document trailer from document and return a pointer to a trailer
+ * structure.
+ */
+TRAILER *
+DocumentTrailer(DOCUMENT * document)
+{
+ TRAILER *trailer;
+
+ trailer = (TRAILER *) nmalloc(sizeof (*trailer));
+ memset(trailer, 0, sizeof (trailer));
+ if (trailer->start = strrstr(document->start, PS_TRAILER,
+ document->start + document->size)) {
+ trailer->label = "Document Trailer";
+ trailer->start += 1;
+ trailer->size = nstrlen(trailer->start,
+ document->start + document->size);
+ } else {
+ free(trailer);
+ trailer = NULL;
+ }
+ return (trailer);
+}
+
+GLOBAL **
+DocumentGlobals(DOCUMENT * document)
+{
+ GLOBAL **globals = NULL, *global;
+ caddr_t start, ptr1;
+ int count = 0;
+ char *bptr = document->start + document->size;
+ long allocated_slots = 0;
+ caddr_t global_end;
+
+ start = nstrstr(document->start, PS_PAGE, bptr);
+ if (start != NULL) {
+ for (ptr1 = nstrstr(start, PS_BEGIN_GLOBAL, bptr); ptr1 != NULL;
+ ptr1 = nstrstr(++ptr1, PS_BEGIN_GLOBAL, bptr)) {
+ count++;
+
+ global = (GLOBAL *) nmalloc(sizeof (GLOBAL));
+ if ((global_end = nstrstr(++ptr1, PS_END_GLOBAL, bptr))
+ == NULL) {
+ fprintf(stderr,
+ "DSC violation: %%%%BeginGlobal "
+ "with no %%%%EndGlobal\n");
+ exit(-1);
+ }
+ memset(global, 0, sizeof (GLOBAL));
+ global->start = ptr1;
+ global->size = strchr(++global_end, '\n') - ptr1 + 1;
+
+ if (count > allocated_slots) {
+ globals = (GLOBAL **) nrealloc(globals,
+ (allocated_slots + BLOCKSIZE) *
+ sizeof (GLOBAL *));
+ memset(globals +
+ allocated_slots * sizeof (GLOBAL *), 0,
+ BLOCKSIZE *
+ sizeof (GLOBAL *));
+ allocated_slots += BLOCKSIZE;
+ }
+
+ globals[count - 1] = global;
+ ptr1 = global->start + global->size;
+ }
+ }
+ return (globals);
+}
+
+
+/*
+ * get the pages from a document and return a pointer a list of PAGE
+ * structures.
+ */
+PAGE **
+DocumentPages(DOCUMENT * document)
+{
+ PAGE **pages = NULL, *page;
+ caddr_t ptr1, page_end;
+ char *bptr = document->start + document->size;
+ long allocated_slots = 0;
+ long no_pages = 0;
+ long number;
+ char *label, *tmp, *tmp_end;
+
+ for (ptr1 = nstrstr(document->start, PS_PAGE, bptr); ptr1 != NULL;
+ ptr1 = nstrstr(++ptr1, PS_PAGE, bptr)) {
+ no_pages++;
+
+ if (no_pages > allocated_slots) {
+ pages = (PAGE **) nrealloc(pages,
+ (allocated_slots + BLOCKSIZE) * sizeof (PAGE *));
+ memset(pages + allocated_slots, 0,
+ BLOCKSIZE * sizeof (PAGE *));
+ allocated_slots += BLOCKSIZE;
+ }
+ page = (PAGE *) nmalloc(sizeof (PAGE));
+ label = NULL;
+ number = -1;
+
+ /* page start & end */
+ if ((page_end = nstrstr(++ptr1, PS_PAGE, bptr)) == NULL)
+ if (document->trailer)
+ page_end = document->trailer->start - 1;
+ else
+ page_end = document->start + document->size;
+
+ /* page label & number */
+ if (tmp = strchr(ptr1, ' ')) {
+
+ if (tmp_end = strchr(++tmp, ' ')) {
+ label = (char *)nmalloc((tmp_end - tmp) + 1);
+ memset(label, 0, (tmp_end - tmp) + 1);
+ strncpy(label, tmp, (tmp_end - tmp));
+ number = atol(++tmp_end);
+ }
+ }
+ memset(page, 0, sizeof (PAGE));
+ page->label = label;
+ page->number = number;
+ page->start = ptr1;
+ page->size = page_end - ptr1 + 1;
+
+ pages[document->pages++] = page;
+ }
+ return (pages);
+}
+
+/*
+ * parse a document and return a pointer to a DOCUMENT structure
+ */
+DOCUMENT *
+DocumentParse(char *name)
+{
+ DOCUMENT *document = NULL;
+ int fd;
+ struct stat st;
+
+ if (stat(name, &st) < 0) {
+ fprintf(stderr, "stat(%s): %s\n", name, strerror(errno));
+ return (NULL);
+ }
+ if (st.st_size == 0) {
+ fprintf(stderr, "%s: empty file\n", name);
+ return (NULL);
+ }
+ if ((fd = open(name, O_RDONLY)) < 0) {
+ fprintf(stderr, "open(%s, O_RDONLY): %s\n", name,
+ strerror(errno));
+ return (NULL);
+ }
+ document = (DOCUMENT *) nmalloc(sizeof (DOCUMENT));
+ memset(document, 0, sizeof (DOCUMENT));
+ if ((document->start = mmap((void *)0, (size_t)st.st_size, PROT_READ,
+ MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) {
+ fprintf(stderr, "mmap(0, %ld, PROT_READ,"
+ " MAP_SHARED, %d, 0): %s\n",
+ st.st_size, fd, strerror(errno));
+ free(document);
+ document = NULL;
+ } else {
+ /* order in important */
+ document->name = strdup(name);
+ document->size = nstrlen(document->start,
+ document->start + st.st_size);
+ document->header = DocumentHeader(document);
+ document->trailer = DocumentTrailer(document);
+ document->page = DocumentPages(document);
+ document->global = DocumentGlobals(document);
+ }
+ close(fd);
+ return (document);
+}
+
+
+#if defined(DEBUG)
+/*
+ * Print out the contents of the document structure
+ */
+void
+PrintDocumentInfo(DOCUMENT * d)
+{
+ if (d) {
+ printf("Document:\n\tname: %s\n\tstart: 0x%x\n\tsize: %ld\n",
+ d->name, d->start, d->size);
+ if (d->header) {
+ HEADER *h = d->header;
+
+ printf("\tHeader: %s (0x%x, %ld)\n",
+ h->label, h->start, h->size);
+ }
+ if (d->global) {
+ int count = 0;
+
+ while (d->global[count++] != NULL);
+ printf("\tDSC violating BeginGlobals: %d\n", count);
+ }
+ if (d->page) {
+ PAGE *p;
+ int count = 0;
+
+ printf("\tPages: (%d)\n", d->pages);
+ for (p = d->page[0]; p != NULL; p = d->page[++count])
+ printf("\t\t %4d (%s) - (0x%x, %ld)\n",
+ p->number,
+ (p->label ? p->label : "Page"),
+ p->start, p->size);
+ }
+ if (d->trailer) {
+ TRAILER *t = d->trailer;
+
+ printf("\tTrailer: %s (0x%x, %ld)\n",
+ t->label, t->start, t->size);
+ }
+ }
+}
+#endif /* DEBUG */
+
+
+int
+main(int ac, char *av[])
+{
+ DOCUMENT *document;
+ char *fileName = NULL;
+ char *programName = NULL;
+ char *unlinkFile = NULL;
+ int reversePages = 1;
+ int **pageList = NULL;
+ int option;
+
+ if (programName = strrchr(av[0], '/'))
+ programName++;
+ else
+ programName = av[0];
+
+ while ((option = getopt(ac, av, "o:r")) != EOF)
+ switch (option) {
+ case 'o':
+ pageList = ParsePageList(optarg);
+ break;
+ case 'r':
+ reversePages = 0;
+ break;
+ case '?':
+ Usage(programName);
+ break;
+ default:
+ fprintf(stderr, "missing case for option %c\n", option);
+ Usage(programName);
+ break;
+ }
+
+ ac -= optind;
+ av += optind;
+
+ switch (ac) {
+ case 0:
+ unlinkFile = fileName = StdinToFile();
+ break;
+ case 1:
+ fileName = av[0];
+ break;
+ default:
+ Usage(programName);
+ }
+
+ if ((document = DocumentParse(fileName)) == NULL) {
+ fprintf(stderr, "Unable to parse document (%s)\n", fileName);
+ exit(0);
+ }
+#if defined(DEBUG) && defined(NOTDEF)
+ PrintDocumentInfo(document);
+#endif /* DEBUG */
+
+ WriteDocument(document, reversePages, pageList);
+
+ if (unlinkFile)
+ unlink(unlinkFile);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/filter/postscript/postreverse/postreverse.h b/usr/src/cmd/lp/filter/postscript/postreverse/postreverse.h
new file mode 100644
index 0000000000..e467140334
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postreverse/postreverse.h
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1993-2001 by Sun Microsystems, Inc.
+ * All Rights Reserved
+ */
+
+#ident "%Z%%M% %I% %E% SMI"
+
+/**
+ * Structures and definitions needed for PostScript page manipulation
+ **/
+#if !defined(_POSTREVERSE_H)
+#define _POSTREVERSE_H
+
+/* PS DSC comments of interest */
+#define PS_PAGE "\n%%Page:"
+#define PS_TRAILER "\n%%Trailer"
+#define PS_BEGIN_GLOBAL "\n%%BeginGlobal"
+#define PS_END_GLOBAL "\n%%EndGlobal"
+
+#define BLOCKSIZE 10
+
+struct _global {
+ caddr_t start;
+ size_t size;
+};
+typedef struct _global GLOBAL;
+
+struct _page {
+ unsigned int number;
+ char *label;
+ caddr_t start;
+ size_t size;
+};
+typedef struct _page PAGE;
+
+struct _header {
+ char *label;
+ caddr_t start;
+ size_t size;
+};
+typedef struct _header HEADER;
+
+struct _trailer {
+ char *label;
+ caddr_t start;
+ size_t size;
+};
+typedef struct _trailer TRAILER;
+
+struct _document {
+ char *name;
+ caddr_t start;
+ size_t size;
+ HEADER *header;
+ PAGE **page;
+ GLOBAL **global;
+ long pages;
+ TRAILER *trailer;
+};
+typedef struct _document DOCUMENT;
+
+#endif /* _POSTREVERSE_H */
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/Makefile b/usr/src/cmd/lp/filter/postscript/postscript/Makefile
new file mode 100644
index 0000000000..89e914697d
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/Makefile
@@ -0,0 +1,58 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/filter/postscript/postscript/Makefile
+#
+
+include ../../../Makefile.lp
+
+COMMONDIR= ../common
+
+TXTFILES = README
+
+FILES = \
+ aps.ps \
+ banner.ps \
+ baseline.ps \
+ color.ps \
+ dpost.ps \
+ draw.ps \
+ fatcourier.ps \
+ forms.ps \
+ postprint.ps \
+ ps.requests \
+ tsol_banner.ps \
+ tsol_separator.ps \
+ tsol_trailer.ps
+
+ROOTPOSTFILES= $(FILES:%=$(ROOTLIBLPPOST)/%)
+
+.KEEP_STATE:
+
+all: $(TXTFILES) $(FILES)
+
+install: all $(ROOTPOSTFILES)
+
+clean clobber strip lint catalog:
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/README b/usr/src/cmd/lp/filter/postscript/postscript/README
new file mode 100644
index 0000000000..ff9b3b2474
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/README
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Prologues and a few other PostScript files that are copied to /usr/lib/postscript
+(ie. LIBDIR in ../Makefile) when you do an install.
+
+Default settings have been moved to these files. All can be changed without
+requiring a recompilation of any programs supplied with this package. In
+addition all the translators understand the -P option that lets you pass
+arbitrary PostScript through to the output file. The option can be useful if
+you want to change parameters that are defined in the prologue but not tied to
+specific command line options.
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/aps.ps b/usr/src/cmd/lp/filter/postscript/postscript/aps.ps
new file mode 100644
index 0000000000..56bc76c68a
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/aps.ps
@@ -0,0 +1,149 @@
+%ident "@(#)lp:filter/postscript/postscript/aps.ps 1.1"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Tune things up so Linotronic output looks more like the APS-5. Pull this file
+% into dpost output using the -C option. To get the best looking output run dpost
+% with the -e2 option and use special font files that look like the APS tables but
+% have character codes (ie. the fourth column in the width tables) appropriate for
+% PostScript fonts. Widths in these tables must be for APS fonts!
+%
+% Start with fat versions of the stroked Courier and Courier-Oblique fonts - from
+% Johnathan Shopiro.
+%
+
+/newdict /Courier findfont length dict def
+/Courier findfont {
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+newdict /StrokeWidth 65 put
+/Courier newdict definefont pop
+
+/newdict /Courier-Oblique findfont length dict def
+/Courier-Oblique findfont {
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+newdict /StrokeWidth 65 put
+/Courier-Oblique newdict definefont pop
+
+%
+% Scaled down versions of the Helvetica font family.
+%
+
+/newdict /Helvetica findfont length dict def
+/Helvetica findfont {
+ 1 index /FontMatrix eq {.922 .922 matrix scale matrix concatmatrix} if
+
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+/Helvetica newdict definefont pop
+
+/newdict /Helvetica-Oblique findfont length dict def
+/Helvetica-Oblique findfont {
+ 1 index /FontMatrix eq {.922 .922 matrix scale matrix concatmatrix} if
+
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+/Helvetica-Oblique newdict definefont pop
+
+/newdict /Helvetica-Bold findfont length dict def
+/Helvetica-Bold findfont {
+ 1 index /FontMatrix eq {.922 .922 matrix scale matrix concatmatrix} if
+
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+/Helvetica-Bold newdict definefont pop
+
+/newdict /Helvetica-BoldOblique findfont length dict def
+/Helvetica-BoldOblique findfont {
+ 1 index /FontMatrix eq {.922 .922 matrix scale matrix concatmatrix} if
+
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+/Helvetica-BoldOblique newdict definefont pop
+
+%
+% Scaled up versions of the Times font family.
+%
+
+/newdict /Times-Roman findfont length dict def
+/Times-Roman findfont {
+ 1 index /FontMatrix eq {1.0225 1.0225 matrix scale matrix concatmatrix} if
+
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+/Times-Roman newdict definefont pop
+
+/newdict /Times-Italic findfont length dict def
+/Times-Italic findfont {
+ 1 index /FontMatrix eq {1.0225 1.0225 matrix scale matrix concatmatrix} if
+
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+/Times-Italic newdict definefont pop
+
+/newdict /Times-Bold findfont length dict def
+/Times-Bold findfont {
+ 1 index /FontMatrix eq {1.0225 1.0225 matrix scale matrix concatmatrix} if
+
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+/Times-Bold newdict definefont pop
+
+/newdict /Times-BoldItalic findfont length dict def
+/Times-BoldItalic findfont {
+ 1 index /FontMatrix eq {1.0225 1.0225 matrix scale matrix concatmatrix} if
+
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+/Times-BoldItalic newdict definefont pop
+
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/banner.ps b/usr/src/cmd/lp/filter/postscript/postscript/banner.ps
new file mode 100644
index 0000000000..27239cca56
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/banner.ps
@@ -0,0 +1,64 @@
+%ident "@(#)lp:filter/postscript/postscript/banner.ps 1.1"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Simple program to print a banner page
+%
+% 04/19/91:
+% Modified to be more compatable with how other LP
+% banner pages look.
+%
+
+/banner {
+ /saveobj save def
+ erasepage initgraphics
+
+ /#copies 1 def
+ /inch {72 mul} bind def
+ /pagebbox [clippath pathbbox newpath] def
+
+ /font /Helvetica def
+ /size 20 def
+ /height pagebbox 3 get def
+ /width pagebbox 2 get .09 mul def
+
+ .92 setgray
+ pagebbox 0 get pagebbox 1 get moveto
+ width 0 rlineto 0 height rlineto width neg 0 rlineto closepath eofill
+ pagebbox 2 get pagebbox 1 get moveto
+ width neg 0 rlineto 0 height rlineto width 0 rlineto closepath eofill
+ 0 setgray
+
+ font findfont size scalefont setfont
+ /linesp size size .15 mul add neg def
+ /tab (Destination) stringwidth pop 1.5 mul def
+ /nextline {0 0 moveto show tab 0 moveto show 0 linesp translate} def
+
+ pagebbox 0 get 1.5 width mul add pagebbox 3 get 2.0 width mul sub translate
+ (Owner:) nextline
+ (Originator:) nextline
+ (Title:) nextline
+ (Job-Id:) nextline
+ (Printed:) nextline
+ showpage
+ saveobj restore
+} bind def
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/baseline.ps b/usr/src/cmd/lp/filter/postscript/postscript/baseline.ps
new file mode 100644
index 0000000000..f3020c9a43
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/baseline.ps
@@ -0,0 +1,178 @@
+%ident "@(#)lp:filter/postscript/postscript/baseline.ps 1.1"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Stuff used to draw or set text along a baseline specified by parametric equations
+% for x and y.
+%
+
+/left -1 def
+/center 0 def
+/right 1 def
+
+/baselinedict 50 dict def
+
+/newbaseline {
+ baselinedict begin
+ /g' exch bind def
+ /f' exch bind def
+ /g exch bind def
+ /f exch bind def
+
+ counttomark 2 eq {/hoffset exch def} if
+ /res exch def
+
+ /t 0 def
+ /s 0 def
+ /voffset false def
+ cleartomark
+ end
+} bind def
+
+/drawfunnytext {
+ baselinedict begin
+ /t exch def
+ /mode exch def
+ /str exch def
+
+ mode left eq {
+ /leftstring emptystring def
+ /rightstring str def
+ } if
+
+ mode right eq {
+ /leftstring str reversestring def
+ /rightstring emptystring def
+ } if
+
+ mode center eq {
+ str splitstring
+ /rightstring exch def
+ /leftstring exch reversestring def
+ } if
+
+ gsave currentpoint translate leftstring left t baselineshow grestore
+ gsave currentpoint translate rightstring right t baselineshow grestore
+
+ /t 0 def
+ /s 0 def
+ /voffset false def
+ cleartomark
+ end
+} bind def
+
+/setfunnytext {
+ baselinedict begin
+ /vpos exch def
+ /hpos exch def
+ /str exch def
+
+ voffset vpos ne {
+ /voffset vpos def
+ /t 0 def
+ /s hoffset def
+ } if
+
+ gsave
+ hoffset voffset translate
+ 0 0 moveto
+ /ds hpos s sub def
+ /dt ds t f' dup mul t g' dup mul add sqrt res mul div def
+ /s s ds add def
+ /t t dt add def
+ str right t baselineshow
+ grestore
+ end
+} bind def
+
+baselinedict begin
+
+/f {} bind def
+/g {pop 0} bind def
+/f' {pop 1} bind def
+/g' {pop 0} bind def
+
+/s 0 def
+/t 0 def
+/res 72 def
+
+/onecharstring ( ) def
+/emptystring () def
+
+/baselineshow {
+ /t exch def
+ /mode exch def
+ /str exch def
+
+ gsave
+ t f res mul t g res mul translate
+ 0 0 moveto
+ t g' t f' atan rotate
+ {
+ mode right eq {pop} if
+ grestore gsave
+ onecharstring 0 3 -1 roll put onecharstring stringwidth pop
+ /ds exch mode mul def
+ /dt ds t f' dup mul t g' dup mul add sqrt res mul div def
+ /t t dt add def
+ /s s ds add def
+ t f res mul t g res mul translate
+ 0 0 moveto
+ t g' t f' atan rotate
+ mode left eq {pop} if
+ } str kshow
+ grestore
+} bind def
+
+/reversestring {
+ /str1 exch def
+
+ /str2 str1 length string def
+ /i 0 def
+ /n str1 length 1 sub def
+
+ {
+ str1 n get str2 exch i exch put
+ /i i 1 add def
+ /n n 1 sub def
+ n 0 lt {exit} if
+ } loop
+ str2
+} bind def
+
+/splitstring {
+ /str1 exch def
+
+ /len str1 stringwidth pop def
+ /s 0 def
+ /n 0 def
+ str1 length {
+ str1 n get onecharstring exch 0 exch put
+ /s onecharstring stringwidth pop s add def
+ s len 2 div ge {exit} if
+ /n n 1 add def
+ } repeat
+ str1 0 n 1 add getinterval
+ str1 n str1 length n sub getinterval
+} bind def
+
+end
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/color.ps b/usr/src/cmd/lp/filter/postscript/postscript/color.ps
new file mode 100644
index 0000000000..a4ae8a82f0
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/color.ps
@@ -0,0 +1,87 @@
+%ident "@(#)lp:filter/postscript/postscript/color.ps 1.1"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Color and reverse video support for dpost. A call made to setcolor with two
+% arguments implies reverse video printing.
+%
+
+/rgb {setrgbcolor} bind def
+/hsb {sethsbcolor} bind def
+
+/colordict 50 dict dup begin
+ /red { 1 0 0 } def
+ /green { 0 1 0 } def
+ /blue { 0 0 1 } def
+ /cyan { 0 1 1 } def
+ /magenta { 1 0 1 } def
+ /yellow { 1 1 0 } def
+ /white { 1 1 1 } def
+ /black { 0 0 0 } def
+end def
+
+/setcolor {
+ counttomark 1 eq {
+ dup colordict exch known not {pop /black} if
+ colordict exch get exec setrgbcolor
+ } if
+ counttomark 2 eq {
+ /backcolor exch def
+ /textcolor exch def
+ colordict backcolor known not colordict textcolor known not or {
+ /backcolor colordict /black get def
+ /textcolor colordict /white get def
+ } if
+ /backcolor colordict backcolor get def
+ /textcolor colordict textcolor get def
+ /dY1 0 def
+ /dY2 0 def
+ textcolor exec setrgbcolor
+ } if
+} bind def
+
+/drawrvbox {
+ /x2 exch def
+ /x1 exch def
+
+ currentpoint dup
+ /y1 exch def
+ /y2 exch def pop
+
+ dY1 0 eq dY2 0 eq and {
+ currentfont /FontBBox get aload pop
+ currentfont /FontMatrix get dtransform /dY2 exch def pop
+ currentfont /FontMatrix get dtransform /dY1 exch def pop
+ } if
+
+ /y1 y1 dY1 add def
+ /y2 y2 dY2 add def
+
+ backcolor exec setrgbcolor
+ newpath
+ x1 y1 moveto
+ x2 y1 lineto
+ x2 y2 lineto
+ x1 y2 lineto
+ closepath fill
+ textcolor exec setrgbcolor
+} bind def
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/dpost.ps b/usr/src/cmd/lp/filter/postscript/postscript/dpost.ps
new file mode 100644
index 0000000000..9e1bd70514
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/dpost.ps
@@ -0,0 +1,223 @@
+%
+% Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+% Use is subject to license terms.
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%ident "%Z%%M% %I% %E% SMI"
+%
+% Version 3.16 prologue for troff files.
+%
+
+/#copies 1 store
+/aspectratio 1 def
+/formsperpage 1 def
+/landscape false def
+/linewidth .3 def
+/magnification 1 def
+/margin 0 def
+/orientation 0 def
+/resolution 720 def
+/xoffset 0 def
+/yoffset 0 def
+
+/roundpage true def
+/useclippath true def
+/pagebbox [0 0 612 792] def
+
+/R /Times-Roman def
+/I /Times-Italic def
+/B /Times-Bold def
+/BI /Times-BoldItalic def
+/H /Helvetica def
+/HI /Helvetica-Oblique def
+/HB /Helvetica-Bold def
+/HX /Helvetica-BoldOblique def
+/CW /Courier def
+/CO /Courier def
+/CI /Courier-Oblique def
+/CB /Courier-Bold def
+/CX /Courier-BoldOblique def
+/PA /Palatino-Roman def
+/PI /Palatino-Italic def
+/PB /Palatino-Bold def
+/PX /Palatino-BoldItalic def
+/Hr /Helvetica-Narrow def
+/Hi /Helvetica-Narrow-Oblique def
+/Hb /Helvetica-Narrow-Bold def
+/Hx /Helvetica-Narrow-BoldOblique def
+/KR /Bookman-Light def
+/KI /Bookman-LightItalic def
+/KB /Bookman-Demi def
+/KX /Bookman-DemiItalic def
+/AR /AvantGarde-Book def
+/AI /AvantGarde-BookOblique def
+/AB /AvantGarde-Demi def
+/AX /AvantGarde-DemiOblique def
+/NR /NewCenturySchlbk-Roman def
+/NI /NewCenturySchlbk-Italic def
+/NB /NewCenturySchlbk-Bold def
+/NX /NewCenturySchlbk-BoldItalic def
+/ZD /ZapfDingbats def
+/ZI /ZapfChancery-MediumItalic def
+/VR /Varitimes#Roman def
+/VI /Varitimes#Italic def
+/VB /Varitimes#Bold def
+/VX /Varitimes#BoldItalic def
+/S /S def
+/S1 /S1 def
+/GR /Symbol def
+
+/inch {72 mul} bind def
+/min {2 copy gt {exch} if pop} bind def
+
+/setup {
+ counttomark 2 idiv {def} repeat pop
+
+ landscape {/orientation 90 orientation add def} if
+ /scaling 72 resolution div def
+ linewidth setlinewidth
+ 1 setlinecap
+
+ pagedimensions
+ xcenter ycenter translate
+ orientation neg rotate
+ width 2 div neg height 2 div translate
+ xoffset inch yoffset inch translate
+ margin 2 div dup neg translate
+ magnification dup aspectratio mul scale
+ scaling scaling scale
+
+ /Symbol /S Sdefs cf
+ /Times-Roman /S1 S1defs cf
+ 0 0 moveto
+} def
+
+/pagedimensions {
+ useclippath userdict /gotpagebbox known not and {
+ /pagebbox [clippath pathbbox newpath] def
+ roundpage currentdict /roundpagebbox known and {roundpagebbox} if
+ } if
+ pagebbox aload pop
+ 4 -1 roll exch 4 1 roll 4 copy
+ landscape {4 2 roll} if
+ sub /width exch def
+ sub /height exch def
+ add 2 div /xcenter exch def
+ add 2 div /ycenter exch def
+ userdict /gotpagebbox true put
+} def
+
+/pagesetup {
+ /page exch def
+ currentdict /pagedict known currentdict page known and {
+ page load pagedict exch get cvx exec
+ } if
+} def
+
+/decodingdefs [
+ {counttomark 2 idiv {y moveto show} repeat}
+ {neg /y exch def counttomark 2 idiv {y moveto show} repeat}
+ {neg moveto {2 index stringwidth pop sub exch div 0 32 4 -1 roll widthshow} repeat}
+ {neg moveto {spacewidth sub 0.0 32 4 -1 roll widthshow} repeat}
+ {counttomark 2 idiv {y moveto show} repeat}
+ {neg setfunnytext}
+] def
+
+/setdecoding {/t decodingdefs 3 -1 roll get bind def} bind def
+
+/w {neg moveto show} bind def
+/m {neg dup /y exch def moveto} bind def
+/done {/lastpage where {pop lastpage} if} def
+
+/f {
+ dup /font exch def findfont exch
+ dup /ptsize exch def scaling div dup /size exch def scalefont setfont
+ linewidth ptsize mul scaling 10 mul div setlinewidth
+ /spacewidth ( ) stringwidth pop def
+} bind def
+
+/changefont {
+ /fontheight exch def
+ /fontslant exch def
+ currentfont [
+ 1 0
+ fontheight ptsize div fontslant sin mul fontslant cos div
+ fontheight ptsize div
+ 0 0
+ ] makefont setfont
+} bind def
+
+/sf {f} bind def
+
+/cf {
+ dup length 2 idiv
+ /entries exch def
+ /chtab exch def
+ /newfont exch def
+
+ findfont dup length 1 add dict
+ /newdict exch def
+ {1 index /FID ne {newdict 3 1 roll put} {pop pop} ifelse} forall
+
+ newdict /Metrics entries dict put
+ newdict /Metrics get
+ begin
+ chtab aload pop
+ 1 1 entries {pop def} for
+ newfont newdict definefont pop
+ end
+} bind def
+
+%
+% A few arrays used to adjust reference points and character widths in some
+% of the printer resident fonts. If square roots are too high try changing
+% the lines describing /radical and /radicalex to,
+%
+% /radical [0 -75 550 0]
+% /radicalex [-50 -75 500 0]
+%
+
+/Sdefs [
+ /bracketlefttp [220 500]
+ /bracketleftbt [220 500]
+ /bracketrighttp [-70 380]
+ /bracketrightbt [-70 380]
+ /braceleftbt [220 490]
+ /bracketrightex [220 -125 500 0]
+ /radical [0 0 550 0]
+ % NeWSprint's \(br is too low, compensate
+ statusdict /product get (NeWS Server) eq {
+ /radicalex [-50 100 500 0]
+ /parenleftex [-20 100 0 0]
+
+ } {
+ /radicalex [-50 0 500 0]
+ /parenleftex [-20 -170 0 0]
+ } ifelse
+ /integral [100 -50 500 0]
+ /infinity [10 -75 730 0]
+] def
+
+/S1defs [
+ /underscore [0 80 500 0]
+ /endash [7 90 650 0]
+] def
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/draw.ps b/usr/src/cmd/lp/filter/postscript/postscript/draw.ps
new file mode 100644
index 0000000000..4208567485
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/draw.ps
@@ -0,0 +1,97 @@
+%ident "@(#)lp:filter/postscript/postscript/draw.ps 1.1"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Version 3.15 drawing procedures for dpost. Automatically pulled in, but only
+% when needed.
+%
+
+/inpath false def
+/savematrix matrix currentmatrix def
+
+/Dl {
+ inpath
+ {pop pop neg lineto}
+ {newpath neg moveto neg lineto stroke}
+ ifelse
+} bind def
+
+/De {
+ /y1 exch 2 div def
+ /x1 exch 2 div def
+ neg exch x1 add exch translate
+ x1 y1 scale
+ 0 0 1 0 360
+ inpath
+ {1 0 moveto arc savematrix setmatrix}
+ {newpath arc savematrix setmatrix stroke}
+ ifelse
+} bind def
+
+/Da {
+ /dy2 exch def
+ /dx2 exch def
+ /dy1 exch def
+ /dx1 exch def
+ dy1 add neg exch dx1 add exch
+ dx1 dx1 mul dy1 dy1 mul add sqrt
+ dy1 dx1 neg atan
+ dy2 neg dx2 atan
+ inpath
+ {arc}
+ {newpath arc stroke}
+ ifelse
+} bind def
+
+/DA {
+ /dy2 exch def
+ /dx2 exch def
+ /dy1 exch def
+ /dx1 exch def
+ dy1 add neg exch dx1 add exch
+ dx1 dx1 mul dy1 dy1 mul add sqrt
+ dy1 dx1 neg atan
+ dy2 neg dx2 atan
+ inpath
+ {arcn}
+ {newpath arcn stroke}
+ ifelse
+} bind def
+
+/Ds {
+ /y2 exch def
+ /x2 exch def
+ /y1 exch def
+ /x1 exch def
+ /y0 exch def
+ /x0 exch def
+ x0 5 x1 mul add 6 div
+ y0 5 y1 mul add -6 div
+ x2 5 x1 mul add 6 div
+ y2 5 y1 mul add -6 div
+ x1 x2 add 2 div
+ y1 y2 add -2 div
+ inpath
+ {curveto}
+ {newpath x0 x1 add 2 div y0 y1 add -2 div moveto curveto stroke}
+ ifelse
+} bind def
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/fatcourier.ps b/usr/src/cmd/lp/filter/postscript/postscript/fatcourier.ps
new file mode 100644
index 0000000000..a0093d4e97
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/fatcourier.ps
@@ -0,0 +1,48 @@
+%ident "@(#)lp:filter/postscript/postscript/fatcourier.ps 1.1"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Fat versions of the stroked Courier and Courier-Oblique - from Johnathan Shopiro.
+% Can be selectively pulled in using the -C option that's available with all the
+% PostScript translators or permanently added to any of the prologues. Helps on
+% Linotronic typesetters, where Courier and Courier-Oblique are too light!
+%
+
+/newdict /Courier findfont length dict def
+/Courier findfont {
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+newdict /StrokeWidth 60 put
+/Courier newdict definefont pop
+
+/newdict /Courier-Oblique findfont length dict def
+/Courier-Oblique findfont {
+ 1 index /FID ne
+ {newdict 3 1 roll put}
+ {pop pop}
+ ifelse
+} forall
+newdict /StrokeWidth 60 put
+/Courier-Oblique newdict definefont pop
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/forms.ps b/usr/src/cmd/lp/filter/postscript/postscript/forms.ps
new file mode 100644
index 0000000000..d19e073620
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/forms.ps
@@ -0,0 +1,218 @@
+%ident "@(#)lp:filter/postscript/postscript/forms.ps 1.1"
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Procedures that let you print any number of pages on each sheet of paper. It's
+% far from perfect and won't handle everything (eg. it's not recursive), but should
+% be good enough for now. Assumes the default page coordinate system has been set
+% up before setupforms is called. lastpage makes certain the last page is printed,
+% and should be called immediately after the %%Trailer comment.
+%
+% Three lines of code needed for page image clipping have been commented out for
+% now. It works, but can really slow things down on some versions of PostScript.
+% Uncomment them if you want to clip pages.
+%
+
+/setupforms {
+ /formsperpage exch def
+
+ /currentform 0 def
+ /slop 5 def
+ /min {2 copy gt {exch} if pop} def
+
+%
+% Save the current environment. Needed because showpage will be redefined. Will be
+% restored in lastpage.
+%
+
+ save
+
+%
+% Number of rows and columns we'll need - may exchange them later.
+%
+
+ /columns formsperpage sqrt ceiling cvi def
+ /rows formsperpage columns div ceiling cvi def
+
+%
+% Slop leaves a little room around the edge so page images can be outlined and have
+% the borders show up. Distance is in default coordinates, so we need to figure out
+% how it maps into user coordinates.
+%
+
+ 6 array defaultmatrix
+ 6 array currentmatrix
+ 6 array invertmatrix
+ 6 array concatmatrix
+ /tempmatrix exch def
+
+ 0 slop tempmatrix dtransform dup mul exch dup mul add sqrt
+ /slop exch def
+
+%
+% Determine how big the image area is, using the clipping path bounding box minus
+% a little and leave the coordinates of the lower left corner of the clipping path
+% on the stack. Also temporarily set the size of each page (ie. formheight and
+% formwidth) from the clipping path - just in case old software uses this stuff.
+% Only works for coordinate systems that have been rotated by a multiple of 90
+% degrees.
+%
+
+ newpath clippath pathbbox
+ 2 index sub dup /formheight exch def slop 2 mul sub /pageheight exch def
+ 2 index sub dup /formwidth exch def slop 2 mul sub /pagewidth exch def
+
+%
+% New translators all store the size of each page in default coordinates in the
+% pagebbox array and it can be different than the size determined by the clipping
+% path. If we can find pagebbox use it to set the real dimensions of each page.
+% Leaves the coordinates of the lower left corner on the stack, (either from
+% pagebbox or clippath) so four numbers are there when we're done.
+%
+
+ userdict /gotpagebbox known userdict /pagebbox known and {
+ newpath
+ pagebbox 0 get pagebbox 1 get tempmatrix transform moveto
+ pagebbox 0 get pagebbox 3 get tempmatrix transform lineto
+ pagebbox 2 get pagebbox 3 get tempmatrix transform lineto
+ pagebbox 2 get pagebbox 1 get tempmatrix transform lineto
+ closepath pathbbox
+ 2 index sub /formheight exch def
+ 2 index sub /formwidth exch def
+ } {2 copy} ifelse
+
+%
+% Top two numbers are the displacement from the job's origin to the lower left
+% corner of each page image when we finish setting up the new coordinate system.
+%
+
+ /ycorner exch def
+ /xcorner exch def
+
+%
+% The two numbers left on the stack are the coordinates of the lower left corner
+% of the clipping path. Go there and then up a bit so page images can be outlined.
+%
+
+ translate
+ slop slop translate
+
+%
+% If the page is wider than high we may be able to do better if we exchange rows
+% and columns. Won't make a difference in the current orientation or if rows and
+% columns are the same.
+%
+
+ pagewidth pageheight gt {
+ rows columns /rows exch def /columns exch def
+ } if
+
+%
+% Find the orientation and scaling that makes things as large as possible. More
+% than what's really needed. First calculation essentially finds the minimum of
+% 1/rows and 1/columns.
+%
+
+ pagewidth formwidth columns mul div pageheight formheight rows mul div min
+ pageheight formwidth columns mul div pagewidth formheight rows mul div min
+
+ 2 copy lt {
+ pagewidth pageheight /pagewidth exch def /pageheight exch def
+ -90 rotate
+ pagewidth neg 0 translate
+ exch
+ } if
+
+%
+% Second number from the top is the best choice. Scale so everything will fit on
+% the current page, go back to the original origin, and then get ready for the
+% first page - which goes in the upper left corner.
+%
+
+ pop dup dup scale
+ xcorner neg ycorner neg translate
+ 0 rows 1 sub formheight mul translate
+
+%
+% Try to center everything on the page - scaling we used is on top of the stack.
+%
+
+ dup pagewidth exch div formwidth columns mul sub 2 div
+ exch pageheight exch div formheight rows mul sub 2 div translate
+
+%
+% Redefine showpage. Assumes a save object is on top of the stack (we put another
+% one there later).
+%
+
+ /showpage {
+ restore
+% initclip
+ formsperpage 1 gt {
+ gsave .1 setlinewidth outlineform stroke grestore
+ } if
+ formwidth 0 translate
+ /currentform currentform 1 add def
+ currentform columns mod 0 eq {
+ columns formwidth mul neg formheight neg translate
+ } if
+ currentform formsperpage mod 0 eq {
+ gsave showpage grestore
+ currentform columns mod formwidth mul neg
+ formsperpage columns idiv formheight mul translate
+ /currentform 0 def
+ } if
+% outlineform clip newpath
+ save
+ } bind def
+
+ /outlineform {
+ newpath
+ xcorner ycorner moveto
+ formwidth 0 rlineto
+ 0 formheight rlineto
+ formwidth neg 0 rlineto
+ closepath
+ } bind def
+
+ /lastpage {
+ formsperpage 1 gt {
+ currentform 0 ne {
+ save
+ 0 1 formsperpage currentform sub formsperpage mod {
+ pop showpage
+ } for
+ restore
+ } if
+ pop restore
+ } if
+ } def
+
+%
+% Clip the first page image and save the environment we just set up, including
+% the redefined showpage.
+%
+
+% outlineform clip
+ newpath
+ save
+} def
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/postprint.ps b/usr/src/cmd/lp/filter/postscript/postscript/postprint.ps
new file mode 100644
index 0000000000..438b7180a1
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/postprint.ps
@@ -0,0 +1,437 @@
+%
+% Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+% Use is subject to license terms.
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+% Use is subject to license terms
+%
+%ident "%Z%%M% %I% %E% SMI"
+%
+
+/add-euro-to-font {
+ /new-font exch def
+ /old-font exch def
+
+ % Begin Euro Font: A single character "Euro" font
+ 10 dict begin
+ /FontType 3 def
+ /FontMatrix [.00060 0 0 .00060 0 0] def
+ /FontBBox [0 0 1000 1000] def
+
+ /Encoding [ /Euro ] def
+
+ /CharProcs 2 dict def
+ CharProcs begin
+ /.notdef { } def
+ /Euro { % Draw an EUR glyph
+ gsave
+ 955.852 232.172 moveto
+ 904.495 180.815 lineto
+ 829.454 117.848 734.626 83.333 636.667 83.333 curveto
+ 406.667 83.333 220 270 220 500 curveto
+ 220 730 406.667 916.667 636.667 916.667 curveto
+ 759.831 916.667 876.684 862.177 955.852 767.828 curveto
+ 988.474 855.291 lineto
+ 894.851 947.996 768.422 1000 636.667 1000 curveto
+ 360.667 1000 136.667 776 136.667 500 curveto
+ 136.667 224 360.667 0 636.667 0 curveto
+ 753.23 0 866.13 40.725 955.852 115.135 curveto
+ closepath fill
+
+ 869.037 541.667 moveto
+ 901.025 625 lineto
+ 31.989 625 lineto
+ 0 541.667 lineto
+ closepath fill
+
+ 805.059 375 moveto
+ 837.048 458.333 lineto
+ 31.989 458.333 lineto
+ 0 375 lineto
+ closepath fill
+ grestore
+ } bind def
+ end
+
+ /BuildGlyph {
+ 1000 0
+ 0 0 1000 1000
+ setcachedevice
+ exch /CharProcs get exch
+ 2 copy known not {pop /.notdef} if
+ get exec
+ } bind def
+
+ /BuildChar {
+ 1 index /Encoding get exch get
+ 1 index /BuildGlyph get exch
+ } bind def
+
+ currentdict
+ end
+ /euro-font exch definefont pop
+ % End of Euro Font
+
+ % Begin Shifted Font: copy font, rotate encoding matrix, redefine it
+ 20 dict begin
+ old-font findfont
+ {1 index /FID ne {def} {pop pop} ifelse} forall
+ mark currentdict /Encoding get aload pop
+ counttomark dup 165 sub roll counttomark array astore
+ /Encoding exch def pop
+ currentdict
+ end
+ /new-shifted exch definefont pop
+ % End of Shifted Shifted Font
+
+ % Begin Composite Font
+ 20 dict begin
+ /FontType 0 def
+ /FontMatrix [1 0 0 1 0 0] def
+ /FontBBox [ 0 0 0 0] def
+ /WMode 0 def
+ /Encoding [0 1 2] def
+ old-font findfont /Encoding get dup /PrefEnc exch def pop
+
+ /FMapType 6 def % Use the SubsVector to figure out which one
+ /FDepVector [ old-font findfont /euro-font findfont
+ /new-shifted findfont ] def
+ /SubsVector <00 a4 01 > readonly def
+
+ currentdict
+ end
+ new-font exch definefont pop
+ % End Composite Font
+} bind def % end of adding euro to font
+
+% if (key not defined) define key=value in current dictionary
+/ifndef { % key value
+ 1 index where { pop pop } { def } ifelse
+} def
+/noheader true def
+/gaudyheader false def
+/def_headerpointsize 10 def
+/headerpointsize def_headerpointsize ifndef
+/gaudy_pointsize 15 def
+/font /Courier ifndef
+/def_pointsize 10 def
+/pointsize def_pointsize ifndef
+/Linespace {/Linespace pointsize 1.1 mul neg dup 3 1 roll def } def
+/must-add-euro-to-font false ifndef
+/#copies 1 ifndef
+/aspectratio 1 ifndef
+/formsperpage 1 ifndef
+/landscape false ifndef
+/magnification 1 ifndef
+/margin 10 def
+/orientation 0 def
+/encoding /ISOLatin1Encoding def
+/def_yoffset -0.30 def
+/def_xoffset .35 def
+/xoffset def_xoffset ifndef
+/yoffset def_yoffset ifndef
+/roundpage true def
+/useclippath true def
+/pagebbox [0 0 612 792] def
+
+%
+% function definitions
+%
+/inch {72 mul} bind def
+/point {72 div} bind def
+/min {2 copy gt {exch} if pop} bind def
+/max {2 copy lt {exch} if pop} bind def
+/rectpath {4 2 roll moveto dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath } def
+
+/setup {
+ counttomark 2 idiv {def} repeat pop
+ landscape {/orientation 90 orientation add def} if
+
+ %
+ % If user requested an encoding that does not exist, issue a warning
+ % and use whatever is available.
+ %
+ /encoding-vec
+ encoding where {
+ begin encoding cvx exec end % convert name to vector
+ }{
+ systemdict /EncodingDirectory known {
+ EncodingDirectory encoding known { % maybe it's there
+ EncodingDirectory encoding get
+ }{
+ /ISOLatin1Encoding where { % find a substitute
+ pop /ISOLatin1Encoding
+ }{
+ /StandardEncoding
+ } ifelse
+
+ %
+ % Tell the user what we're substituting for what.
+ %
+ (%% [ ) print
+ encoding 100 string cvs print
+ ( not found, substituting ) print
+ dup 100 string cvs print
+ ( ] %%\n) print
+
+ cvx exec % now convert name to vector
+ } ifelse
+ }{
+ /ISOLatin1Encoding where { % find a substitute
+ pop /ISOLatin1Encoding
+ }{
+ /StandardEncoding
+ } ifelse
+
+ %
+ % Tell the user what we're substituting for what.
+ %
+ (%% [ ) print
+ encoding 100 string cvs print
+ ( not found, substituting ) print
+ dup 100 string cvs print
+ ( ] %%\n) print
+
+ cvx exec % now convert name to vector
+ } ifelse
+ } ifelse
+ def
+
+ systemdict /encodefont known
+ {
+ font findfont pointsize scalefont encoding-vec encodefont setfont
+ }{
+ font findfont
+ dup length dict begin
+ {1 index /FID ne {def} {pop pop} ifelse} forall
+ /Encoding encoding-vec def
+ currentdict
+ end
+ /font-newencoding exch definefont pop
+ % if we need the Euro
+ must-add-euro-to-font { % add the euro and use the new font
+ /font-newencoding /font-newencoding-euro add-euro-to-font
+ /font-newencoding-euro
+ } { % just use the new encoding
+ /font-newencoding
+ } ifelse findfont
+ pointsize scalefont setfont
+ } ifelse
+
+ /charwidth (M) stringwidth pop def
+ /linespace pointsize pointsize .10 mul add neg def
+ /headerspace headerpointsize headerpointsize .10 mul add 2 linespace mul sub neg def
+
+ pagedimensions
+
+ % if height is less than what's needed, omit top margin to avoid clipping off text from the bottom
+ % if weight is less than what's needed, omit left margin to avoid clipping off text from the right
+
+ /standard_height 66 def_pointsize def_pointsize .10 mul add mul yoffset inch sub margin 2 div add def
+ /standard_gaudy_height .5 inch 64 def_pointsize def_pointsize .10 mul add mul add .1 inch add margin 2 div add def
+
+ landscape { %yoffset not to be changed for landscape mode because it will cut off the top part
+ /rel_height standard_height def
+ gaudyheader { /rel_width 10.25 inch def }
+ { /rel_width 10.0 inch def } ifelse
+ }
+ { /rel_height height def
+ gaudyheader { /rel_width 7.75 inch def }
+ { /rel_width 7.5 inch def } ifelse
+ } ifelse
+
+ noheader { rel_height height lt
+ { /yoffset yoffset def_yoffset sub margin point 2 div add def }if
+ width rel_width lt
+ { /xoffset xoffset def_xoffset sub margin point 2 div sub def }if
+ }
+ { gaudyheader
+ { rel_height standard_gaudy_height lt
+ { /yoffset yoffset .1 add margin point 2 div add def }if
+ width rel_width lt
+ { /xoffset xoffset .10 sub margin point 2 div sub def }if
+ }
+ { rel_height height lt
+ { /yoffset yoffset def_yoffset sub margin point 2 div add def }if
+ width rel_width lt
+ { /xoffset xoffset def_xoffset sub margin point 2 div sub def }if
+ } ifelse
+ } ifelse
+
+ xcenter ycenter translate
+ orientation neg rotate
+ width 2 div neg height 2 div translate
+ xoffset inch yoffset inch translate
+ margin 2 div dup neg translate
+ magnification dup aspectratio mul scale
+
+ noheader{ landscape {0 linespace 2 mul translate }
+ {0 linespace translate } ifelse
+ }
+ { gaudyheader { 0 linespace translate }
+ { landscape { 0 headerspace linespace add translate }
+ { 0 headerspace translate } ifelse
+ } ifelse
+ } ifelse
+} def
+
+/pagedimensions {
+ useclippath userdict /gotpagebbox known not and {
+ /pagebbox [clippath pathbbox newpath] def
+ roundpage currentdict /roundpagebbox known and {roundpagebbox} if
+ } if
+ pagebbox aload pop
+
+ %
+ % Adjust page dimensions to "ignore" the header.
+ %
+ noheader not {
+ landscape {
+ exch
+ .5 sub
+ headerpointsize def_headerpointsize gt { headerpointsize def_headerpointsize sub 72 div sub } if
+ exch
+ }{
+ .5 sub
+ headerpointsize def_headerpointsize gt { headerpointsize def_headerpointsize sub 72 div sub } if
+ } ifelse
+ } if
+
+ 4 -1 roll exch 4 1 roll 4 copy
+ landscape {4 2 roll} if
+ sub /width exch def
+ sub /height exch def
+ add 2 div /xcenter exch def
+ add 2 div /ycenter exch def
+ userdict /gotpagebbox true put
+} def
+
+
+/show_date_and_time { % show the date and the time
+ /Times-Roman findfont 15 scalefont setfont
+ currentdict /date known
+ { 0 13 moveto date 0 setgray show } if
+} def
+
+/show_heading { % show the page heading
+ 0 exch moveto
+ currentdict /headerfont known
+ {headerfont findfont gaudy_pointsize scalefont setfont}
+ {/Times-Roman findfont gaudy_pointsize scalefont setfont} ifelse
+ dup stringwidth pop 2 div width xoffset inch .5 inch add sub 2 div exch sub
+ 0 rmoveto 0 setgray show
+} def
+
+/page_num_len { % count number of digits of the current page number
+ /digits 1 def
+ /tens 10 def
+ { page tens lt
+ { exit }
+ { /digits digits 1 add def
+ /tens tens 10 mul def } ifelse
+ } loop
+} def
+
+/page_num { % convert page to a string
+ page_num_len page digits string cvs
+} def
+
+/printpage { % stk:int (right justified from this "int" value)
+ page_num stringwidth pop % get length of string
+ sub % calculate white space
+ 0 rmoveto page_num % move over to the right that much
+ 0 setgray show
+} def
+
+/show_pagenum { % shows the page number
+ 0 12 moveto
+ /Times-Roman findfont 20 scalefont setfont
+ width xoffset inch .5 inch add sub printpage
+} def
+
+/show_gaudyheader {
+ -20 0 width xoffset inch -.10 inch add sub .5 inch rectpath .9 setgray fill
+ show_date_and_time
+ currentdict /pageheading known currentdict /filename known and
+ { pageheading 22 show_heading
+ filename 6 show_heading }
+ { currentdict /pageheading known { pageheading 14 show_heading } if
+ currentdict /filename known { filename 14 show_heading } if
+ } ifelse
+ show_pagenum
+} def
+
+/show_simpleheader {
+ currentdict /headerfont known
+ {headerfont findfont headerpointsize scalefont setfont}
+ {/Courier-Bold findfont headerpointsize scalefont setfont} ifelse
+ currentdict /pageheading known {
+
+ %
+ % if header given then don't print page number and date and filename
+ %
+
+ 0 0 moveto
+ pageheading stringwidth pop 2 div width xoffset inch .5 inch add sub 2 div exch sub
+ 0 rmoveto pageheading 0 setgray show }
+
+ %
+ % else print those stuff
+ %
+
+ { currentdict /date known
+ { 0 0 moveto date 0 setgray show } if
+ currentdict /filename known
+ { 0 0 moveto
+ filename stringwidth pop 2 div width xoffset inch .5 inch add sub 2 div exch sub
+ 0 rmoveto filename 0 setgray show } if
+ 0 0 moveto width xoffset inch .75 inch add sub printpage
+ } ifelse
+} def
+
+/pagesetup {
+ /page exch def
+ gsave
+
+ noheader { 0 linespace neg translate }
+ { gaudyheader { 0 linespace neg translate }
+ { 0 headerpointsize .10 mul 2 linespace mul sub translate } ifelse
+ } ifelse
+
+ noheader not { gaudyheader { show_gaudyheader }
+ { show_simpleheader }
+ ifelse }
+ if
+
+ grestore
+ 0 0 moveto 0
+
+} bind def
+
+/L {
+ counttomark 2 idiv {charwidth mul currentpoint exch pop moveto show} repeat
+ Linespace add dup 0 exch moveto
+} bind def
+
+/l {show Linespace add dup 0 exch moveto} bind def
+
+/done {/lastpage where {pop lastpage} if} def
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/ps.requests b/usr/src/cmd/lp/filter/postscript/postscript/ps.requests
new file mode 100644
index 0000000000..16bf1ee4de
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/ps.requests
@@ -0,0 +1,36 @@
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License, Version 1.0 only
+% (the "License"). You may not use this file except in compliance
+% with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+% Keywords begin with an @ in the first column. The value follows on the next line
+% and includes everything up to next keyword line, except for comments which are
+% lines that begin with % in the first column.
+%
+
+@manualfeed
+ statusdict begin
+ /manualfeedtimeout 300 def
+ /manualfeed true def
+ end
+
+@ledgertray
+ statusdict begin
+ ledgertray
+ end
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/tsol_banner.ps b/usr/src/cmd/lp/filter/postscript/postscript/tsol_banner.ps
new file mode 100644
index 0000000000..babf5df1c5
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/tsol_banner.ps
@@ -0,0 +1,30 @@
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License (the "License").
+% You may not use this file except in compliance with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+% Use is subject to license terms.
+%
+%ident "%Z%%M% %I% %E% SMI"
+%
+% works in conjunction with tsol_separator.ps to do a banner page
+%
+
+SeparatorPagesDict /Banner get exec
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/tsol_separator.ps b/usr/src/cmd/lp/filter/postscript/postscript/tsol_separator.ps
new file mode 100644
index 0000000000..50c4820551
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/tsol_separator.ps
@@ -0,0 +1,687 @@
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License (the "License").
+% You may not use this file except in compliance with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+% Use is subject to license terms.
+%
+%ident "%Z%%M% %I% %E% SMI"
+%
+%% This PostScript file is normally used as input to the lp.tsol_separator
+%% program, which will prepend code to set the values of a number of
+%% variables. lp.tsol_separator is called by the printer interface script.
+
+%% This PostScript file may be modified for local customizations or
+%% internationalization. Comments marked "INTERNATIONALIZE:" show
+%% places where changes may be made for internationalization. Comments
+%% marked "CUSTOMIZE:" show places where some typical customization
+%% changes may be made.
+
+
+%% The following comments describe variables set by lp.tsol_separator
+
+%% These variables are from the print job information that can be
+%% displayed with lpstat or lpq.
+%%
+%% /Job_Classification The classification (from the sensitivity label) to
+%% be displayed at the top and bottom of the banner
+%% /Job_Printer Printer Name
+%% /Job_Host Host job was submitted from
+%% /Job_User User who submitted the job
+%% /Job_JobID Job number
+%% /Job_Title Job title
+%%
+%%
+%% This variable is NO if an authorized user used the lp -o nobanner option
+%% and the printer was set up to allow bannerless jobs. Otherwise it is YES.
+%%
+%% /Job_DoPageLabels Print page labels YES/NO.
+%%
+%% These variables are generated from the system clock value.
+%%
+%% /Job_Date Date and time the job is being printed, in the
+%% locale's default format
+%% /Job_Hash A randomly generatred identifying number for
+%% matching up the banner and trailer pages of the job
+%%
+%%
+%% The following variables are the job's labels
+%% as interpreted by the bcltobanner(3TSOL) library routine.
+%%
+%% /Job_Classification The classification (from the sensitivity label) to be
+%% displayed at the top and bottom of the banner page.
+%% /Job_Protect The sensitivity label to be displayed in the protect-as
+%% field.
+%% /Job_Caveats The caveats from the sesitivity label.
+%% /Job_Channels The channels from the sesitivity label.
+%%
+%%
+%% The following variables are the job's Sensitivity Label and
+%% Information Label as interpreted by the bsltos and biltos library
+%% routines.
+%%
+%% /Job_SL_Internal The sensitivity label in internal view format.
+%% /Job_SL_External The sensitivity label in external view format.
+
+/SeparatorPagesDict 100 dict def
+userdict /JobDict known not {
+ userdict /JobDict 100 dict put
+} if
+
+SeparatorPagesDict
+begin
+
+ %% CUSTOMIZE: To print header page label left-justified, set this to false
+ /center_label true def
+
+ /center_show where {
+ pop
+ } {
+ userdict /center_show
+ {
+ dup stringwidth exch
+ 2 div neg exch rmoveto show
+ } put
+ } ifelse
+
+ /append where
+ { pop }
+ {
+ /append
+ {
+ 1 index length 1 index length add
+ 1 index dup type /dicttype eq
+ {
+ pop dict
+ begin
+ exch { def } forall
+ { def } forall
+ currentdict
+ end
+ }
+ {
+ /arraytype eq { array } { string } ifelse
+ dup 4 -1 roll 1 index copy length 4 -1 roll putinterval
+ }
+ ifelse
+ } def
+ } ifelse
+
+ /fontheight
+ systemdict /fontheight known
+ { systemdict /fontheight get }
+ {
+ {
+ gsave
+ setfont (qf) true charpath flattenpath pathbbox
+ 4 -1 roll pop exch pop exch sub
+ grestore
+ }
+ } ifelse
+ def
+
+ /m { moveto } def
+ /r { rmoveto } def
+ /rl { rlineto } def
+
+ /NewLine {
+ currentpoint exch pop
+ currentfont fontheight sub errorx0 exch moveto
+ } def
+
+ /clipSL {
+ /MaxWidth exch def
+ dup stringwidth pop MaxWidth gt {
+ {
+ dup stringwidth pop (<-) stringwidth pop add MaxWidth le {exit} if
+ dup 0 exch length 1 sub getinterval
+ } loop
+ (<-)
+ %% Concatenate strings
+ dup length 2 index length add 1 index pop string
+ dup 0 4 index putinterval
+ dup 4 -1 roll length 4 -1 roll putinterval
+ } if
+ } def
+
+ /BreakWithBlanks {
+
+ {restoftext ( ) search
+ {
+ /blank_nextword exch def pop
+ /blank_restoftext exch def
+ /blank_wordwidth blank_nextword stringwidth pop def
+
+ restoftext (/) search
+ {
+ /slash_nextword exch def pop
+ /slash_restoftext exch def
+ /slash_wordwidth slash_nextword stringwidth pop def
+
+ blank_wordwidth slash_wordwidth lt
+ {
+ /nextword blank_nextword def
+ /restoftext blank_restoftext def
+ /wordwidth blank_wordwidth def
+ /breakwidth ( ) stringwidth pop def
+ }
+ {
+ /nextword slash_nextword def
+ /restoftext slash_restoftext def
+ /wordwidth slash_wordwidth def
+ /breakwidth (/) stringwidth pop def
+ }ifelse
+ }
+ {
+ pop
+ /nextword blank_nextword def
+ /restoftext blank_restoftext def
+ /wordwidth blank_wordwidth def
+ /breakwidth ( ) stringwidth pop def
+ }ifelse
+
+ curwidth wordwidth add linewidth gt
+ {textstring startchar
+ lastwordbreak startchar sub
+ getinterval proc
+ /startchar lastwordbreak def
+ /curwidth wordwidth breakwidth add def }
+
+ {/curwidth curwidth wordwidth add
+ breakwidth add def
+ } ifelse
+ /lastwordbreak lastwordbreak
+ nextword length add 1 add def
+ }
+ {pop BreakWithSlashes exit}
+ ifelse
+ }loop
+}def
+
+ /BreakWithSlashes
+ {
+ /breakchar (/) def
+ /breakwidth breakchar stringwidth pop def
+ {restoftext breakchar search
+ {/nextword exch def pop
+ /restoftext exch def
+ /wordwidth nextword stringwidth pop def
+
+ curwidth wordwidth add linewidth gt
+ {textstring startchar
+ lastwordbreak startchar sub
+ getinterval proc
+ /startchar lastwordbreak def
+ /curwidth wordwidth breakwidth add def }
+
+ {/curwidth curwidth wordwidth add
+ breakwidth add def
+ } ifelse
+ /lastwordbreak lastwordbreak
+ nextword length add 1 add def
+ }
+ {pop exit}
+ ifelse
+ }loop
+ }def
+
+ /BreakIntoLines
+ {/proc exch def
+ /linewidth exch 40 sub def
+ /textstring exch def
+
+ /curwidth 0 def
+ /lastwordbreak 0 def
+ /startchar 0 def
+ /restoftext textstring def
+
+ % begin scale the font if necessary
+
+ /allowedarea linewidth fbh 10 div mul def
+ /currentarea currentfont fontheight textstring stringwidth pop mul def
+
+ currentarea allowedarea gt
+ {
+ currentfont allowedarea currentarea div scalefont setfont
+ }if
+
+ % end scale the font if necessary
+
+ BreakWithBlanks
+ /lastchar textstring length def
+ textstring startchar lastchar startchar sub
+ getinterval proc
+ }def
+
+
+ /ShowBanner {
+ JobDict /Job_Proclam? get {
+ systemdict /showpage get cvx exec
+ } if
+ } def
+
+ /Init {
+
+ initgraphics
+ /#copies 1 def
+ initmatrix
+ erasepage
+
+ clippath pathbbox /fbh exch def
+ /fbw exch def
+ pop pop newpath
+ 0 0 moveto
+ 0 fbh translate
+ 0 0 moveto
+
+ /margin fbh 20 div def
+ /imargin margin 1.1 mul def
+ /errorx0 imargin def
+ /errorx1 fbw imargin sub def
+ /errory1 imargin def
+
+ gsave
+ } def
+
+% this stuff is lpd dependant.
+
+ /lpdglue {
+ userdict
+ begin
+ JobDict
+ begin
+ % If Job_Printer is defined, assume the others are too,
+ /Job_Printer where
+ {
+ pop
+ /Job_Proclam? true def
+ /Job_Endclam? true def
+
+ /Printer Job_Printer def
+ /Host Job_Host def
+ /User Job_User def
+ /Title Job_Title def
+ /JobID Job_JobID def
+ /Date Job_Date def
+
+ %% CUSTOMIZE: To use a different string at the top and
+ %% bottom of each page, change the following line. For
+ %% instance, to use the sensitivity label in external view
+ %% format, change the line to: /PageLabel Job_SL_External def
+ %% To eliminate page labels completely, change this line to
+ %% set the page label to an empty string: /PageLabel () def
+ /PageLabel Job_SL_Internal def
+ Job_Protect () eq
+ {
+ %% Job_Protect is empty because SLs are turned
+ %% off in secconf. (Turning off SLs is actually not yet
+ %% supported by the system.)
+ /Protect () def
+ /Protect_Text1 () def
+ /Protect_Text2 () def
+ }
+ {
+ %% INTERNATIONALIZE/CUSTOMIZE: Replace the text between
+ %% parentheses with the appropriate text to display
+ %% above and below the SL.
+ /Protect Job_Protect def
+ /Protect_Text1 (This output must be protected as:) def
+ /Protect_Text2 (unless manually reviewed and downgraded.) def
+ }
+ ifelse
+
+ %% CUSTOMIZE: To not print the caveats, change
+ %% this line to /Caveats () def
+ /Caveats Job_Caveats def
+ %% CUSTOMIZE: To not print the channels, change
+ %% this line to /Channels () def
+ /Channels Job_Channels def
+
+ %% CUSTOMIZE: To not print the hash number, change
+ %% this line to /Hash () def
+ /Hash Job_Hash def
+
+ %% CUSTOMIZE: To not print the head label, change
+ %% this line to /HeadLabel () def
+ %% You may also substitute another string. For example, to use
+ %% the SL in internal view format: /HeadLabel Job_SL_Internal def
+ /HeadLabel Job_Classification def
+ } {
+ /Job_Proclam? false def
+ /Job_Endclam? false def
+ } ifelse
+ end
+ end
+ } def
+
+ /border {
+ gsave
+ setlinewidth
+ setgray
+ 30 -20 moveto
+ 0 60 fbh sub rlineto
+ fbw 60 sub 0 rlineto
+ 0 fbh 60 sub rlineto
+ 60 currentlinewidth 2 div sub fbw sub 0 rlineto
+ stroke
+ grestore
+ } def
+
+ /TSOLJobInfo {
+ gsave
+
+ /fontscale fbh 50 div def
+ /Courier-Bold findfont fontscale scalefont setfont
+ /ClippedLabel
+ JobDict /HeadLabel get
+ SeparatorPagesDict /fbw get 90 sub
+ SeparatorPagesDict /clipSL get exec
+ def
+
+ /head_len {
+ ClippedLabel stringwidth pop 5 add
+ HeadLabel () eq { pop 0 } if
+ } def
+ 15 setlinewidth
+ fbw 2 div head_len 2 div sub -20 moveto
+ head_len 0 rlineto stroke
+ 1 setgray
+ fbw 10 div -25 m gsave ClippedLabel
+ currentpoint exch pop fbw 2 div exch moveto
+ center_show NewLine grestore
+
+ 0 setgray
+ /fontscale fbh 70 div def
+
+ /Helvetica findfont fontscale scalefont setfont
+ 0 fbh 8 div neg r Protect_Text1
+ currentpoint exch pop
+ center_label {
+ fbw 2 div exch moveto center_show
+ }
+ {
+ fbw 10 div exch moveto show
+ }
+ ifelse
+ /fontscale fbh 60 div def
+ /Helvetica-Bold findfont fontscale scalefont setfont
+
+ 0 fbh 150 div neg r
+ Protect
+ fbw errorx0 3 mul sub % width minus margins
+
+ center_label {
+ {NewLine currentpoint exch pop fbw 2 div exch moveto center_show}
+ BreakIntoLines
+ }
+ {
+ {NewLine currentpoint exch pop fbw 10 div exch moveto show}
+ BreakIntoLines
+ }
+ ifelse
+
+ /fontscale fbh 70 div def
+ /Helvetica findfont fontscale scalefont setfont
+ 0 fbh 50 div neg r Protect_Text2
+ currentpoint exch pop
+ center_label {
+ fbw 2 div exch moveto center_show
+ }
+ {
+ fbw 10 div exch moveto show
+ }
+ ifelse
+
+ /fontscale fbh 60 div def
+ /Helvetica-Bold findfont fontscale scalefont setfont
+ 0 fbh 200 div neg r
+
+ 0 fbh 10 div neg r
+
+ /fontscale fbh 40 div def
+ /Helvetica-Bold findfont fontscale scalefont setfont
+
+ 0 fbh 30 div neg r gsave
+ %% INTERNATIONALIZE: Replace the text between
+ %% parentheses with the appropriate text.
+ (User: ) User (@) Host append append append
+ currentpoint exch pop fbw 2 div exch moveto center_show
+ NewLine grestore
+ 0 fbh 30 div neg r gsave
+ %% INTERNATIONALIZE: Replace the text between
+ %% parentheses with the appropriate text.
+ (Job: ) JobID append
+ currentpoint exch pop fbw 2 div exch moveto center_show
+ NewLine grestore
+ 0 fbh 30 div neg r gsave
+ Title
+ currentpoint exch pop fbw 2 div exch moveto center_show
+ NewLine grestore
+ /fontscale fbh 70 div def
+ /Helvetica findfont fontscale scalefont setfont
+ 0 fbh 30 div neg r gsave
+ %% INTERNATIONALIZE: Replace the text between
+ %% parentheses with the appropriate text.
+ (Printed at: ) Date append
+ currentpoint exch pop fbw 2 div exch moveto center_show
+ NewLine grestore
+ 0 fbh 30 div neg r gsave
+ %% INTERNATIONALIZE: Replace the text between
+ %% parentheses with the appropriate text.
+ (Printer queue: ) Printer append
+ currentpoint exch pop fbw 2 div exch moveto center_show
+ NewLine grestore
+
+ /Helvetica-Bold findfont fontscale scalefont setfont
+ 0 fbh 20 div neg r
+ Caveats
+ fbw errorx0 3 mul sub % width minus margins
+ {NewLine currentpoint exch pop fbw 2 div exch moveto center_show}
+ BreakIntoLines
+
+ 0 fbh 30 div neg r
+ Channels
+ fbw errorx0 3 mul sub % width minus margins
+ {NewLine currentpoint exch pop fbw 2 div exch moveto center_show}
+ BreakIntoLines
+
+ /fontscale fbh 50 div def
+ /Courier-Bold findfont fontscale scalefont setfont
+ 15 setlinewidth
+ fbw 2 div head_len 2 div sub 40 fbh sub moveto
+ head_len 0 rlineto stroke
+ 1 setgray
+ fbw 10 div 35 fbh sub m gsave ClippedLabel
+ currentpoint exch pop fbw 2 div exch moveto center_show
+ NewLine grestore
+
+ grestore
+ } def
+
+ /JobHashInfo {
+ gsave
+ 0 setgray
+ /fontscale fbh 50 div def
+ /Helvetica-Bold findfont fontscale scalefont setfont
+
+ %% Upper left corner
+ Hash
+ fbw 12 div 50 neg m gsave show grestore
+
+ %% Lower left corner
+ Hash
+ fbw 12 div fbh 60 sub neg m gsave show grestore
+
+ %% Lower right corner
+ Hash dup stringwidth pop
+ fbw 11 mul 12 div exch sub fbh 60 sub neg m gsave show grestore
+
+ %% Upper right corner
+ Hash dup stringwidth pop
+ fbw 11 mul 12 div exch sub 50 neg m gsave show grestore
+
+ /fontscale fbh 40 div def
+ /Helvetica-Bold findfont fontscale scalefont setfont
+ fbw 10 div 120 fbh sub m gsave
+ currentpoint exch pop fbw 2 div exch moveto center_show
+
+ grestore
+ } def
+
+
+ /jobproclam {
+ JobDict
+ begin
+ Job_Proclam?
+ %% INTERNATIONALIZE: Replace the text between
+ %% parentheses with the appropriate text.
+ { TSOLJobInfo (JOB START) JobHashInfo}
+ { 0 -100 rmoveto }
+ ifelse
+ end
+ } def
+
+ /jobendclam {
+ JobDict
+ begin
+ Job_Endclam?
+ %% INTERNATIONALIZE: Replace the text between
+ %% parentheses with the appropriate text.
+ { TSOLJobInfo (JOB END) JobHashInfo}
+ { 0 -100 rmoveto }
+ ifelse
+ end
+ } def
+
+
+ /JobProclam {
+ jobproclam
+ } def
+
+ /JobEndclam {
+ jobendclam
+ } def
+
+% A fancy box around page
+
+ /BannerBorder {
+ .7 16 border
+ } def
+
+ /TrailerBorder {
+ 0 4 border
+ } def
+
+%
+% -------------------------------------------------------------------------
+%
+% The structure of separator pages is defined below. This is invoked by
+% using a line like:
+%
+% SeparatorPagesDict /Banner get exec
+%
+
+ /Banner {
+ SeparatorPagesDict
+ begin
+ Init
+ lpdglue
+ BannerBorder
+ JobProclam
+ /SkipPageLabels true def
+ ShowBanner
+ /SkipPageLabels false def
+ end
+ } def
+
+ /Trailer {
+ SeparatorPagesDict
+ begin
+ Init
+ lpdglue
+ TrailerBorder
+ JobEndclam
+ /SkipPageLabels true def
+ ShowBanner
+ /SkipPageLabels false def
+ end
+ } def
+
+ /SkipPageLabels false def
+end
+
+SeparatorPagesDict begin
+ clippath pathbbox /fbh exch def
+ /fbw exch def
+ pop pop
+ lpdglue
+end
+
+
+JobDict /Job_DoPageLabels get (YES) eq
+ JobDict /PageLabel get () ne and {
+ userdict begin
+ /showpage {
+ SeparatorPagesDict /SkipPageLabels get false eq {
+ gsave
+ initgraphics
+ /Courier-Bold findfont
+ 12 scalefont setfont
+
+ /ClippedLabel
+ JobDict /PageLabel get
+ SeparatorPagesDict /fbw get 60 sub
+ SeparatorPagesDict /clipSL get exec
+ def
+
+ /inf_len {
+ ClippedLabel stringwidth pop 6 add
+ } def
+
+ /page_mid SeparatorPagesDict /fbw get 2 div def
+
+ 10 setlinewidth
+
+ % print label for bottom of page
+ 0 setgray
+ page_mid inf_len 2 div sub 17 moveto
+ inf_len 0 rlineto stroke
+
+ 1 setgray
+ page_mid inf_len 2 div sub 14 moveto
+ ClippedLabel show
+
+ % print label for top of page
+ 0 setgray
+ page_mid inf_len 2 div sub
+ SeparatorPagesDict /fbh get 5 sub moveto
+ inf_len 0 rlineto stroke
+
+ 1 setgray
+ page_mid inf_len 2 div sub SeparatorPagesDict /fbh get 8
+ sub moveto ClippedLabel show
+ grestore
+ } if
+ systemdict /showpage get cvx exec
+ } bind def
+ end
+}if
+
+%% End of tsol_separator.ps
diff --git a/usr/src/cmd/lp/filter/postscript/postscript/tsol_trailer.ps b/usr/src/cmd/lp/filter/postscript/postscript/tsol_trailer.ps
new file mode 100644
index 0000000000..f716b3df06
--- /dev/null
+++ b/usr/src/cmd/lp/filter/postscript/postscript/tsol_trailer.ps
@@ -0,0 +1,29 @@
+%
+% CDDL HEADER START
+%
+% The contents of this file are subject to the terms of the
+% Common Development and Distribution License (the "License").
+% You may not use this file except in compliance with the License.
+%
+% You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+% or http://www.opensolaris.org/os/licensing.
+% See the License for the specific language governing permissions
+% and limitations under the License.
+%
+% When distributing Covered Code, include this CDDL HEADER in each
+% file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+% If applicable, add the following below this CDDL HEADER, with the
+% fields enclosed by brackets "[]" replaced with your own identifying
+% information: Portions Copyright [yyyy] [name of copyright owner]
+%
+% CDDL HEADER END
+%
+%
+% Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+% Use is subject to license terms.
+%
+%ident "%Z%%M% %I% %E% SMI"
+%
+% used in conjunction with tsol_separator.ps to create a trailer page
+%
+SeparatorPagesDict /Trailer get exec
diff --git a/usr/src/cmd/lp/filter/slow.filter b/usr/src/cmd/lp/filter/slow.filter
new file mode 100644
index 0000000000..be5a5d3427
--- /dev/null
+++ b/usr/src/cmd/lp/filter/slow.filter
@@ -0,0 +1,115 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+###########
+##
+## Simple shell script that saves the Spooler alot of headaches.
+## This routine invokes a slow filter on each of the files in a
+## user's print request, sending the output to separate files.
+## The Spooler will take ANYTHING that goes to standard error
+## and give it to the user. Non-empty standard error or non-zero
+## exit code cause cancellation of the print request.
+##
+## Calling sequence:
+##
+## slow.filter prefix file1 file2 ... fileN
+##
+## "prefix" is prefix of full path name for output files. All we
+## do is append a ``-k'' for k = 1, 2, ..., N.
+##########
+
+#####
+#
+# Most of the time we don't want the standard error to be captured
+# by the Spooler, mainly to avoid "Terminated" messages that the
+# shell puts out when we get a SIGTERM. We'll save the standard
+# error channel under another number, so we can use it when it
+# should be captured.
+#####
+exec 5>&2 2>/dev/null
+
+#####
+# Error message formatter:
+#
+# Invoke as
+#
+# errmsg severity message-number problem help
+#
+# where severity is "ERROR" or "WARNING", message-number is
+# a unique identifier, problem is a short description of the
+# problem, and help is a short suggestion for fixing the problem.
+#####
+
+LP_ERR_LABEL="UX:lp"
+
+E_IP_ARGS=1
+E_IP_OPTS=2
+E_IP_FILTER=3
+E_IP_STTY=4
+E_IP_UNKNOWN=5
+E_IP_BADFILE=6
+E_IP_BADCHARSET=7
+E_IP_BADCPI=8
+E_IP_BADLPI=9
+E_IP_BADWIDTH=10
+E_IP_BADLENGTH=11
+E_IP_ERRORS=12
+
+errmsg () {
+ case $1 in
+ ERROR )
+ sev=" ERROR";
+ ;;
+ WARNING )
+ sev="WARNING";
+ ;;
+ esac
+# tag=`expr "${LP_ERR_LABEL}" : "\(.*\):"``expr "${LP_ERR_LABEL}" : ".*:\(.*\)"`
+ echo "${LP_ERR_LABEL}: ${sev}: $3
+ TO FIX: $4" >&5
+}
+
+prefix=$1
+shift
+
+k=1
+for file in "$@"
+do
+ if [ ! -r "${file}" ]
+ then
+ errmsg ERROR ${E_IP_BADFILE} \
+ "Cannot read the file \"${file}\"." \
+ "See if it still exists and is readable, or
+ consult your system administrator."
+ else
+ 0<${file} 1>${prefix}-${k} eval "2>&5 ${FILTER}" || {
+ exit_code=$?
+ while [ 127 -lt "${exit_code}" ]
+ do
+ exit_code=`expr "${exit_code}" - 128`
+ done
+ exit ${exit_code}
+ }
+ fi
+ k=`expr "${k}" + 1`
+done
diff --git a/usr/src/cmd/lp/include/access.h b/usr/src/cmd/lp/include/access.h
new file mode 100644
index 0000000000..7010e0a01a
--- /dev/null
+++ b/usr/src/cmd/lp/include/access.h
@@ -0,0 +1,69 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+
+#if !defined(_LP_ACCESS_H)
+#define _LP_ACCESS_H
+
+#include "stdio.h"
+
+/*
+ * To speed up reading in each allow/deny file, ACC_MAX_GUESS slots
+ * will be preallocated for the internal copy. If these files
+ * are expected to be substantially larger than this, bump it up.
+ */
+#define ACC_MAX_GUESS 100
+
+int allow_form_printer ( char **, char * );
+int allow_user_form ( char ** , char * );
+int allow_user_printer ( char **, char * );
+int allowed ( char *, char **, char ** );
+int deny_form_printer ( char **, char * );
+int deny_user_form ( char ** , char * );
+int deny_user_printer ( char **, char * );
+int dumpaccess ( char *, char *, char *, char ***, char *** );
+int is_form_allowed_printer ( char *, char * );
+int is_user_admin ( void );
+int is_user_allowed ( char *, char ** , char ** );
+int is_user_allowed_form ( char *, char * );
+int is_user_allowed_printer ( char *, char * );
+int load_formprinter_access ( char *, char ***, char *** );
+int load_paperprinter_access(char *, char ***, char ***);
+int load_userform_access ( char *, char ***, char *** );
+int load_userprinter_access ( char *, char ***, char *** );
+int loadaccess ( char *, char *, char *, char ***, char *** );
+int bangequ ( char * , char * );
+int bang_searchlist ( char * , char ** );
+int bang_dellist ( char *** , char * );
+
+char * getaccessfile ( char *, char *, char *, char * );
+
+#endif
diff --git a/usr/src/cmd/lp/include/class.h b/usr/src/cmd/lp/include/class.h
new file mode 100644
index 0000000000..3147a5f31b
--- /dev/null
+++ b/usr/src/cmd/lp/include/class.h
@@ -0,0 +1,74 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+
+#if !defined(_LP_CLASS_H)
+#define _LP_CLASS_H
+
+/**
+ ** The internal flags seen by the Spooler/Scheduler and anyone who asks.
+ **/
+
+#define CS_REJECTED 0x001
+
+/**
+ ** The internal copy of a class as seen by the rest of the world:
+ **/
+
+/*
+ * A (char **) list is an array of string pointers (char *) with
+ * a null pointer after the last item.
+ */
+typedef struct CLASS {
+ char *name; /* name of class (redundant) */
+ char **members; /* members of class */
+} CLASS;
+
+/**
+ ** Various routines.
+ **/
+
+#if defined(__STDC__)
+
+CLASS *getclass ( char * );
+
+int putclass ( char *, CLASS * );
+int delclass ( char * );
+
+void freeclass ( CLASS * );
+
+#else
+
+CLASS *getclass();
+
+int putclass(),
+ delclass();
+
+void freeclass();
+
+#endif
+
+#endif
diff --git a/usr/src/cmd/lp/include/filters.h b/usr/src/cmd/lp/include/filters.h
new file mode 100644
index 0000000000..c0b2a89103
--- /dev/null
+++ b/usr/src/cmd/lp/include/filters.h
@@ -0,0 +1,248 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+/**
+ ** The disk copy of the filter table:
+ **/
+
+/*
+ * There are 9 fields in the filter table (the first one is ignored).
+ */
+#define FL_MAX 9
+# define FL_IGN 0
+# define FL_PTYPS 1
+# define FL_PRTRS 2
+# define FL_ITYPS 3
+# define FL_NAME 4
+# define FL_OTYPS 5
+# define FL_TYPE 6
+# define FL_CMD 7
+# define FL_TMPS 8
+
+/*
+ * Various strings.
+ */
+#define FL_SEP ":"
+#define FL_END "\n"
+#define FL_FAST "fast"
+#define FL_SLOW "slow"
+
+/**
+ ** The internal copy of a filter as seen by the rest of the world:
+ **/
+
+typedef enum FILTERTYPE {
+ fl_none,
+ fl_fast,
+ fl_slow,
+ fl_both
+} FILTERTYPE;
+
+/*
+ * A (char **) list is an array of string pointers (char *) with
+ * a null pointer after the last item.
+ */
+typedef struct FILTER {
+ char * name; /* name of filter (redundant) */
+ char * command; /* shell command (full path) */
+ FILTERTYPE type; /* type of filter (fast/slow) */
+ char ** printer_types; /* list of valid printer types */
+ char ** printers; /* list of valid printers */
+ char ** input_types; /* list of valid input types */
+ char ** output_types; /* list of valid output types */
+ char ** templates; /* list of option templates */
+} FILTER;
+
+/**
+ ** The internal copy of a filter as seen by the filter routines:
+ **/
+
+/*
+ * To speed up processing the filter table, FL_MAX_GUESS slots
+ * will be preallocated for the internal copy. If filter tables
+ * are expected to be substantially larger than this, bump it up.
+ */
+#define FL_MAX_GUESS 10
+
+typedef struct TYPE {
+ char * name;
+ unsigned short info; /* 1 iff "name" is in Terminfo */
+} TYPE;
+
+#define PATT_STAR "*"
+
+typedef struct TEMPLATE {
+ char * keyword;
+ char * pattern;
+ char * re;
+ char * result;
+ int nbra;
+} TEMPLATE;
+
+/*
+ * A (TYPE *) list is an array of content-types (TYPE) with a null
+ * "name" element. A (TEMPLATE *) list is an array of templates (TEMPLATE)
+ * with a null "keyword" element.
+ */
+typedef struct _FILTER {
+ struct _FILTER * next; /* for linking several */
+ char * name;
+ char * command;
+ char ** printers;
+ TYPE * printer_types;
+ TYPE * input_types; /* all possible choices */
+ TYPE * output_types; /* all possible choices */
+ TYPE * inputp; /* the one to be used */
+ TYPE * outputp; /* the one to be used */
+ TEMPLATE * templates;
+ FILTERTYPE type;
+ unsigned char mark,
+ level;
+} _FILTER;
+
+#define FL_CLEAR 0x00
+#define FL_SKIP 0x01
+#define FL_LEFT 0x02
+#define FL_RIGHT 0x04
+
+#define PARM_INPUT "INPUT"
+#define PARM_OUTPUT "OUTPUT"
+#define PARM_TERM "TERM"
+#define PARM_PRINTER "PRINTER"
+
+#define NPARM_SPEC 8
+# define PARM_CPI "CPI"
+# define PARM_LPI "LPI"
+# define PARM_LENGTH "LENGTH"
+# define PARM_WIDTH "WIDTH"
+# define PARM_PAGES "PAGES"
+# define PARM_CHARSET "CHARSET"
+# define PARM_FORM "FORM"
+# define PARM_COPIES "COPIES"
+
+#define PARM_MODES "MODES"
+
+#define FPARM_CPI 0x0001
+#define FPARM_LPI 0x0002
+#define FPARM_LENGTH 0x0004
+#define FPARM_WIDTH 0x0008
+#define FPARM_PAGES 0x0010
+#define FPARM_CHARSET 0x0020
+#define FPARM_FORM 0x0040
+#define FPARM_COPIES 0x0080
+#define FPARM_MODES 0x0100
+
+/**
+ ** Various routines.
+ **/
+
+/*
+ * Null terminated list (filters[i].name == NULL).
+ */
+extern _FILTER *filters;
+
+extern size_t nfilters;
+
+#if defined(__STDC__)
+
+FILTER * getfilter ( char * );
+
+_FILTER * search_filter ( char * );
+
+FILTERTYPE insfilter ( char ** , char * , char * , char * , char * , char ** , unsigned short * );
+FILTERTYPE s_to_filtertype ( char * );
+
+TEMPLATE s_to_template ( char * );
+
+TEMPLATE * sl_to_templatel ( char ** );
+
+TYPE s_to_type ( char * );
+
+TYPE * sl_to_typel ( char ** );
+
+char * template_to_s ( TEMPLATE );
+char * type_to_s ( TYPE );
+
+char ** templatel_to_sl ( TEMPLATE * );
+char ** typel_to_sl ( TYPE * );
+
+int open_filtertable ( char * , char * );
+
+int get_and_load ( void );
+int putfilter ( char * , FILTER * );
+int delfilter ( char * );
+int loadfilters ( char * );
+int dumpfilters( char * );
+
+void freetempl ( TEMPLATE * );
+void freefilter ( FILTER * );
+void free_filter ( _FILTER * );
+void trash_filters ( void );
+void close_filtertable ( FILE * );
+
+#else
+
+extern FILTER *getfilter();
+
+extern _FILTER *search_filter();
+
+extern FILTERTYPE insfilter(),
+ s_to_filtertype();
+
+extern TYPE s_to_type(),
+ *sl_to_typel();
+
+extern TEMPLATE s_to_template(),
+ *sl_to_templatel();
+
+#if defined(BUFSIZ)
+extern FILE *open_filtertable();
+#endif
+
+extern char **typel_to_sl(),
+ **templatel_to_sl(),
+ *getfilterfile();
+
+extern int putfilter(),
+ delfilter(),
+ loadfilters(),
+ get_and_load();
+
+extern void freefilter(),
+ free_filter(),
+ freetempl(),
+ trash_filters(),
+ close_filtertable();
+
+#endif
diff --git a/usr/src/cmd/lp/include/form.h b/usr/src/cmd/lp/include/form.h
new file mode 100644
index 0000000000..a742cc9060
--- /dev/null
+++ b/usr/src/cmd/lp/include/form.h
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+
+#if !defined(_LP_FORM_H)
+#define _LP_FORM_H
+
+/**
+ ** The disk copy of the form files:
+ **/
+
+/*
+ * There are 10 fields in the form configuration file.
+ */
+# define FO_MAX 10
+# define FO_PLEN 0
+# define FO_PWID 1
+# define FO_NP 2
+# define FO_LPI 3
+# define FO_CPI 4
+# define FO_CHSET 5
+# define FO_RCOLOR 6
+# define FO_CMT 7
+# define FO_ALIGN 8
+# define FO_PAPER 9
+
+/**
+ ** The internal copy of a form as seen by the rest of the world:
+ **/
+
+typedef struct FORM {
+ SCALED plen;
+ SCALED pwid;
+ SCALED lpi;
+ SCALED cpi;
+ int np;
+ char * chset;
+ short mandatory;
+ char * rcolor;
+ char * comment;
+ char * conttype;
+ char * name;
+ char * paper;
+ short isDefault;
+} FORM;
+
+/*
+ * Default configuration values:
+ */
+#define DPLEN 66
+#define DPWIDTH 80
+#define DNP 1
+#define DLPITCH 6
+#define DCPITCH 10
+#define DCHSET NAME_ANY
+#define DRCOLOR NAME_ANY
+#define DCONTYP NAME_SIMPLE
+#define ENDENV "#ENDOF_ENV\n"
+#define MANSTR "mandatory"
+#define DFTSTR "default"
+
+/*
+ * These are the filenames that may be used for storing a form
+ */
+#define DESCRIBE "describe"
+#define COMMENT "comment"
+#define ALIGN_PTRN "align_ptrn"
+#define ALERTSH "alert.sh"
+#define ALERTVARS "alert.vars"
+
+#define err_hndlr int (*)( int , int , int )
+
+int delform ( char * );
+int getform ( char * , FORM * , FALERT * , FILE ** );
+int putform ( char * , FORM * , FALERT * , FILE ** );
+int rdform ( char * , FORM * , int , err_hndlr , int * );
+int wrform ( char * , FORM * , int , err_hndlr , int * );
+
+void freeform ( FORM * );
+
+#undef err_hndlr
+
+#endif
diff --git a/usr/src/cmd/lp/include/lp.h b/usr/src/cmd/lp/include/lp.h
new file mode 100644
index 0000000000..50cef37ade
--- /dev/null
+++ b/usr/src/cmd/lp/include/lp.h
@@ -0,0 +1,606 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#ifndef _LP_LP_H
+#define _LP_LP_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <dirent.h>
+
+/**
+ ** Types:
+ **/
+
+typedef struct SCALED {
+ float val; /* value of number, scaled according to "sc" */
+ char sc; /* 'i' inches, 'c' centimeters, ' ' lines/cols */
+} SCALED;
+
+typedef struct FALERT {
+ char * shcmd; /* shell command used to perform the alert */
+ int Q; /* # requests queued to activate alert */
+ int W; /* alert is sent every "W" minutes */
+} FALERT;
+
+
+#define LP_USE_PAPI_ATTR 1 /* use PAPI attributes for printing */
+ /* TODO: is this best place for this ? */
+
+/**
+ ** Places:
+ **/
+
+/*
+ * These functions no longer exist. The defines take care
+ * of recompiling code that expects these and the null functions
+ * in getpaths.c take care of relinking objects that expect these.
+ */
+#define getpaths()
+#define getadminpaths(x)
+
+#define LPDIR "/usr/lib/lp"
+#define ETCDIR "/etc/lp"
+#define SPOOLDIR "/var/spool/lp"
+#define LOGDIR "/var/lp/logs"
+
+#define TERMINFO "/usr/share/lib/terminfo"
+
+#define LPUSER "lp"
+#define ROOTUSER "root"
+
+#define BANG_S "!"
+#define BANG_C '!'
+
+#define LOCAL_LPUSER BANG_S LPUSER
+#define LOCAL_ROOTUSER BANG_S ROOTUSER
+#define ALL_BANG_ALL NAME_ALL BANG_S NAME_ALL
+
+/* #define ADMINSDIR "admins" */
+/* # define CLASSESDIR "classes" */
+/* # define FORMSDIR "forms" */
+/* # define INTERFACESDIR "interfaces" */
+/* # define PRINTERSDIR "printers" */
+/* # define PRINTWHEELSDIR "pwheels" */
+/* #define BINDIR "bin" */
+/* #define LOGSDIR "logs" */
+/* #define MODELSDIR "model" */
+/* #define NETWORKDIR "network" */
+#define FIFOSDIR "fifos"
+/* # define PRIVFIFODIR "private" */
+/* # define PUBFIFODIR "public" */
+/* #define REQUESTSDIR "requests" */
+/* #define SYSTEMDIR "system" */
+/* #define TEMPDIR "temp" */
+/* #define TMPDIR "tmp" */
+
+/* #define SCHEDLOCK "SCHEDLOCK" */
+/* #define FIFO "FIFO" */
+
+#define FILTERTABLE "filter.table"
+#define FILTERTABLE_I "filter.table.i"
+
+/* #define DESCRIBEFILE "describe" */
+/* #define ALIGNFILE "align_ptrn" */
+#define COMMENTFILE "comment"
+#define ALLOWFILE "allow"
+#define DENYFILE "deny"
+#define ALERTSHFILE "alert.sh"
+#define ALERTVARSFILE "alert.vars"
+#define ALERTPROTOFILE "alert.proto"
+#define CONFIGFILE "configuration"
+#define FACCESSPREFIX "forms."
+#define PACCESSPREFIX "paper."
+#define UACCESSPREFIX "users."
+#define FALLOWFILE FACCESSPREFIX ALLOWFILE
+#define FDENYFILE FACCESSPREFIX DENYFILE
+#define UALLOWFILE UACCESSPREFIX ALLOWFILE
+#define UDENYFILE UACCESSPREFIX DENYFILE
+/* #define DEFAULTFILE "default" */
+#define STATUSFILE "status"
+/* #define USERSFILE "users" */
+/* #define NAMEFILE "name" */
+/* #define XFERFILE "transfer" */
+/* #define EXECFILE "execute" */
+#define PSTATUSFILE "pstatus"
+#define CSTATUSFILE "cstatus"
+/* #define REQLOGFILE "requests" */
+
+#define STANDARD "standard"
+/* #define SLOWFILTER "slow.filter" */
+#define FAULTMESSAGEFILE "faultMessage"
+#define FORMMESSAGEFILE "formMessage"
+
+#define LPNET "/usr/lib/lp/lpNet"
+
+#ifdef LP_USE_PAPI_ATTR
+#define STANDARD_FOOMATIC "standard_foomatic"
+ /*
+ * The default model interface script to use if a printer is configured
+ * with a PPD (PostScript Printer Definition) file.
+ */
+#define LP_PAPIATTRNAME "attributes"
+ /*
+ * Job attributes filename extension,
+ * eg. /var/spool/lp/temp/123-attributes
+ */
+#endif
+
+/**
+ ** Names and phrases:
+ **/
+
+/*
+ * If you change these from macros to defined (char *) strings,
+ * be aware that in several places the lengths of the strings
+ * are computed using "sizeof()", not "strlen()"!
+ */
+#define NAME_ALL "all"
+#define NAME_ANY "any"
+#define NAME_NONE "none"
+#define NAME_TERMINFO "terminfo"
+#define NAME_SIMPLE "simple"
+#define NAME_HOLD "hold"
+#define NAME_RESUME "resume"
+#define NAME_IMMEDIATE "immediate"
+#define NAME_CONTINUE "continue"
+#define NAME_BEGINNING "beginning"
+#define NAME_WAIT "wait"
+#define NAME_MAIL "mail"
+#define NAME_WRITE "write"
+#define NAME_QUIET "quiet"
+#define NAME_LIST "list"
+#define NAME_ON "on"
+#define NAME_OFF "off"
+#define NAME_OPTIONAL "optional"
+#define NAME_ALWAYS "Always"
+#define NAME_UNKNOWN "unknown"
+#define NAME_REJECTING "rejecting"
+#define NAME_ACCEPTING "accepting"
+#define NAME_DISABLED "disabled"
+#define NAME_ENABLED "enabled"
+#define NAME_DIRECT "direct"
+#define NAME_PICA "pica"
+#define NAME_ELITE "elite"
+#define NAME_COMPRESSED "compressed"
+#define NAME_ALLOW "allow"
+#define NAME_DENY "deny"
+#define NAME_ONCE "once"
+#define NAME_DEFAULT "default"
+#define NAME_KEEP "keep"
+
+/**
+ ** Common messages:
+ **/
+
+#define CUZ_NEW_PRINTER "new printer"
+#define CUZ_NEW_DEST "new destination"
+#define CUZ_STOPPED "stopped with printer fault"
+#define CUZ_FAULT "printer fault"
+#define CUZ_LOGIN_PRINTER "disabled by Spooler: login terminal"
+#define CUZ_MOUNTING "mounting a form"
+#define CUZ_NOFORK "can't fork"
+#define CUZ_PRINTING_OK "ready and printing"
+
+#define TIMEOUT_FAULT \
+"Timed-out trying to open the printer port.\n"
+
+#define OPEN_FAULT \
+"Failed to open the printer port.\n"
+
+#define PUSH_FAULT \
+"Failed to push module(s) onto the printer port stream.\n"
+
+/*
+ * When the Spooler detected the hangup, this message is used.
+ */
+#define HANGUP_FAULT \
+"The connection to the printer dropped; perhaps the printer went off-line!\n"
+
+/*
+ * When lp.cat detected the hangup, this message is used.
+ */
+#define HANGUP_FAULT_LPCAT \
+"The connection to the printer dropped; perhaps the printer went off-line.\n"
+
+#define INTERRUPT_FAULT \
+"Received an interrupt from the printer. The reason is unknown,\nalthough a common cause is that the printer's buffer capacity\nwas exceeded. Using XON/XOFF flow control, adding carriage-return\ndelays, or lowering the baud rate may fix the problem.\nSee stty(1) and lpadmin(1M) man-pages for help in doing this.\n"
+
+#define PIPE_FAULT \
+"The output ``port'', a FIFO, was closed before all output was written.\n"
+
+#define EXIT_FAULT \
+"The interface program returned with a reserved exit code.\n"
+
+/**
+ ** Lp-errno #defines, etc.
+ **/
+
+#define LP_EBADSDN 1
+#define LP_EBADINT 2
+#define LP_EBADNAME 3
+#define LP_EBADARG 4
+#define LP_ETRAILIN 5
+#define LP_ENOCMT 6
+#define LP_EBADCTYPE 7
+#define LP_ENOALP 8
+#define LP_ENULLPTR 9
+#define LP_EBADHDR 10
+#define LP_ETEMPLATE 11
+#define LP_EKEYWORD 12
+#define LP_EPATTERN 13
+#define LP_ERESULT 14
+#define LP_EREGEX 15 /* and see extern int regerrno, regexpr(3G) */
+#define LP_ENOMEM 99
+
+extern int lp_errno;
+
+/**
+ ** Misc. Macros
+ **/
+
+#define LP_WS " " /* Whitespace (also list separator) */
+#define LP_SEP "," /* List separator */
+#define LP_QUOTES "'\""
+
+#define MAIL "mail"
+#define WRITE "write"
+
+#define STATUS_BREAK "=========="
+
+#define STREQU(A,B) ( (!(A) || !(B)) ? 0: (strcmp((A), (B)) == 0) )
+#define STRNEQU(A,B,N) ( (!(A) || !(B)) ? 0: (strncmp((A), (B), (N)) == 0) )
+#define CS_STREQU(A,B) (cs_strcmp((A), (B)) == 0)
+#define CS_STRNEQU(A,B,N) (cs_strncmp((A), (B), (N)) == 0)
+#define STRSIZE(X) (sizeof(X) - 1)
+
+/*
+ * Almost STREQU but compares null pointers as equal, too.
+ */
+#define SAME(A,B) ((A) == (B) || (A) && (B) && STREQU((A), (B)))
+
+#define PRINTF (void)printf
+#define SPRINTF (void)sprintf
+#define FPRINTF (void)fprintf
+
+#define NB(X) (X? X : "")
+
+#define PERROR strerror(errno)
+
+/*
+ * Largest number we'll ever expect to get from doing %ld in printf,
+ * as a string and number. ULONG_MAX from limits.h gives us the number,
+ * but I can't figure out how to get that into a string.
+ */
+#define BIGGEST_NUMBER ULONG_MAX
+#define BIGGEST_NUMBER_S "4294967295"
+
+/*
+ * Largest request ID (numerical part), as string and number.
+ * See comment above.
+ */
+#define BIGGEST_REQID 999999
+#define BIGGEST_REQID_S "999999"
+
+/*
+ * Maximum number of files queued per request, as string and number.
+ * See earlier comment above.
+ */
+#define MOST_FILES 999999
+#define MOST_FILES_S "999999"
+
+/**
+ ** Alert macros:
+ **/
+
+/*
+ * Type of alert to be S_QUIET'd
+ */
+#define QA_FORM 1
+#define QA_PRINTER 2
+#define QA_PRINTWHEEL 3
+
+/**
+ ** File modes:
+ ** (The "NO" prefix is relative to ``others''.)
+ **/
+
+#define MODE_READ (mode_t)0664
+#define MODE_NOREAD (mode_t)0660
+#define MODE_EXEC (mode_t)0775
+#define MODE_NOEXEC (mode_t)0770
+#define MODE_DIR (mode_t)0775
+#define MODE_NODIR (mode_t)0770
+
+extern int printlist_qsep;
+
+extern char Lp_Spooldir[],
+ Lp_Admins[],
+ Lp_Bin[],
+ Lp_FIFO[],
+ Lp_Logs[],
+ Lp_ReqLog[],
+ Lp_Model[],
+ Lp_Requests[],
+ Lp_Secure[],
+ Lp_Schedlock[],
+ Lp_Slow_Filter[],
+ Lp_System[],
+ Lp_Temp[],
+ Lp_Tmp[],
+ Lp_Users[],
+ Lp_A[],
+ Lp_A_Classes[],
+ Lp_A_Forms[],
+ Lp_A_Interfaces[],
+ Lp_A_Logs[],
+ Lp_A_Printers[],
+ Lp_A_PrintWheels[],
+ Lp_A_Filters[],
+ Lp_A_Systems[],
+ Lp_Default[],
+ Lp_A_Faults[];
+
+/*
+ * File access:
+ */
+
+extern int open_locked(char *, char *, mode_t);
+extern char *fdgets(char *, int, int);
+extern int fdprintf(int, char *, ...);
+extern int fdputs(char *, int);
+extern int fdputc(char, int);
+
+extern int is_printer_uri(char *);
+
+FILE *open_lpfile ( char * , char * , mode_t );
+int close_lpfile ( FILE * );
+int chown_lppath ( char * path );
+int mkdir_lpdir ( char * path , int mode );
+int rmfile ( char * path );
+int dumpstring ( char * path , char * str );
+
+char * loadstring ( char * path );
+char * loadline ( char * path );
+char * sop_up_rest (int, char * endsop );
+
+/*
+ * List manipulation routines:
+ */
+
+#define emptylist(LP) (!(LP) || !(LP)[0])
+
+int addlist ( char *** , char * );
+int addstring ( char ** , char * );
+int appendlist ( char *** , char * );
+int dellist ( char *** , char * );
+int joinlist ( char *** , char ** );
+int lenlist ( char ** );
+int printlist ( FILE * , char ** );
+int fdprintlist(int , char ** );
+int searchlist ( char *, char ** );
+int searchlist_with_terminfo ( char * , char ** );
+
+char ** duplist ( char ** );
+char ** getlist ( char * , char * , char * );
+char ** dashos ( char * );
+char ** wherelist ( char * , char ** );
+
+char * sprintlist ( char ** );
+char * search_cslist ( char * , char ** );
+
+void freelist ( char ** );
+void printlist_setup ( char * , char * , char * , char * );
+void printlist_unsetup ( void );
+
+/*
+ * Scaled decimal number routines:
+ */
+
+#define getsdn(S) _getsdn(S, (char **)0, 0)
+#define getcpi(S) _getsdn(S, (char **)0, 1)
+
+#define N_COMPRESSED 9999
+
+void printsdn ( FILE * , SCALED );
+void fdprintsdn ( int , SCALED );
+void printsdn_setup ( char * , char * , char * );
+void printsdn_unsetup ( void );
+
+SCALED _getsdn ( char * , char ** , int );
+
+/*
+ * File name routines:
+ */
+
+char * makepath ( char * , ... );
+char * getspooldir ( void );
+char * getrequestfile ( char * );
+char * getprinterfile ( char * , char * );
+char * getsystemfile ( char * , char * );
+char * getclassfile ( char * );
+char * getfilterfile ( char * );
+char * getformfile ( char * , char * );
+
+/*
+ * Additional string manipulation routines:
+ */
+
+int cs_strcmp ( char * , char * );
+int cs_strncmp ( char * , char * , int );
+
+/*
+ * Syntax checking routines:
+ */
+
+int syn_name ( char * );
+int syn_text ( char * );
+int syn_comment ( char * );
+int syn_machine_name ( char * );
+int syn_option ( char * );
+
+/*
+ * Alert management routines:
+ */
+
+int putalert ( char * , char * , FALERT * );
+int delalert ( char * , char * );
+
+FALERT * getalert ( char * , char * );
+
+void printalert ( FILE * , FALERT * , int );
+
+/*
+ * Terminfo Database Inquiry Tool
+ */
+
+int tidbit ( char * , char * , ... );
+void untidbit ( char * );
+
+/*
+ * Auto-restarting and other system calls:
+ * The two versions are here to reduce the chance of colliding
+ * with similar names in standard libraries (e.g. dial(3C) uses
+ * Read/Write).
+ */
+
+#define Access _Access
+#define Chdir _Chdir
+#define Chmod _Chmod
+#define Chown _Chown
+#define Close _Close
+#define Creat _Creat
+#define Fcntl _Fcntl
+#define Fstat _Fstat
+#define Link _Link
+#define Lstat _Lstat
+#define Mknod _Mknod
+#define Open _Open
+#define Read _Read
+#define Readlink _Readlink
+#define Rename _Rename
+#define Stat _Stat
+#define Symlink _Symlink
+#define Unlink _Unlink
+#define Wait _Wait
+#define Write _Write
+
+#define Malloc(size) _Malloc(size, __FILE__, __LINE__)
+#define Realloc(ptr,size) _Realloc(ptr, size, __FILE__, __LINE__)
+#define Calloc(nelem,elsize) _Calloc(nelem, elsize, __FILE__, __LINE__)
+#define Strdup(s) _Strdup(s, __FILE__, __LINE__)
+#define Free(ptr) _Free(ptr, __FILE__, __LINE__)
+
+int _Access ( char * , int );
+int _Chdir ( char * );
+int _Chmod ( char * , int );
+int _Chown ( char * , int , int );
+int _Close ( int );
+int _Creat ( char * , int );
+int _Fcntl ( int , int , ... );
+int _Fstat ( int , struct stat * );
+int _Link ( char * , char * );
+int _Lstat ( char * , struct stat * );
+int _Mknod ( char * , int , int );
+int _Mkpipe ( char * , int , int );
+int _Open ( char * , int , ... /* mode_t */ );
+int _Read ( int , char * , unsigned int );
+int _Readlink ( char * , char * , unsigned int );
+int _Rename ( char * , char * );
+int _Symlink ( char * , char * );
+int _Stat ( char * , struct stat * );
+int _Unlink ( char * );
+int _Wait ( int * );
+int _Write ( int , char * , unsigned int );
+
+void * _Malloc ( size_t , const char * , int );
+void * _Realloc ( void * , size_t , const char * , int );
+void * _Calloc ( size_t , size_t , const char * , int );
+char * _Strdup ( const char * , const char * , int );
+void _Free ( void * , const char * , int );
+
+/*
+ * Misc. routines:
+ */
+
+int isterminfo ( char * );
+int isprinter ( char * );
+int isrequest ( char * );
+int isnumber ( char * );
+
+char * getname ( void );
+char * makestr ( char * , ... );
+char * strip ( char * );
+
+void sendmail ( char * , char * );
+
+void (*lp_alloc_fail_handler)( void );
+
+/*
+ * Originally part of liblpfs.a and fs.h, now no longer needed
+ * since the code doesn't have to work on pre-SVR4.0.
+ */
+#define Opendir opendir
+#define Telldir telldir
+#define Seekdir seekdir
+#define Rewinddir(dirp) Seekdir(dirp, 0L)
+#define Closedir closedir
+#define Readdir readdir
+#define Mkdir mkdir
+#define Rmdir rmdir
+
+#define next_dir(base, ptr) next_x(base, ptr, S_IFDIR)
+#define next_file(base, ptr) next_x(base, ptr, S_IFREG)
+
+extern int chownmod(char *path, uid_t owner, gid_t group, mode_t mode);
+
+
+char * next_x ( char * , long * , unsigned int );
+
+/*
+ * Stuff needed for Trusted Extensions
+ */
+
+extern char *get_labeled_zonename(char *);
+extern int get_peer_label(int fd, char **slabel);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LP_LP_H */
diff --git a/usr/src/cmd/lp/include/lp.set.h b/usr/src/cmd/lp/include/lp.set.h
new file mode 100644
index 0000000000..e2a32abad4
--- /dev/null
+++ b/usr/src/cmd/lp/include/lp.set.h
@@ -0,0 +1,67 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+
+
+#if !defined(_LP_LP_SET_H)
+#define _LP_LP_SET_H
+
+/*
+ * How far should we check for "compressed" horizontal pitch?
+ * Keep in mind that (1) too far and the user can't read it, and
+ * (2) some Terminfo entries don't limit their parameters like
+ * they should. Keep in mind the other hand, though: What is too
+ * compact for you may be fine for the eagle eyes next to you!
+ */
+#define MAX_COMPRESSED 30 /* CPI */
+
+#define E_SUCCESS 0
+#define E_FAILURE 1
+#define E_BAD_ARGS 2
+#define E_MALLOC 3
+
+#define OKAY(P) ((P) && (*P))
+#define R(F) (int)((F) + .5)
+
+#if !defined(CHARSETDIR)
+# define CHARSETDIR "/usr/share/lib/charset"
+#endif
+
+#if defined(__STDC__)
+
+int set_pitch ( char * , int , int );
+int set_size ( char * , int , int );
+int set_charset ( char * , int , char * );
+
+#else
+
+int set_pitch(),
+ set_size(),
+ set_charset();
+
+#endif
+
+#endif
diff --git a/usr/src/cmd/lp/include/msgs.h b/usr/src/cmd/lp/include/msgs.h
new file mode 100644
index 0000000000..90d1f3f186
--- /dev/null
+++ b/usr/src/cmd/lp/include/msgs.h
@@ -0,0 +1,442 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+# include <sys/types.h>
+# include <poll.h>
+# include <stdarg.h>
+# include <stropts.h>
+
+#if !defined(_LP_MSGS_H)
+# define _LP_MSGS_H
+
+/*
+ * THE DISPATCH TABLE DEPENDS ON EACH R_... MESSAGE FOLLOWING
+ * IMMEDIATELY AFTER ITS CORRESPONDING S_... COUNTERPART.
+ * I.E R_... MESSAGE FOR A S_... MESSAGE IS (S_... + 1)
+ */
+# define R_BAD_MESSAGE 0
+/* # define S_NEW_QUEUE 1 DEFUNCT */
+/* # define R_NEW_QUEUE 2 DEFUNCT */
+# define S_ALLOC_FILES 3
+# define R_ALLOC_FILES 4
+# define S_PRINT_REQUEST 5
+# define R_PRINT_REQUEST 6
+# define S_START_CHANGE_REQUEST 7
+# define R_START_CHANGE_REQUEST 8
+# define S_END_CHANGE_REQUEST 9
+# define R_END_CHANGE_REQUEST 10
+# define S_CANCEL_REQUEST 11
+# define R_CANCEL_REQUEST 12
+/* # define S_INQUIRE_REQUEST 13 DEFUNCT */
+/* # define R_INQUIRE_REQUEST 14 DEFUNCT */
+# define S_LOAD_PRINTER 15
+# define R_LOAD_PRINTER 16
+# define S_UNLOAD_PRINTER 17
+# define R_UNLOAD_PRINTER 18
+# define S_INQUIRE_PRINTER_STATUS 19
+# define R_INQUIRE_PRINTER_STATUS 20
+# define S_LOAD_CLASS 21
+# define R_LOAD_CLASS 22
+# define S_UNLOAD_CLASS 23
+# define R_UNLOAD_CLASS 24
+# define S_INQUIRE_CLASS 25
+# define R_INQUIRE_CLASS 26
+# define S_MOUNT 27
+# define R_MOUNT 28
+# define S_UNMOUNT 29
+# define R_UNMOUNT 30
+# define S_MOVE_REQUEST 31
+# define R_MOVE_REQUEST 32
+# define S_MOVE_DEST 33
+# define R_MOVE_DEST 34
+# define S_ACCEPT_DEST 35
+# define R_ACCEPT_DEST 36
+# define S_REJECT_DEST 37
+# define R_REJECT_DEST 38
+# define S_ENABLE_DEST 39
+# define R_ENABLE_DEST 40
+# define S_DISABLE_DEST 41
+# define R_DISABLE_DEST 42
+# define S_LOAD_FILTER_TABLE 43
+# define R_LOAD_FILTER_TABLE 44
+# define S_UNLOAD_FILTER_TABLE 45
+# define R_UNLOAD_FILTER_TABLE 46
+# define S_LOAD_PRINTWHEEL 47
+# define R_LOAD_PRINTWHEEL 48
+# define S_UNLOAD_PRINTWHEEL 49
+# define R_UNLOAD_PRINTWHEEL 50
+# define S_LOAD_USER_FILE 51
+# define R_LOAD_USER_FILE 52
+# define S_UNLOAD_USER_FILE 53
+# define R_UNLOAD_USER_FILE 54
+# define S_LOAD_FORM 55
+# define R_LOAD_FORM 56
+# define S_UNLOAD_FORM 57
+# define R_UNLOAD_FORM 58
+/* # define S_GETSTATUS 59 DEFUNCT */
+/* # define R_GETSTATUS 60 DEFUNCT */
+# define S_QUIET_ALERT 61
+# define R_QUIET_ALERT 62
+# define S_SEND_FAULT 63
+# define R_SEND_FAULT 64
+# define S_SHUTDOWN 65
+# define R_SHUTDOWN 66
+# define S_GOODBYE 67
+# define S_CHILD_DONE 68
+
+/*
+** These are for use by the scheduler only
+*/
+# define I_GET_TYPE 69
+# define I_QUEUE_CHK 70
+/* # define R_CONNECT 71 DEFUNCT */
+
+/* # define S_GET_STATUS 72 DEFUNCT */
+/* # define R_GET_STATUS 73 DEFUNCT */
+# define S_INQUIRE_REQUEST_RANK 74
+# define R_INQUIRE_REQUEST_RANK 75
+# define S_CANCEL 76
+# define R_CANCEL 77
+/* # define S_NEW_CHILD 78 DEFUNCT */
+/* # define R_NEW_CHILD 79 DEFUNCT */
+/* # define S_SEND_JOB 80 DEFUNCT */
+/* # define R_SEND_JOB 81 DEFUNCT */
+/* # define S_JOB_COMPLETED 82 DEFUNCT */
+/* # define R_JOB_COMPLETED 83 DEFUNCT */
+/* # define S_INQUIRE_REMOTE_PRINTER 84 DEFUNCT */
+/* # define R_INQUIRE_REMOTE_PRINTER 20 DEFUNCT */
+/* # define S_CHILD_SYNC 85 DEFUNCT */
+/* # define S_LOAD_SYSTEM 86 DEFUNCT */
+/* # define R_LOAD_SYSTEM 87 DEFUNCT */
+/* # define S_UNLOAD_SYSTEM 88 DEFUNCT */
+/* # define R_UNLOAD_SYSTEM 89 DEFUNCT */
+/* new messages */
+# define S_CLEAR_FAULT 90
+# define R_CLEAR_FAULT 91
+# define S_MOUNT_TRAY 92
+# define R_MOUNT_TRAY 93
+# define S_UNMOUNT_TRAY 94
+# define R_UNMOUNT_TRAY 95
+# define S_MAX_TRAYS 96
+# define R_MAX_TRAYS 97
+# define S_PAPER_CHANGED 98
+# define R_PAPER_CHANGED 99
+# define S_PAPER_ALLOWED 100
+# define R_PAPER_ALLOWED 101
+# define S_PASS_PEER_CONNECTION 102
+# define R_PASS_PEER_CONNECTION 103
+/*
+** Last available message
+*/
+# define LAST_MESSAGE 104
+
+/*
+** These are the possible status codes returned by the scheduler
+*/
+# define MOK 0
+# define MOKMORE 1
+# define MOKREMOTE 2
+# define MMORERR 3
+# define MNODEST 4
+# define MERRDEST 5
+# define MDENYDEST 6
+# define MNOMEDIA 7
+# define MDENYMEDIA 8
+# define MNOFILTER 9
+# define MNOINFO 10
+# define MNOMEM 11
+# define MNOMOUNT 12
+# define MNOOPEN 13
+# define MNOPERM 14
+# define MNOSTART 15
+# define MUNKNOWN 16
+# define M2LATE 17
+# define MNOSPACE 18
+# define MBUSY 19
+# define MTRANSMITERR 20
+# define MNOMORE 21
+# define MGONEREMOTE 22
+# define MNOTRAY 23
+
+/*
+** Offsets and lengths of the various elements of the message header.
+**
+** Macro Data Type Size Comment
+**
+** HEAD_RESYNC 2 bytes (2) *
+** HEAD_AUTHCODE short + long (6) *
+**
+** HEAD_SIZE 4 bytes (4) \
+** HEAD_TYPE 4 bytes (4) > message propper
+** HEAD_DATA n bytes (n) /
+**
+** TAIL_CHKSUM 4 bytes (4) *
+** TAIL_ENDSYNC 2 bytes (2) *
+**
+** Items marked with an asterisk are only used with the 3.2
+** Spooler protocol.
+*/
+
+/*
+** 3.2 Protocol Header Information:
+** 2-byte message introduction
+** 6-byte client authorization data
+*/
+#define HEAD_RESYNC (0)
+#define HEAD_RESYNC_LEN 2
+#define HEAD_AUTHCODE (HEAD_RESYNC + HEAD_RESYNC_LEN)
+#define HEAD_AUTHCODE_LEN (sizeof(short) + sizeof(long))
+
+/*
+** 3.2 Protocol Message Information:
+** 4-byte message size
+** 4-byte message type
+** n-byte message data
+*/
+#define HEAD_SIZE (HEAD_AUTHCODE + HEAD_AUTHCODE_LEN)
+#define HEAD_SIZE_LEN 4
+#define HEAD_TYPE (HEAD_SIZE + HEAD_SIZE_LEN)
+#define HEAD_TYPE_LEN 4
+#define HEAD_DATA (HEAD_TYPE + HEAD_TYPE_LEN)
+
+/*
+** 3.2 Protocol Size of non-data header information
+*/
+#define HEAD_LEN HEAD_DATA
+
+/*
+** Equivalents for 4.0 protocol
+*/
+#define MESG_SIZE (0)
+#define MESG_SIZE_LEN 4
+#define MESG_TYPE (MESG_SIZE + MESG_SIZE_LEN)
+#define MESG_TYPE_LEN 4
+#define MESG_DATA (MESG_TYPE + MESG_TYPE_LEN)
+
+#define MESG_LEN MESG_DATA
+
+/*
+** 3.2 Protocol Trailer Information:
+** 4-byte message check sum
+** 2-byte message closing identifier
+**
+** "N" is the decoded value of buffer[HEAD_SIZE]. This must
+** be provided because messages are variable length.
+*/
+#define TAIL_ENDSYNC_LEN 2
+#define TAIL_ENDSYNC(N) (N - TAIL_ENDSYNC_LEN)
+#define TAIL_CHKSUM_LEN 4
+#define TAIL_CHKSUM(N) (TAIL_ENDSYNC(N) - TAIL_CHKSUM_LEN)
+
+/*
+** 3.2 Protocol Size of non-data trailer information
+*/
+#define TAIL_LEN (TAIL_CHKSUM_LEN + TAIL_ENDSYNC_LEN)
+
+/*
+** 3.2 Protocol Size of all non-data information
+** (This is also the minimum size for 3.2 protocol messages)
+*/
+#define CONTROL_LEN (HEAD_LEN + TAIL_LEN)
+
+/*
+** Size of excess data induced by 3.2 Protocol.
+** (This is also the size differance between 3.2 & 4.0 protocols)
+*/
+#define EXCESS_3_2_LEN (HEAD_SIZE + TAIL_LEN)
+/**
+ ** Checksum:
+ **/
+#define CALC_CHKSUM(B,SZ,RC) \
+if (SZ >= CONTROL_LEN) \
+{ \
+ register unsigned char *p = (unsigned char *)B, \
+ *pend = p + SZ - TAIL_LEN; \
+ RC = 0; \
+ while (p < pend) \
+ RC += *p++; /* let it overflow */ \
+} \
+else \
+ return ((errno = EINVAL, -1))
+
+/*
+** Largest size permitted for any given message
+*/
+# define MSGMAX 2048
+
+/*
+** Possible values of the type field of S_QUIET_ALERT
+*/
+# define QA_FORM 1
+# define QA_PRINTER 2
+# define QA_PRINTWHEEL 3
+
+typedef struct strbuf strbuf_t; /* STREAMS buffer */
+
+typedef struct mque
+{
+ struct mque *next;
+ struct strbuf *dat;
+} MQUE;
+
+/*
+** Definition of a message descriptor
+*/
+typedef struct
+{
+ short type; /* type of connection */
+ int readfd; /* STREAM fd to read from */
+ int writefd; /* STREAM fd to write to */
+ int wait; /* number of systems waiting for */
+ char *file; /* pipe name if type==MD_FIFO */
+ short state; /* Current state of client */
+ short admin; /* Non zero if admin */
+ short event; /* Event returned from poll */
+ MQUE * mque; /* backlogged message ptr */
+ uid_t uid; /* Clients UID */
+ gid_t gid; /* Clients GID */
+ char * slabel; /* Clients SLABEL */
+ void (**on_discon)(); /* Clean up functions */
+} MESG;
+
+# define MDSIZE (sizeof(MESG))
+
+/*
+** Possible values of MESG.state
+*/
+# define MDS_IDLE 0
+
+# define MDS_32PROTO 320
+# define MDS_32CONNECT 321
+
+/*
+** Possible values of MESG.type
+*/
+# define MD_UNKNOWN 0 /* We don't know just yet */
+# define MD_STREAM 1 /* 4.0 STREAMS pipe protocol */
+# define MD_BOUND 2 /* 4.0 STREAMS fd protocol */
+# define MD_SYS_FIFO 3 /* 3.2 named-pipe protocol */
+# define MD_USR_FIFO 4 /* 3.2 named-pipe protocol */
+# define MD_MASTER 5 /* MD_STREAM used by lpsched */
+# define MD_CHILD 6 /* MD_STREAM to a child process */
+
+/*
+** Definition for a FIFO buffer (used
+** in read_fifo.
+*/
+typedef struct
+{
+ int full;
+ char save [MSGMAX],
+ *psave,
+ *psave_end;
+} fifobuffer_t;
+
+/*
+** Definitions for the rest of the world and lint
+*/
+/*
+** Server functions in order of usage
+*/
+MESG * mcreate ( char * );
+int mlisteninit ( MESG * );
+MESG * mlisten ( void );
+int mlistenadd ( MESG *, short );
+int mon_discon ( MESG *, void (*)());
+MESG * mlistenreset ( void );
+int mdestroy ( MESG * );
+
+/*
+** Client functions in order of typical usage
+*/
+MESG * mconnect ( char *, int, int );
+int mgetm ( MESG *, int, ... );
+int mwrite ( MESG *, char * );
+int mputm ( MESG *, int, ... );
+int mread ( MESG *, char *, int );
+short msize ( char * );
+short mpeek ( MESG * );
+int mdisconnect ( MESG * );
+
+/*
+** This may be called to deallocate internal buffers allocated
+** by mgetm and mputm. Probably not useful except right before
+** a fork().
+*/
+void __mbfree ( void );
+
+/*
+** Client functions for pre-4.0 compatability
+*/
+int mclose ( void );
+int mneeds ( void );
+int mopen ( void );
+int mrecv ( char *, int );
+int msend ( char * );
+
+int Putmsg (MESG *, strbuf_t *, strbuf_t *, int);
+int Getmsg (MESG *, strbuf_t *, strbuf_t *, int *);
+int read3_2 (MESG * md, char *msgbuf, int size);
+int write3_2 (MESG *, char *, int);
+int read_fifo (int, char *, unsigned int);
+int write_fifo (int, char *, unsigned int);
+int ResetFifoBuffer (int);
+fifobuffer_t *GetFifoBuffer (int);
+
+/*
+** General purpose message manipulating functions
+*/
+char * htos ( char *, unsigned short );
+char * ltos ( char *, unsigned long );
+unsigned long stol ( char * );
+unsigned short stoh ( char * );
+int _getmessage ( char *, short, va_list );
+int _putmessage ( char *, short, va_list );
+int getmessage ( char *, short, ... );
+int putmessage ( char *, short, ... );
+
+/*
+** This will yield the type of a message
+*/
+# define mtype(buffer) (getmessage(buffer, I_GET_TYPE))
+
+/*
+** This will yeild the size of a message
+*/
+# define msize(buffer) (stoh(buffer))
+
+/*
+** Pass this for the request-id argument of S_CANCEL
+** to obtain the effect of the 3.2 S_CANCEL_REQUEST.
+*/
+# define CURRENT_REQ "current"
+
+#endif /* !defined (_LP_MSGS_H) */
diff --git a/usr/src/cmd/lp/include/oam.h b/usr/src/cmd/lp/include/oam.h
new file mode 100644
index 0000000000..52176315b6
--- /dev/null
+++ b/usr/src/cmd/lp/include/oam.h
@@ -0,0 +1,174 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+
+
+#if !defined(_LP_OAM_H)
+# define _LP_OAM_H
+/*
+ * Change the following lines to include the appropriate
+ * standard header file when it becomes available.
+ * Or change all the LP source to include it directly,
+ * and get rid of the following stuff (up to the ====...==== line).
+ */
+
+char *agettxt(long msg_id, char *buf, int buflen);
+
+void fmtmsg(char * label, int severity, char * text, char * action);
+
+/*
+ * Possible values of "severity":
+ */
+#define MIN_SEVERITY 0
+#define HALT 0
+#define ERROR 1
+#define WARNING 2
+#define INFO 3
+#define MAX_SEVERITY 3
+
+/**======================================================================
+ **
+ ** LP Spooler specific error message handling.
+ **/
+
+#define MSGSIZ 512
+
+#if defined(WHO_AM_I)
+
+#include "oam_def.h"
+
+#if WHO_AM_I == I_AM_CANCEL
+static char *who_am_i = "UX:cancel";
+
+#elif WHO_AM_I == I_AM_COMB
+static char *who_am_i = "UX:comb ";
+ /* changed inside pgm */
+
+#elif WHO_AM_I == I_AM_LPMOVE
+static char *who_am_i = "UX:lpmove";
+
+#elif WHO_AM_I == I_AM_LPUSERS
+static char *who_am_i = "UX:lpusers";
+
+#elif WHO_AM_I == I_AM_LPNETWORK
+static char *who_am_i = "UX:lpnetwork";
+
+#elif WHO_AM_I == I_AM_LP
+static char *who_am_i = "UX:lp";
+
+#elif WHO_AM_I == I_AM_LPADMIN
+static char *who_am_i = "UX:lpadmin";
+
+#elif WHO_AM_I == I_AM_LPFILTER
+static char *who_am_i = "UX:lpfilter";
+
+#elif WHO_AM_I == I_AM_LPFORMS
+static char *who_am_i = "UX:lpforms";
+
+#elif WHO_AM_I == I_AM_LPPRIVATE
+static char *who_am_i = "UX:lpprivate";
+
+#elif WHO_AM_I == I_AM_LPSCHED
+static char *who_am_i = "UX:lpsched";
+
+#elif WHO_AM_I == I_AM_LPSHUT
+static char *who_am_i = "UX:lpshut";
+
+#elif WHO_AM_I == I_AM_LPSTAT
+static char *who_am_i = "UX:lpstat";
+
+#elif WHO_AM_I == I_AM_LPSYSTEM
+static char *who_am_i = "UX:lpsystem";
+
+#else
+static char *who_am_i = "UX:mysterious";
+
+#endif
+
+/*
+ * Simpler interfaces to the "fmtmsg()" and "agettxt()" stuff.
+ */
+
+#if defined(lint)
+
+#define LP_ERRMSG(C,X) (void)printf("", C, X)
+#define LP_ERRMSG1(C,X,A) (void)printf("", C, X, A)
+#define LP_ERRMSG2(C,X,A1,A2) (void)printf("", C, X, A1, A2)
+#define LP_ERRMSG3(C,X,A1,A2,A3) (void)printf("", C, X, A1, A2, A3)
+
+#else
+
+#define LP_ERRMSG(C,X) \
+ fmtmsg ( \
+ who_am_i, \
+ C, \
+ agettxt((X), _m_, MSGSIZ), \
+ agettxt((X+1), _a_, MSGSIZ) \
+ )
+#define LP_ERRMSG1(C,X,A) \
+ fmtmsg ( \
+ who_am_i, \
+ C, \
+ fmt1((X), A), \
+ agettxt((X+1), _a_, MSGSIZ) \
+ )
+#define LP_ERRMSG2(C,X,A1,A2) \
+ fmtmsg ( \
+ who_am_i, \
+ C, \
+ fmt2((X), A1, A2), \
+ agettxt((X+1), _a_, MSGSIZ) \
+ )
+#define LP_ERRMSG3(C,X,A1,A2,A3) \
+ fmtmsg ( \
+ who_am_i, \
+ C, \
+ fmt3((X), A1, A2, A3), \
+ agettxt((X+1), _a_, MSGSIZ) \
+ )
+
+
+#define vsnp (void)snprintf
+
+#define fmt1(X,A) (vsnp(_m_, MSGSIZ, agettxt((X),_f_,MSGSIZ), A), _m_)
+#define fmt2(X,A,B) (vsnp(_m_, MSGSIZ, agettxt((X),_f_,MSGSIZ), A,B), _m_)
+#define fmt3(X,A,B,C) (vsnp(_m_, MSGSIZ, agettxt((X),_f_,MSGSIZ), A,B,C), _m_)
+
+#endif /* lint */
+
+extern char _m_[],
+ _a_[],
+ _f_[],
+ *_t_;
+
+#endif /* WHO_AM_I */
+
+#endif
diff --git a/usr/src/cmd/lp/include/printers.h b/usr/src/cmd/lp/include/printers.h
new file mode 100644
index 0000000000..baf8698645
--- /dev/null
+++ b/usr/src/cmd/lp/include/printers.h
@@ -0,0 +1,215 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#if !defined(_LP_PRINTERS_H)
+#define _LP_PRINTERS_H
+
+/*
+ * Define the following to support administrator configurable
+ * streams modules:
+ */
+#define CAN_DO_MODULES 1 /* */
+
+/**
+ ** The disk copy of the printer files:
+ **/
+
+/*
+ * There are 19 fields in the printer configuration file.
+ */
+#define PR_MAX 19
+# define PR_BAN 0
+# define PR_CPI 1
+# define PR_CS 2
+# define PR_ITYPES 3
+# define PR_DEV 4
+# define PR_DIAL 5
+# define PR_RECOV 6
+# define PR_INTFC 7
+# define PR_LPI 8
+# define PR_LEN 9
+# define PR_LOGIN 10
+# define PR_PTYPE 11
+# define PR_REMOTE 12
+# define PR_SPEED 13
+# define PR_STTY 14
+# define PR_WIDTH 15
+# define PR_MODULES 16
+#define PR_OPTIONS 17
+#define PR_PPD 18
+
+/**
+ ** The internal flags seen by the Spooler/Scheduler and anyone who asks.
+ **/
+
+#define PS_REJECTED 0x001
+#define PS_DISABLED 0x002
+#define PS_FAULTED 0x004
+#define PS_BUSY 0x008
+#define PS_LATER 0x010 /* Printer is scheduled for service */
+#define PS_SHOW_FAULT 0x100 /* set if exMess should be run when fault */
+#define PS_USE_AS_KEY 0x200 /* to insure that status used as key is non 0 */
+#define PS_FORM_FAULT 0x400 /* set a form fault rather a printer fault*/
+
+/**
+ ** The internal copy of a printer as seen by the rest of the world:
+ **/
+
+/*
+ * A (char **) list is an array of string pointers (char *) with
+ * a null pointer after the last item.
+ */
+typedef struct PRINTER {
+ char *name; /* name of printer (redundant) */
+ unsigned short banner; /* banner page conditions */
+ SCALED cpi; /* default character pitch */
+ char **char_sets; /* list of okay char-sets/print-wheels */
+ char **input_types; /* list of types acceptable to printer */
+ char *device; /* printer port full path name */
+ char *dial_info; /* system name or phone # for dial-up */
+ char *fault_rec; /* printer fault recovery procedure */
+ char *interface; /* interface program full path name */
+ SCALED lpi; /* default line pitch */
+ SCALED plen; /* default page length */
+ unsigned short login; /* is/isn't a login terminal */
+ char *printer_type; /* Terminfo look-up value (obsolete) */
+ char *remote; /* remote machine!printer-name */
+ char *speed; /* baud rate for connection */
+ char *stty; /* space separated list of stty options */
+ SCALED pwid; /* default page width */
+ char *description; /* comment about printer */
+ FALERT fault_alert; /* how to alert on printer fault */
+ short daisy; /* 1/0 - printwheels/character-sets */
+#if defined(CAN_DO_MODULES)
+ char **modules; /* streams modules to push */
+#endif
+ char **printer_types; /* Terminfo look-up values */
+ char **options; /* space separated list of undefined -o options */
+
+#ifdef LP_USE_PAPI_ATTR
+ char *ppd; /* printer's PPD file full path name */
+#endif
+ /*
+ * Adding new members to this structure? Check out
+ * cmd/lpadmin/do_printer.c, where we initialize
+ * each new printer structure.
+ */
+} PRINTER;
+
+#define BAN_ALWAYS 0x01 /* user can't override banner */
+#define BAN_OFF 0x02 /* don't print banner page */
+#define BAN_NEVER BAN_OFF
+#define BAN_OPTIONAL (BAN_ALWAYS | BAN_NEVER) /* user can override banner */
+
+#define LOG_IN 0x01 /* printer is login terminal */
+
+#define PCK_TYPE 0x0001 /* printer type isn't in Terminfo */
+#define PCK_CHARSET 0x0002 /* printer type can't handle ".char_sets" */
+#define PCK_CPI 0x0004 /* printer type can't handle ".cpi" */
+#define PCK_LPI 0x0008 /* printer type can't handle ".lpi" */
+#define PCK_WIDTH 0x0010 /* printer type can't handle ".pwid" */
+#define PCK_LENGTH 0x0020 /* printer type can't handle ".plen" */
+#define PCK_PAPER 0x0040 /* printer type can't handle paper */
+
+/*
+ * The following PCK_... bits are only set by the Spooler,
+ * when refusing a request.
+ */
+#define PCK_BANNER 0x1000 /* printer needs banner */
+
+/*
+ * Flags set by "putprinter()" for things that go wrong.
+ */
+#define BAD_REMOTE 0x0001 /* has attributes of remote and local */
+#define BAD_INTERFACE 0x0002 /* no interface or can't read it */
+#define BAD_DEVDIAL 0x0004 /* no device or dial information */
+#define BAD_FAULT 0x0008 /* not recognized fault recovery */
+#define BAD_ALERT 0x0010 /* has reserved word for alert command */
+#define BAD_ITYPES 0x0020 /* multiple printer AND input types */
+#define BAD_PTYPES 0x0040 /* multiple printer types, incl unknown */
+#define BAD_DAISY 0x0080 /* printer types don't agree on "daisy" */
+
+/*
+ * A comma separated list of STREAMS modules to be pushed on an
+ * opened port.
+ */
+#define DEFMODULES "ldterm"
+
+/*
+ * For print wheels:
+ */
+
+typedef struct PWHEEL {
+ char *name; /* name of print wheel */
+ FALERT alert; /* how to alert when mount needed */
+} PWHEEL;
+
+extern unsigned long badprinter,
+ ignprinter;
+
+/*
+ * Set if ppd file information is from the user rather than
+ * the configuration file.
+ */
+extern int ppdopt;
+
+/**
+ ** Various routines.
+ **/
+
+PRINTER * getprinter ( char * );
+
+PWHEEL * getpwheel ( char * );
+
+char * getdefault ( void );
+
+int putprinter ( char *, PRINTER *);
+int delprinter ( char * );
+int putdefault ( char * );
+int deldefault ( void );
+int putpwheel ( char * , PWHEEL * );
+int delpwheel ( char * );
+int okprinter ( char * , PRINTER * , int );
+
+unsigned long chkprinter (char *, char *, char *, char *, char *, char *);
+
+void freeprinter ( PRINTER * );
+void freepwheel ( PWHEEL * );
+
+char * getpentry(char *, int);
+
+/**
+ ** Aliases (copies) of some important Terminfo caps.
+ **/
+
+extern int ti_daisy;
+
+#endif
diff --git a/usr/src/cmd/lp/include/requests.h b/usr/src/cmd/lp/include/requests.h
new file mode 100644
index 0000000000..feaae89232
--- /dev/null
+++ b/usr/src/cmd/lp/include/requests.h
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#if !defined(_LP_REQUESTS_H)
+#define _LP_REQUESTS_H
+
+/**
+ ** The disk copy of the request files:
+ **/
+
+/*
+ * There are 18 fields in the request file.
+ */
+#define RQ_MAX 18
+# define RQ_COPIES 0
+# define RQ_DEST 1
+# define RQ_FILE 2
+# define RQ_FORM 3
+# define RQ_HANDL 4
+# define RQ_NOTIFY 5
+# define RQ_OPTS 6
+# define RQ_PRIOR 7
+# define RQ_PAGES 8
+# define RQ_CHARS 9
+# define RQ_TITLE 10
+# define RQ_MODES 11
+# define RQ_TYPE 12
+# define RQ_USER 13
+# define RQ_RAW 14
+# define RQ_FAST 15
+# define RQ_STAT 16
+
+/**
+ ** The internal copy of a request as seen by the rest of the world:
+ **/
+
+/*
+ * A (char **) list is an array of string pointers (char *) with
+ * a null pointer after the last item.
+ */
+typedef struct REQUEST {
+ short copies; /* number of copies of request to print */
+ char *destination; /* printer or class name */
+ char **file_list; /* list of files to print: req. content */
+ char *form; /* preprinted form to print on */
+ ushort actions; /* mail/write, immediate/hold/resume, raw */
+ char *alert; /* program to run to alert user when done */
+ char *options; /* print options; space separated list */
+ short priority; /* priority level, 0-39, of the request */
+ char *pages; /* list of pages to print (uniq. please!) */
+ char *charset; /* character set to select or mount */
+ char *modes; /* mode(s) of operation; space sep. list */
+ char *title; /* optional title for banner page */
+ char *input_type; /* type of content */
+ char *user; /* user name of person submitting */
+ ushort outcome; /* success/fauilure */
+} REQUEST;
+
+
+/*
+ * Bit flags for the "actions" member:
+ */
+#define ACT_MAIL 0x0001 /* send mail when finished printing */
+#define ACT_WRITE 0x0002 /* write to the terminal when finished */
+#define ACT_NOTIFY 0x0004 /* tell the remote that this is done */
+#define ACT_IMMEDIATE 0x0010 /* print immediately */
+#define ACT_HOLD 0x0020 /* don't print until resumed */
+#define ACT_RESUME 0x0030 /* resume a held request */
+#define ACT_SPECIAL 0x0030 /* bit mask of immediate/hold/resume */
+#define ACT_RAW 0x0100 /* don't filter the input */
+
+/*
+ * Currently, the following is used only for alignment patterns:
+ */
+#define ACT_FAST 0x8000 /* force all filters to be fast */
+
+
+/*
+ * Bit flags for the "outcome" member:
+ */
+#define RS_HELD 0x0001 /* held pending resume */
+#define RS_FILTERING 0x0002 /* slow filter is running */
+#define RS_FILTERED 0x0004 /* slow filter has finished running */
+#define RS_PRINTING 0x0008 /* on printer */
+#define RS_PRINTED 0x0010 /* has finished printing */
+#define RS_CHANGING 0x0020 /* request held pending user change */
+#define RS_CANCELLED 0x0040 /* request was cancelled */
+#define RS_IMMEDIATE 0x0080 /* should be next to print */
+#define RS_FAILED 0x0100 /* slow filter or interface failed */
+#define RS_NOTIFY 0x0400 /* user is to be notified (alert) */
+#define RS_NOTIFYING 0x0800 /* notification (alert) is running */
+#define RS_ADMINHELD 0x2000 /* administrator placed RS_HELD */
+#define RS_REFILTER 0x4000 /* had to change filters */
+#define RS_STOPPED 0x8000 /* temporarily stopped the request */
+
+/*
+ * Some bit combinations, for convenience and consistency:
+ *
+ * RS_DONE request is finished printing or was cancelled
+ * RS_ACTIVE request is being handled, can be skipped
+ */
+#define RS_DONE (RS_CANCELLED|RS_PRINTED|RS_FAILED)
+#define RS_ACTIVE (RS_FILTERING|RS_PRINTING|RS_CHANGING|RS_NOTIFYING)
+
+/**
+ ** Various routines.
+ **/
+
+REQUEST * getrequest ( char * );
+int putrequest ( char *, REQUEST * );
+void freerequest ( REQUEST * );
+
+#endif
diff --git a/usr/src/cmd/lp/include/secure.h b/usr/src/cmd/lp/include/secure.h
new file mode 100644
index 0000000000..c1ff7f8657
--- /dev/null
+++ b/usr/src/cmd/lp/include/secure.h
@@ -0,0 +1,76 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#if !defined(_LP_SECURE_H)
+#define _LP_SECURE_H
+
+#include "sys/types.h"
+
+/**
+ ** The disk copy of the secure request files:
+ **/
+
+/*
+ * There are 8 fields in the secure request file.
+ */
+#define SC_MAX 7
+# define SC_REQID 0 /* Original request id */
+# define SC_UID 1 /* Originator's user ID */
+# define SC_USER 2 /* Originator's real login name */
+# define SC_GID 3 /* Originator's group ID */
+# define SC_SIZE 4 /* Total size of the request data */
+# define SC_DATE 5 /* Date submitted (in seconds) */
+# define SC_SLABEL 6 /* Sensitivity Label */
+
+/**
+ ** The internal copy of a request as seen by the rest of the world:
+ **/
+
+typedef struct SECURE {
+ uid_t uid;
+ gid_t gid;
+ off_t size;
+ time_t date;
+ char *user;
+ char *req_id;
+ char *slabel;
+} SECURE;
+
+/**
+ ** Various routines.
+ **/
+
+SECURE * getsecure ( char * );
+int putsecure ( char *, SECURE * );
+int rmsecure (char *);
+void freesecure ( SECURE * );
+
+#endif
diff --git a/usr/src/cmd/lp/include/users.h b/usr/src/cmd/lp/include/users.h
new file mode 100644
index 0000000000..cafd153d24
--- /dev/null
+++ b/usr/src/cmd/lp/include/users.h
@@ -0,0 +1,65 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+
+#if !defined(_LP_USERS_H)
+#define _LP_USERS_H
+
+#include "stdio.h"
+
+typedef struct
+{
+ short priority_limit;
+}
+USER;
+
+int putuser ( char * , USER * );
+int deluser ( char * );
+int getdfltpri ( void );
+void trashusers ( void );
+
+USER * getuser ( char *);
+
+#define LEVEL_DFLT 20
+#define LIMIT_DFLT 0
+
+#define TRUE 1
+#define FALSE 0
+
+#define PRI_MAX 39
+#define PRI_MIN 0
+
+#define LPU_MODE 0644
+
+struct user_priority
+{
+ short deflt; /* priority to use when not specified */
+ short deflt_limit; /* priority limit for users not
+ otherwise specified */
+ char **users[PRI_MAX - PRI_MIN + 1];
+};
+
+#endif
diff --git a/usr/src/cmd/lp/lib/Makefile b/usr/src/cmd/lp/lib/Makefile
new file mode 100644
index 0000000000..05b200bfc9
--- /dev/null
+++ b/usr/src/cmd/lp/lib/Makefile
@@ -0,0 +1,74 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# cmd/lp/lib/Makefile
+#
+
+SUBDIRS = \
+ access \
+ class \
+ filters \
+ forms \
+ lp \
+ msgs \
+ oam \
+ requests\
+ secure \
+ printers\
+ users \
+ papi
+
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+strip := TARGET= strip
+catalog := TARGET= catalog
+
+.KEEP_STATE:
+
+all install: $(SUBDIRS)
+
+clean lint: $(SUBDIRS)
+
+clobber: $(SUBDIRS) local_clobber
+
+strip:
+
+local_clobber:
+ $(RM) $(CLOBBERFILES)
+
+catalog: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/lp/lib/Makefile.msg b/usr/src/cmd/lp/lib/Makefile.msg
new file mode 100644
index 0000000000..6139f92225
--- /dev/null
+++ b/usr/src/cmd/lp/lib/Makefile.msg
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/lib/Makefile.msg
+
+POFILES = $(OBJECTS:%.o=%.po)
+
+include ../../Makefile.lp.msg
+
+catalog: $(POFILE)
+ $(CP) $(POFILE) ../..
diff --git a/usr/src/cmd/lp/lib/access/Makefile b/usr/src/cmd/lp/lib/access/Makefile
new file mode 100644
index 0000000000..7734b7a65f
--- /dev/null
+++ b/usr/src/cmd/lp/lib/access/Makefile
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/access/Makefile
+#
+
+LIBRARY = liblpacc.a
+
+OBJECTS = allowed.o \
+ bang.o \
+ change.o \
+ dumpaccess.o \
+ files.o \
+ loadaccess.o
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master) $(C_PICFLAGS) -D_TS_ERRNO
+
+POFILE = lp_lib_access.po
+
+.KEEP_STATE :
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpacc.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+
+lint: lintlib
+ $(LINT.c) $(LINTFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT.c) $(LINTFLAGS) -o lpacc llib-llpacc
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/access/allowed.c b/usr/src/cmd/lp/lib/access/allowed.c
new file mode 100644
index 0000000000..c8f6844af6
--- /dev/null
+++ b/usr/src/cmd/lp/lib/access/allowed.c
@@ -0,0 +1,219 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "unistd.h"
+
+#include "lp.h"
+#include "access.h"
+#include <pwd.h>
+#include <auth_attr.h>
+#include <auth_list.h>
+#include <tsol/label.h>
+
+/**
+ ** is_user_admin() - CHECK IF CURRENT USER IS AN ADMINISTRATOR
+ **/
+
+int
+#if defined(__STDC__)
+is_user_admin (
+ void
+)
+#else
+is_user_admin ()
+#endif
+{
+ /* For a labeled system, tsol_check_admin_auth is called
+ * instead of using Access.
+ */
+ if (is_system_labeled()) {
+ /* Check that user has print admin authorization */
+ return (tsol_check_admin_auth(getuid()));
+ } else {
+ return (Access(Lp_A, W_OK) == -1? 0 : 1);
+ }
+}
+
+/**
+ ** is_user_allowed() - CHECK USER ACCESS ACCORDING TO ALLOW/DENY LISTS
+ **/
+
+int
+#if defined(__STDC__)
+is_user_allowed (
+ char * user,
+ char ** allow,
+ char ** deny
+)
+#else
+is_user_allowed (user, allow, deny)
+ char *user,
+ **allow,
+ **deny;
+#endif
+{
+ if (bangequ(user, LOCAL_LPUSER) || bangequ(user, LOCAL_ROOTUSER))
+ return (1);
+
+ return (allowed(user, allow, deny));
+}
+
+/**
+ ** is_user_allowed_form() - CHECK USER ACCESS TO FORM
+ **/
+
+int
+#if defined(__STDC__)
+is_user_allowed_form (
+ char * user,
+ char * form
+)
+#else
+is_user_allowed_form (user, form)
+ char *user,
+ *form;
+#endif
+{
+ char **allow,
+ **deny;
+
+ if (loadaccess(Lp_A_Forms, form, "", &allow, &deny) == -1)
+ return (-1);
+
+ return (is_user_allowed(user, allow, deny));
+}
+
+/**
+ ** is_user_allowed_printer() - CHECK USER ACCESS TO PRINTER
+ **/
+
+int
+#if defined(__STDC__)
+is_user_allowed_printer (
+ char * user,
+ char * printer
+)
+#else
+is_user_allowed_printer (user, printer)
+ char *user,
+ *printer;
+#endif
+{
+ char **allow,
+ **deny;
+
+ if (loadaccess(Lp_A_Printers, printer, UACCESSPREFIX, &allow, &deny) == -1)
+ return (-1);
+
+ return (is_user_allowed(user, allow, deny));
+}
+
+/**
+ ** is_form_allowed_printer() - CHECK FORM USE ON PRINTER
+ **/
+
+int
+#if defined(__STDC__)
+is_form_allowed_printer (
+ char * form,
+ char * printer
+)
+#else
+is_form_allowed_printer (form, printer)
+ char *form,
+ *printer;
+#endif
+{
+ char **allow,
+ **deny;
+
+ if (loadaccess(Lp_A_Printers, printer, FACCESSPREFIX, &allow, &deny) == -1)
+ return (-1);
+
+ return (allowed(form, allow, deny));
+}
+
+/**
+ ** allowed() - GENERAL ROUTINE TO CHECK ALLOW/DENY LISTS
+ **/
+
+int
+#if defined(__STDC__)
+allowed (
+ char * item,
+ char ** allow,
+ char ** deny
+)
+#else
+allowed (item, allow, deny)
+ char *item,
+ **allow,
+ **deny;
+#endif
+{
+ if (allow) {
+ if (bang_searchlist(item, allow))
+ return (1);
+ else
+ return (0);
+ }
+
+ if (deny) {
+ if (bang_searchlist(item, deny))
+ return (0);
+ else
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Check to see if the specified user has the administer the printing
+ * system authorization.
+ */
+int
+tsol_check_admin_auth(uid_t uid)
+{
+ struct passwd *p;
+ char *name;
+
+ p = getpwuid(uid);
+ if (p != NULL && p->pw_name != NULL)
+ name = p->pw_name;
+ else
+ name = "";
+
+ return (chkauthattr(PRINT_ADMIN_AUTH, name));
+}
diff --git a/usr/src/cmd/lp/lib/access/bang.c b/usr/src/cmd/lp/lib/access/bang.c
new file mode 100644
index 0000000000..9e68839f78
--- /dev/null
+++ b/usr/src/cmd/lp/lib/access/bang.c
@@ -0,0 +1,238 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1999 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "unistd.h"
+#include "stdlib.h"
+#include "sys/utsname.h"
+
+#include "lp.h"
+
+/*
+ * The rules:
+ *
+ * Key: A - some system
+ * X - some user
+ *
+ * X a user named X on the local system
+ * A!X the user named X from the system A
+ * all!X all users named X from any system
+ * all all users from local system
+ * A!all all users from the system A
+ * all!all all users from any system
+ */
+
+
+/**
+ ** bangequ() - LIKE STREQU, BUT HANDLES system!name CASES
+ **/
+
+int
+bangequ (char *user1p, char *user2p)
+{
+ int sysname1_all = 0,
+ username1_all = 0;
+ int sysname2_all = 0,
+ username2_all = 0;
+ char sysname1[BUFSIZ],
+ sysname2[BUFSIZ];
+ char username1[BUFSIZ],
+ username2[BUFSIZ],
+ *sp;
+
+ static char *Nodenamep = (char *) 0;
+
+ if (! user1p || ! user2p)
+ return 1;
+
+ if (! Nodenamep) {
+ struct utsname utsbuf;
+
+ (void) uname (&utsbuf);
+ Nodenamep = Strdup (utsbuf.nodename);
+ }
+
+ /* pattern=all */
+ if (STREQU (NAME_ALL, user2p) || STREQU(NAME_ALL, user1p))
+ return 1;
+
+ if ((sp = strrchr(user1p, '@')) != NULL) { /* user@host */
+ *sp++ = '\0';
+ (void) snprintf(sysname1, sizeof (sysname1), "%s", sp);
+ (void) snprintf(username1, sizeof (username1), "%s", user1p);
+ *--sp = '@';
+ } else if ((sp = strchr(user1p, '!')) != NULL) { /* host!user */
+ *sp++ = '\0';
+ (void) snprintf(sysname1, sizeof (sysname1), "%s", user1p);
+ (void) snprintf(username1, sizeof (username1), "%s", sp);
+ *--sp = '!';
+ } else { /* user */
+ (void) snprintf(sysname1, sizeof (sysname1), "%s", Nodenamep);
+ (void) snprintf(username1, sizeof (username1), "%s", user1p);
+ }
+
+ sysname1_all = STREQU (NAME_ALL, sysname1);
+ username1_all = STREQU (NAME_ALL, username1);
+
+ /* user2p is simple user name */
+ if (strpbrk (user2p, "!@") == NULL)
+ return (username1_all && sysname1_all) ||
+ STREQU (username1, user2p);
+
+ if ((sp = strrchr(user2p, '@')) != NULL) { /* user@host */
+ *sp++ = '\0';
+ (void) snprintf(sysname2, sizeof (sysname2), "%s", sp);
+ (void) snprintf(username2, sizeof (username2), "%s", user2p);
+ *--sp = '@';
+ } else if ((sp = strchr(user2p, '!')) != NULL) { /* host!user */
+ *sp++ = '\0';
+ (void) snprintf(sysname2, sizeof (sysname2), "%s", user2p);
+ (void) snprintf(username2, sizeof (username2), "%s", sp);
+ *--sp = '!';
+ } else { /* user */
+ (void) snprintf(sysname2, sizeof (sysname2), "%s", Nodenamep);
+ (void) snprintf(username2, sizeof (username2), "%s", user1p);
+ }
+
+ sysname2_all = STREQU (NAME_ALL, sysname2);
+ username2_all = STREQU (NAME_ALL, username2);
+
+ if ((sysname1_all && username1_all) ||
+ (sysname2_all && username2_all) ||
+ (sysname1_all && username2_all) ||
+ (sysname2_all && username1_all))
+ return 1;
+
+ if (sysname1_all || sysname2_all)
+ return STREQU (username1, username2);
+
+ if (username1_all || username2_all)
+ return STREQU (sysname1, sysname2);
+
+ if (STREQU (sysname1, sysname2) && STREQU (username1, username2))
+ return 1;
+
+ return 0;
+}
+
+/**
+ ** bang_searchlist() - SEARCH (char **) LIST FOR "system!user" ITEM
+ **/
+int
+bang_searchlist(char *item, char **list)
+{
+ if (!list || !*list)
+ return (0);
+
+ /*
+ * This is a linear search--we believe that the lists
+ * will be short.
+ */
+ while (*list) {
+ if (bangequ(item, *list))
+ return (1);
+ list++;
+ }
+ return (0);
+}
+
+/**
+ ** bang_dellist() - REMOVE "system!name" ITEM FROM (char **) LIST
+ **/
+
+int
+bang_dellist(char ***plist, char *item)
+{
+ register char ** pl;
+ register char ** ql;
+
+ register int n;
+
+ /*
+ * "hole" is a pointer guaranteed not
+ * to point to anyplace malloc'd.
+ */
+ char * hole = "";
+
+
+ /*
+ * There are two ways this routine is different from the
+ * regular "dellist()" routine: First, the items are of the form
+ * ``system!name'', which means there is a two part matching
+ * for ``all'' cases (all systems and/or all names). Second,
+ * ALL matching items in the list are deleted.
+ *
+ * Now suppose the list contains just the word ``all'', and
+ * the item to be deleted is the name ``fred''. What will
+ * happen? The word ``all'' will be deleted, leaving the list
+ * empty (null)! This may sound odd at first, but keep in mind
+ * that this routine is paired with the regular "addlist()"
+ * routine; the item (``fred'') is ADDED to an opposite list
+ * (we are either deleting from a deny list and adding to an allow
+ * list or vice versa). So, to continue the example, if previously
+ * ``all'' were allowed, removing ``fred'' from the allow list
+ * does indeed empty that list, but then putting him in the deny
+ * list means only ``fred'' is denied, which is the effect we
+ * want.
+ */
+
+ if (*plist) {
+
+ for (pl = *plist; *pl; pl++)
+ if (bangequ(item, *pl)) {
+ Free (*pl);
+ *pl = hole;
+ }
+
+ for (n = 0, ql = pl = *plist; *pl; pl++)
+ if (*pl != hole) {
+ *ql++ = *pl;
+ n++;
+ }
+
+ if (n == 0) {
+ Free ((char *)*plist);
+ *plist = 0;
+ } else {
+ *plist = (char **)Realloc(
+ (char *)*plist,
+ (n + 1) * sizeof(char *)
+ );
+ if (!*plist)
+ return (-1);
+ (*plist)[n] = 0;
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/access/change.c b/usr/src/cmd/lp/lib/access/change.c
new file mode 100644
index 0000000000..892586e5c3
--- /dev/null
+++ b/usr/src/cmd/lp/lib/access/change.c
@@ -0,0 +1,220 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "access.h"
+
+static int chgaccess ( int , char ** , char * , char * , char * );
+static char ** empty_list ( void );
+
+/**
+ ** deny_user_form() - DENY USER ACCESS TO FORM
+ **/
+
+int
+deny_user_form(char **user_list, char *form)
+{
+ return (chgaccess(0, user_list, form, Lp_A_Forms, ""));
+}
+
+/**
+ ** allow_user_form() - ALLOW USER ACCESS TO FORM
+ **/
+
+int
+allow_user_form(char **user_list, char *form)
+{
+ return (chgaccess(1, user_list, form, Lp_A_Forms, ""));
+}
+
+/**
+ ** deny_user_printer() - DENY USER ACCESS TO PRINTER
+ **/
+
+int
+deny_user_printer(char **user_list, char *printer)
+{
+ return (chgaccess(0, user_list, printer, Lp_A_Printers, UACCESSPREFIX));
+}
+
+/**
+ ** allow_user_printer() - ALLOW USER ACCESS TO PRINTER
+ **/
+
+int
+allow_user_printer(char **user_list, char *printer)
+{
+ return (chgaccess(1, user_list, printer, Lp_A_Printers, UACCESSPREFIX));
+}
+
+/**
+ ** deny_form_printer() - DENY FORM USE ON PRINTER
+ **/
+
+int
+deny_form_printer(char **form_list, char *printer)
+{
+ return (chgaccess(0, form_list, printer, Lp_A_Printers, FACCESSPREFIX));
+}
+
+/**
+ ** allow_form_printer() - ALLOW FORM USE ON PRINTER
+ **/
+
+int
+allow_form_printer(char **form_list, char *printer)
+{
+ return (chgaccess(1, form_list, printer, Lp_A_Printers, FACCESSPREFIX));
+}
+
+/**
+ ** remove_paper_from_printer() - DENY FORM USE ON PRINTER
+ **/
+
+int
+remove_paper_from_printer(char **form_list, char *printer)
+{
+ return (chgaccess(0, form_list, printer, Lp_A_Printers, PACCESSPREFIX));
+}
+
+/**
+ ** add_paper_to_printer() - ALLOW FORM USE ON PRINTER
+ **/
+
+int
+add_paper_to_printer(char **form_list, char *printer)
+{
+ return (chgaccess(1, form_list, printer, Lp_A_Printers, PACCESSPREFIX));
+}
+
+/**
+ ** chgaccess() - UPDATE ALLOW/DENY ACCESS OF ITEM TO RESOURCE
+ **/
+
+static int
+chgaccess(int isallow, char **list, char *name, char *dir, char *prefix)
+{
+ register char ***padd_list,
+ ***prem_list,
+ **pl;
+
+ char **allow_list,
+ **deny_list;
+
+ if (loadaccess(dir, name, prefix, &allow_list, &deny_list) == -1)
+ return (-1);
+
+ if (isallow) {
+ padd_list = &allow_list;
+ prem_list = &deny_list;
+ } else {
+ padd_list = &deny_list;
+ prem_list = &allow_list;
+ }
+
+ for (pl = list; *pl; pl++) {
+
+ /*
+ * Do the ``all'' and ``none'' cases explicitly,
+ * so that we can clean up the lists nicely.
+ */
+ if (STREQU(*pl, NAME_NONE)) {
+ isallow = !isallow;
+ goto AllCase;
+ }
+ if (
+ STREQU(*pl, NAME_ALL)
+ || STREQU(*pl, NAME_ANY)
+ || STREQU(*pl, ALL_BANG_ALL)
+ ) {
+AllCase:
+ freelist (allow_list);
+ freelist (deny_list);
+ if (isallow) {
+ allow_list = 0;
+ deny_list = empty_list();
+ } else {
+ allow_list = 0;
+ deny_list = 0;
+ }
+ break;
+
+ } else {
+
+ /*
+ * For each regular item in the list,
+ * we add it to the ``add list'' and remove it
+ * from the ``remove list''. This is not
+ * efficient, especially if there are a lot of
+ * items in the caller's list; doing it the
+ * way we do, however, has the side effect
+ * of skipping duplicate names in the caller's
+ * list.
+ *
+ * Do a regular "addlist()"--the resulting
+ * list may have redundancies, but it will
+ * still be correct.
+ */
+ if (addlist(padd_list, *pl) == -1)
+ return (-1);
+ if (bang_dellist(prem_list, *pl) == -1)
+ return (-1);
+
+ }
+
+ }
+
+ return (dumpaccess(dir, name, prefix, &allow_list, &deny_list));
+}
+
+/**
+ ** empty_list() - CREATE AN EMPTY LIST
+ **/
+
+static char **
+empty_list(void)
+{
+ register char **empty;
+
+
+ if (!(empty = (char **)Malloc(sizeof(char *)))) {
+ errno = ENOMEM;
+ return (0);
+ }
+ *empty = 0;
+ return (empty);
+}
diff --git a/usr/src/cmd/lp/lib/access/dumpaccess.c b/usr/src/cmd/lp/lib/access/dumpaccess.c
new file mode 100644
index 0000000000..2bdc1462dc
--- /dev/null
+++ b/usr/src/cmd/lp/lib/access/dumpaccess.c
@@ -0,0 +1,105 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "access.h"
+
+#if defined(__STDC__)
+static int _dumpaccess ( char * , char ** );
+#else
+static int _dumpaccess();
+#endif
+
+/**
+ ** dumpaccess() - DUMP ALLOW OR DENY LISTS
+ **/
+
+int
+dumpaccess(char *dir, char *name, char *prefix, char ***pallow, char ***pdeny)
+{
+ register char *allow_file = 0,
+ *deny_file = 0;
+
+ int ret;
+
+ if (
+ !(allow_file = getaccessfile(dir, name, prefix, "allow"))
+ || _dumpaccess(allow_file, *pallow) == -1 && errno != ENOENT
+ || !(deny_file = getaccessfile(dir, name, prefix, "deny"))
+ || _dumpaccess(deny_file, *pdeny) == -1 && errno != ENOENT
+ )
+ ret = -1;
+ else
+ ret = 0;
+
+ if (allow_file)
+ Free (allow_file);
+ if (deny_file)
+ Free (deny_file);
+
+ return (ret);
+}
+
+/**
+ ** _dumpaccess() - DUMP ALLOW OR DENY FILE
+ **/
+
+static int
+_dumpaccess(char *file, char **list)
+{
+ register char **pl;
+
+ register int ret;
+
+ int fd;
+
+ if (list) {
+ if ((fd = open_locked(file, "w", MODE_READ)) < 0)
+ return (-1);
+ errno = 0;
+ for (pl = list; *pl; pl++)
+ fdprintf (fd, "%s\n", *pl);
+ if (errno != 0)
+ ret = -1;
+ else
+ ret = 0;
+ close(fd);
+ } else
+ ret = Unlink(file);
+
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/access/files.c b/usr/src/cmd/lp/lib/access/files.c
new file mode 100644
index 0000000000..6c8470e1f5
--- /dev/null
+++ b/usr/src/cmd/lp/lib/access/files.c
@@ -0,0 +1,88 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "stdio.h"
+#include "string.h"
+#include "unistd.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** getaccessfile() - BUILD NAME OF ALLOW OR DENY FILE
+ **/
+
+char *
+#if defined(__STDC__)
+getaccessfile (
+ char * dir,
+ char * name,
+ char * prefix,
+ char * base
+)
+#else
+getaccessfile (dir, name, prefix, base)
+ char *dir,
+ *name,
+ *prefix,
+ *base;
+#endif
+{
+ register char *parent,
+ *file,
+ *f;
+
+ /*
+ * It makes no sense talking about the access files if
+ * the directory for the form or printer doesn't exist.
+ */
+ parent = makepath(dir, name, (char *)0);
+ if (!parent)
+ return (0);
+ if (Access(parent, F_OK) == -1) {
+ Free(parent);
+ return (0);
+ }
+
+ if (!(f = makestr(prefix, base, (char *)0))) {
+ Free(parent);
+ errno = ENOMEM;
+ return (0);
+ }
+ file = makepath(parent, f, (char *)0);
+ Free (f);
+ Free (parent);
+
+ return (file);
+}
diff --git a/usr/src/cmd/lp/lib/access/llib-llpacc b/usr/src/cmd/lp/lib/access/llib-llpacc
new file mode 100644
index 0000000000..8e15c15c3f
--- /dev/null
+++ b/usr/src/cmd/lp/lib/access/llib-llpacc
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+int allow_form_printer ( char **, char * );
+int allow_user_form ( char ** , char * );
+int allow_user_printer ( char **, char * );
+int allowed ( char *, char **, char ** );
+int deny_form_printer ( char **, char * );
+int deny_user_form ( char ** , char * );
+int deny_user_printer ( char **, char * );
+int dumpaccess ( char *, char *, char *, char ***, char *** );
+int is_form_allowed_printer ( char *, char * );
+int is_user_admin ( void );
+int is_user_allowed ( char *, char ** , char ** );
+int is_user_allowed_form ( char *, char * );
+int is_user_allowed_printer ( char *, char * );
+int load_formprinter_access ( char *, char ***, char *** );
+int load_paperprinter_access(char *, char ***, char ***);
+int load_userform_access ( char *, char ***, char *** );
+int load_userprinter_access ( char *, char ***, char *** );
+int loadaccess ( char *, char *, char *, char ***, char *** );
+int bangequ ( char * , char * );
+int bang_searchlist ( char * , char ** );
+int bang_dellist ( char *** , char * );
+
+char * getaccessfile ( char *, char *, char *, char * );
+
diff --git a/usr/src/cmd/lp/lib/access/loadaccess.c b/usr/src/cmd/lp/lib/access/loadaccess.c
new file mode 100644
index 0000000000..9541528b22
--- /dev/null
+++ b/usr/src/cmd/lp/lib/access/loadaccess.c
@@ -0,0 +1,200 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "access.h"
+
+static char **_loadaccess ( char * );
+
+/**
+ ** load_userform_access() - LOAD ALLOW/DENY LISTS FOR USER+FORM
+ **/
+
+int
+load_userform_access(char *form, char ***pallow, char ***pdeny)
+{
+ return (loadaccess(Lp_A_Forms, form, "", pallow, pdeny));
+}
+
+/**
+ ** load_userprinter_access() - LOAD ALLOW/DENY LISTS FOR USER+PRINTER
+ **/
+
+int
+load_userprinter_access(char *printer, char ***pallow, char ***pdeny)
+{
+ return (loadaccess(Lp_A_Printers, printer, UACCESSPREFIX, pallow,
+ pdeny));
+}
+
+/**
+ ** load_formprinter_access() - LOAD ALLOW/DENY LISTS FOR FORM+PRINTER
+ **/
+
+int
+load_formprinter_access(char *printer, char ***pallow, char ***pdeny)
+{
+ return (loadaccess(Lp_A_Printers, printer, FACCESSPREFIX, pallow,
+ pdeny));
+}
+
+/**
+ ** load_paperprinter_access() - LOAD ALLOW/DENY LISTS FOR FORM+PRINTER
+ **/
+
+int
+load_paperprinter_access(char *printer, char ***pallow, char ***pdeny)
+{
+ return (loadaccess(Lp_A_Printers, printer, PACCESSPREFIX, pallow,
+ pdeny));
+}
+
+/**
+ ** loadaccess() - LOAD ALLOW OR DENY LISTS
+ **/
+
+int
+loadaccess(char *dir, char *name, char *prefix, char ***pallow, char ***pdeny)
+{
+ register char *allow_file = 0,
+ *deny_file = 0;
+
+ int ret;
+
+ if (
+ !(allow_file = getaccessfile(dir, name, prefix, ALLOWFILE))
+ || !(*pallow = _loadaccess(allow_file)) && errno != ENOENT
+ || !(deny_file = getaccessfile(dir, name, prefix, DENYFILE))
+ || !(*pdeny = _loadaccess(deny_file)) && errno != ENOENT
+ )
+ ret = -1;
+ else
+ ret = 0;
+
+ if (allow_file)
+ Free (allow_file);
+ if (deny_file)
+ Free (deny_file);
+
+ return (ret);
+}
+
+/**
+ ** _loadaccess() - LOAD ALLOW OR DENY FILE
+ **/
+
+static char **
+_loadaccess(char *file)
+{
+ register size_t nalloc,
+ nlist;
+
+ register char **list;
+
+ int fd;
+
+ char buf[BUFSIZ];
+
+
+ if ((fd = open_locked(file, "r", 0)) < 0)
+ return (0);
+
+ /*
+ * Preallocate space for the initial list. We'll always
+ * allocate one more than the list size, for the terminating null.
+ */
+ nalloc = ACC_MAX_GUESS;
+ list = (char **)Malloc((nalloc + 1) * sizeof(char *));
+ if (!list) {
+ close(fd);
+ errno = ENOMEM;
+ return (0);
+ }
+
+ errno = 0;
+ for (nlist = 0; fdgets(buf, BUFSIZ, fd); ) {
+
+ buf[strlen(buf) - 1] = 0;
+
+ /*
+ * Allocate more space if needed.
+ */
+ if (nlist >= nalloc) {
+ nalloc += ACC_MAX_GUESS;
+ list = (char **)Realloc(
+ (char *)list,
+ (nalloc + 1) * sizeof(char *)
+ );
+ if (!list) {
+ close(fd);
+ return (0);
+ }
+ }
+
+ list[nlist] = Strdup(buf); /* if fail, minor problem */
+ list[++nlist] = 0;
+
+ }
+ if (errno != 0) {
+ int save_errno = errno;
+
+ close(fd);
+ freelist (list);
+ errno = save_errno;
+ return (0);
+ }
+ close(fd);
+
+ /*
+ * If we have more space allocated than we need,
+ * return the extra.
+ */
+ if (nlist != nalloc) {
+ list = (char **)Realloc(
+ (char *)list,
+ (nlist + 1) * sizeof(char *)
+ );
+ if (!list) {
+ errno = ENOMEM;
+ return (0);
+ }
+ }
+ list[nlist] = 0;
+
+ return (list);
+}
diff --git a/usr/src/cmd/lp/lib/class/Makefile b/usr/src/cmd/lp/lib/class/Makefile
new file mode 100644
index 0000000000..c6003dd8b6
--- /dev/null
+++ b/usr/src/cmd/lp/lib/class/Makefile
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/class/Makefile
+#
+
+LIBRARY = liblpcls.a
+
+OBJECTS = delclass.o \
+ freeclass.o \
+ getclass.o \
+ putclass.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master) $(C_PICFLAGS)
+
+POFILE = lp_lib_class.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpcls.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+LINT_CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+lint: lintlib
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) -o lpcls llib-llpcls
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/class/delclass.c b/usr/src/cmd/lp/lib/class/delclass.c
new file mode 100644
index 0000000000..ee88b33bce
--- /dev/null
+++ b/usr/src/cmd/lp/lib/class/delclass.c
@@ -0,0 +1,89 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+/* LINTLIBRARY */
+
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "sys/types.h"
+#include "string.h"
+
+#include "lp.h"
+#include "class.h"
+
+static int _delclass ( char * );
+
+/**
+ ** delclass() - WRITE CLASS OUT TO DISK
+ **/
+
+int
+delclass(char *name)
+{
+ long lastdir;
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ lastdir = -1;
+ while ((name = next_file(Lp_A_Classes, &lastdir)))
+ if (_delclass(name) == -1)
+ return (-1);
+ return (0);
+ } else
+ return (_delclass(name));
+}
+
+/**
+ ** _delclass()
+ **/
+
+static int
+#if defined(__STDC__)
+_delclass (
+ char * name
+)
+#else
+_delclass (name)
+ char *name;
+#endif
+{
+ char *path;
+
+ if (!(path = getclassfile(name)))
+ return (-1);
+ if (rmfile(path) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+ return (0);
+}
+
diff --git a/usr/src/cmd/lp/lib/class/freeclass.c b/usr/src/cmd/lp/lib/class/freeclass.c
new file mode 100644
index 0000000000..dc6fd9f448
--- /dev/null
+++ b/usr/src/cmd/lp/lib/class/freeclass.c
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* LINTLIBRARY */
+
+#include <syslog.h>
+#include "lp.h"
+#include "class.h"
+
+/**
+ ** freeclass() - FREE SPACE USED BY CLASS STRUCTURE
+ **/
+
+void
+#if defined(__STDC__)
+freeclass (
+ CLASS * clsbufp
+)
+#else
+freeclass (clsbufp)
+ CLASS *clsbufp;
+#endif
+{
+ if (!clsbufp)
+ return;
+ syslog(LOG_DEBUG, "freeclass(%s)", clsbufp->name ? clsbufp->name : "");
+ if (clsbufp->name)
+ Free (clsbufp->name);
+ freelist (clsbufp->members);
+ Free(clsbufp);
+
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/class/getclass.c b/usr/src/cmd/lp/lib/class/getclass.c
new file mode 100644
index 0000000000..ad888370f4
--- /dev/null
+++ b/usr/src/cmd/lp/lib/class/getclass.c
@@ -0,0 +1,124 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include <syslog.h>
+
+#include "lp.h"
+#include "class.h"
+
+/**
+ ** getclass() - READ CLASS FROM TO DISK
+ **/
+
+CLASS *
+getclass(char *name)
+{
+ static long lastdir = -1;
+
+ CLASS *clsp;
+
+ char *file,
+ buf[BUFSIZ];
+
+ int fd;
+
+ syslog(LOG_DEBUG, "getclass(%s)", name ? name : "");
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ /*
+ * Getting ``all''? If so, jump into the directory
+ * wherever we left off.
+ */
+ if (STREQU(NAME_ALL, name)) {
+ if (!(name = next_file(Lp_A_Classes, &lastdir)))
+ return (0);
+ } else
+ lastdir = -1;
+
+ /*
+ * Get the class list.
+ */
+
+ if (!(file = getclassfile(name)))
+ return (0);
+
+ if ((fd = open_locked(file, "r", 0)) < 0) {
+ Free (file);
+ return (0);
+ }
+ Free (file);
+
+ clsp = (CLASS *)calloc(sizeof (*clsp), 1);
+
+ if (!(clsp->name = Strdup(name))) {
+ Free (clsp);
+ close(fd);
+ errno = ENOMEM;
+ return (0);
+ }
+
+ clsp->members = 0;
+ errno = 0;
+ while (fdgets(buf, BUFSIZ, fd)) {
+ buf[strlen(buf) - 1] = 0;
+ addlist (&clsp->members, buf);
+ }
+ if (errno != 0) {
+ int save_errno = errno;
+
+ freelist (clsp->members);
+ Free (clsp->name);
+ Free (clsp);
+ close(fd);
+ errno = save_errno;
+ return (0);
+ }
+ close(fd);
+
+ if (!clsp->members) {
+ Free (clsp->name);
+ Free (clsp);
+ errno = EBADF;
+ return (0);
+ }
+
+ return (clsp);
+}
diff --git a/usr/src/cmd/lp/lib/class/llib-llpcls b/usr/src/cmd/lp/lib/class/llib-llpcls
new file mode 100644
index 0000000000..fea59cd737
--- /dev/null
+++ b/usr/src/cmd/lp/lib/class/llib-llpcls
@@ -0,0 +1,44 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+typedef struct CLASS {
+ char *name; /* name of class (redundant) */
+ char **members; /* members of class */
+} CLASS;
+
+int putclass ( char *, CLASS * );
+int delclass ( char * );
+
+void freeclass ( CLASS * );
+
diff --git a/usr/src/cmd/lp/lib/class/putclass.c b/usr/src/cmd/lp/lib/class/putclass.c
new file mode 100644
index 0000000000..8f85a082af
--- /dev/null
+++ b/usr/src/cmd/lp/lib/class/putclass.c
@@ -0,0 +1,84 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "string.h"
+
+#include "lp.h"
+#include "class.h"
+
+/**
+ ** putclass() - WRITE CLASS OUT TO DISK
+ **/
+
+int
+putclass(char *name, CLASS *clsbufp)
+{
+ char *file;
+ int fd;
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Open the class file and write out the class members.
+ */
+
+ if (!(file = getclassfile(name)))
+ return (-1);
+
+ if ((fd = open_locked(file, "w", MODE_READ)) < 0) {
+ Free (file);
+ return (-1);
+ }
+ Free (file);
+
+ errno = 0;
+ fdprintlist(fd, clsbufp->members);
+ if (errno != 0) {
+ close(fd);
+ return (-1);
+ }
+ close(fd);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/filters/Makefile b/usr/src/cmd/lp/lib/filters/Makefile
new file mode 100644
index 0000000000..4b91ddcc4b
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/Makefile
@@ -0,0 +1,73 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1990-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = liblpflt.a
+
+OBJECTS = conv.o \
+ delfilter.o \
+ dumpfilters.o \
+ freefilter.o \
+ getfilter.o \
+ filtertable.o \
+ insfilter.o \
+ loadfilters.o \
+ putfilter.o \
+ regex.o \
+ search.o \
+ trash.o
+
+include ../../Makefile.lp
+
+include ../../../../lib/Makefile.lib
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+CERRWARN += -_gcc=-Wno-uninitialized
+CERRWARN += -_gcc=-Wno-parentheses
+
+POFILE = lp_lib_filters.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpflt.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+
+lint: lintlib
+ $(LINT.c) $(LINTFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT.c) $(LINTFLAGS) -o lpflt llib-llpflt
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/filters/conv.c b/usr/src/cmd/lp/lib/filters/conv.c
new file mode 100644
index 0000000000..f5167265d5
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/conv.c
@@ -0,0 +1,494 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+#include "regexpr.h"
+
+#include "lp.h"
+#include "filters.h"
+
+static char *keyword_list[] = {
+ PARM_INPUT,
+ PARM_OUTPUT,
+ PARM_TERM,
+ PARM_PRINTER,
+ PARM_CPI,
+ PARM_LPI,
+ PARM_LENGTH,
+ PARM_WIDTH,
+ PARM_PAGES,
+ PARM_CHARSET,
+ PARM_FORM,
+ PARM_COPIES,
+ PARM_MODES,
+ 0
+};
+
+#if defined(__STDC__)
+static char * q_strchr ( char * , char );
+static char * q_strdup ( char * );
+#else
+static char *q_strchr(),
+ *q_strdup();
+#endif
+
+/**
+ ** s_to_filtertype() - CONVERT (char *) TO (FILTERTYPE)
+ **/
+
+FILTERTYPE
+#if defined(__STDC__)
+s_to_filtertype (
+ char * str
+)
+#else
+s_to_filtertype (str)
+ char *str;
+#endif
+{
+ /*
+ * The default type, if none is given, is ``slow''.
+ */
+ if (STREQU(str, FL_FAST))
+ return (fl_fast);
+ else
+ return (fl_slow);
+}
+
+/**
+ ** s_to_type() - CONVERT (char *) TO (TYPE)
+ **/
+
+TYPE
+#if defined(__STDC__)
+s_to_type (
+ char * str
+)
+#else
+s_to_type (str)
+ register char *str;
+#endif
+{
+ TYPE ret;
+
+ if ((ret.name = Strdup(str)))
+ ret.info = isterminfo(str);
+ return (ret);
+}
+
+/**
+ ** s_to_template() - CONVERT (char *) TO (TEMPLATE)
+ **/
+
+TEMPLATE
+#if defined(__STDC__)
+s_to_template (
+ char * str
+)
+#else
+s_to_template (str)
+ register char *str;
+#endif
+{
+ TEMPLATE ret;
+
+ register char *p,
+ c;
+
+
+ if (!*(str += strspn(str, " "))) {
+ lp_errno = LP_ETEMPLATE;
+ ret.keyword = 0;
+ goto Done;
+ }
+
+ if (!(p = strchr(str, ' '))) {
+ lp_errno = LP_EPATTERN;
+ ret.keyword = 0;
+ goto Done;
+ }
+
+ c = *p;
+ *p = 0;
+ ret.keyword = Strdup(str);
+ *p = c;
+
+ if (!ret.keyword) {
+ lp_errno = LP_ENOMEM;
+ goto Done;
+ }
+ if (!searchlist(ret.keyword, keyword_list)) {
+ lp_errno = LP_EKEYWORD;
+ ret.keyword = 0;
+ goto Done;
+ }
+
+ str = p + strspn(p, " ");
+ if (!(p = q_strchr(str, '='))) {
+ lp_errno = LP_ERESULT;
+ ret.keyword = 0;
+ goto Done;
+ }
+ while (p[-1] == ' ' && p > str)
+ p--;
+
+ c = *p;
+ *p = 0;
+ ret.pattern = q_strdup(str);
+ *p = c;
+
+ if (!ret.pattern) {
+ lp_errno = LP_ENOMEM;
+ ret.keyword = 0;
+ goto Done;
+ }
+
+ if (!*ret.pattern) {
+ lp_errno = LP_EPATTERN;
+ ret.keyword = 0;
+ goto Done;
+ }
+
+ if (!(ret.re = compile(ret.pattern, (char *)0, (char *)0))) {
+ lp_errno = LP_EREGEX;
+ ret.keyword = 0;
+ goto Done;
+ }
+ ret.nbra = nbra;
+
+ if (!*(str = p + strspn(p, " ="))) {
+ lp_errno = LP_ERESULT;
+ ret.keyword = 0;
+ goto Done;
+ }
+ ret.result = q_strdup(str);
+ if (!ret.result) {
+ lp_errno = LP_ENOMEM;
+ ret.keyword = 0;
+ }
+
+Done: return (ret);
+}
+
+/**
+ ** sl_to_typel() - CONVERT (char **) LIST TO (TYPE *) LIST
+ **/
+
+TYPE *
+#if defined(__STDC__)
+sl_to_typel (
+ char ** src
+)
+#else
+sl_to_typel (src)
+ char **src;
+#endif
+{
+ register TYPE *dst;
+
+ register int nitems,
+ n;
+
+ if (!src || !*src)
+ return (0);
+
+ for (nitems = 0; src[nitems]; nitems++)
+ ;
+
+ if (!(dst = (TYPE *)Malloc((nitems + 1) * sizeof(TYPE)))) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+ for (n = 0; n < nitems; n++)
+ dst[n] = s_to_type(src[n]);
+ dst[nitems].name = 0;
+
+ return (dst);
+}
+
+/**
+ ** sl_to_templatel() - DUPLICATE A (char **) LIST AS (TEMPLATE *) LIST
+ **/
+
+TEMPLATE *
+#if defined(__STDC__)
+sl_to_templatel (
+ char ** src
+)
+#else
+sl_to_templatel (src)
+ register char **src;
+#endif
+{
+ register TEMPLATE *dst;
+
+ register int nitems,
+ n;
+
+ if (!src || !*src)
+ return (0);
+
+ for (nitems = 0; src[nitems]; nitems++)
+ ;
+
+ if (!(dst = (TEMPLATE *)Malloc((nitems + 1) * sizeof(TEMPLATE)))){
+ errno = ENOMEM;
+ return (0);
+ }
+
+ for (n = 0; n < nitems; n++) {
+ dst[n] = s_to_template(src[n]);
+ if (dst[n].keyword == 0) {
+ freetempl (dst);
+ return (0);
+ }
+ }
+ dst[nitems].keyword = 0;
+
+ return (dst);
+}
+
+/**
+ ** type_to_s() - CONVERT (TYPE) TO (char *)
+ **/
+
+char *
+#if defined(__STDC__)
+type_to_s (
+ TYPE t
+)
+#else
+type_to_s (t)
+ TYPE t;
+#endif
+{
+ return (Strdup(t.name));
+}
+
+/**
+ ** template_to_s() - CONVERT (TEMPLATE) TO (char *)
+ **/
+
+char *
+#if defined(__STDC__)
+template_to_s (
+ TEMPLATE t
+)
+#else
+template_to_s (t)
+ TEMPLATE t;
+#endif
+{
+ register char *ret,
+ *p,
+ *r;
+
+ register size_t len;
+
+
+ len = strlen(t.keyword) + 1;
+ for (p = t.pattern; *p; p++) {
+ if (*p == '=')
+ len++;
+ len++;
+ }
+ len += 3 + strlen(t.result);
+
+ ret = Malloc(len + 1);
+ if (!ret) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+ r = ret;
+ for (p = t.keyword; *p; )
+ *r++ = *p++;
+ *r++ = ' ';
+ for (p = t.pattern; *p; ) {
+ if (*p == '=')
+ *r++ = '\\';
+ *r++ = *p++;
+ }
+ *r++ = ' ';
+ *r++ = '=';
+ *r++ = ' ';
+ for (p = t.result; *p; )
+ *r++ = *p++;
+ *r = 0;
+
+ return (ret);
+}
+
+/**
+ ** typel_to_sl() - DUPLICATE (TYPE *) LIST AS (char **) LIST
+ **/
+
+char **
+#if defined(__STDC__)
+typel_to_sl (
+ TYPE * src
+)
+#else
+typel_to_sl (src)
+ TYPE *src;
+#endif
+{
+ register char **dst;
+
+ register size_t nitems;
+
+ register int n;
+
+
+ if (!src || !src->name)
+ return (0);
+
+ for (nitems = 0; src[nitems].name; nitems++)
+ ;
+
+ if (!(dst = (char **)Malloc((nitems + 1) * sizeof(char *)))) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+ for (n = 0; n < nitems; n++)
+ dst[n] = type_to_s(src[n]);
+ dst[nitems] = 0;
+
+ return (dst);
+}
+
+/**
+ ** templatel_to_sl() - DUPLICATE A (TEMPLATE *) LIST AS (char **) LIST
+ **/
+
+char **
+#if defined(__STDC__)
+templatel_to_sl (
+ TEMPLATE * src
+)
+#else
+templatel_to_sl (src)
+ register TEMPLATE *src;
+#endif
+{
+ register char **dst;
+
+ register size_t nitems;
+
+ register int n;
+
+
+ if (!src || !src->keyword)
+ return (0);
+
+ for (nitems = 0; src[nitems].keyword; nitems++)
+ ;
+
+ if (!(dst = (char **)Malloc((nitems + 1) * sizeof(char *)))) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+ for (n = 0; n < nitems; n++)
+ dst[n] = template_to_s(src[n]);
+ dst[nitems] = 0;
+
+ return (dst);
+}
+
+/**
+ ** q_strpbrk() - strpbrk() WITH BACKSLASH QUOTING
+ ** q_strdup() - strdup() WITH BACKSLASHES OMITTED
+ **/
+
+static char *
+#if defined(__STDC__)
+q_strchr (
+ char * sp,
+ char c
+)
+#else
+q_strchr (sp, c)
+ register char *sp,
+ c;
+#endif
+{
+ do {
+ if (*sp == '\\' && sp[1])
+ sp += 2;
+ if (*sp == c)
+ return (sp);
+ } while (*sp++);
+ return (0);
+}
+
+static char *
+#if defined(__STDC__)
+q_strdup (
+ char * str
+)
+#else
+q_strdup (str)
+ char *str;
+#endif
+{
+ char *ret;
+
+ register char *p,
+ *q;
+
+ register int len = 0;
+
+
+ for (p = str; *p; p++) {
+ if (*p == '\\' && p[1] == '=')
+ p++;
+ len++;
+ }
+
+ if (!(ret = q = Malloc(len + 1)))
+ return (0);
+
+ for (p = str; *p; p++) {
+ if (*p == '\\' && p[1] == '=')
+ p++;
+ *q++ = *p;
+ }
+ *q = 0;
+
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/filters/delfilter.c b/usr/src/cmd/lp/lib/filters/delfilter.c
new file mode 100644
index 0000000000..5d1d0fa041
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/delfilter.c
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "filters.h"
+
+/**
+ ** delfilter() - DELETE A FILTER FROM FILTER TABLE
+ **/
+
+int
+#if defined(__STDC__)
+delfilter (
+ char * name
+)
+#else
+delfilter (name)
+ char *name;
+#endif
+{
+ register _FILTER *pf;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ trash_filters ();
+ goto Done;
+ }
+
+ /*
+ * Don't need to check for ENOENT, because if it is set,
+ * well that's what we want to return anyway!
+ */
+ if (!filters && get_and_load() == -1 /* && errno != ENOENT */ )
+ return (-1);
+
+ if (!(pf = search_filter(name))) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ free_filter (pf);
+ for (; pf->name; pf++)
+ *pf = *(pf+1);
+
+ nfilters--;
+ filters = (_FILTER *)Realloc(
+ (char *)filters, (nfilters + 1) * sizeof(_FILTER)
+ );
+ if (!filters) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+/* filters[nfilters].name = 0; */ /* last for loop above did this */
+
+Done: return (dumpfilters((char *)0));
+}
diff --git a/usr/src/cmd/lp/lib/filters/dumpfilters.c b/usr/src/cmd/lp/lib/filters/dumpfilters.c
new file mode 100644
index 0000000000..1395657fb4
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/dumpfilters.c
@@ -0,0 +1,224 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "stdlib.h"
+#include "unistd.h"
+
+#include "lp.h"
+#include "filters.h"
+
+static void q_print ( int , char * );
+
+static char *fw_zDblQte (char *zBuf);
+
+/**
+ ** dumpfilters() - WRITE FILTERS FROM INTERNAL STRUCTURE TO FILTER TABLE
+ **/
+
+int
+dumpfilters(char *file)
+{
+ register _FILTER *pf;
+ register TEMPLATE *pt;
+ register TYPE *pty;
+ register char *p,
+ *sep;
+ register int fld;
+ int fd;
+
+ if ((fd = open_filtertable(file, "w")) < 0)
+ return (-1);
+
+ printlist_setup ("", "", LP_SEP, "");
+ if (filters) for (pf = filters; pf->name; pf++) {
+
+ for (fld = 0; fld < FL_MAX; fld++) switch (fld) {
+ case FL_IGN:
+ break;
+ case FL_NAME:
+ p = pf->name;
+ goto String;
+ case FL_CMD:
+ if ((p = fw_zDblQte (pf->command)) != NULL) {
+ (void)fdprintf (fd, "%s%s", FL_SEP, p);
+ free (p);
+ break;
+ }
+ /* zDblQte failed so go without quotes */
+ p = pf->command;
+String: (void)fdprintf (fd, "%s%s", FL_SEP, (p? p : ""));
+ break;
+ case FL_TYPE:
+ (void)fdprintf(fd, "%s%s", FL_SEP,
+ (pf->type == fl_fast? FL_FAST : FL_SLOW));
+ break;
+ case FL_PTYPS:
+ pty = pf->printer_types;
+ goto Types;
+ case FL_ITYPS:
+ pty = pf->input_types;
+ goto Types;
+ case FL_OTYPS:
+ pty = pf->output_types;
+Types: (void)fdprintf(fd, "%s", FL_SEP);
+ sep = "";
+ if (pty) {
+ for (; pty->name; pty++) {
+ (void)fdprintf(fd, "%s%s", sep,
+ pty->name);
+ sep = ",";
+ }
+ } else
+ (void)fdprintf(fd, "%s", NAME_ANY);
+ break;
+ case FL_PRTRS:
+ (void)fdprintf(fd, "%s", FL_SEP);
+ if (pf->printers)
+ fdprintlist (fd, pf->printers);
+ else
+ (void)fdprintf(fd, "%s", NAME_ANY);
+ break;
+ case FL_TMPS:
+ (void)fdprintf(fd, "%s", FL_SEP);
+ sep = "";
+ if ((pt = pf->templates))
+ for(; pt->keyword; pt++) {
+ (void)fdprintf(fd, "%s%s ", sep,
+ pt->keyword);
+ q_print(fd, pt->pattern);
+ (void)fdprintf(fd, " = ");
+ q_print(fd, pt->result);
+ sep = ",";
+ }
+ break;
+ }
+ (void)fdprintf(fd, FL_END);
+ }
+
+ close(fd);
+ return (0);
+}
+
+/**
+ ** q_print() - PRINT STRING, QUOTING SEPARATOR CHARACTERS
+ **/
+
+static void
+q_print(int fd, char *str)
+{
+ /*
+ * There are four reasons to quote a character: It is
+ * a quote (backslash) character, it is a field separator,
+ * it is a list separator, or it is a template separator.
+ * "loadfilters()" strips the quote (backslash), but not
+ * in one place.
+ */
+ if (!str)
+ return;
+ while (*str) {
+ if (
+ *str == '\\' /* quote reason #1 */
+ || strchr(FL_SEP, *str) /* quote reason #2 */
+ || strchr(LP_SEP, *str) /* quote reason #3 */
+ || strchr("=", *str) /* quote reason #4 */
+ )
+ fdputc ('\\', fd);
+ fdputc (*str, fd);
+ str++;
+ }
+ return;
+}
+
+/*********************************************************
+
+ fw_zDblQte
+
+ Duplicates the given string allocating memory
+ using malloc.
+
+ Double quotes are used to encase the string
+ and a backslash s put infront of any embedded
+ quotes.
+
+ returns a pointer to the string provided.
+
+ It the function runs out of memory it returns
+ NULL.
+
+
+*/
+static char *fw_zDblQte (char *zBuf)
+{
+ char *zT;
+ int i;
+ int j;
+ int iNewSize;
+
+ /* count the embedded double quotes */
+ for (i = j = 0; zBuf[i]; i++) {
+ if (zBuf[i] == '"') {
+ j++;
+ }
+ }
+
+ /*
+ Allocate a new buffer
+ add 3 extra bytes for:
+ the new leading double quote
+ the new trailing double quote
+ and the NULL
+ add an extra byte for each embedded double quote
+ */
+ iNewSize = (strlen (zBuf) + 3 + j);
+ if ((zT = malloc (iNewSize)) == NULL) {
+ return (NULL); /* buffer overflow */
+ }
+
+ j = 0;
+ zT[j++] = '"'; /* start with a leading double quote */
+ for (i = 0; zBuf[i]; i++) {
+ if (zBuf[i] == '"') {
+ zT[j++] = '\\';
+ }
+ zT[j++] = zBuf[i];
+ }
+
+ zT[j++] = '"'; /* add a trailing double quote */
+ zT[j] = '\0';
+
+ return (zT);
+}
+
diff --git a/usr/src/cmd/lp/lib/filters/filtertable.c b/usr/src/cmd/lp/lib/filters/filtertable.c
new file mode 100644
index 0000000000..b8898f93b9
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/filtertable.c
@@ -0,0 +1,85 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "stdio.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "filters.h"
+
+/**
+ ** get_and_load() - LOAD REGULAR FILTER TABLE
+ **/
+
+int
+get_and_load()
+{
+ register char *file;
+
+ if (!(file = getfilterfile(FILTERTABLE)))
+ return (-1);
+ if (loadfilters(file) == -1) {
+ Free (file);
+ return (-1);
+ }
+ Free (file);
+ return (0);
+}
+
+/**
+ ** open_filtertable()
+ **/
+
+int
+open_filtertable(char *file, char *mode)
+{
+ int freeit;
+
+ int fd;
+
+ if (!file) {
+ if (!(file = getfilterfile(FILTERTABLE)))
+ return (0);
+ freeit = 1;
+ } else
+ freeit = 0;
+
+ fd = open_locked(file, mode, MODE_READ);
+
+ if (freeit)
+ Free (file);
+
+ return (fd);
+}
diff --git a/usr/src/cmd/lp/lib/filters/freefilter.c b/usr/src/cmd/lp/lib/filters/freefilter.c
new file mode 100644
index 0000000000..0ea87175b4
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/freefilter.c
@@ -0,0 +1,134 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.11 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdlib.h"
+
+#include "lp.h"
+#include "filters.h"
+
+/**
+ ** freefilter() - FREE INTERNAL SPACE ALLOCATED FOR A FILTER
+ ** free_filter() - FREE INTERNAL SPACE ALLOCATED FOR A _FILTER
+ **/
+
+static void
+#if defined(__STDC__)
+freetypel (
+ TYPE * typel
+)
+#else
+freetypel (typel)
+ register TYPE *typel;
+#endif
+{
+ register TYPE *pt;
+
+ if (typel) {
+ for (pt = typel; pt->name; pt++)
+ Free (pt->name);
+ Free ((char *)typel);
+ }
+ return;
+}
+
+void
+#if defined(__STDC__)
+freetempl (
+ TEMPLATE * templ
+)
+#else
+freetempl (templ)
+ register TEMPLATE *templ;
+#endif
+{
+ register TEMPLATE *pt;
+
+ if (templ) {
+ for (pt = templ; pt->keyword; pt++) {
+ Free (pt->keyword);
+ if (pt->pattern)
+ Free (pt->pattern);
+ if (pt->re)
+ Free (pt->re);
+ if (pt->result)
+ Free (pt->result);
+ }
+ Free ((char *)templ);
+ }
+ return;
+}
+
+void
+#if defined(__STDC__)
+freefilter (
+ FILTER * pf
+)
+#else
+freefilter (pf)
+ FILTER *pf;
+#endif
+{
+ if (!pf)
+ return;
+ if (pf->name)
+ Free (pf->name);
+ if (pf->command)
+ Free (pf->command);
+ freelist (pf->printers);
+ freelist (pf->printer_types);
+ freelist (pf->input_types);
+ freelist (pf->output_types);
+ freelist (pf->templates);
+
+ return;
+}
+
+void
+#if defined(__STDC__)
+free_filter (
+ _FILTER * pf
+)
+#else
+free_filter (pf)
+ _FILTER *pf;
+#endif
+{
+ if (!pf)
+ return;
+ if (pf->name)
+ Free (pf->name);
+ if (pf->command)
+ Free (pf->command);
+ freelist (pf->printers);
+ freetypel (pf->printer_types);
+ freetypel (pf->input_types);
+ freetypel (pf->output_types);
+ freetempl (pf->templates);
+
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/filters/getfilter.c b/usr/src/cmd/lp/lib/filters/getfilter.c
new file mode 100644
index 0000000000..95f2847592
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/getfilter.c
@@ -0,0 +1,98 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "filters.h"
+
+/**
+ ** getfilter() - GET FILTER FROM FILTER TABLE
+ **/
+
+FILTER *
+#if defined(__STDC__)
+getfilter (
+ char * name
+)
+#else
+getfilter (name)
+ char *name;
+#endif
+{
+ static _FILTER *pf = 0;
+
+ static FILTER flbuf;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ /*
+ * Don't need to check for ENOENT, because if it is set,
+ * well that's what we want to return anyway!
+ */
+ if (!filters && get_and_load() == -1 /* && errno != ENOENT */ )
+ return (0);
+
+ if (STREQU(NAME_ALL, name))
+ if (pf) {
+ if (!(++pf)->name)
+ pf = 0;
+ } else
+ pf = filters;
+ else
+ pf = search_filter(name);
+
+ if (!pf || !pf->name) {
+ errno = ENOENT;
+ return (0);
+ }
+
+ flbuf.name = Strdup(pf->name);
+ flbuf.command = (pf->command? Strdup(pf->command) : 0);
+ flbuf.type = pf->type;
+ flbuf.printer_types = typel_to_sl(pf->printer_types);
+ flbuf.printers = duplist(pf->printers);
+ flbuf.input_types = typel_to_sl(pf->input_types);
+ flbuf.output_types = typel_to_sl(pf->output_types);
+ flbuf.templates = templatel_to_sl(pf->templates);
+
+ /*
+ * Make sure a subsequent ``all'' query starts getting
+ * filters from the beginning.
+ */
+ if (!STREQU(NAME_ALL, name))
+ pf = 0;
+
+ return (&flbuf);
+}
diff --git a/usr/src/cmd/lp/lib/filters/insfilter.c b/usr/src/cmd/lp/lib/filters/insfilter.c
new file mode 100644
index 0000000000..51614dff9f
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/insfilter.c
@@ -0,0 +1,869 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "assert.h"
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "filters.h"
+
+#include "regex.h"
+
+
+#define MATCH(PT, PM) (STREQU((PT)->pattern, PATT_STAR) || \
+ match((PT)->re, *((PM)->pvalue)))
+
+
+typedef struct PARM {
+ char *keyword;
+ unsigned short flags;
+ char **pvalue;
+} PARM;
+
+#define X_MUST 0x0800 /* Pipeline MUST use this parm */
+#define X_FIRST 0x1000 /* Use parm only in 1st cmd of pipeline */
+#define X_FIXED 0x2000 /* Get value from elsewhere, not parms */
+#define X_MANY 0x4000 /* Several values allowed for parm */
+#define X_USED 0x8000 /* Used already, don't use again */
+
+static struct S {
+ TYPE input_type;
+ TYPE output_type;
+ TYPE printer_type;
+ char *printer;
+ PARM *parms;
+} S;
+
+#if defined(__STDC__)
+
+static int searchlist_t(TYPE *, TYPE *);
+static int instantiate(_FILTER **, TYPE *, TYPE *,
+ int (*)(), void *);
+static int check_pipeline(_FILTER *, PARM *);
+static char *build_pipe(_FILTER *, PARM *, unsigned short *);
+#else
+
+static int searchlist_t();
+static int instantiate();
+static int check_pipeline();
+static char *build_pipe();
+
+#endif
+
+/*
+ * Table of recognized keywords, with info. about them.
+ */
+
+#define NFIXED 4
+
+static PARM parmtable[] = {
+
+/* These must be the first NFIXED, and in this order */
+PARM_INPUT, X_FIXED, &S.input_type.name,
+PARM_OUTPUT, X_FIXED, &S.output_type.name,
+PARM_TERM, X_FIXED, &S.printer_type.name,
+PARM_PRINTER, X_FIXED, &S.printer,
+
+PARM_CPI, FPARM_CPI, 0,
+PARM_LPI, FPARM_LPI, 0,
+PARM_LENGTH, FPARM_LENGTH, 0,
+PARM_WIDTH, FPARM_WIDTH, 0,
+PARM_PAGES, FPARM_PAGES | X_FIRST | X_MUST, 0,
+PARM_CHARSET, FPARM_CHARSET, 0,
+PARM_FORM, FPARM_FORM, 0,
+PARM_COPIES, FPARM_COPIES | X_FIRST, 0,
+PARM_MODES, FPARM_MODES | X_MANY | X_MUST, 0,
+0, 0, 0,
+};
+
+/*
+ * insfilter()
+ */
+
+FILTERTYPE
+#if defined(__STDC__)
+insfilter(
+ char **pipes,
+ char *input_type,
+ char *output_type,
+ char *printer_type,
+ char *printer,
+ char **parms,
+ unsigned short *flagsp
+)
+#else
+insfilter(pipes, input_type, output_type, printer_type, printer, parms, flagsp)
+ char **pipes,
+ *input_type,
+ *output_type,
+ *printer_type,
+ *printer,
+ **parms;
+ unsigned short *flagsp;
+#endif
+{
+ _FILTER *pipeline;
+
+ FILTERTYPE ret;
+
+
+ S.input_type.name = input_type;
+ S.input_type.info = isterminfo(input_type);
+ S.output_type.name = output_type;
+ S.output_type.info = isterminfo(output_type);
+ S.printer_type.name = printer_type;
+ S.printer_type.info = isterminfo(printer_type);
+ S.printer = printer;
+
+ /*
+ * If the filters have't been loaded yet, do so now.
+ * We'll load the standard table, but the caller can override
+ * this by first calling "loadfilters()" with the appropriate
+ * filter table name.
+ */
+ if (!filters && loadfilters((char *)0) == -1)
+ return (fl_none);
+
+ /*
+ * Allocate and initialize space to hold additional
+ * information about each item in "parms".
+ * THIS SPACE MUST BE FREED BEFORE EXITING THIS ROUTINE!
+ */
+ {
+ register int n;
+
+ register PARM * pp;
+ register PARM * ppt;
+
+ register char ** p;
+
+
+
+ for (n = 0, p = parms; *p; n++, p++)
+ ;
+ n /= 2;
+ n += NFIXED; /* for fixed parms (in/out/printer types) */
+
+ if (!(S.parms = (PARM *)Malloc((n + 1) * sizeof (PARM)))) {
+ errno = ENOMEM;
+ return (fl_none);
+ }
+
+ for (ppt = parmtable; ppt->keyword; ppt++)
+ ppt->flags &= ~X_USED;
+
+ /*
+ * Load the parameter list with the fixed ``type''
+ * parameters. Mark them as used (if appropriate)
+ * so we don't pick them up from the callers list.
+ */
+ pp = S.parms;
+ for (ppt = parmtable; ppt < parmtable + NFIXED; ppt++) {
+ pp->keyword = ppt->keyword;
+ pp->flags = ppt->flags;
+ if (ppt->flags & X_FIXED)
+ pp->pvalue = ppt->pvalue;
+ else
+ pp->pvalue = parms + 1;
+ if (!(ppt->flags & X_MANY))
+ ppt->flags |= X_USED;
+ pp++;
+ }
+
+ /*
+ * Copy each parameter from the caller supplied list
+ * to another list, adding information gathered from
+ * the keyword table. Note that some keywords should
+ * be given only once; additional occurrances in the
+ * caller's list will be ignored.
+ */
+ for (p = parms; *p; p += 2)
+ for (ppt = parmtable; ppt->keyword; ppt++)
+ if (STREQU(*p, ppt->keyword) &&
+ !(ppt->flags & X_USED)) {
+
+ pp->keyword = ppt->keyword;
+ pp->flags = ppt->flags;
+ if (ppt->flags & X_FIXED)
+ pp->pvalue = ppt->pvalue;
+ else
+ pp->pvalue = p + 1;
+
+ if (!(ppt->flags & X_MANY))
+ ppt->flags |= X_USED;
+
+ pp++;
+ break;
+
+ }
+
+ pp->keyword = 0;
+
+ }
+
+ /*
+ * Preview the list of filters, to rule out those that
+ * can't possibly work.
+ */
+ {
+ register _FILTER * pf;
+
+ for (pf = filters; pf->name; pf++) {
+
+ pf->mark = FL_CLEAR;
+
+ if (printer && !searchlist(printer, pf->printers))
+ pf->mark = FL_SKIP;
+
+ else if (printer_type &&
+ !searchlist_t(&(S.printer_type),
+ pf->printer_types))
+ pf->mark = FL_SKIP;
+
+ }
+ }
+
+ /*
+ * Find a pipeline that will convert the input-type to the
+ * output-type and map the parameters as well.
+ */
+ if (!instantiate(&pipeline, &S.input_type, &S.output_type,
+ check_pipeline, S.parms)) {
+ ret = fl_none;
+ goto Return;
+ }
+
+ if (!pipes) {
+ ret = fl_both;
+ goto Return;
+
+ } else {
+ register _FILTER * pf;
+ register _FILTER * pfastf; /* first in fast pipe */
+ register _FILTER * pslowf; /* last in slow pipe */
+
+ /*
+ * Found a pipeline, so now build it.
+ */
+
+ /*
+ * Split pipeline after last slow filter.
+ * "pipeline" will point to first filter in slow
+ * pipe, "pfastf" will point to first filter in
+ * fast pipe.
+ */
+ for (pf = pfastf = pipeline, pslowf = 0; pf; pf = pf->next)
+ if (pf->type == fl_slow) {
+ pslowf = pf;
+ pfastf = pf->next;
+ }
+
+ if (pslowf) {
+ assert(pslowf != pfastf);
+ pslowf->next = 0;
+ pipes[0] = build_pipe(pipeline, S.parms, flagsp);
+ ret = fl_slow;
+ } else
+ pipes[0] = 0;
+
+ if (pfastf) {
+ pipes[1] = build_pipe(pfastf, S.parms, flagsp);
+ ret = fl_fast;
+ } else
+ pipes[1] = 0;
+
+ if (pslowf && pfastf)
+ ret = fl_both;
+
+ /*
+ * Check for the oops case.
+ */
+ if (pslowf && !pipes[0] || pfastf && !pipes[1])
+ ret = fl_none;
+
+ }
+
+Return: Free((char *)S.parms);
+
+ return (ret);
+}
+
+/*
+ * searchlist_t() - SEARCH (TYPE *) LIST FOR ITEM
+ */
+
+static int
+#if defined(__STDC__)
+typematch(
+ TYPE *type1,
+ TYPE *type2
+)
+#else
+typematch(type1, type2)
+ TYPE *type1, *type2;
+#endif
+{
+ if (STREQU(type1->name, NAME_ANY) || STREQU(type2->name, NAME_ANY) ||
+ STREQU(type1->name, type2->name) ||
+ (STREQU(type1->name, NAME_TERMINFO) && type2->info) ||
+ (STREQU(type2->name, NAME_TERMINFO) && type1->info))
+ return (1);
+ else
+ return (0);
+}
+
+static int
+#if defined(__STDC__)
+searchlist_t(
+ TYPE *itemp,
+ TYPE *list
+)
+#else
+searchlist_t(itemp, list)
+ TYPE *itemp;
+ register TYPE *list;
+#endif
+{
+ if (!list || !list->name)
+ return (0);
+
+ /*
+ * This is a linear search--we believe that the lists
+ * will be short.
+ */
+ while (list->name) {
+ if (typematch(itemp, list))
+ return (1);
+ list++;
+ }
+ return (0);
+}
+
+/*
+ * instantiate() - CREATE FILTER-PIPELINE KNOWING INPUT/OUTPUT TYPES
+ */
+
+/*
+ * The "instantiate()" routine is the meat of the "insfilter()"
+ * algorithm. It is given an input-type and output-type and finds a
+ * filter-pipline that will convert the input-type into the
+ * output-type. Since the filter-pipeline must meet other criteria,
+ * a function "verify" is also given, along with the set of criteria;
+ * these are used by "instantiate()" to verify a filter-pipeline.
+ *
+ * The filter-pipeline is built up and returned in "pipeline".
+ * Conceptually this is just a list of filters, with the pipeline to
+ * be constructed by simply concatenating the filter simple-commmands
+ * (after filling in option templates) in the order found in the
+ * list. What is used in the routine, though, is a pair of linked
+ * lists, one list forming the ``right-half'' of the pipeline, the
+ * other forming the ``left-half''. The pipeline is then the two
+ * lists taken together.
+ *
+ * The "instantiate()" routine looks for a single filter that matches
+ * the input-type and output-type and satisfies the criteria. If one
+ * is found, it is added to the end of the ``left-half'' list (it
+ * could be added to the beginning of the ``right-half'' list with no
+ * problem). The two lists are linked together to form one linked
+ * list, which is passed, along with the set of criteria, to the
+ * "verify" routine to check the filter-pipeline. If it passes the
+ * check, the work is done.
+ *
+ * If a single filter is not found, "instantiate()" examines all
+ * pairs of filters where one in the pair can accept the input-type
+ * and the other can produce the output-type. For each of these, it
+ * calls itself again to find a filter that can join the pair
+ * together--one that accepts as input the output-type of the first
+ * in the pair, and produces as output the input-type of the second
+ * in the pair. This joining filter may be a single filter or may
+ * be a filter-pipeline. "instantiate()" checks for the trivial case
+ * where the input-type is the output-type; with trivial cases it
+ * links the two lists without adding a filter and checks it with
+ * "verify".
+ */
+
+/*
+ * instantiate()
+ */
+
+/*
+ * A PIPELIST is what is passed to each recursive call to "instantiate()".
+ * It contains a pointer to the end of the ``left-list'', a pointer to the
+ * head of the ``right-list'', and a pointer to the head of the left-list.
+ * The latter is passed to "verify". The end of the right-list (and thus
+ * the end of the entire list when left and right are joined) is the
+ * filter with a null ``next'' pointer.
+ */
+typedef struct PIPELIST {
+ _FILTER * lhead;
+ _FILTER * ltail;
+ _FILTER * rhead;
+} PIPELIST;
+
+#if defined(__STDC__)
+static int _instantiate(PIPELIST *, TYPE *, TYPE *,
+ int (*)(_FILTER *, void *), void *);
+#else
+static int _instantiate();
+#endif
+
+static int peg;
+
+static int
+#if defined(__STDC__)
+instantiate(
+ _FILTER **pline,
+ TYPE *input,
+ TYPE *output,
+ int (*verify)(_FILTER *, void *),
+ void *criteria
+)
+#else
+instantiate(pline, input, output, verify, criteria)
+ _FILTER **pline;
+ TYPE *input,
+ *output;
+ int (*verify)();
+ char *criteria;
+#endif
+{
+ PIPELIST p;
+ int ret;
+
+ peg = 0;
+ p.lhead = p.ltail = p.rhead = 0;
+ ret = _instantiate(&p, input, output, verify, criteria);
+ *pline = p.lhead;
+ return (ret);
+}
+
+#define ENTER() int our_tag; our_tag = ++peg;
+
+#define LEAVE(Y) if (!Y) { \
+ register _FILTER *f; \
+ for (f = filters; f->name; f++) \
+ CLEAR(f); \
+ return (0); \
+ } else \
+ return (1)
+
+#define MARK(F, M) (((F)->mark |= M), (F)->level = our_tag)
+
+#define CLEAR(F) if ((F)->level == our_tag) \
+ (F)->level = 0, (F)->mark = FL_CLEAR
+
+#define CHECK(F, M) (((F)->mark & M) && (F)->level == our_tag)
+
+#define USED(F) ((F)->mark)
+
+static int
+#if defined(__STDC__)
+_instantiate(
+ PIPELIST *pp,
+ TYPE *inputp,
+ TYPE *outputp,
+ int (*verify)(_FILTER *, void *),
+ void *criteria
+)
+#else
+_instantiate(pp, inputp, outputp, verify, criteria)
+ PIPELIST *pp;
+ TYPE *inputp,
+ *outputp;
+ int (*verify)();
+ char *criteria;
+#endif
+{
+ register _FILTER *prev_lhead;
+ register _FILTER *prev_ltail;
+
+
+ /*
+ * Must be first ``statement'' after declarations.
+ */
+ ENTER();
+
+ /*
+ * We're done when we've added filters on the left and right
+ * that let us connect the left and right directly; i.e. when
+ * the output of the left is the same type as the input of the
+ * right. HOWEVER, there must be at least one filter involved,
+ * to allow the filter feature to be used for handling modes,
+ * pages, copies, etc. not just FILTERING data.
+ */
+ if (typematch(inputp, outputp) && pp->lhead) {
+
+ /*
+ * Getting here means that we must have a left and right
+ * pipeline. Why? For "pp->lhead" to be non-zero it
+ * must have been set below. The first place below
+ * doesn't set the right pipeline, but it also doesn't
+ * get us here (at least not directly). The only
+ * place we can get to here again is the second place
+ * "pp->phead" is set, and THAT sets the right pipeline.
+ */
+ pp->ltail->next = pp->rhead;
+ if ((*verify)(pp->lhead, criteria))
+ LEAVE(1);
+ else
+ LEAVE(0);
+
+ }
+
+ /*
+ * Each time we search the list of filters, we examine
+ * them in the order given and stop searching when a filter
+ * that meets the needs is found. If the list is ordered with
+ * fast filters before slow filters, then fast filters will
+ * be chosen over otherwise-equal filters.
+ */
+
+ /*
+ * See if there's a single filter that will work.
+ * Just in case we can't find one, mark those that
+ * will work as left- or right-filters, to save time
+ * later.
+ *
+ * Also, record exactly *which* input/output
+ * type would be needed if the filter was used.
+ * This record will be complete (both input and output
+ * recorded) IF the single filter works. Otherwise,
+ * only the input, for the left possible filters,
+ * and the output, for the right possible filters,
+ * will be recorded. Thus, we'll have to record the
+ * missing types later.
+ */
+ {
+ register _FILTER * pf;
+
+
+ for (pf = filters; pf->name; pf++) {
+
+ if (USED(pf))
+ continue;
+
+ if (searchlist_t(inputp, pf->input_types)) {
+ MARK(pf, FL_LEFT);
+ pf->inputp = inputp;
+ }
+ if (searchlist_t(outputp, pf->output_types)) {
+ MARK(pf, FL_RIGHT);
+ pf->outputp = outputp;
+ }
+
+ if (CHECK(pf, FL_LEFT) && CHECK(pf, FL_RIGHT)) {
+ prev_lhead = pp->lhead;
+ prev_ltail = pp->ltail;
+
+ if (!pp->lhead)
+ pp->lhead = pf;
+ else
+ pp->ltail->next = pf;
+ (pp->ltail = pf)->next = pp->rhead;
+
+ if ((*verify)(pp->lhead, criteria))
+ LEAVE(1);
+
+ if ((pp->ltail = prev_ltail))
+ pp->ltail->next = 0;
+ pp->lhead = prev_lhead;
+
+ }
+
+ }
+ }
+
+ /*
+ * Try all DISJOINT pairs of left- and right-filters; recursively
+ * call this function to find a filter that will connect
+ * them (it might be a ``null'' filter).
+ */
+ {
+ register _FILTER * pfl;
+ register _FILTER * pfr;
+
+ register TYPE * llist;
+ register TYPE * rlist;
+
+
+ for (pfl = filters; pfl->name; pfl++) {
+
+ if (!CHECK(pfl, FL_LEFT))
+ continue;
+
+ for (pfr = filters; pfr->name; pfr++) {
+
+ if (pfr == pfl || !CHECK(pfr, FL_RIGHT))
+ continue;
+
+ prev_lhead = pp->lhead;
+ prev_ltail = pp->ltail;
+
+ if (!pp->lhead)
+ pp->lhead = pfl;
+ else
+ pp->ltail->next = pfl;
+ (pp->ltail = pfl)->next = 0;
+
+ pfr->next = pp->rhead;
+ pp->rhead = pfr;
+
+ /*
+ * Try all the possible output types of
+ * the left filter with all the possible
+ * input types of the right filter. If
+ * we find a combo. that works, record
+ * the output and input types for the
+ * respective filters.
+ */
+ for (llist = pfl->output_types; llist->name;
+ llist++)
+ for (rlist = pfr->input_types;
+ rlist->name; rlist++)
+ if (_instantiate(pp, llist,
+ rlist, verify,
+ criteria)) {
+ pfl->outputp = llist;
+ pfr->inputp = rlist;
+ LEAVE(1);
+ }
+ pp->rhead = pfr->next;
+ if ((pp->ltail = prev_ltail))
+ pp->ltail->next = 0;
+ pp->lhead = prev_lhead;
+
+ }
+
+ }
+ }
+
+ LEAVE(0);
+}
+
+/*
+ * check_pipeline() - CHECK THAT PIPELINE HANDLES MODES, PAGE-LIST
+ */
+
+static int
+#if defined(__STDC__)
+check_pipeline(
+ _FILTER *pipeline,
+ PARM *parms
+)
+#else
+check_pipeline(pipeline, parms)
+ _FILTER *pipeline;
+ PARM *parms;
+#endif
+{
+ register PARM *pm;
+
+ register _FILTER *pf;
+
+ register TEMPLATE *pt;
+
+ register int fail;
+
+
+ for (fail = 0, pm = parms; !fail && pm->keyword; pm++) {
+
+ if (!(pm->flags & X_MUST))
+ continue;
+
+ for (pf = pipeline; pf; pf = pf->next) {
+
+ if (!(pt = pf->templates))
+ continue;
+
+ for (; pt->keyword; pt++)
+ if (STREQU(pt->keyword, pm->keyword) &&
+ pt->result && MATCH(pt, pm))
+ goto Okay;
+
+ }
+ fail = 1;
+ continue;
+
+Okay:;
+
+ }
+
+ return (fail? 0 : 1);
+}
+
+/*
+ * build_filter() - CONSTRUCT PIPELINE FROM LINKED LIST OF FILTERS
+ */
+
+#if defined(__STDC__)
+static size_t build_simple_cmd(char **, _FILTER *, PARM *,
+ unsigned short *);
+#else
+static size_t build_simple_cmd();
+#endif
+
+static char *
+#if defined(__STDC__)
+build_pipe(
+ _FILTER *pipeline,
+ PARM *parms,
+ unsigned short *fp
+)
+#else
+build_pipe(pipeline, parms, fp)
+ _FILTER *pipeline;
+ PARM *parms;
+ unsigned short *fp;
+#endif
+{
+ register _FILTER *pf;
+
+ register size_t nchars;
+ register size_t n;
+
+ char *p; /* NOT register */
+ char *ret;
+
+
+ /*
+ * This is a two-pass routine. In the first pass we add
+ * up how much space is needed for the pipeline, in the second
+ * pass we allocate the space and construct the pipeline.
+ */
+
+ for (nchars = 0, pf = pipeline; pf; pf = pf->next)
+ if ((n = build_simple_cmd((char **)0, pf, parms, fp)) > 0)
+ nchars += n + 1; /* +1 for '|' or ending null */
+
+ if (!(ret = p = Malloc(nchars))) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+ for (pf = pipeline; pf; pf = pf->next, *p++ = (pf? '|' : 0))
+ (void) build_simple_cmd(&p, pf, parms, fp);
+
+ return (ret);
+}
+
+/*
+ * build_simple_cmd()
+ */
+
+static size_t
+#if defined(__STDC__)
+build_simple_cmd(
+ char **pp,
+ _FILTER *pf,
+ PARM *parms,
+ unsigned short *flagsp
+)
+#else
+build_simple_cmd(pp, pf, parms, flagsp)
+ char **pp;
+ _FILTER *pf;
+ PARM *parms;
+ unsigned short *flagsp;
+#endif
+{
+ register size_t ncount;
+
+ register TEMPLATE *pt;
+
+ register PARM *pm;
+
+
+ if (pf->command) {
+ ncount = strlen(pf->command);
+ if (pp) {
+ strcpy (*pp, pf->command);
+ *pp += ncount;
+ }
+ } else
+ ncount = 0;
+
+ if (!pf->templates)
+ return (ncount);
+
+ for (pm = parms; pm->keyword; pm++) {
+
+ if ((pm->flags & X_USED) || !*(pm->pvalue))
+ continue;
+
+ for (pt = pf->templates; pt->keyword; pt++) {
+
+ if (!STREQU(pt->keyword, pm->keyword) || !pt->result)
+ continue;
+
+ /*
+ * INPUT and OUTPUT are those for *this* filter,
+ * not for the entire pipeline.
+ */
+ if (STREQU(pt->keyword, PARM_INPUT))
+ pm->pvalue = &(pf->inputp->name);
+ else if (STREQU(pt->keyword, PARM_OUTPUT))
+ pm->pvalue = &(pf->outputp->name);
+
+ if (MATCH(pt, pm)) {
+ if (pp)
+ *(*pp)++ = ' ';
+ ncount++;
+
+ ncount += replace(pp, pt->result,
+ *(pm->pvalue), pt->nbra);
+
+ /*
+ * Difficulty here due to the two pass
+ * nature of this code. The first pass
+ * just counts the number of bytes; if
+ * we mark the once-only parms as being
+ * used, then we don't pick them up the
+ * second time through. We could get
+ * difficult and mark them temporarily,
+ * but that's hard. So on the first pass
+ * we don't mark the flags. The only
+ * problem is an estimate too high.
+ */
+ if (pp && pm->flags & X_FIRST)
+ pm->flags |= X_USED;
+
+ *flagsp |= pm->flags;
+
+ }
+ }
+ }
+
+ return (ncount);
+}
diff --git a/usr/src/cmd/lp/lib/filters/llib-llpflt b/usr/src/cmd/lp/lib/filters/llib-llpflt
new file mode 100644
index 0000000000..61db757567
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/llib-llpflt
@@ -0,0 +1,120 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+
+typedef enum FILTERTYPE {
+ fl_none,
+ fl_fast,
+ fl_slow,
+ fl_both
+} FILTERTYPE;
+
+typedef struct FILTER {
+ char * name; /* name of filter (redundant) */
+ char * command; /* shell command (full path) */
+ FILTERTYPE type; /* type of filter (fast/slow) */
+ char ** printer_types; /* list of valid printer types */
+ char ** printers; /* list of valid printers */
+ char ** input_types; /* list of valid input types */
+ char ** output_types; /* list of valid output types */
+ char ** templates; /* list of option templates */
+} FILTER;
+
+
+
+typedef struct TYPE {
+ char * name;
+ unsigned short info; /* 1 iff "name" is in Terminfo */
+} TYPE;
+
+
+typedef struct TEMPLATE {
+ char * keyword;
+ char * pattern;
+ char * re;
+ char * result;
+ int nbra;
+} TEMPLATE;
+
+typedef struct _FILTER {
+ struct _FILTER * next; /* for linking several */
+ char * name;
+ char * command;
+ char ** printers;
+ TYPE * printer_types;
+ TYPE * input_types; /* all possible choices */
+ TYPE * output_types; /* all possible choices */
+ TYPE * inputp; /* the one to be used */
+ TYPE * outputp; /* the one to be used */
+ TEMPLATE * templates;
+ FILTERTYPE type;
+ unsigned char mark,
+ level;
+} _FILTER;
+
+
+FILTER * getfilter ( char * );
+
+_FILTER * search_filter ( char * );
+
+FILTERTYPE insfilter ( char ** , char * , char * , char * , char * , char ** , unsigned short * );
+FILTERTYPE s_to_filtertype ( char * );
+
+TEMPLATE s_to_template ( char * );
+
+TEMPLATE * sl_to_templatel ( char ** );
+
+TYPE s_to_type ( char * );
+
+TYPE * sl_to_typel ( char ** );
+
+char * template_to_s ( TEMPLATE );
+char * type_to_s ( TYPE );
+
+char ** templatel_to_sl ( TEMPLATE * );
+char ** typel_to_sl ( TYPE * );
+
+int open_filtertable ( char * , char * );
+
+int get_and_load ( void );
+int putfilter ( char * , FILTER * );
+int delfilter ( char * );
+int loadfilters ( char * );
+
+void freetempl ( TEMPLATE * );
+void freefilter ( FILTER * );
+void free_filter ( _FILTER * );
+void trash_filters ( void );
+void close_filtertable ( FILE * );
diff --git a/usr/src/cmd/lp/lib/filters/loadfilters.c b/usr/src/cmd/lp/lib/filters/loadfilters.c
new file mode 100644
index 0000000000..a4f1912bc5
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/loadfilters.c
@@ -0,0 +1,271 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+#include "unistd.h"
+
+#include "lp.h"
+#include "filters.h"
+
+_FILTER *filters;
+
+size_t nfilters;
+
+static int getfields (int, char *[], char *, int, int, char *);
+static int fs_cmp(const void *, const void *);
+
+/**
+ ** loadfilters() - READ FILTERS FROM FILTER TABLE INTO INTERNAL STRUCTURE
+ **/
+
+int
+loadfilters(char *file)
+{
+ register _FILTER *pf;
+ int fd;
+ char *filt[FL_MAX],
+ buf[3 * BUFSIZ];
+ size_t nalloc;
+
+ if (filters) {
+ nalloc = nfilters;
+ trash_filters ();
+ } else
+ nalloc = FL_MAX_GUESS;
+
+ if ((fd = open_filtertable(file, "r")) < 0)
+ return (-1);
+
+ /*
+ * Preallocate space for the internal filter table.
+ * Our guess is the number of filters previously read in,
+ * if any have been read in before (see above).
+ */
+ filters = (_FILTER *)Malloc((nalloc + 1) * sizeof(_FILTER));
+ if (!filters) {
+ close(fd);
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ for (
+ pf = filters, nfilters = 0;
+ getfields(fd, filt, buf, sizeof(buf), FL_MAX, FL_SEP) != -1;
+ pf++
+ ) {
+
+ char **list;
+
+ /*
+ * Allocate more space if needed.
+ */
+ if (++nfilters > nalloc) {
+ nalloc = nfilters;
+ filters = (_FILTER *)Realloc(
+ filters,
+ (nalloc + 1) * sizeof(_FILTER)
+ );
+ if (!filters) {
+ close(fd);
+ errno = ENOMEM;
+ return (-1);
+ }
+ pf = &filters[nfilters - 1];
+ }
+
+#define DFLT(X) (filt[X] && *filt[X]? filt[X] : NAME_ANY)
+
+ pf->name = Strdup(filt[FL_NAME]);
+ pf->type = s_to_filtertype(filt[FL_TYPE]);
+ pf->command = Strdup(filt[FL_CMD]);
+
+ pf->printers = getlist(DFLT(FL_PRTRS), LP_WS, LP_SEP);
+
+ list = getlist(DFLT(FL_PTYPS), LP_WS, LP_SEP);
+ pf->printer_types = sl_to_typel(list);
+ freelist (list);
+
+ list = getlist(DFLT(FL_ITYPS), LP_WS, LP_SEP);
+ pf->input_types = sl_to_typel(list);
+ freelist (list);
+
+ list = getlist(DFLT(FL_OTYPS), LP_WS, LP_SEP);
+ pf->output_types = sl_to_typel(list);
+ freelist (list);
+
+ /*
+ * Note the use of "" instead of LP_WS. The
+ * "sl_to_templatel()" routine will take care
+ * of stripping leading blanks. Stripping trailing
+ * blanks would be nice but shouldn't matter.
+ */
+
+/* quote reason #3 (in "getlist()") */
+ list = getlist(filt[FL_TMPS], "", LP_SEP);
+
+/* quote reason #4 (in "s_to_template()") */
+ pf->templates = sl_to_templatel(list);
+ freelist (list);
+
+ }
+ if (errno != 0) {
+ int save_errno = errno;
+
+ free_filter (pf);
+ close(fd);
+ errno = save_errno;
+ return (-1);
+ }
+ close(fd);
+
+ /*
+ * If we have more space allocated than we need,
+ * return the extra.
+ */
+ if (nfilters != nalloc) {
+ filters = (_FILTER *)Realloc(
+ filters,
+ (nfilters + 1) * sizeof(_FILTER)
+ );
+ if (!filters) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ }
+ filters[nfilters].name = 0;
+
+ /*
+ * Sort the filters, putting ``fast'' filters before
+ * ``slow'' filters. This preps the list for "insfilter()"
+ * so that it can easily pick fast filters over otherwise
+ * equivalent slow filters. This sorting is done every
+ * time we read in the table; one might think that if
+ * "putfilter()" would insert in the correct order then
+ * the table, when written out to disk, would be sorted
+ * already--removing the need to sort it here. We don't
+ * take that approach, because (1) sorting it isn't that
+ * expensive and (2) someone might tamper with the table
+ * file.
+ */
+ qsort ((char *)filters, nfilters, sizeof(_FILTER), fs_cmp);
+
+ return (0);
+}
+
+/**
+ ** getfields() - PARSE NON-COMMENT LINE FROM FILE INTO FIELDS
+ **/
+
+static int
+getfields(int fd, char *fields[], char *buf, int bufsiz, int max, char *seps)
+{
+ register char *p,
+ *q;
+
+ register int n = 0;
+ enum ParsingMode {CHECK_LEAD_DBL_QUOTE, NORMAL_PARSING, LITERAL_READ} eMode;
+ errno = 0;
+ while (fdgets(buf, bufsiz, fd) != NULL) {
+ buf[strlen(buf) - 1] = 0;
+ p = buf + strspn(buf, " \t");
+ if (*p && *p != '#') {
+ for (eMode = CHECK_LEAD_DBL_QUOTE, fields[n++] = q = p; *p; ) {
+ switch (eMode) {
+ case CHECK_LEAD_DBL_QUOTE: /* check for leading double quote */
+ if (*p == '"') {
+ eMode = LITERAL_READ;
+ p++;
+ break;
+ }
+ eMode = NORMAL_PARSING;
+ /* drop through to NORMAL_PARSING case */
+
+ case NORMAL_PARSING: /* default legacy editing */
+ if (*p == '\\') {
+ if (
+/* quote reason #1 */ p[1] == '\\'
+/* quote reason #2 */ || strchr(seps, p[1])
+ )
+ p++;
+ *q++ = *p++;
+ } else if (strchr(seps, *p)) {
+ *q++ = 0;
+ p++;
+ if (n < max) {
+ fields[n++] = q;
+ eMode = CHECK_LEAD_DBL_QUOTE;
+ }
+ } else
+ *q++ = *p++;
+ break;
+
+ case LITERAL_READ: /* read literally until another double quote */
+ if (*p == '\\' && p[1] == '"') { /* embedded double quote */
+ p++;
+ *q++ = *p++;
+ } else if (*p == '"') { /* end of literal read */
+ p++;
+ eMode = NORMAL_PARSING;
+ } else {
+ *q++ = *p++; /* capture as is */
+ }
+ break;
+ }
+ }
+ *q = 0;
+ while (n < max)
+ fields[n++] = "";
+ return (n);
+ }
+ }
+ return (-1);
+}
+
+/**
+ ** fs_cmp() - COMPARE TWO FILTERS BY "FILTERTYPE"
+ **/
+
+static int
+fs_cmp(const void *pfa, const void *pfb)
+{
+ if (((_FILTER *)pfa)->type == ((_FILTER *)pfb)->type)
+ return (0);
+ else if (((_FILTER *)pfa)->type == fl_fast)
+ return (-1);
+ else
+ return (1);
+}
diff --git a/usr/src/cmd/lp/lib/filters/putfilter.c b/usr/src/cmd/lp/lib/filters/putfilter.c
new file mode 100644
index 0000000000..fad8e0d28c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/putfilter.c
@@ -0,0 +1,124 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "filters.h"
+
+/**
+ ** putfilter() - PUT FILTER INTO FILTER TABLE
+ **/
+
+int
+#if defined(__STDC__)
+putfilter (
+ char * name,
+ FILTER * flbufp
+)
+#else
+putfilter (name, flbufp)
+ char *name;
+ FILTER *flbufp;
+#endif
+{
+ _FILTER _flbuf;
+
+ register _FILTER *pf;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ _flbuf.name = Strdup(name);
+ _flbuf.command = (flbufp->command? Strdup(flbufp->command) : 0);
+ _flbuf.type = flbufp->type;
+ _flbuf.printer_types = sl_to_typel(flbufp->printer_types);
+ _flbuf.printers = duplist(flbufp->printers);
+ _flbuf.input_types = sl_to_typel(flbufp->input_types);
+ _flbuf.output_types = sl_to_typel(flbufp->output_types);
+ if (!flbufp->templates)
+ _flbuf.templates = 0;
+ else if (!(_flbuf.templates = sl_to_templatel(flbufp->templates))) {
+ free_filter (&_flbuf);
+ errno = EBADF;
+ return (-1);
+ }
+
+ if (!filters && get_and_load() == -1 && errno != ENOENT) {
+ free_filter (&_flbuf);
+ return (-1);
+ }
+
+ if (filters) {
+
+ if ((pf = search_filter(name)))
+ free_filter (pf);
+ else {
+ nfilters++;
+ filters = (_FILTER *)Realloc(
+ (char *)filters,
+ (nfilters + 1) * sizeof(_FILTER)
+ );
+ if (!filters) {
+ free_filter (&_flbuf);
+ errno = ENOMEM;
+ return (-1);
+ }
+ filters[nfilters].name = 0;
+ pf = filters + nfilters - 1;
+ }
+
+ } else {
+
+ nfilters = 1;
+ pf = filters = (_FILTER *)Malloc(
+ (nfilters + 1) * sizeof(_FILTER)
+ );
+ if (!filters) {
+ free_filter (&_flbuf);
+ errno = ENOMEM;
+ return (-1);
+ }
+ filters[nfilters].name = 0;
+
+ }
+
+ *pf = _flbuf;
+
+ return (dumpfilters((char *)0));
+}
diff --git a/usr/src/cmd/lp/lib/filters/regex.c b/usr/src/cmd/lp/lib/filters/regex.c
new file mode 100644
index 0000000000..e6931d2fcf
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/regex.c
@@ -0,0 +1,164 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "regexpr.h"
+#include "regex.h"
+#include "string.h"
+
+/**
+ ** match() - TEST MATCH OF TEMPLATE/PATTERN WITH PARAMETER
+ **/
+
+int
+#if defined(__STDC__)
+match (
+ char * re,
+ char * value
+)
+#else
+match (re, value)
+ register char * re;
+ register char * value;
+#endif
+{
+ int ret;
+
+ /*
+ * We want exact matches, just as if the regular expression
+ * was ^...$, to explicitly match the beginning and end of line.
+ * Using "advance" instead of "step" takes care of the ^ and
+ * checking where the match left off takes care of the $.
+ * We don't do something silly like add the ^ and $ ourselves,
+ * because the user may have done that already.
+ */
+ ret = advance(value, re);
+ if (ret && *loc2)
+ ret = 0;
+ return (ret);
+}
+
+/**
+ ** replace() - REPLACE TEMPLATE WITH EXPANDED REGULAR EXPRESSION MATCH
+ **/
+
+size_t
+#if defined(__STDC__)
+replace (
+ char ** pp,
+ char * result,
+ char * value,
+ int nbra
+)
+#else
+replace (pp, result, value)
+ char ** pp;
+ char * result;
+ char * value;
+ int nbra;
+#endif
+{
+ register char * p;
+ register char * q;
+
+ register size_t ncount = 0;
+
+
+/*
+ * Count and perhaps copy a single character:
+ */
+#define CCPY(SRC) if ((ncount++, pp)) \
+ *p++ = SRC
+
+/*
+ * Count and perhaps copy a string:
+ */
+#define SCPY(SRC) if (pp) { \
+ register char * r; \
+ for (r = (SRC); *r; ncount++) \
+ *p++ = *r++; \
+ } else \
+ ncount += strlen(SRC)
+
+
+ if (pp)
+ p = *pp;
+
+ for (q = result; *q; q++) switch (*q) {
+
+ case '*':
+ case '&':
+ SCPY (value);
+ break;
+
+ case '\\':
+ switch (*++q) {
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ register int n = *q-'1';
+
+ if (n < nbra) {
+ register char c = *(braelist[n]);
+
+ *(braelist[n]) = 0;
+ SCPY (braslist[n]);
+ *(braelist[n]) = c;
+ }
+ break;
+ }
+
+ default:
+ CCPY (*q);
+ break;
+ }
+ break;
+
+ default:
+ CCPY (*q);
+ break;
+ }
+
+ if (pp)
+ *pp = p;
+
+ return (ncount);
+}
diff --git a/usr/src/cmd/lp/lib/filters/regex.h b/usr/src/cmd/lp/lib/filters/regex.h
new file mode 100644
index 0000000000..e8fa4c78aa
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/regex.h
@@ -0,0 +1,39 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+
+#if defined(__STDC__)
+
+int match ( char * , char * );
+size_t replace ( char ** , char * , char * , int );
+
+#else
+
+int match();
+size_t replace();
+
+#endif
diff --git a/usr/src/cmd/lp/lib/filters/search.c b/usr/src/cmd/lp/lib/filters/search.c
new file mode 100644
index 0000000000..428139ab32
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/search.c
@@ -0,0 +1,54 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+
+#include "lp.h"
+#include "filters.h"
+
+/**
+ ** search_filter() - SEARCH INTERNAL FILTER TABLE FOR FILTER BY NAME
+ **/
+
+_FILTER *
+#if defined(__STDC__)
+search_filter (
+ char * name
+)
+#else
+search_filter (name)
+ register char *name;
+#endif
+{
+ register _FILTER *pf;
+
+ for (pf = filters; pf->name; pf++)
+ if (STREQU(pf->name, name))
+ break;
+ return (pf->name? pf : 0);
+}
diff --git a/usr/src/cmd/lp/lib/filters/trash.c b/usr/src/cmd/lp/lib/filters/trash.c
new file mode 100644
index 0000000000..06e6953d39
--- /dev/null
+++ b/usr/src/cmd/lp/lib/filters/trash.c
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdlib.h"
+
+#include "lp.h"
+#include "filters.h"
+
+/**
+ ** trash_filters() - FREE ALL SPACE ALLOCATED FOR FILTER TABLE
+ **/
+
+void trash_filters ()
+{
+ register _FILTER *pf;
+
+ if (filters) {
+ for (pf = filters; pf->name; pf++)
+ free_filter (pf);
+ Free ((char *)filters);
+ nfilters = 0;
+ filters = 0;
+ }
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/forms/Makefile b/usr/src/cmd/lp/lib/forms/Makefile
new file mode 100644
index 0000000000..a085f5f66b
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/Makefile
@@ -0,0 +1,69 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/forms/Makefile
+#
+
+LIBRARY = liblpfrm.a
+
+OBJECTS = delform.o \
+ f_head.o \
+ freeform.o \
+ getform.o \
+ putform.o \
+ rdform.o \
+ wrform.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CFLAGS += $(C_BIGPICFLAGS)
+CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+POFILE = lp_lib_forms.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpfrm.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+
+lint: lintcheck
+
+lintlib:
+ $(LINT.c) $(LINTFLAGS) -o lpfrm llib-llpfrm
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/forms/delform.c b/usr/src/cmd/lp/lib/forms/delform.c
new file mode 100644
index 0000000000..6c367bbff1
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/delform.c
@@ -0,0 +1,114 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.11 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "form.h"
+
+#if defined(__STDC__)
+static int _delform ( char * );
+#else
+static int _delform();
+#endif
+
+/**
+ ** delform()
+ **/
+
+int
+#if defined(__STDC__)
+delform (
+ char * name
+)
+#else
+delform (name)
+ char *name;
+#endif
+{
+ long lastdir;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ lastdir = -1;
+ while ((name = next_dir(Lp_A_Forms, &lastdir)))
+ if (_delform(name) == -1)
+ return (-1);
+ return (0);
+ } else
+ return (_delform(name));
+}
+
+/**
+ ** _delform()
+ **/
+
+static int
+#if defined(__STDC__)
+_delform (
+ char * name
+)
+#else
+_delform (name)
+ char *name;
+#endif
+{
+ register char *path;
+
+#define RMFILE(X) if (!(path = getformfile(name, X))) \
+ return (-1); \
+ if (rmfile(path) == -1) { \
+ Free (path); \
+ return (-1); \
+ } \
+ Free (path)
+ RMFILE (DESCRIBE);
+ RMFILE (COMMENT);
+ RMFILE (ALIGN_PTRN);
+ RMFILE (ALLOWFILE);
+ RMFILE (DENYFILE);
+
+ delalert (Lp_A_Forms, name);
+
+ if (!(path = getformfile(name, (char *)0)))
+ return (-1);
+ if (Rmdir(path) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/forms/f_head.c b/usr/src/cmd/lp/lib/forms/f_head.c
new file mode 100644
index 0000000000..39cd34956a
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/f_head.c
@@ -0,0 +1,92 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+
+#include "lp.h"
+#include "form.h"
+
+struct {
+ char *v;
+ short len;
+ short infile;
+} formheadings[FO_MAX] = {
+
+#define ENTRY(X) X, sizeof(X)-1
+
+ ENTRY("page length:"), 1, /* FO_PLEN */
+ ENTRY("page width:"), 1, /* FO_PWID */
+ ENTRY("number of pages:"), 1, /* FO_NP */
+ ENTRY("line pitch:"), 1, /* FO_LPI */
+ ENTRY("character pitch:"), 1, /* FO_CPI */
+ ENTRY("character set choice:"), 1, /* FO_CHSET */
+ ENTRY("ribbon color:"), 1, /* FO_RCOLOR */
+ ENTRY("comment:"), 0, /* FO_CMT */
+ ENTRY("alignment pattern:"), 1, /* FO_ALIGN */
+ ENTRY("paper:"), 1, /* FO_PAPER */
+
+#undef ENTRY
+
+};
+
+/**
+ ** _search_fheading()
+ **/
+
+int
+#if defined(__STDC__)
+_search_fheading (
+ char * buf
+)
+#else
+_search_fheading (buf)
+ char * buf;
+#endif
+{
+ int fld;
+
+
+ for (fld = 0; fld < FO_MAX; fld++)
+ if (
+ formheadings[fld].v
+ && formheadings[fld].len
+ && CS_STRNEQU(
+ buf,
+ formheadings[fld].v,
+ formheadings[fld].len
+ )
+ )
+ break;
+
+ return (fld);
+}
diff --git a/usr/src/cmd/lp/lib/forms/freeform.c b/usr/src/cmd/lp/lib/forms/freeform.c
new file mode 100644
index 0000000000..451650fe27
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/freeform.c
@@ -0,0 +1,64 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "form.h"
+
+/**
+ ** freeform() - FREE MEMORY ALLOCATED FOR FORM STRUCTURE
+ **/
+
+void
+#if defined(__STDC__)
+freeform (
+ FORM * pf
+)
+#else
+freeform (pf)
+ FORM * pf;
+#endif
+{
+ if (!pf)
+ return;
+ if (pf->chset)
+ Free (pf->chset);
+ if (pf->rcolor)
+ Free (pf->rcolor);
+ if (pf->comment)
+ Free (pf->comment);
+ if (pf->conttype)
+ Free (pf->conttype);
+ if (pf->name)
+ Free (pf->name);
+ pf->name = 0;
+
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/forms/getform.c b/usr/src/cmd/lp/lib/forms/getform.c
new file mode 100644
index 0000000000..d0cf592484
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/getform.c
@@ -0,0 +1,153 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.14 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "form.h"
+
+/*
+ * getform() - EXTRACT FORM STRUCTURE FROM DISK FILE
+ *
+ * The FILE **align_fp doesn't need to be changed for scalability, because
+ * it is always NULL when getform is called by lpsched.
+ */
+int
+getform(char *name, FORM *formp, FALERT *alertp, FILE **align_fp)
+{
+ static long lastdir = -1;
+
+ int fd;
+
+ register char * path;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Getting ``all''? If so, jump into the directory
+ * wherever we left off.
+ */
+ if (STREQU(NAME_ALL, name)) {
+ if (!(name = next_dir(Lp_A_Forms, &lastdir)))
+ return (-1);
+ } else
+ lastdir = -1;
+
+
+ /*
+ * Get the form configuration information (?)
+ */
+ if (formp) {
+ path = getformfile(name, DESCRIBE);
+ if (!path)
+ return (-1);
+ if ((fd = open_locked(path, "r", 0)) < 0) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ if (rdform(name, formp, fd, 0, (int *)0) == -1) {
+ close(fd);
+ return (-1);
+ }
+ close(fd);
+ }
+
+ /*
+ * Get the alert information (?)
+ */
+ if (alertp) {
+
+ FALERT * pa = getalert(Lp_A_Forms, name);
+
+
+ /*
+ * Don't fail if we can't read it because of access
+ * permission UNLESS we're "root" or "lp"
+ */
+ if (!pa) {
+
+ if (errno == ENOENT) {
+ alertp->shcmd = 0;
+ alertp->Q = alertp->W = -1;
+
+ } else if (errno == ENOTDIR) {
+ freeform (formp);
+ errno = ENOENT; /* form doesn't exist */
+ return (-1);
+
+ } else if (
+ errno != EACCES
+ || !getpid() /* we be root */
+ || STREQU(getname(), LPUSER) /* we be lp */
+ ) {
+ freeform (formp);
+ return (-1);
+ }
+
+ } else
+ *alertp = *pa;
+ }
+
+ /*
+ * Get the alignment pattern (?)
+ */
+ if (align_fp) {
+ path = getformfile(name, ALIGN_PTRN);
+ if (!path) {
+ freeform (formp);
+ errno = ENOMEM;
+ return (-1);
+ }
+ if (
+ !(*align_fp = open_lpfile(path, "r", 0))
+ && errno != ENOENT
+ ) {
+ Free (path);
+ freeform (formp);
+ return (-1);
+ }
+ Free (path);
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/forms/llib-llpfrm b/usr/src/cmd/lp/lib/forms/llib-llpfrm
new file mode 100644
index 0000000000..625d3e7be5
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/llib-llpfrm
@@ -0,0 +1,62 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "../../include/lp.h"
+
+typedef struct FORM {
+ SCALED plen;
+ SCALED pwid;
+ SCALED lpi;
+ SCALED cpi;
+ int np;
+ char * chset;
+ short mandatory;
+ char * rcolor;
+ char * comment;
+ char * conttype;
+ char * name;
+ char * paper;
+ short isDefault;
+} FORM;
+
+#define err_hndlr int (*)( int , int , int )
+
+int delform ( char * );
+int getform ( char * , FORM * , FALERT * , FILE ** );
+int putform ( char * , FORM * , FALERT * , FILE ** );
+int rdform ( char * , FORM * , int , err_hndlr , int * );
+int wrform ( char * , FORM * , int , err_hndlr , int * );
+
+void freeform ( FORM * );
+
diff --git a/usr/src/cmd/lp/lib/forms/putform.c b/usr/src/cmd/lp/lib/forms/putform.c
new file mode 100644
index 0000000000..beaff08220
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/putform.c
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "form.h"
+
+/**
+ ** putform() - WRITE FORM STRUCTURE TO DISK FILES
+ **/
+
+int
+putform(char *name, FORM *formp, FALERT *alertp, FILE **p_align_fp)
+{
+ register char * path;
+
+ int fd;
+
+ struct stat statbuf;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Create the parent directory for this form
+ * if it doesn't yet exist.
+ */
+ if (!(path = getformfile(name, (char *)0)))
+ return (-1);
+ if (Stat(path, &statbuf) == 0) {
+ if (!S_ISDIR(statbuf.st_mode)) {
+ Free (path);
+ errno = ENOTDIR;
+ return (-1);
+ }
+ } else if (errno != ENOENT || mkdir_lpdir(path, MODE_DIR) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ /*
+ * Open the configuration file and write out the form
+ * configuration (?)
+ */
+ if (formp) {
+ if (!(path = getformfile(name, DESCRIBE)))
+ return (-1);
+ if ((fd = open_locked(path, "w", MODE_READ)) < 0) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ if (wrform(name, formp, fd, 0, (int *)0) == -1) {
+ close(fd);
+ return (-1);
+ }
+ close(fd);
+ }
+
+ /*
+ * Write out the alert condition (?)
+ */
+ if (alertp) {
+ if (
+ alertp->shcmd
+ && putalert(Lp_A_Forms, name, alertp) == -1
+ )
+ return (-1);
+ }
+
+ /*
+ * Write out the alignment pattern (?)
+ */
+ if (p_align_fp && *p_align_fp) {
+
+ int size = 0,
+ n;
+
+ char buf[BUFSIZ];
+
+
+ if (!(path = getformfile(name, ALIGN_PTRN)))
+ return (-1);
+ if ((fd = open_locked(path, "w", MODE_READ)) < 0) {
+ Free (path);
+ return (-1);
+ }
+
+ while ((n = fread(buf, 1, BUFSIZ, *p_align_fp)) != 0) {
+ size += n;
+ write (fd, buf, n);
+ }
+ close(fd);
+
+ if (!size)
+ Unlink(path);
+
+ Free(path);
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/forms/rdform.c b/usr/src/cmd/lp/lib/forms/rdform.c
new file mode 100644
index 0000000000..a92ebb70f4
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/rdform.c
@@ -0,0 +1,379 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.17 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "form.h"
+
+extern struct {
+ char *v;
+ short len;
+ short infile;
+} formheadings[];
+
+#if defined(__STDC__)
+int _search_fheading ( char * );
+#else
+int _search_fheading();
+#endif
+
+int
+rdform(char *name, FORM *formp, int fd, int (*error_handler)( int , int , int ),
+ int *which_set)
+{
+ char buf[BUFSIZ];
+
+ char * rest;
+ char * mandp;
+ char * dftp;
+ char * here;
+
+ int fld;
+ int have_line_already;
+ int found_alignment_pattern;
+ int size;
+ int add_size;
+ int linenum;
+ int i;
+
+ SCALED sdn;
+
+ register char * p;
+
+
+ /*
+ * Initialize the entire structure, to ensure no random
+ * values get in it. However, make sure some values won't
+ * be null or empty. Do the latter here as opposed to
+ * after reading the file, because sometimes the file
+ * contains an empty header to FORCE a null/empty value.
+ */
+ (void)memset ((char *)formp, 0, sizeof(*formp));
+ formp->name = Strdup(name);
+ formp->plen.val = DPLEN;
+ formp->plen.sc = 0;
+ formp->pwid.val = DPWIDTH;
+ formp->pwid.sc = 0;
+ formp->lpi.val = DLPITCH;
+ formp->lpi.sc = 0;
+ formp->cpi.val = DCPITCH;
+ formp->cpi.sc = 0;
+ formp->np = DNP;
+ formp->chset = Strdup(DCHSET);
+ formp->mandatory = 0;
+ formp->rcolor = Strdup(DRCOLOR);
+ formp->conttype = Strdup(DCONTYP);
+ formp->paper = NULL;
+ formp->isDefault = 0;
+
+ /*
+ * Read the file.
+ */
+
+#define FGETS(B,S,F) (linenum++, fdgets(B,S,F))
+
+ have_line_already = 0;
+ found_alignment_pattern = 0;
+ linenum = 0;
+ errno = 0;
+ while (!found_alignment_pattern
+ && (have_line_already || FGETS(buf, BUFSIZ, fd))
+ ) {
+
+ int pos = strlen(buf) - 1;
+
+
+ have_line_already = 0;
+
+ while (isspace(buf[pos]))
+ buf[pos--] = 0;
+
+ fld = _search_fheading(buf);
+ if (fld >= FO_MAX) {
+ lp_errno = LP_EBADHDR;
+BadFile: errno = EBADF;
+ if (error_handler) {
+ if ((*error_handler)(errno, lp_errno, linenum) == -1)
+ return (-1);
+ continue;
+ } else {
+ /*
+ * To allow future extensions to not
+ * impact applications using old versions
+ * of this routine, ignore strange fields.
+ */
+ continue;
+ }
+ }
+
+ p = buf + formheadings[fld].len;
+ while (isspace(*p))
+ p++;
+
+ if (which_set)
+ which_set[fld] = 1;
+
+ if (
+ formheadings[fld].infile
+ || error_handler
+ ) switch (fld) {
+
+ case FO_PLEN:
+ sdn = getsdn(p);
+ if (errno == EINVAL) {
+ lp_errno = LP_EBADSDN;
+ goto BadFile;
+ }
+ formp->plen = sdn;
+ break;
+
+ case FO_PWID:
+ sdn = getsdn(p);
+ if (errno == EINVAL) {
+ lp_errno = LP_EBADSDN;
+ goto BadFile;
+ }
+ formp->pwid = sdn;
+ break;
+
+ case FO_CPI:
+ sdn = getcpi(p);
+ if (errno == EINVAL) {
+ lp_errno = LP_EBADSDN;
+ goto BadFile;
+ }
+ formp->cpi = sdn;
+ break;
+
+ case FO_LPI:
+ sdn = getsdn(p);
+ if (errno == EINVAL) {
+ lp_errno = LP_EBADSDN;
+ goto BadFile;
+ }
+ formp->lpi = sdn;
+ break;
+
+ case FO_NP:
+ if (
+ (i = strtol(p, &rest, 10)) <= 0
+ || *rest
+ ) {
+ lp_errno = LP_EBADINT;
+ goto BadFile;
+ }
+ formp->np = i;
+ break;
+
+ case FO_CHSET:
+ if (!(mandp = strchr(p, ',')))
+ formp->mandatory = 0;
+ else {
+ do
+ *mandp++ = 0;
+ while (*mandp && isspace(*mandp));
+ if (CS_STREQU(MANSTR, mandp))
+ formp->mandatory = 1;
+ else {
+ lp_errno = LP_EBADARG;
+ goto BadFile;
+ }
+ }
+ if (!syn_name(p)) {
+ lp_errno = LP_EBADNAME;
+ goto BadFile;
+ }
+ if (formp->chset)
+ Free (formp->chset);
+ formp->chset = Strdup(p);
+ break;
+
+ case FO_RCOLOR:
+ if (formp->rcolor)
+ Free (formp->rcolor);
+ formp->rcolor = Strdup(p);
+ break;
+
+ case FO_CMT:
+ if (*p) {
+ lp_errno = LP_ETRAILIN;
+ goto BadFile;
+ }
+ if (formp->comment)
+ Free (formp->comment);
+ formp->comment = 0;
+ size = 0;
+ while (FGETS(buf, BUFSIZ, fd)) {
+ p = buf;
+
+ /*
+ * A recognized header ends the comment.
+ */
+ if (_search_fheading(p) < FO_MAX) {
+ have_line_already = 1;
+ break;
+ }
+
+ /*
+ * On the other hand, a '>' may hide what
+ * would otherwise look like a header.
+ */
+ if (
+ p[0] == '>'
+ && _search_fheading(p+1) < FO_MAX
+ )
+ p++;
+
+ /*
+ * (Re)allocate space to hold this
+ * (additional) line of the comment.
+ */
+ add_size = strlen(p);
+ if (formp->comment)
+ formp->comment = Realloc(
+ formp->comment,
+ size + add_size + 1
+ );
+ else
+ formp->comment = Malloc(
+ size + add_size + 1
+ );
+ if (!formp->comment) {
+ freeform (formp);
+ close(fd);
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ /*
+ * Copy this (additional) line of the
+ * comment to the allocated space. "here"
+ * points to where to copy the line.
+ */
+ strcpy (formp->comment + size, p);
+ size += add_size;
+ }
+ if (errno != 0)
+ goto BadFile;
+
+ /*
+ * The comment is held internally without a
+ * trailing newline.
+ */
+ if (size && formp->comment[size - 1] == '\n')
+ formp->comment[size - 1] = 0;
+
+ break;
+
+ case FO_ALIGN:
+ if (*p) {
+ if (!syn_type(p)) {
+ lp_errno = LP_EBADCTYPE;
+ goto BadFile;
+ }
+ if (formp->conttype)
+ Free (formp->conttype);
+ formp->conttype = Strdup(p);
+ }
+
+ /*
+ * Actual alignment pattern has to be read in
+ * by caller; we leave the file pointer ready.
+ */
+ found_alignment_pattern = 1;
+ break;
+
+ case FO_PAPER:
+ if (!(dftp = strchr(p, ',')))
+ formp->isDefault = 0;
+ else {
+ do
+ *dftp++ = 0;
+ while (*dftp && isspace(*dftp));
+ if (CS_STREQU(DFTSTR, dftp))
+ formp->isDefault = 1;
+ else {
+ lp_errno = LP_EBADARG;
+ goto BadFile;
+ }
+ }
+ if (!syn_name(p)) {
+ lp_errno = LP_EBADNAME;
+ goto BadFile;
+ }
+ if (formp->paper)
+ Free (formp->paper);
+ formp->paper = Strdup(p);
+ break;
+ }
+
+ }
+ if (errno != 0) {
+ int save_errno = errno;
+
+ freeform (formp);
+ errno = save_errno;
+ return (-1);
+ }
+
+ /*
+ * Get the form description (if it exists) (?)
+ */
+ if (!error_handler) {
+
+ char * path;
+
+
+ if (!(path = getformfile(name, COMMENTFILE))) {
+ freeform (formp);
+ errno = ENOMEM;
+ return (-1);
+ }
+ if (
+ !(formp->comment = loadstring(path))
+ && errno != ENOENT
+ ) {
+ Free (path);
+ freeform (formp);
+ return (-1);
+ }
+ Free (path);
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/forms/wrform.c b/usr/src/cmd/lp/lib/forms/wrform.c
new file mode 100644
index 0000000000..a3a21a92cc
--- /dev/null
+++ b/usr/src/cmd/lp/lib/forms/wrform.c
@@ -0,0 +1,209 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "form.h"
+
+extern struct {
+ char *v;
+ short len;
+ short infile;
+} formheadings[];
+
+int _search_fheading ( char * );
+
+static void print_sdn(int, char *, SCALED);
+static void print_str(int, char *, char *);
+
+/**
+ ** wrform()
+ **/
+
+int
+wrform(char *name, FORM *formp, int fd, int (*error_handler)( int , int , int ),
+ int *which_set)
+{
+ int fld;
+
+ char * cp;
+
+
+ errno = 0;
+ for (fld = 0; fld < FO_MAX; fld++)
+ if ((!which_set || which_set[fld]) &&
+ (formheadings[fld].infile || error_handler))
+ switch (fld) {
+
+#define HEAD formheadings[fld].v
+
+ case FO_PLEN:
+ print_sdn(fd, HEAD, formp->plen);
+ break;
+
+ case FO_PWID:
+ print_sdn(fd, HEAD, formp->pwid);
+ break;
+
+ case FO_LPI:
+ print_sdn(fd, HEAD, formp->lpi);
+ break;
+
+ case FO_CPI:
+ if (formp->cpi.val == N_COMPRESSED)
+ print_str(fd, HEAD, NAME_COMPRESSED);
+ else
+ print_sdn(fd, HEAD, formp->cpi);
+ break;
+
+ case FO_NP:
+ fdprintf(fd, "%s %d\n", HEAD, formp->np);
+ break;
+
+ case FO_CHSET:
+ fdprintf(fd, "%s %s", HEAD, formp->chset);
+ if (formp->mandatory == 1)
+ fdprintf(fd, ",%s", MANSTR);
+ fdprintf(fd, "\n");
+ break;
+
+ case FO_RCOLOR:
+ print_str(fd, HEAD, formp->rcolor);
+ break;
+
+ case FO_CMT:
+ if ((cp = formp->comment) && *cp) {
+ fdprintf(fd, "%s\n", HEAD);
+ do {
+ char * nl = strchr(cp, '\n');
+
+ if (nl)
+ *nl = 0;
+ if (_search_fheading(cp) < FO_MAX)
+ fdputc ('>', fd);
+ fdprintf(fd, "%s\n", cp);
+ if (nl)
+ *nl = '\n';
+ cp = nl;
+ } while (cp++); /* NOT *cp++ */
+ }
+ break;
+
+ case FO_ALIGN:
+ /* this must always be the last field in the file
+ it is done outside of this loop */
+ break;
+
+ case FO_PAPER:
+ if (formp->paper) {
+ fdprintf(fd, "%s %s", HEAD, formp->paper);
+ if (formp->isDefault == 1)
+ fdprintf(fd, ",%s", DFTSTR);
+ fdprintf(fd, "\n");
+ }
+ break;
+
+ }
+
+ if ((!which_set || which_set[FO_ALIGN]) &&
+ (formheadings[FO_ALIGN].infile || error_handler)) {
+ print_str(fd, formheadings[FO_ALIGN].v, formp->conttype);
+ /*
+ * Actual alignment pattern has to be written
+ * out by caller; we leave the file pointer ready.
+ */
+ }
+
+ if (errno != 0)
+ return (-1);
+
+ /*
+ * Write out comment to a separate file (?)
+ */
+ if (!error_handler) {
+
+ char * path;
+
+
+ if (!(path = getformfile(name, COMMENT)))
+ return (-1);
+
+ if (formp->comment) {
+ if (dumpstring(path, formp->comment) == -1) {
+ Free (path);
+ return (-1);
+ }
+
+ } else
+ Unlink (path);
+
+ Free (path);
+
+ }
+
+ return (0);
+}
+
+/**
+ ** print_sdn() - PRINT SCALED DECIMAL NUMBER WITH HEADER
+ ** print_str() - PRINT STRING WITH HEADER
+ **/
+
+static void
+print_sdn(int fd, char *head, SCALED sdn)
+{
+ if (sdn.val <= 0)
+ return;
+
+ (void)fdprintf(fd, "%s ", head);
+ fdprintsdn(fd, sdn);
+
+ return;
+}
+
+static void
+print_str(int fd, char *head, char *str)
+{
+ if (!str || !*str)
+ return;
+
+ (void)fdprintf(fd, "%s %s\n", head, str);
+
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/lp/Makefile b/usr/src/cmd/lp/lib/lp/Makefile
new file mode 100644
index 0000000000..7161681ef4
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/Makefile
@@ -0,0 +1,106 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+
+
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/lp/Makefile
+#
+
+LIBRARY = liblp.a
+
+OBJECTS = Syscalls.o \
+ Sys_malloc.o \
+ addlist.o \
+ addstring.o \
+ appendlist.o \
+ alerts.o \
+ charset.o \
+ cs_strcmp.o \
+ cs_strncmp.o \
+ dellist.o \
+ dashos.o \
+ dirs.o \
+ duplist.o \
+ files.o \
+ freelist.o \
+ getlist.o \
+ getname.o \
+ getpaths.o \
+ getspooldir.o \
+ isterminfo.o \
+ joinlist.o \
+ lenlist.o \
+ lp_errno.o \
+ makepath.o \
+ makestr.o \
+ mergelist.o \
+ next.o \
+ printlist.o \
+ sdn.o \
+ sprintlist.o \
+ searchlist.o \
+ set_charset.o \
+ set_pitch.o \
+ set_size.o \
+ sop.o \
+ strip.o \
+ syntax.o \
+ tidbit.o \
+ tx.o \
+ wherelist.o \
+ which.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master) $(C_PICFLAGS)
+
+POFILE = lp_lib_lp.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llp.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+# lint does not take $(C_PICFLAGS)
+LINT_CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+lint: lintlib
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) -o lp llib-llp
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/lp/Sys_malloc.c b/usr/src/cmd/lp/lib/lp/Sys_malloc.c
new file mode 100644
index 0000000000..1a6364f0da
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/Sys_malloc.c
@@ -0,0 +1,189 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.14 */
+/* LINTLIBRARY */
+
+#include "unistd.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "errno.h"
+#include "fcntl.h"
+#include "stdlib.h"
+#include "string.h"
+
+/**
+ ** _Malloc()
+ ** _Realloc()
+ ** _Calloc()
+ ** _Strdup()
+ ** _Free()
+ **/
+
+#if !defined(TRACE_MALLOC)
+
+#if defined(__STDC__)
+void (*lp_alloc_fail_handler)( void ) = 0;
+#else
+void (*lp_alloc_fail_handler)() = 0;
+#endif
+
+#if defined(__STDC__)
+typedef void *alloc_type;
+#else
+typedef char *alloc_type;
+#endif
+
+alloc_type
+#if defined(__STDC__)
+_Malloc (
+ size_t size,
+ const char * file,
+ int line
+)
+#else
+_Malloc (size, file, line)
+ size_t size;
+ char * file;
+ int line;
+#endif
+{
+ alloc_type ret = malloc(size);
+
+ if (!ret) {
+ if (lp_alloc_fail_handler)
+ (*lp_alloc_fail_handler)();
+ errno = ENOMEM;
+ }
+ return (ret);
+}
+
+alloc_type
+#if defined(__STDC__)
+_Realloc (
+ void * ptr,
+ size_t size,
+ const char * file,
+ int line
+)
+#else
+_Realloc (ptr, size, file, line)
+ char * ptr;
+ size_t size;
+ char * file;
+ int line;
+#endif
+{
+ alloc_type ret = realloc(ptr, size);
+
+ if (!ret) {
+ if (lp_alloc_fail_handler)
+ (*lp_alloc_fail_handler)();
+ errno = ENOMEM;
+ }
+ return (ret);
+}
+
+alloc_type
+#if defined(__STDC__)
+_Calloc (
+ size_t nelem,
+ size_t elsize,
+ const char * file,
+ int line
+)
+#else
+_Calloc (nelem, elsize, file, line)
+ size_t nelem;
+ size_t elsize;
+ char * file;
+ int line;
+#endif
+{
+ alloc_type ret = calloc(nelem, elsize);
+
+ if (!ret) {
+ if (lp_alloc_fail_handler)
+ (*lp_alloc_fail_handler)();
+ errno = ENOMEM;
+ }
+ return (ret);
+}
+
+char *
+#if defined(__STDC__)
+_Strdup (
+ const char * s,
+ const char * file,
+ int line
+)
+#else
+_Strdup (s, file, line)
+ char * s;
+ char * file;
+ int line;
+#endif
+{
+ char * ret;
+
+ if (!s)
+ return( (char *) 0);
+
+ ret = strdup(s);
+
+ if (!ret) {
+ if (lp_alloc_fail_handler)
+ (*lp_alloc_fail_handler)();
+ errno = ENOMEM;
+ }
+ return (ret);
+}
+
+void
+#if defined(__STDC__)
+_Free (
+ void * ptr,
+ const char * file,
+ int line
+)
+#else
+_Free (ptr, file, line)
+ char * ptr;
+ char * file;
+ int line;
+#endif
+{
+ free (ptr);
+ return;
+}
+
+#else
+# include "mdl.c"
+#endif
diff --git a/usr/src/cmd/lp/lib/lp/Syscalls.c b/usr/src/cmd/lp/lib/lp/Syscalls.c
new file mode 100644
index 0000000000..aeb73eb785
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/Syscalls.c
@@ -0,0 +1,425 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.14 */
+/* LINTLIBRARY */
+
+#include "unistd.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "errno.h"
+#include "fcntl.h"
+#include "stdlib.h"
+#include "string.h"
+
+/**
+ ** Auto-restarting system calls:
+ **/
+
+int
+#if defined(__STDC__)
+_Access (
+ char * s,
+ int i
+)
+#else
+_Access (s, i)
+ char * s;
+ int i;
+#endif
+{
+ register int n;
+
+ while ((n = access(s, i)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Chdir (
+ char * s
+)
+#else
+_Chdir (s)
+ char * s;
+#endif
+{
+ register int n;
+
+ while ((n = chdir(s)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Chmod (
+ char * s,
+ int i
+)
+#else
+_Chmod (s, i)
+ char * s;
+ int i;
+#endif
+{
+ register int n;
+
+ while ((n = chmod(s, i)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Chown (
+ char * s,
+ int i,
+ int j
+)
+#else
+_Chown (s, i, j)
+ char * s;
+ int i;
+ int j;
+#endif
+{
+ register int n;
+
+ while ((n = chown(s, i, j)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Close (
+ int i
+)
+#else
+_Close (i)
+ int i;
+#endif
+{
+ register int n;
+
+ while ((n = close(i)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Creat (
+ char * s,
+ int i
+)
+#else
+_Creat (s, i)
+ char * s;
+ int i;
+#endif
+{
+ register int n;
+
+ while ((n = creat(s, i)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Fcntl (
+ int i,
+ int j,
+ struct flock * k
+)
+#else
+_Fcntl (i, j, k)
+ int i;
+ int j;
+ struct flock * k;
+#endif
+{
+ register int n;
+
+ while ((n = fcntl(i, j, k)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Fstat (
+ int i,
+ struct stat * st
+)
+#else
+_Fstat (i, st)
+ int i;
+ struct stat * st;
+#endif
+{
+ register int n;
+
+ while ((n = fstat(i, st)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Link (
+ char * s1,
+ char * s2
+)
+#else
+_Link (s1, s2)
+ char * s1;
+ char * s2;
+#endif
+{
+ register int n;
+
+ while ((n = link(s1, s2)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Lstat (
+ char * s,
+ struct stat * st
+)
+#else
+_Lstat (s, st)
+ char * s;
+ struct stat * st;
+#endif
+{
+ register int n;
+
+ while ((n = lstat(s, st)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Mknod (
+ char * s,
+ int i,
+ int j
+)
+#else
+_Mknod (s, i, j)
+ char * s;
+ int i;
+ int j;
+#endif
+{
+ register int n;
+
+ while ((n = mknod(s, i, j)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Open (
+ char * s,
+ int i,
+ int j
+)
+#else
+_Open (s, i, j)
+ char * s;
+ int i;
+ int j;
+#endif
+{
+ register int n;
+
+ while ((n = open(s, i, j)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Read (
+ int i,
+ char * s,
+ unsigned int j
+)
+#else
+_Read (i, s, j)
+ int i;
+ char * s;
+ unsigned int j;
+#endif
+{
+ register int n;
+
+ while ((n = read(i, s, j)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Readlink (
+ char * s1,
+ char * s2,
+ unsigned int j
+)
+#else
+_Readlink (s1, s2, j)
+ char * s1;
+ char * s2;
+ unsigned int j;
+#endif
+{
+ register int n;
+
+ while ((n = readlink(s1, s2, j)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Rename (
+ char * s1,
+ char * s2
+)
+#else
+_Rename (s1, s2)
+ char * s1;
+ char * s2;
+#endif
+{
+ register int n;
+
+ while ((n = rename(s1, s2)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Stat (
+ char * s,
+ struct stat * st
+)
+#else
+_Stat (s, st)
+ char * s;
+ struct stat * st;
+#endif
+{
+ register int n;
+
+ while ((n = stat(s, st)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Symlink (
+ char * s1,
+ char * s2
+)
+#else
+_Symlink (s1, s2)
+ char * s1;
+ char * s2;
+#endif
+{
+ register int n;
+
+ while ((n = symlink(s1, s2)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Unlink (
+ char * s
+)
+#else
+_Unlink (s)
+ char * s;
+#endif
+{
+ register int n;
+
+ while ((n = unlink(s)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Wait (
+ int * i
+)
+#else
+_Wait (i)
+ int * i;
+#endif
+{
+ register int n;
+
+ while ((n = wait(i)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
+
+int
+#if defined(__STDC__)
+_Write (
+ int i,
+ char * s,
+ unsigned int j
+)
+#else
+_Write (i, s, j)
+ int i;
+ char * s;
+ unsigned int j;
+#endif
+{
+ register int n;
+
+ while ((n = write(i, s, j)) == -1 && errno == EINTR)
+ ;
+ return (n);
+}
diff --git a/usr/src/cmd/lp/lib/lp/addlist.c b/usr/src/cmd/lp/lib/lp/addlist.c
new file mode 100644
index 0000000000..0608b5f914
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/addlist.c
@@ -0,0 +1,92 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** addlist() - ADD ITEM TO (char **) LIST
+ **/
+
+int
+#if defined(__STDC__)
+addlist (
+ char *** plist,
+ char * item
+)
+#else
+addlist (plist, item)
+ register char ***plist,
+ *item;
+#endif
+{
+ register char **pl;
+
+ register int n;
+
+ if (*plist) {
+
+ n = lenlist(*plist);
+
+ for (pl = *plist; *pl; pl++)
+ if (STREQU(*pl, item))
+ break;
+
+ if (!*pl) {
+
+ n++;
+ *plist = (char **)Realloc(
+ (char *)*plist,
+ (n + 1) * sizeof(char *)
+ );
+ if (!*plist) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ (*plist)[n - 1] = Strdup(item);
+ (*plist)[n] = 0;
+
+ }
+
+ } else {
+
+ *plist = (char **)Malloc(2 * sizeof(char *));
+ if (!*plist) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ (*plist)[0] = Strdup(item);
+ (*plist)[1] = 0;
+
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/addstring.c b/usr/src/cmd/lp/lib/lp/addstring.c
new file mode 100644
index 0000000000..ee2900435a
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/addstring.c
@@ -0,0 +1,74 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** addstring() - ADD ONE STRING TO ANOTHER, ALLOCATING SPACE AS NEEDED
+ **/
+
+int
+#if defined(__STDC__)
+addstring (
+ char ** dst,
+ char * src
+)
+#else
+addstring (dst, src)
+ char **dst;
+ char *src;
+#endif
+{
+ size_t len;
+
+ if (!dst || !src) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ len = strlen(src) + 1;
+
+ if (*dst) {
+ if (!(*dst = Realloc(*dst, strlen(*dst) + len))) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ } else {
+ if (!(*dst = Malloc(len))) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ (*dst)[0] = '\0';
+ }
+
+ (void) strcat(*dst, src);
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/alerts.c b/usr/src/cmd/lp/lib/lp/alerts.c
new file mode 100644
index 0000000000..34c8ac1160
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/alerts.c
@@ -0,0 +1,513 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.17 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "limits.h"
+#include "unistd.h"
+
+#include "lp.h"
+
+extern char **environ;
+
+static void envlist(int, char **);
+
+/*
+ * We recognize the following key phrases in the alert prototype
+ * file, and replace them with appropriate values.
+ */
+#define NALRT_KEYS 7
+# define ALRT_ENV 0
+# define ALRT_PWD 1
+# define ALRT_ULIMIT 2
+# define ALRT_UMASK 3
+# define ALRT_INTERVAL 4
+# define ALRT_CMD 5
+# define ALRT_USER 6
+
+static struct {
+ char *v;
+ short len;
+} shell_keys[NALRT_KEYS] = {
+#define ENTRY(X) X, sizeof(X)-1
+ ENTRY("-ENVIRONMENT-"),
+ ENTRY("-PWD-"),
+ ENTRY("-ULIMIT-"),
+ ENTRY("-UMASK-"),
+ ENTRY("-INTERVAL-"),
+ ENTRY("-CMD-"),
+ ENTRY("-USER-"),
+};
+
+/*
+ * These are used to bracket the administrator's command, so that
+ * we can find it easily. We're out of luck if the administrator
+ * includes an identical phrase in his or her command.
+ */
+#define ALRT_CMDSTART "## YOUR COMMAND STARTS HERE -- DON'T TOUCH ABOVE!!"
+#define ALRT_CMDEND "## YOUR COMMAND ENDS HERE -- DON'T TOUCH BELOW!!"
+
+/**
+ ** putalert() - WRITE ALERT TO FILES
+ **/
+
+int
+putalert(char *parent, char *name, FALERT *alertp)
+{
+ char *path,
+ cur_dir[PATH_MAX + 1],
+ buf[BUFSIZ];
+
+ int cur_umask;
+
+ int fdout, fdin;
+
+
+ if (!parent || !*parent || !name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!alertp->shcmd) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(alertp->shcmd, NAME_NONE))
+ return (delalert(parent, name));
+
+ /*
+ * See if the form/printer/print-wheel exists.
+ */
+
+ if (!(path = makepath(parent, name, (char *)0)))
+ return (-1);
+
+ if (Access(path, F_OK) == -1) {
+ if (errno == ENOENT)
+ errno = ENOTDIR; /* not quite, but what else? */
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ /*
+ * First, the shell command file.
+ */
+
+ if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0)))
+ return (-1);
+
+ if ((fdout = open_locked(path, "w", MODE_NOEXEC)) < 0) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ /*
+ * We use a prototype file to build the shell command,
+ * so that the alerts are easily customized. The shell
+ * is expected to handle repeat alerts and failed alerts,
+ * because the Spooler doesn't. Also, the Spooler runs
+ * each alert with the UID and GID of the administrator
+ * who defined the alert. Otherwise, anything goes.
+ */
+
+ if (!Lp_Bin) {
+ getpaths ();
+ if (!Lp_Bin)
+ return (-1);
+ }
+ if (!(path = makepath(Lp_Bin, ALERTPROTOFILE, (char *)0)))
+ return (-1);
+
+ if ((fdin = open_locked(path, "r", 0)) < 0) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ errno = 0;
+ while (fdgets(buf, BUFSIZ, fdin)) {
+ int key;
+ char *cp,
+ *dash;
+
+ cp = buf;
+ while ((dash = strchr(cp, '-'))) {
+
+ *dash = 0;
+ fdputs (cp, fdout);
+ *(cp = dash) = '-';
+
+ for (key = 0; key < NALRT_KEYS; key++)
+ if (STRNEQU(
+ cp,
+ shell_keys[key].v,
+ shell_keys[key].len
+ )) {
+ register char *newline =
+ (cp != buf)? "\n" : "";
+
+ cp += shell_keys[key].len;
+
+ switch (key) {
+
+ case ALRT_ENV:
+ fdprintf(fdout, newline);
+ envlist(fdout, environ);
+ break;
+
+ case ALRT_PWD:
+ getcwd (cur_dir, PATH_MAX);
+ fdprintf (fdout, "%s", cur_dir);
+ break;
+
+ case ALRT_ULIMIT:
+ fdprintf (fdout, "%ld", ulimit(1, (long)0));
+ break;
+
+ case ALRT_UMASK:
+ umask (cur_umask = umask(0));
+ fdprintf (fdout, "%03o", cur_umask);
+ break;
+
+ case ALRT_INTERVAL:
+ fdprintf(fdout, "%ld", (long)alertp->W);
+ break;
+
+ case ALRT_CMD:
+ fdprintf(fdout, newline);
+ fdprintf(fdout, "%s\n", ALRT_CMDSTART);
+ fdprintf(fdout, "%s\n", alertp->shcmd);
+ fdprintf(fdout, "%s\n", ALRT_CMDEND);
+ break;
+
+ case ALRT_USER:
+ fdprintf(fdout, "%s", getname());
+ break;
+
+ }
+
+ break;
+ }
+ if (key >= NALRT_KEYS)
+ fdputc(*cp++, fdout);
+
+ }
+ fdputs(cp, fdout);
+
+ }
+ if (errno != 0) {
+ int save_errno = errno;
+
+ close(fdin);
+ close(fdout);
+ errno = save_errno;
+ return (-1);
+ }
+ close(fdin);
+ close(fdout);
+
+ /*
+ * Next, the variables file.
+ */
+
+ if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0)))
+ return (-1);
+
+ if ((fdout = open_locked(path, "w", MODE_NOREAD)) < 0) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ fdprintf(fdout, "%d\n", alertp->Q > 0? alertp->Q : 1);
+ fdprintf(fdout, "%d\n", alertp->W >= 0? alertp->W : 0);
+
+ close(fdout);
+
+ return (0);
+}
+
+/**
+ ** getalert() - EXTRACT ALERT FROM FILES
+ **/
+
+FALERT *
+getalert(char *parent, char *name)
+{
+ int fd;
+ char *tmp;
+ static FALERT alert;
+ register char *path;
+ char buf[BUFSIZ];
+ int len;
+
+ if (!parent || !*parent || !name || !*name) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ /*
+ * See if the form/printer/print-wheel exists.
+ */
+
+ if (!(path = makepath(parent, name, (char *)0)))
+ return (0);
+
+ if (Access(path, F_OK) == -1) {
+ if (errno == ENOENT)
+ errno = ENOTDIR; /* not quite, but what else? */
+ Free (path);
+ return (0);
+ }
+ Free (path);
+
+ /*
+ * First, the shell command file.
+ */
+
+ if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0)))
+ return (0);
+
+ if ((fd = open_locked(path, "r", 0)) < 0) {
+ Free (path);
+ return (0);
+ }
+ Free (path);
+
+ /*
+ * Skip over environment setting stuff, while loop, etc.,
+ * to find the beginning of the command.
+ */
+ errno = 0;
+ while ((tmp = fdgets(buf, BUFSIZ, fd)) &&
+ !STRNEQU(buf, ALRT_CMDSTART, sizeof(ALRT_CMDSTART)-1))
+ ;
+ if ((tmp == NULL) || (errno != 0)) {
+ int save_errno = errno;
+
+ close(fd);
+ errno = save_errno;
+ return (0);
+ }
+
+ alert.shcmd = sop_up_rest(fd, ALRT_CMDEND);
+
+ close(fd);
+
+ if (!alert.shcmd)
+ return (0);
+
+ /*
+ * Drop terminating newline.
+ */
+ if (alert.shcmd[(len = strlen(alert.shcmd)) - 1] == '\n')
+ alert.shcmd[len - 1] = 0;
+
+
+ /*
+ * Next, the variables file.
+ */
+
+ if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0)))
+ return (0);
+
+ if ((fd = open_locked(path, "r", 0)) < 0) {
+ Free (path);
+ return (0);
+ }
+ Free (path);
+
+ errno = 0;
+ (void)fdgets (buf, BUFSIZ, fd);
+ if (errno != 0) {
+ int save_errno = errno;
+
+ close(fd);
+ errno = save_errno;
+ return (0);
+ }
+ alert.Q = atoi(buf);
+
+ (void)fdgets (buf, BUFSIZ, fd);
+ if (errno != 0) {
+ int save_errno = errno;
+
+ close(fd);
+ errno = save_errno;
+ return (0);
+ }
+ alert.W = atoi(buf);
+
+ close(fd);
+
+ return (&alert);
+}
+
+/**
+ ** delalert() - DELETE ALERT FILES
+ **/
+
+int
+delalert(char *parent, char *name)
+{
+ char *path;
+
+
+ if (!parent || !*parent || !name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * See if the form/printer/print-wheel exists.
+ */
+
+ if (!(path = makepath(parent, name, (char *)0)))
+ return (-1);
+
+ if (Access(path, F_OK) == -1) {
+ if (errno == ENOENT)
+ errno = ENOTDIR; /* not quite, but what else? */
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ /*
+ * Remove the two files.
+ */
+
+ if (!(path = makepath(parent, name, ALERTSHFILE, (char *)0)))
+ return (-1);
+ if (rmfile(path) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ if (!(path = makepath(parent, name, ALERTVARSFILE, (char *)0)))
+ return (-1);
+ if (rmfile(path) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ return (0);
+}
+
+/**
+ ** envlist() - PRINT OUT ENVIRONMENT LIST SAFELY
+ **/
+
+static void
+envlist(int fd, char **list)
+{
+ register char *env,
+ *value;
+
+ if (!list || !*list)
+ return;
+
+ while ((env = *list++)) {
+ if (!(value = strchr(env, '=')))
+ continue;
+ *value++ = 0;
+ if (!strchr(value, '\''))
+ fdprintf(fd, (char *)gettext("export %s; %s='%s'\n"),
+ env, env, value);
+ *--value = '=';
+ }
+}
+
+/*
+ * printalert() - PRINT ALERT DESCRIPTION
+ *
+ * This is not used in the scheduler, so we don't need to switch to using
+ * file descriptors for scalability.
+ */
+
+void
+printalert(FILE *fp, FALERT *alertp, int isfault)
+{
+ if (!alertp->shcmd) {
+ if (isfault)
+ (void)fprintf (fp, (char *)gettext("On fault: no alert\n"));
+ else
+ (void)fprintf (fp, (char *)gettext("No alert\n"));
+
+ } else {
+ register char *copy = Strdup(alertp->shcmd),
+ *cp;
+
+ if (isfault)
+ (void)fprintf (fp, (char *)gettext("On fault: "));
+ else
+ if (alertp->Q > 1)
+ (void)fprintf (
+ fp,
+ (char *)gettext("When %d are queued: "),
+ alertp->Q
+ );
+ else
+ (void)fprintf (fp, (char *)gettext("Upon any being queued: "));
+
+ if (copy && (cp = strchr(copy, ' ')))
+ while (*cp == ' ')
+ *cp++ = 0;
+
+ if (
+ copy
+ && syn_name(cp)
+ && (
+ STREQU(copy, NAME_WRITE)
+ || STREQU(copy, NAME_MAIL)
+ )
+ )
+ (void)fprintf (fp, "%s to %s ", copy, cp);
+ else
+ (void)fprintf (fp, (char *)gettext("alert with \"%s\" "), alertp->shcmd);
+
+ if (alertp->W > 0)
+ (void)fprintf (fp, (char *)gettext("every %d minutes\n"), alertp->W);
+ else
+ (void)fprintf (fp, (char *)gettext("once\n"));
+
+ Free (copy);
+ }
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/lp/appendlist.c b/usr/src/cmd/lp/lib/lp/appendlist.c
new file mode 100644
index 0000000000..3c936ad70a
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/appendlist.c
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** appendlist() - ADD ITEM TO (char **) LIST
+ **/
+
+int
+#if defined(__STDC__)
+appendlist (
+ char *** plist,
+ char * item
+)
+#else
+appendlist (plist, item)
+ register char ***plist,
+ *item;
+#endif
+{
+ register int n;
+
+ if (*plist) {
+
+ n = lenlist(*plist);
+
+ n++;
+ *plist = (char **)Realloc(
+ (char *)*plist,
+ (n + 1) * sizeof(char *)
+ );
+ if (!*plist) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ (*plist)[n - 1] = Strdup(item);
+ (*plist)[n] = 0;
+
+ } else {
+
+ *plist = (char **)Malloc(2 * sizeof(char *));
+ if (!*plist) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ (*plist)[0] = Strdup(item);
+ (*plist)[1] = 0;
+
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/charset.c b/usr/src/cmd/lp/lib/lp/charset.c
new file mode 100644
index 0000000000..60633ce1cb
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/charset.c
@@ -0,0 +1,69 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+
+#include "lp.h"
+
+/**
+ ** search_cslist() - SEARCH CHARACTER SET ALIASES FOR CHARACTER SET
+ **/
+
+char *
+#if defined(__STDC__)
+search_cslist (
+ char * item,
+ char ** list
+)
+#else
+search_cslist (item, list)
+ register char *item;
+ register char **list;
+#endif
+{
+ register char *alias;
+
+
+ if (!list || !*list)
+ return (0);
+
+ else if (STREQU(item, NAME_ANY))
+ return (item);
+
+ /*
+ * This is a linear search--we believe that the lists
+ * will be short.
+ */
+ while (*list) {
+ alias = strchr(*list, '=');
+ if (alias && STREQU(alias+1, item))
+ return (*list);
+ list++;
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/cs_strcmp.c b/usr/src/cmd/lp/lib/lp/cs_strcmp.c
new file mode 100644
index 0000000000..842859b8b3
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/cs_strcmp.c
@@ -0,0 +1,53 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "ctype.h"
+
+/*
+ * Compare strings ignoring case: s1>s2: >0 s1==s2: 0 s1<s2: <0
+ */
+
+int
+#if defined(__STDC__)
+cs_strcmp(
+ char * s1,
+ char * s2
+)
+#else
+cs_strcmp(s1, s2)
+register char *s1, *s2;
+#endif
+{
+
+ if(s1 == s2)
+ return(0);
+ while(toupper(*s1) == toupper(*s2++))
+ if(*s1++ == '\0')
+ return(0);
+ return(toupper(*s1) - toupper(*--s2));
+}
diff --git a/usr/src/cmd/lp/lib/lp/cs_strncmp.c b/usr/src/cmd/lp/lib/lp/cs_strncmp.c
new file mode 100644
index 0000000000..516e402a7c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/cs_strncmp.c
@@ -0,0 +1,55 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "ctype.h"
+
+/*
+ * Compare strings (at most n bytes) ignoring case
+ * returns: s1>s2; >0 s1==s2; 0 s1<s2; <0
+ */
+
+int
+#if defined(__STDC__)
+cs_strncmp(
+ char * s1,
+ char * s2,
+ int n
+)
+#else
+cs_strncmp(s1, s2, n)
+register char *s1, *s2;
+register n;
+#endif
+{
+ if(s1 == s2)
+ return(0);
+ while(--n >= 0 && toupper(*s1) == toupper(*s2++))
+ if(*s1++ == '\0')
+ return(0);
+ return((n < 0)? 0: (toupper(*s1) - toupper(*--s2)));
+}
diff --git a/usr/src/cmd/lp/lib/lp/dashos.c b/usr/src/cmd/lp/lib/lp/dashos.c
new file mode 100644
index 0000000000..482d7e0395
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/dashos.c
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1990 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+
+#include "lp.h"
+
+#define issep(X) strchr(LP_WS, X)
+
+/**
+ ** dashos() - PARSE -o OPTIONS, (char *) --> (char **)
+ **/
+
+char **
+#if defined(__STDC__)
+dashos (
+ char * o
+)
+#else
+dashos (o)
+ register char *o;
+#endif
+{
+ register char quote,
+ c,
+ *option;
+
+ char **list = 0;
+
+ if (!o)
+ return(0);
+
+ while (*o) {
+
+ while (*o && issep(*o))
+ o++;
+
+ for (option = o; *o && !issep(*o); o++)
+ if (strchr(LP_QUOTES, (quote = *o)))
+ for (o++; *o && *o != quote; o++)
+ if (*o == '\\' && o[1])
+ o++;
+
+ if (option < o) {
+ c = *o;
+ *o = 0;
+ addlist (&list, option);
+ *o = c;
+ }
+
+ }
+ return (list);
+}
diff --git a/usr/src/cmd/lp/lib/lp/dellist.c b/usr/src/cmd/lp/lib/lp/dellist.c
new file mode 100644
index 0000000000..6840cdc8e6
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/dellist.c
@@ -0,0 +1,85 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** dellist() - REMOVE ITEM FROM (char **) LIST
+ **/
+
+int
+#if defined(__STDC__)
+dellist (
+ char *** plist,
+ char * item
+)
+#else
+dellist (plist, item)
+ register char ***plist,
+ *item;
+#endif
+{
+ register char **pl;
+
+ register int n;
+
+ if (*plist) {
+
+ n = lenlist(*plist);
+
+ for (pl = *plist; *pl; pl++)
+ if (STREQU(*pl, item))
+ break;
+
+ if (*pl) {
+ Free (*pl);
+ for (; *pl; pl++)
+ *pl = *(pl+1);
+ if (--n == 0) {
+ Free ((char *)*plist);
+ *plist = 0;
+ } else {
+ *plist = (char **)Realloc(
+ (char *)*plist,
+ (n + 1) * sizeof(char *)
+ );
+ if (!*plist) {
+ errno = ENOMEM;
+ return (-1);
+ }
+/* (*plist)[n] = 0; */ /* done in "for" loop */
+ }
+ }
+
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/dirs.c b/usr/src/cmd/lp/lib/lp/dirs.c
new file mode 100644
index 0000000000..16e7efb6a1
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/dirs.c
@@ -0,0 +1,63 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "errno.h"
+
+#include "lp.h"
+
+/**
+ ** mkdir_lpdir()
+ **/
+
+int
+#if defined(__STDC__)
+mkdir_lpdir (
+ char * path,
+ int mode
+)
+#else
+mkdir_lpdir (path, mode)
+ char *path;
+ int mode;
+#endif
+{
+ int old_umask = umask(0);
+ int ret;
+ int save_errno;
+
+
+ ret = Mkdir(path, mode);
+ if (ret != -1)
+ ret = chown_lppath(path);
+ save_errno = errno;
+ if (old_umask)
+ umask (old_umask);
+ errno = save_errno;
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/lp/duplist.c b/usr/src/cmd/lp/lib/lp/duplist.c
new file mode 100644
index 0000000000..b2419fd731
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/duplist.c
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** duplist() - DUPLICATE A LIST OF STRINGS
+ **/
+
+char **
+#if defined(__STDC__)
+duplist (
+ char ** src
+)
+#else
+duplist (src)
+ register char **src;
+#endif
+{
+ register char **dst;
+
+ register int nitems,
+ n;
+
+ if (!src || !*src)
+ return (0);
+
+ nitems = lenlist(src);
+ if (!(dst = (char **)Malloc((nitems + 1) * sizeof(char *)))) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+ for (n = 0; n < nitems; n++)
+ if (!(dst[n] = Strdup(src[n]))) {
+ while (n--)
+ Free (dst[n]);
+ Free ((char *)dst);
+ errno = ENOMEM;
+ return (0);
+ }
+ dst[nitems] = 0;
+
+ return (dst);
+}
+
diff --git a/usr/src/cmd/lp/lib/lp/files.c b/usr/src/cmd/lp/lib/lp/files.c
new file mode 100644
index 0000000000..d85484f547
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/files.c
@@ -0,0 +1,332 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "fcntl.h"
+#include "string.h"
+#include "errno.h"
+#include "pwd.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "stdlib.h"
+#include <stdarg.h>
+#include <unistd.h>
+#include "pwd.h"
+
+#include "lp.h"
+
+int
+is_printer_uri(char *value)
+{
+ if (value == NULL)
+ return (-1);
+
+ if ((value[0] == '/') && (access(value, F_OK) == 0))
+ return (-1); /* a valid path */
+
+ if (strstr(value, "://") == NULL)
+ return (-1); /* not in uri form */
+
+ return (0);
+}
+
+/*
+ * To avoid a race condition, chown() should always be called before
+ * chmod().
+ */
+int
+chownmod(char *path, uid_t owner, gid_t group, mode_t mode)
+{
+ int rc;
+
+ if ((rc = Chown(path, owner, group)) == 0)
+ rc = Chmod(path, mode);
+
+ return (rc);
+}
+
+
+int
+fdprintf(int fd, char *fmt, ...)
+{
+ char buf[BUFSIZ];
+ va_list ap;
+
+ if (fd == 1)
+ fflush(stdout);
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof (buf), fmt, ap);
+ va_end(ap);
+ return (Write(fd, buf, (int)strlen(buf)));
+}
+
+char *
+fdgets(char *buf, int len, int fd)
+{
+ char tmp;
+ int count = 0;
+
+ memset(buf, NULL, len);
+ while ((count < len) && (Read(fd, &tmp, 1) > 0))
+ if ((buf[count++] = tmp) == '\n') break;
+
+ if (count != 0)
+ return (buf);
+ return (NULL);
+}
+
+int
+fdputs(char *buf, int fd)
+{
+ return (fdprintf(fd, "%s", buf));
+}
+
+int
+fdputc(char c, int fd)
+{
+ if (fd == 1)
+ fflush(stdout);
+ return (write(fd, &c, 1));
+}
+
+int
+open_locked(char *path, char *type, mode_t mode)
+{
+ struct flock l;
+ int fd,
+ oflag,
+ create,
+ truncate = 0;
+
+ if (!path || !type) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+#define plus (type[1] == '+')
+ switch (type[0]) {
+ case 'w':
+ oflag = plus? O_RDWR : O_WRONLY;
+ create = 1;
+ truncate = 1;
+ break;
+ case 'a':
+ oflag = (plus? O_RDWR : O_WRONLY) | O_APPEND;
+ create = 1;
+ break;
+ case 'r':
+ oflag = plus? O_RDWR : O_RDONLY;
+ create = 0;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((fd = Open(path, oflag, mode)) == -1)
+ if (errno == ENOENT && create) {
+ int old_umask = umask(0);
+ int save_errno;
+
+ if ((fd = Open(path, oflag|O_CREAT, mode)) != -1)
+ chown_lppath(path);
+ save_errno = errno;
+ if (old_umask)
+ umask(old_umask);
+ errno = save_errno;
+ }
+
+ if (fd == -1)
+ switch (errno) {
+ case ENOTDIR:
+ errno = EACCES;
+ /* FALLTHROUGH */
+ default:
+ return (-1);
+ }
+
+ l.l_type = (oflag & (O_WRONLY|O_RDWR)? F_WRLCK : F_RDLCK);
+ l.l_whence = 1;
+ l.l_start = 0;
+ l.l_len = 0;
+ if (Fcntl(fd, F_SETLK, &l) == -1) {
+ /*
+ * Early UNIX op. sys. have wrong errno.
+ */
+ if (errno == EACCES)
+ errno = EAGAIN;
+ Close(fd);
+ return (-1);
+ }
+
+ if (truncate) {
+ if ((lseek(fd, 0, SEEK_SET) == (off_t)-1) ||
+ (ftruncate(fd, 0) == -1)) {
+ Close(fd);
+ return (-1);
+ }
+ }
+
+ return (fd);
+}
+
+
+FILE *
+open_lpfile(char *path, char *type, mode_t mode)
+{
+ FILE *fp = NULL;
+ int fd;
+
+ if ((fd = open_locked(path, type, mode)) >= 0) {
+ errno = 0; /* fdopen() may fail and not set errno */
+ if (!(fp = fdopen(fd, type))) {
+ Close(fd);
+ }
+ }
+ return (fp);
+}
+int
+close_lpfile(FILE *fp)
+{
+ return (fclose(fp));
+}
+
+/*
+ * chown_lppath()
+ */
+
+int
+chown_lppath(char *path)
+{
+ static uid_t lp_uid;
+
+ static gid_t lp_gid;
+
+ static int gotids = 0;
+
+ struct passwd *ppw;
+
+
+ if (!gotids) {
+ if (!(ppw = getpwnam(LPUSER)))
+ ppw = getpwnam(ROOTUSER);
+ endpwent();
+ if (!ppw)
+ return (-1);
+ lp_uid = ppw->pw_uid;
+ lp_gid = ppw->pw_gid;
+ gotids = 1;
+ }
+ return (Chown(path, lp_uid, lp_gid));
+}
+
+/*
+ * rmfile() - UNLINK FILE BUT NO COMPLAINT IF NOT THERE
+ */
+
+int
+rmfile(char *path)
+{
+ return (Unlink(path) == 0 || errno == ENOENT);
+}
+
+/*
+ * loadline() - LOAD A ONE-LINE CHARACTER STRING FROM FILE
+ */
+
+char *
+loadline(char *path)
+{
+ int fd;
+ register char *ret;
+ register int len;
+ char buf[BUFSIZ];
+
+ if ((fd = open_locked(path, "r", MODE_READ)) < 0)
+ return (0);
+
+ if (fdgets(buf, BUFSIZ, fd)) {
+ if ((len = strlen(buf)) && buf[len - 1] == '\n')
+ buf[--len] = 0;
+ if ((ret = Malloc(len + 1)))
+ strcpy(ret, buf);
+ } else {
+ errno = 0;
+ ret = 0;
+ }
+
+ close(fd);
+ return (ret);
+}
+
+/*
+ * loadstring() - LOAD A CHARACTER STRING FROM FILE
+ */
+
+char *
+loadstring(char *path)
+{
+ int fd;
+ register char *ret;
+ register int len;
+
+ if ((fd = open_locked(path, "r", MODE_READ)) < 0)
+ return (0);
+
+ if ((ret = sop_up_rest(fd, (char *)0))) {
+ if ((len = strlen(ret)) && ret[len - 1] == '\n')
+ ret[len - 1] = 0;
+ } else
+ errno = 0;
+
+ close(fd);
+ return (ret);
+}
+
+/*
+ * dumpstring() - DUMP CHARACTER STRING TO FILE
+ */
+
+int
+dumpstring(char *path, char *str)
+{
+ int fd;
+
+ if (!str)
+ return (rmfile(path));
+
+ if ((fd = open_locked(path, "w", MODE_READ)) < 0)
+ return (-1);
+ fdprintf(fd, "%s\n", str);
+ close(fd);
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/freelist.c b/usr/src/cmd/lp/lib/lp/freelist.c
new file mode 100644
index 0000000000..e8d4d6a803
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/freelist.c
@@ -0,0 +1,56 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** freelist() - FREE ALL SPACE USED BY LIST
+ **/
+
+void
+#if defined(__STDC__)
+freelist (
+ char ** list
+)
+#else
+freelist (list)
+ char **list;
+#endif
+{
+ register char **pp;
+
+ if (list) {
+ for (pp = list; *pp; pp++)
+ Free (*pp);
+ Free ((char *)list);
+ }
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/lp/getlist.c b/usr/src/cmd/lp/lib/lp/getlist.c
new file mode 100644
index 0000000000..f64e7a4a1d
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/getlist.c
@@ -0,0 +1,209 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+#if defined(__STDC__)
+static char *unq_strdup ( char * , char * );
+#else
+static char *unq_strdup();
+#endif
+
+/**
+ ** getlist() - CONSTRUCT LIST FROM STRING
+ **/
+
+/*
+ * Any number of characters from "ws", or a single
+ * character from "hardsep", can separate items in the list.
+ */
+
+char **
+#if defined(__STDC__)
+getlist (
+ char * str,
+ char * ws,
+ char * hardsep
+)
+#else
+getlist (str, ws, hardsep)
+ register char *str,
+ *ws;
+ char *hardsep;
+#endif
+{
+ register char **list,
+ *p,
+ *sep,
+ c;
+
+ int n,
+ len;
+
+ char buf[10];
+
+
+ if (!str || !*str)
+ return (0);
+
+ /*
+ * Construct in "sep" the full list of characters that
+ * can separate items in the list. Avoid a "malloc()"
+ * if possible.
+ */
+ len = strlen(ws) + strlen(hardsep) + 1;
+ if (len > sizeof(buf)) {
+ if (!(sep = Malloc(len))) {
+ errno = ENOMEM;
+ return (0);
+ }
+ } else
+ sep = buf;
+ strcpy (sep, hardsep);
+ strcat (sep, ws);
+
+ /*
+ * Skip leading white-space.
+ */
+ str += strspn(str, ws);
+ if (!*str)
+ return (0);
+
+ /*
+ * Strip trailing white-space.
+ */
+ p = strchr(str, '\0');
+ while (--p != str && strchr(ws, *p))
+ ;
+ *++p = 0;
+
+ /*
+ * Pass 1: Count the number of items in the list.
+ */
+ for (n = 0, p = str; *p; ) {
+ if ((c = *p++) == '\\')
+ p++;
+ else
+ if (strchr(sep, c)) {
+ n++;
+ p += strspn(p, ws);
+ if (
+ !strchr(hardsep, c)
+ && strchr(hardsep, *p)
+ ) {
+ p++;
+ p += strspn(p, ws);
+ }
+ }
+ }
+
+ /*
+ * Pass 2: Create the list.
+ */
+
+ /*
+ * Pass 1 counted the number of list separaters, so
+ * add 2 to the count (includes 1 for terminating null).
+ */
+ if (!(list = (char **)Malloc((n+2) * sizeof(char *)))) {
+ errno = ENOMEM;
+ goto Done;
+ }
+
+ /*
+ * This loop will copy all but the last item.
+ */
+ for (n = 0, p = str; *p; )
+ if ((c = *p++) == '\\')
+ p++;
+ else
+ if (strchr(sep, c)) {
+
+ p[-1] = 0;
+ list[n++] = unq_strdup(str, sep);
+ p[-1] = c;
+
+ p += strspn(p, ws);
+ if (
+ !strchr(hardsep, c)
+ && strchr(hardsep, *p)
+ ) {
+ p++;
+ p += strspn(p, ws);
+ }
+ str = p;
+
+ }
+
+ list[n++] = unq_strdup(str, sep);
+
+ list[n] = 0;
+
+Done: if (sep != buf)
+ Free (sep);
+ return (list);
+}
+
+/**
+ ** unq_strdup()
+ **/
+
+static char *
+#if defined(__STDC__)
+unq_strdup (
+ char * str,
+ char * sep
+)
+#else
+unq_strdup (str, sep)
+ char *str,
+ *sep;
+#endif
+{
+ register int len = 0;
+
+ register char *p,
+ *q,
+ *ret;
+
+
+ for (p = str; *p; p++)
+ if (*p != '\\' || !p[1] || !strchr(sep, p[1]))
+ len++;
+ if (!(q = ret = Malloc(len + 1)))
+ return (0);
+ for (p = str; *p; p++)
+ if (*p != '\\' || !p[1] || !strchr(sep, p[1]))
+ *q++ = *p;
+ *q = 0;
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/lp/getname.c b/usr/src/cmd/lp/lib/lp/getname.c
new file mode 100644
index 0000000000..ecda8a5b89
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/getname.c
@@ -0,0 +1,106 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * getname(name) -- get logname
+ *
+ * getname tries to find the user's logname from:
+ * ${LOGNAME}, if set and if it is telling the truth
+ * /etc/passwd, otherwise
+ *
+ * The logname is returned as the value of the function.
+ *
+ * Getname returns the user's user id converted to ASCII
+ * for unknown lognames.
+ *
+ */
+
+#include "string.h"
+#include "pwd.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+#include "unistd.h"
+
+#include "lp.h"
+
+char *
+#if defined(__STDC__)
+getname (
+ void
+)
+#else
+getname ()
+#endif
+{
+ uid_t uid;
+ struct passwd *p;
+ static char *logname = 0;
+ char *l;
+
+ if (logname)
+ return (logname);
+
+ uid = getuid();
+
+ setpwent ();
+ if (
+ !(l = getenv("LOGNAME"))
+ || !(p = getpwnam(l))
+ || p->pw_uid != uid
+ )
+ if ((p = getpwuid(uid)))
+ l = p->pw_name;
+ else
+ l = 0;
+ endpwent ();
+
+ if (l)
+ logname = Strdup(l);
+ else {
+ if (uid > 0) {
+ logname = Malloc(10 + 1);
+ if (logname)
+ sprintf (logname, "%d", uid);
+ }
+ }
+
+ if (!logname)
+ {
+ errno = ENOMEM;
+ }
+ else
+ {
+ errno = 0;
+ }
+
+ return (logname);
+}
diff --git a/usr/src/cmd/lp/lib/lp/getpaths.c b/usr/src/cmd/lp/lib/lp/getpaths.c
new file mode 100644
index 0000000000..f664beaed5
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/getpaths.c
@@ -0,0 +1,161 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* LINTLIBRARY */
+
+#include "stdlib.h"
+
+#include "lp.h"
+
+char Lp_Spooldir[] = SPOOLDIR;
+char Lp_Admins[] = SPOOLDIR "/admins";
+char Lp_FIFO[] = SPOOLDIR "/fifos/FIFO";
+char Lp_Requests[] = SPOOLDIR "/requests";
+char Lp_Schedlock[] = SPOOLDIR "/SCHEDLOCK";
+char Lp_System[] = SPOOLDIR "/system";
+char Lp_Temp[] = SPOOLDIR "/temp";
+char Lp_Tmp[] = SPOOLDIR "/tmp";
+
+char Lp_Bin[] = LPDIR "/bin";
+char Lp_Model[] = LPDIR "/model";
+char Lp_Slow_Filter[] = LPDIR "/bin/slow.filter";
+
+char Lp_A_Logs[] = LOGDIR;
+char Lp_Logs[] = LOGDIR;
+char Lp_ReqLog[] = LOGDIR "/requests";
+
+char Lp_A[] = ETCDIR;
+char Lp_Users[] = ETCDIR "/users";
+char Lp_A_Classes[] = ETCDIR "/classes";
+char Lp_A_Forms[] = ETCDIR "/forms";
+char Lp_A_Interfaces[] = ETCDIR "/interfaces";
+char Lp_A_Printers[] = ETCDIR "/printers";
+char Lp_A_PrintWheels[] = ETCDIR "/pwheels";
+char Lp_A_Systems[] = ETCDIR "/systems";
+char Lp_A_Filters[] = ETCDIR "/filter.table";
+char Lp_Default[] = ETCDIR "/default";
+char Lp_A_Faults[] = ETCDIR "/alerts";
+
+/*
+** Sorry about these nonfunctional functions. The data is
+** static now. These exist for historical reasons.
+*/
+
+#undef getpaths
+#undef getadminpaths
+
+void getpaths ( void ) { return; }
+void getadminpaths ( char * admin) { return; }
+
+/**
+ ** getprinterfile() - BUILD NAME OF PRINTER FILE
+ **/
+
+char *
+getprinterfile(char *name, char *component)
+{
+ char *path;
+
+ if (!name)
+ return (0);
+
+ path = makepath(Lp_A_Printers, name, component, NULL);
+
+ return (path);
+}
+
+/**
+ ** getsystemfile() - BUILD NAME OF SYSTEM FILE
+ **/
+
+char *
+getsystemfile(char *name, char *component)
+{
+ char *path;
+
+ if (!name)
+ return (0);
+
+ path = makepath(Lp_A_Systems, name, component, NULL);
+
+ return (path);
+}
+
+/**
+ ** getclassfile() - BUILD NAME OF CLASS FILE
+ **/
+
+char *
+getclassfile(char *name)
+{
+ char *path;
+
+ if (!name)
+ return (0);
+
+ path = makepath(Lp_A_Classes, name, NULL);
+
+ return (path);
+}
+
+/**
+ ** getfilterfile() - BUILD NAME OF FILTER TABLE FILE
+ **/
+
+char *
+getfilterfile(char *table)
+{
+ char *path;
+
+ if (!table)
+ table = FILTERTABLE;
+
+ path = makepath(ETCDIR, table, NULL);
+
+ return (path);
+}
+
+/**
+ ** getformfile() - BUILD NAME OF PRINTER FILE
+ **/
+
+char *
+getformfile(char *name, char *component)
+{
+ char *path;
+
+ if (!name)
+ return (0);
+
+ path = makepath(Lp_A_Forms, name, component, NULL);
+
+ return (path);
+}
diff --git a/usr/src/cmd/lp/lib/lp/getspooldir.c b/usr/src/cmd/lp/lib/lp/getspooldir.c
new file mode 100644
index 0000000000..9b23d9d4a8
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/getspooldir.c
@@ -0,0 +1,41 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "lp.h"
+
+char *
+#if defined(__STDC__)
+getspooldir (
+ void
+)
+#else
+getspooldir ()
+#endif
+{
+ return (Lp_Spooldir);
+}
diff --git a/usr/src/cmd/lp/lib/lp/isterminfo.c b/usr/src/cmd/lp/lib/lp/isterminfo.c
new file mode 100644
index 0000000000..9c3ad91699
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/isterminfo.c
@@ -0,0 +1,225 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include "fcntl.h"
+#include "errno.h"
+#include "string.h"
+#include "unistd.h"
+#include "search.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+#if defined(__STDC__)
+typedef void ** A2;
+typedef int (*A3)(const void *, const void *);
+#else
+typedef char ** A2;
+typedef int (*A3)();
+#endif
+
+/*
+ * Define the following if you want to do a stronger check:
+ * that a type names a valid entry in the Terminfo database.
+ * The stronger check reads the entry and verifies the magic
+ * number in the header. The weaker check is to see if we
+ * have read access to the file. The weaker check will be a
+ * tad faster.
+ */
+/* #define STRONG_CHECK 1 */ /* */
+
+/*
+ * Define the following if you want to cache hits and/or misses.
+ * One reason for NOT caching is to guard against crazies who try
+ * submitting print requests with goofball types, or every valid type
+ * under the sun. Since Terminfo is limited, the hit cache is effectively
+ * limited, so it shouldn't be a problem searching the cache (the search
+ * is binary) but the cache can become big. The miss cache, on the other
+ * hand, could cause a problem. This problem can become severe, so
+ * consider limiting the size of the cache (see below).
+ * Another reason for NOT caching is to pick up changes in the Terminfo
+ * database. The "terminfo" type is not likely to be an oft used feature,
+ * though, so this shouldn't be a big problem.
+ * The reason FOR caching is to limit the number of file system accesses.
+ * This routine is called OFTEN, so limiting the number of open() or
+ * access() calls is a good idea.
+ */
+#define CACHE_HITS 1 /* */
+#define CACHE_MISSES 1 /* */
+
+/*
+ * Define the following if you want to limit the sizes of the caches.
+ */
+#define HIT_CACHE_LIMIT 100 /* */
+#define MISS_CACHE_LIMIT 100 /* */
+
+#if defined(CACHE_HITS)
+static char *hit_cache = 0;
+
+# if defined(HIT_CACHE_LIMIT)
+static int hit_cache_size = 0;
+# endif
+#endif
+
+#if defined(CACHE_MISSES)
+static char *miss_cache = 0;
+
+# if defined(MISS_CACHE_LIMIT)
+static int miss_cache_size = 0;
+# endif
+#endif
+
+#if defined(__STDC__)
+static int _isterminfo ( char * , char * );
+#else
+static int _isterminfo();
+#endif
+
+/**
+ ** isterminfo() - SEE IF TYPE IS IN TERMINFO DATABASE
+ **/
+
+int
+#if defined(__STDC__)
+isterminfo (
+ char * type
+)
+#else
+isterminfo (type)
+ char *type;
+#endif
+{
+ register int ret;
+
+ static char *envTERMINFO = 0;
+
+
+ if (!type || !*type)
+ return (0);
+
+#if defined(CACHE_HITS)
+ if (tfind(type, (A2)&hit_cache, (A3)strcmp))
+ return (1);
+#endif
+
+#if defined(CACHE_MISSES)
+ if (tfind(type, (A2)&miss_cache, (A3)strcmp))
+ return (0);
+#endif
+
+ if (!envTERMINFO)
+ envTERMINFO = getenv("TERMNIFO");
+ if (
+ envTERMINFO
+ && _isterminfo(type, envTERMINFO)
+#if defined(TERMINFO)
+ || _isterminfo(type, TERMINFO)
+#endif
+ ) {
+ ret = 1;
+
+#if defined(CACHE_HITS)
+# if defined(HIT_CACHE_LIMIT)
+ if (hit_cache_size++ < HIT_CACHE_LIMIT)
+# endif
+ (void)tsearch (Strdup(type), (A2)&hit_cache, (A3)strcmp);
+#endif
+
+ } else {
+ ret = 0;
+
+#if defined(CACHE_MISSES)
+# if defined(MISS_CACHE_LIMIT)
+ if (miss_cache_size++ < MISS_CACHE_LIMIT)
+# endif
+ (void)tsearch (Strdup(type), (A2)&miss_cache, (A3)strcmp);
+#endif
+ }
+ return (ret);
+}
+
+/**
+ ** _isterminfo()
+ **/
+
+static int
+#if defined(__STDC__)
+_isterminfo (
+ char * type,
+ char * parent
+)
+#else
+_isterminfo (type, parent)
+ char *type,
+ *parent;
+#endif
+{
+ char *path,
+ type_letter[] = "X";
+
+ int ret;
+
+#if defined(STRONG_CHECK)
+ int fd;
+#endif
+
+
+ type_letter[0] = type[0];
+ if (!(path = makepath(parent, type_letter, type, (char *)0)))
+ return (0);
+
+#if defined(STRONG_CHECK)
+ if (!(fd = Open(path, O_RDONLY))) {
+
+ /*
+ * If we can't open the TERMINFO file because we
+ * don't have any open channels left, let's err on
+ * the side of likelihood--if the file can be
+ * accessed, figure that it's okay.
+ */
+ if (errno == EMFILE && Access(path, R_OK) == 0)
+ ret = 1;
+ else
+ ret = 0;
+
+ } else {
+
+ char buf[2];
+
+ if (Read(fd, buf, 2) == 2 && buf[0] == 26 && buf[1] == 1)
+ ret = 1;
+ else
+ ret = 0;
+
+ Close (fd);
+
+ }
+#else
+ ret = (Access(path, R_OK) == 0);
+#endif
+
+ Free (path);
+
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/lp/joinlist.c b/usr/src/cmd/lp/lib/lp/joinlist.c
new file mode 100644
index 0000000000..516434c126
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/joinlist.c
@@ -0,0 +1,55 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+/* LINTLIBRARY */
+
+#include "lp.h"
+
+/**
+ ** mergelist() - ADD CONTENT OF ONE LIST TO ANOTHER
+ **/
+
+int
+#if defined(__STDC__)
+joinlist (
+ char *** dstlist,
+ char ** srclist
+)
+#else
+joinlist (dstlist, srclist)
+ char *** dstlist;
+ char ** srclist;
+#endif
+{
+ if (!srclist || !*srclist)
+ return (0);
+
+ while (*srclist)
+ if (appendlist(dstlist, *srclist++) == -1)
+ return (-1);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/lenlist.c b/usr/src/cmd/lp/lib/lp/lenlist.c
new file mode 100644
index 0000000000..90f8d6d376
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/lenlist.c
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+/**
+ ** lenlist() - COMPUTE LENGTH OF LIST
+ **/
+
+int
+#if defined(__STDC__)
+lenlist (
+ char ** list
+)
+#else
+lenlist (list)
+ char **list;
+#endif
+{
+ register char ** pl;
+
+ if (!list)
+ return (0);
+ for (pl = list; *pl; pl++)
+ ;
+ return (pl - list);
+}
diff --git a/usr/src/cmd/lp/lib/lp/llib-llp b/usr/src/cmd/lp/lib/lp/llib-llp
new file mode 100644
index 0000000000..b1faa81b20
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/llib-llp
@@ -0,0 +1,173 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "errno.h"
+#include "fcntl.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "stdio.h"
+#include "dirent.h"
+
+typedef struct SCALED {
+ float val; /* value of number, scaled according to "sc" */
+ char sc; /* 'i' inches, 'c' centimeters, ' ' lines/cols */
+} SCALED;
+
+typedef struct FALERT {
+ char * shcmd; /* shell command used to perform the alert */
+ int Q; /* # requests queued to activate alert */
+ int W; /* alert is sent every "W" minutes */
+} FALERT;
+
+extern int open_locked(char *, char *, mode_t);
+extern char *fdgets(char *, int, int);
+extern int fdprintf(int, char *, ...);
+extern int fdputs(char *, int);
+extern int fdputc(char, int);
+
+
+FILE *open_lpfile ( char * , char * , mode_t );
+int close_lpfile ( FILE * );
+int chown_lppath ( char * path );
+int mkdir_lpdir ( char * path , int mode );
+int rmfile ( char * path );
+int dumpstring ( char * path , char * str );
+
+char * loadstring ( char * path );
+char * loadline ( char * path );
+char * sop_up_rest (int, char * endsop );
+
+int addlist ( char *** , char * );
+int addstring ( char ** , char * );
+int appendlist ( char *** , char * );
+int dellist ( char *** , char * );
+int joinlist ( char *** , char ** );
+int lenlist ( char ** );
+int printlist ( FILE * , char ** );
+int fdprintlist(int , char ** );
+int searchlist ( char *, char ** );
+int searchlist_with_terminfo ( char * , char ** );
+
+char ** duplist ( char ** );
+char ** getlist ( char * , char * , char * );
+char ** dashos ( char * );
+char ** wherelist ( char * , char ** );
+
+char * sprintlist ( char ** );
+char * search_cslist ( char * , char ** );
+
+void freelist ( char ** );
+void printlist_setup ( char * , char * , char * , char * );
+void printlist_unsetup ( void );
+
+
+void printsdn ( FILE * , SCALED );
+void fdprintsdn ( int , SCALED );
+void printsdn_setup ( char * , char * , char * );
+void printsdn_unsetup ( void );
+
+SCALED _getsdn ( char * , char ** , int );
+
+char * makepath ( char * , ... );
+char * getspooldir ( void );
+char * getrequestfile ( char * );
+char * getprinterfile ( char * , char * );
+char * getsystemfile ( char * , char * );
+char * getclassfile ( char * );
+char * getfilterfile ( char * );
+char * getformfile ( char * , char * );
+
+int cs_strcmp ( char * , char * );
+int cs_strncmp ( char * , char * , int );
+
+int syn_name ( char * );
+int syn_text ( char * );
+int syn_comment ( char * );
+int syn_machine_name ( char * );
+int syn_option ( char * );
+
+int putalert ( char * , char * , FALERT * );
+int delalert ( char * , char * );
+
+FALERT * getalert ( char * , char * );
+
+void printalert ( FILE * , FALERT * , int );
+
+int tidbit ( char * , char * , ... );
+void untidbit ( char * );
+
+int _Access ( char * , int );
+int _Chdir ( char * );
+int _Chmod ( char * , int );
+int _Chown ( char * , int , int );
+int _Close ( int );
+int _Creat ( char * , int );
+int _Fcntl ( int , int , ... );
+int _Fstat ( int , struct stat * );
+int _Link ( char * , char * );
+int _Lstat ( char * , struct stat * );
+int _Mknod ( char * , int , int );
+int _Mkpipe ( char * , int , int );
+int _Open ( char * , int , ... /* mode_t */ );
+int _Read ( int , char * , unsigned int );
+int _Readlink ( char * , char * , unsigned int );
+int _Rename ( char * , char * );
+int _Symlink ( char * , char * );
+int _Stat ( char * , struct stat * );
+int _Unlink ( char * );
+int _Wait ( int * );
+int _Write ( int , char * , unsigned int );
+
+void * _Malloc ( size_t , const char * , int );
+void * _Realloc ( void * , size_t , const char * , int );
+void * _Calloc ( size_t , size_t , const char * , int );
+char * _Strdup ( const char * , const char * , int );
+void _Free ( void * , const char * , int );
+
+
+int isterminfo ( char * );
+int isprinter ( char * );
+int isrequest ( char * );
+int isnumber ( char * );
+
+char * getname ( void );
+char * makestr ( char * , ... );
+char * strip ( char * );
+
+void sendmail ( char * , char * );
+
+void (*lp_alloc_fail_handler)( void );
+
+char * next_x ( char * , long * , unsigned int );
+
diff --git a/usr/src/cmd/lp/lib/lp/lp_errno.c b/usr/src/cmd/lp/lib/lp/lp_errno.c
new file mode 100644
index 0000000000..0ae21ff312
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/lp_errno.c
@@ -0,0 +1,28 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/* LINTLIBRARY */
+int lp_errno;
diff --git a/usr/src/cmd/lp/lib/lp/makepath.c b/usr/src/cmd/lp/lib/lp/makepath.c
new file mode 100644
index 0000000000..d3ab6d8220
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/makepath.c
@@ -0,0 +1,113 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* LINTLIBRARY */
+
+#if defined(__STDC__)
+#include "stdarg.h"
+#else
+#include "varargs.h"
+#endif
+
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** makepath() - CREATE PATHNAME FROM COMPONENTS
+ **/
+
+/*VARARGS1*/
+char *
+#if defined(__STDC__)
+makepath (
+ char * s,
+ ...
+)
+#else
+makepath (s, va_alist)
+ char * s;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ register char *component,
+ *p,
+ *q;
+
+ register int len;
+
+ char *ret;
+
+
+#if defined(__STDC__)
+ va_start (ap, s);
+#else
+ va_start (ap);
+#endif
+
+ for (len = strlen(s) + 1; (component = va_arg(ap, char *)); )
+ len += strlen(component) + 1;
+
+ va_end (ap);
+
+ if (!len) {
+ errno = 0;
+ return (0);
+ }
+
+ if (!(ret = Malloc(len))) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+#if defined(__STDC__)
+ va_start (ap, s);
+#else
+ va_start (ap);
+#endif
+
+ for (
+ p = ret, component = s;
+ component;
+ component = va_arg(ap, char *)
+ ) {
+ for (q = component; *q; )
+ *p++ = *q++;
+ *p++ = '/';
+ }
+ p[-1] = 0;
+
+ va_end (ap);
+
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/lp/makestr.c b/usr/src/cmd/lp/lib/lp/makestr.c
new file mode 100644
index 0000000000..c61476a8dd
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/makestr.c
@@ -0,0 +1,108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* LINTLIBRARY */
+
+#if defined(__STDC__)
+#include "stdarg.h"
+#else
+#include "varargs.h"
+#endif
+
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** makestr() - CONSTRUCT SINGLE STRING FROM SEVERAL
+ **/
+
+/*VARARGS1*/
+char *
+#if defined(__STDC__)
+makestr (
+ char * s,
+ ...
+)
+#else
+makestr (s, va_alist)
+ char * s;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ register char *component,
+ *p,
+ *q;
+
+ register int len;
+
+ char *ret;
+
+
+#if defined(__STDC__)
+ va_start (ap, s);
+#else
+ va_start (ap);
+#endif
+
+ for (len = strlen(s); (component = va_arg(ap, char *)); )
+ len += strlen(component);
+
+ va_end (ap);
+
+ if (!len) {
+ errno = 0;
+ return (0);
+ }
+
+ if (!(ret = Malloc(len + 1))) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+#if defined(__STDC__)
+ va_start (ap, s);
+#else
+ va_start (ap);
+#endif
+
+ for (
+ p = ret, component = s;
+ component;
+ component = va_arg(ap, char *)
+ )
+ for (q = component; *q; )
+ *p++ = *q++;
+ *p = 0;
+
+ va_end(ap);
+
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/lp/mergelist.c b/usr/src/cmd/lp/lib/lp/mergelist.c
new file mode 100644
index 0000000000..8fdbad0880
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/mergelist.c
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+/**
+ ** mergelist() - ADD CONTENT OF ONE LIST TO ANOTHER
+ **/
+
+int
+#if defined(__STDC__)
+mergelist (
+ char *** dstlist,
+ char ** srclist
+)
+#else
+mergelist (dstlist, srclist)
+ register char ***dstlist,
+ **srclist;
+#endif
+{
+ if (!srclist || !*srclist)
+ return (0);
+
+ while (*srclist)
+ if (addlist(dstlist, *srclist++) == -1)
+ return (-1);
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/next.c b/usr/src/cmd/lp/lib/lp/next.c
new file mode 100644
index 0000000000..5af076c69a
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/next.c
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10 */
+/* LINTLIBRARY */
+
+#include "string.h"
+#include "errno.h"
+
+#include "lp.h"
+
+#if defined(__STDC__)
+static int is ( char *, char *, unsigned int );
+#else
+static int is();
+#endif
+
+/**
+ ** next_x() - GO TO NEXT ENTRY UNDER PARENT DIRECTORY
+ **/
+
+char *
+#if defined(__STDC__)
+next_x (
+ char * parent,
+ long * lastdirp,
+ unsigned int what
+)
+#else
+next_x (parent, lastdirp, what)
+ char *parent;
+ long *lastdirp;
+ unsigned int what;
+#endif
+{
+ DIR *dirp;
+
+ register char *ret = 0;
+
+ struct dirent *direntp;
+
+
+ if (!(dirp = Opendir(parent)))
+ return (0);
+
+ if (*lastdirp != -1)
+ Seekdir (dirp, *lastdirp);
+
+ do
+ direntp = Readdir(dirp);
+ while (
+ direntp
+ && (
+ STREQU(direntp->d_name, ".")
+ || STREQU(direntp->d_name, "..")
+ || !is(parent, direntp->d_name, what)
+ )
+ );
+
+ if (direntp) {
+ if (!(ret = Strdup(direntp->d_name)))
+ errno = ENOMEM;
+ *lastdirp = Telldir(dirp);
+ } else {
+ errno = ENOENT;
+ *lastdirp = -1;
+ }
+
+ Closedir (dirp);
+
+ return (ret);
+}
+
+static int
+#if defined(__STDC__)
+is (
+ char * parent,
+ char * name,
+ unsigned int what
+)
+#else
+is (parent, name, what)
+ char *parent;
+ char *name;
+ unsigned int what;
+#endif
+{
+ char *path;
+
+ struct stat statbuf;
+
+ if (!(path = makepath(parent, name, (char *)0)))
+ return (0);
+ if (Stat(path, &statbuf) == -1) {
+ Free (path);
+ return (0);
+ }
+ Free (path);
+ return ((statbuf.st_mode & S_IFMT) == what);
+}
diff --git a/usr/src/cmd/lp/lib/lp/printlist.c b/usr/src/cmd/lp/lib/lp/printlist.c
new file mode 100644
index 0000000000..e0cec19d33
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/printlist.c
@@ -0,0 +1,127 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+
+#include "lp.h"
+
+#define DFLT_PREFIX 0
+#define DFLT_SUFFIX 0
+#define DFLT_SEP "\n"
+#define DFLT_NEWLINE "\n"
+
+int printlist_qsep = 0;
+
+static char *print_prefix = DFLT_PREFIX,
+ *print_suffix = DFLT_SUFFIX,
+ *print_sep = DFLT_SEP,
+ *print_newline = DFLT_NEWLINE;
+
+static void q_print( int, char * , char * );
+
+/**
+ ** printlist_setup() - ARRANGE FOR CUSTOM PRINTING
+ ** printlist_unsetup() - RESET STANDARD PRINTING
+ **/
+
+void
+printlist_setup(char *prefix, char *suffix, char *sep, char *newline)
+{
+ if (prefix)
+ print_prefix = prefix;
+ if (suffix)
+ print_suffix = suffix;
+ if (sep)
+ print_sep = sep;
+ if (newline)
+ print_newline = newline;
+ return;
+}
+
+void
+printlist_unsetup()
+{
+ print_prefix = DFLT_PREFIX;
+ print_suffix = DFLT_SUFFIX;
+ print_sep = DFLT_SEP;
+ print_newline = DFLT_NEWLINE;
+ return;
+}
+
+/**
+ ** printlist() - PRINT LIST ON OPEN CHANNEL
+ **/
+
+int
+printlist(FILE *fp, char **list)
+{
+ return (fdprintlist(fileno(fp), list));
+}
+
+int
+fdprintlist(int fd, char **list)
+{
+ register char *sep;
+
+ if (list)
+ for (sep = ""; *list; *list++, sep = print_sep) {
+
+ (void)fdprintf (fd, "%s%s", sep, NB(print_prefix));
+ if (printlist_qsep)
+ q_print (fd, *list, print_sep);
+ else
+ (void)fdprintf (fd, "%s", *list);
+ errno = 0;
+ (void)fdprintf (fd, "%s", NB(print_suffix));
+ if (errno != 0)
+ return (-1);
+
+ }
+ (void)fdprintf (fd, print_newline);
+
+ return (0);
+}
+
+
+static void
+q_print(int fd, char *str, char *sep)
+{
+ while (*str) {
+ if (strchr(sep, *str))
+ fdputc('\\', fd);
+ fdputc(*str, fd);
+ str++;
+ }
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/lp/sdn.c b/usr/src/cmd/lp/lib/lp/sdn.c
new file mode 100644
index 0000000000..151717830f
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/sdn.c
@@ -0,0 +1,202 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+#define N_COMPRESSED 9999
+
+/**
+ ** printsdn() - PRINT A SCALED DECIMAL NUMBER NICELY
+ **/
+
+#define DFLT_PREFIX 0
+#define DFLT_SUFFIX 0
+#define DFLT_NEWLINE "\n"
+
+static char *print_prefix = DFLT_PREFIX,
+ *print_suffix = DFLT_SUFFIX,
+ *print_newline = DFLT_NEWLINE;
+
+void
+printsdn_setup(char *prefix, char *suffix, char *newline)
+{
+ if (prefix)
+ print_prefix = prefix;
+ if (suffix)
+ print_suffix = suffix;
+ if (newline)
+ print_newline = newline;
+ return;
+}
+
+void
+printsdn_unsetup ()
+{
+ print_prefix = DFLT_PREFIX;
+ print_suffix = DFLT_SUFFIX;
+ print_newline = DFLT_NEWLINE;
+ return;
+}
+
+
+void
+printsdn(FILE *fp, SCALED sdn)
+{
+ fdprintsdn(fileno(fp), sdn);
+}
+
+
+void
+fdprintsdn(int fd, SCALED sdn)
+{
+ register char *dec = "9999.999",
+ *z;
+
+ if (sdn.val <= 0)
+ return;
+
+ (void)fdprintf (fd, "%s", NB(print_prefix));
+
+ /*
+ * Let's try to be a bit clever in dealing with decimal
+ * numbers. If the number is an integer, don't print
+ * a decimal point. If it isn't an integer, strip trailing
+ * zeros from the fraction part, and don't print more
+ * than the thousandths place.
+ */
+ if (-1000. < sdn.val && sdn.val < 10000.) {
+
+ /*
+ * Printing 0 will give us 0.000.
+ */
+ sprintf (dec, "%.3f", sdn.val);
+
+ /*
+ * Skip zeroes from the end until we hit
+ * '.' or not-0. If we hit '.', clobber it;
+ * if we hit not-0, it has to be in fraction
+ * part, so leave it.
+ */
+ z = dec + strlen(dec) - 1;
+ while (*z == '0' && *z != '.')
+ z--;
+ if (*z == '.')
+ *z = '\0';
+ else
+ *++z = '\0';
+
+ (void)fdprintf(fd, "%s", dec);
+
+ } else
+ (void)fdprintf(fd, "%.3f", sdn.val);
+
+ if (sdn.sc == 'i' || sdn.sc == 'c')
+ fdputc(sdn.sc, fd);
+
+ (void)fdprintf(fd, "%s%s", NB(print_suffix), NB(print_newline));
+ return;
+}
+
+
+/**
+ ** _getsdn() - PARSE SCALED DECIMAL NUMBER
+ **/
+
+SCALED
+_getsdn(char *str, char **p_after, int is_cpi)
+{
+ static SCALED sdn = { 0.0 , 0 };
+
+ char * rest;
+
+
+ /*
+ * A nonzero "errno" is our only method of indicating error.
+ */
+ errno = 0;
+
+ if (is_cpi && STREQU(str, NAME_PICA)) {
+ sdn.val = 10;
+ sdn.sc = 0;
+ if (p_after)
+ *p_after = str + strlen(NAME_PICA);
+
+ } else if (is_cpi && STREQU(str, NAME_ELITE)) {
+ sdn.val = 12;
+ sdn.sc = 0;
+ if (p_after)
+ *p_after = str + strlen(NAME_ELITE);
+
+ } else if (is_cpi && STREQU(str, NAME_COMPRESSED)) {
+ sdn.val = N_COMPRESSED;
+ sdn.sc = 0;
+ if (p_after)
+ *p_after = str + strlen(NAME_COMPRESSED);
+
+ } else {
+ sdn.val = strtod(str, &rest);
+ if (sdn.val <= 0) {
+ lp_errno = LP_EBADSDN;
+ errno = EINVAL;
+ return (sdn);
+ }
+
+ while (*rest && *rest == ' ')
+ rest++;
+
+ switch (*rest) {
+ case 0:
+ sdn.sc = 0;
+ if (p_after)
+ *p_after = rest;
+ break;
+ case 'i':
+ case 'c':
+ sdn.sc = *rest++;
+ if (p_after)
+ *p_after = rest;
+ break;
+ default:
+ lp_errno = LP_EBADSDN;
+ errno = EINVAL;
+ sdn.sc = 0;
+ break;
+ }
+ }
+
+ return (sdn);
+}
diff --git a/usr/src/cmd/lp/lib/lp/searchlist.c b/usr/src/cmd/lp/lib/lp/searchlist.c
new file mode 100644
index 0000000000..46b5b476a0
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/searchlist.c
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+
+#include "lp.h"
+
+/**
+ ** searchlist() - SEARCH (char **) LIST FOR ITEM
+ **/
+
+int
+#if defined(__STDC__)
+searchlist (
+ char * item,
+ char ** list
+)
+#else
+searchlist (item, list)
+ register char *item;
+ register char **list;
+#endif
+{
+ if (!list || !*list)
+ return (0);
+
+ else if (STREQU(item, NAME_ANY) || STREQU(item, NAME_ALL))
+ return (1);
+
+ /*
+ * This is a linear search--we believe that the lists
+ * will be short.
+ */
+ while (*list) {
+ if (
+ STREQU(*list, item)
+ || STREQU(*list, NAME_ANY)
+ || STREQU(*list, NAME_ALL)
+ )
+ return (1);
+ list++;
+ }
+ return (0);
+}
+
+/**
+ ** searchlist_with_terminfo() - SEARCH (char **) LIST FOR ITEM
+ **/
+
+int
+#if defined(__STDC__)
+searchlist_with_terminfo (
+ char * item,
+ char ** list
+)
+#else
+searchlist_with_terminfo (item, list)
+ register char *item;
+ register char **list;
+#endif
+{
+ if (!list || !*list)
+ return (0);
+
+ else if (STREQU(item, NAME_ANY) || STREQU(item, NAME_ALL))
+ return (1);
+
+ /*
+ * This is a linear search--we believe that the lists
+ * will be short.
+ */
+ while (*list) {
+ if (
+ STREQU(*list, item)
+ || STREQU(*list, NAME_ANY)
+ || STREQU(*list, NAME_ALL)
+ || (
+ STREQU(*list, NAME_TERMINFO)
+ && isterminfo(item)
+ )
+ )
+ return (1);
+ list++;
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/set_charset.c b/usr/src/cmd/lp/lib/lp/set_charset.c
new file mode 100644
index 0000000000..628ae30296
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/set_charset.c
@@ -0,0 +1,237 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.11 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "lp.set.h"
+
+#if defined(__STDC__)
+char * tparm ( char * , ... );
+#else
+extern char *tparm();
+#endif
+
+#if defined(__STDC__)
+static int cat_charset ( char *, int , char * , int );
+#else
+static int cat_charset();
+#endif
+
+/**
+ ** set_charset()
+ **/
+
+int
+#if defined(__STDC__)
+set_charset (
+ char * char_set,
+ int putout,
+ char * type
+)
+#else
+set_charset (char_set, putout, type)
+ char *char_set;
+ int putout;
+ char *type;
+#endif
+{
+ int cs,
+ ret;
+
+ char *rest,
+ *char_set_nm,
+ *char_set_names,
+ *select_char_set,
+ *start_char_set_def,
+ *p,
+ *q;
+
+ unsigned short has_print_wheel;
+
+
+ tidbit ((char *)0, "daisy", &has_print_wheel);
+ if (has_print_wheel)
+ return (E_SUCCESS);
+
+ tidbit ((char *)0, "csnm", &char_set_names);
+ if (
+ strlen(char_set) > (size_t) 2
+ && char_set[0] == 'c'
+ && char_set[1] == 's'
+ && char_set[2]
+ && 0 <= (cs = strtol(char_set + 2, &rest, 10)) && cs <= 63
+ && !*rest
+ )
+ char_set_nm = tparm(char_set_names, cs);
+
+ else {
+ for (cs = 0; cs <= 63; cs++)
+ if (
+ (char_set_nm = tparm(char_set_names, cs))
+ && *char_set_nm
+ && STREQU(char_set_nm, char_set)
+ )
+ break;
+ if (cs > 63)
+ return (E_FAILURE);
+ }
+
+ if (cs == 0)
+ return (E_SUCCESS);
+
+ if (char_set_nm)
+ if (!(char_set_nm = Strdup(char_set_nm))) {
+ errno = ENOMEM;
+ ret = E_FAILURE;
+ goto Return;
+ }
+
+ tidbit ((char *)0, "scs", &select_char_set);
+ p = q = 0;
+ if ((p = tparm(select_char_set, cs)) && *p && (p = Strdup(p))) {
+
+ tidbit ((char *)0, "scsd", &start_char_set_def);
+ if ((q = tparm(start_char_set_def, cs)) && *q) {
+ /*
+ * The ``start char. set def'n.'' capability
+ * is defined and set, so assume we MUST
+ * download the character set before using it.
+ */
+ if (
+ OKAY(char_set_nm)
+ && cat_charset(char_set_nm, 0, type, putout) != -1
+ || cat_charset((char *)0, cs, type, putout) != -1
+ || cat_charset(char_set, 0, type, putout) != -1
+ )
+ ;
+ else {
+ ret = E_FAILURE;
+ goto Return;
+ }
+
+ } else {
+ /*
+ * The ``start char. set def'n.'' capability
+ * is not defined and or set, so assume we MAY
+ * download the character set before using it.
+ */
+ if (
+ OKAY(char_set_nm)
+ && cat_charset(char_set_nm, 0, type, putout) != -1
+ || cat_charset((char *)0, cs, type, putout) != -1
+ || cat_charset(char_set, 0, type, putout) != -1
+ )
+ ;
+ }
+
+ if (putout)
+ putp (p);
+ ret = E_SUCCESS;
+
+ } else
+ ret = E_FAILURE;
+
+Return: if (p)
+ Free (p);
+ if (q)
+ Free (q);
+ if (char_set_nm)
+ Free (char_set_nm);
+ return (ret);
+}
+
+/**
+ ** cat_charset() - DUMP CONTENT OF CHARACTER SET DEF'N FILE
+ **/
+
+static int
+#if defined(__STDC__)
+cat_charset (
+ char * name,
+ int number,
+ char * type,
+ int putout
+)
+#else
+cat_charset (name, number, type, putout)
+ char *name;
+ int number,
+ putout;
+ char *type;
+#endif
+{
+ int fd;
+
+ char *p,
+ *parent,
+ *T,
+ buf[BUFSIZ];
+
+ int n,
+ ret;
+
+ if (!name)
+ sprintf ((name = "63"), "%d", number);
+
+ if (!(parent = getenv("CHARSETDIR")))
+ parent = CHARSETDIR;
+
+ (T = "x")[0] = type[0];
+ p = makepath(parent, T, type, name, (char *)0);
+ if (!p)
+ return (-1);
+ if ((fd = open_locked(p, "r", 0)) < 0) {
+ Free (p);
+ return (-1);
+ }
+ Free (p);
+
+ if (putout) {
+
+ errno = 0;
+ while ((n = read(fd, buf, BUFSIZ)))
+ fwrite (buf, 1, n, stdout);
+
+ if (errno != 0)
+ ret = -1;
+ else
+ ret = 0;
+
+ }
+ close(fd);
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/lp/set_pitch.c b/usr/src/cmd/lp/lib/lp/set_pitch.c
new file mode 100644
index 0000000000..ee317cdcad
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/set_pitch.c
@@ -0,0 +1,210 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "lp.set.h"
+
+extern char *tparm();
+
+short output_res_char = -1,
+ output_res_line = -1,
+ output_res_horz_inch = -1,
+ output_res_vert_inch = -1;
+
+/**
+ ** set_pitch()
+ **/
+
+int
+#if defined(__STDC__)
+set_pitch (
+ char * str,
+ int which,
+ int putout
+)
+#else
+set_pitch (str, which, putout)
+ char *str;
+ int which,
+ putout;
+#endif
+{
+ double xpi;
+
+ int ixpi;
+
+ short *output_res_p,
+ *output_res_inch_p;
+
+ unsigned short xpi_changes_res;
+
+ char *rest,
+ *change_pitch,
+ *change_res,
+ *p;
+
+
+ if (which == 'H') {
+
+ tidbit ((char *)0, "cpi", &change_pitch);
+ tidbit ((char *)0, "chr", &change_res);
+
+ output_res_inch_p = &output_res_horz_inch;
+ if (output_res_horz_inch == -1)
+ tidbit ((char *)0, "orhi", output_res_inch_p);
+
+ output_res_p = &output_res_char;
+ if (output_res_char == -1)
+ tidbit ((char *)0, "orc", output_res_p);
+
+ tidbit ((char *)0, "cpix", &xpi_changes_res);
+
+ } else {
+
+ tidbit ((char *)0, "lpi", &change_pitch);;
+ tidbit ((char *)0, "cvr", &change_res);;
+
+ output_res_inch_p = &output_res_vert_inch;
+ if (output_res_vert_inch == -1)
+ tidbit ((char *)0, "orvi", output_res_inch_p);
+
+ output_res_p = &output_res_line;
+ if (output_res_line == -1)
+ tidbit ((char *)0, "orl", output_res_p);
+
+ tidbit ((char *)0, "lpix", &xpi_changes_res);;
+
+ }
+
+ xpi = strtod(str, &rest);
+ if (which == 'H' && STREQU(str, NAME_PICA))
+ ixpi = R(xpi = 10);
+
+ else if (which == 'H' && STREQU(str, NAME_ELITE))
+ ixpi = R(xpi = 12);
+
+ else if (
+ which == 'H'
+ && (
+ STREQU(str, NAME_COMPRESSED)
+ || xpi >= N_COMPRESSED
+ )
+ ) {
+ if (change_pitch) {
+
+ for (ixpi = MAX_COMPRESSED; ixpi; ixpi--)
+ if ((p = tparm(change_pitch, ixpi)) && *p)
+ break;
+ if (!ixpi)
+ ixpi = 10;
+ xpi = (double)ixpi;
+
+ } else if (change_res && *output_res_inch_p != -1) {
+
+ for (xpi = MAX_COMPRESSED; xpi >= 1.; xpi -= 1.)
+ if (
+ (p = tparm(change_res, R(*output_res_inch_p / xpi)))
+ && *p
+ )
+ break;
+ if (xpi < 1.)
+ xpi = 10.;
+ ixpi = R(xpi);
+
+ } else
+ return (E_FAILURE);
+
+ } else {
+
+ if (xpi <= 0)
+ return (E_BAD_ARGS);
+
+ switch (*rest) {
+ case ' ':
+ case 0:
+ break;
+ case 'c':
+ /*
+ * Convert to [lines|chars] per inch.
+ */
+ xpi *= 2.54;
+ /* fall through */
+ case 'i':
+ break;
+ default:
+ return (E_BAD_ARGS);
+ }
+
+ ixpi = R(xpi);
+
+ }
+
+ if (
+ *output_res_inch_p != -1
+ && *output_res_p != -1
+ && R(*output_res_inch_p / (double)*output_res_p) == ixpi
+ )
+ return (E_SUCCESS);
+
+ else if (
+ change_pitch
+ && (p = tparm(change_pitch, ixpi))
+ && *p
+ ) {
+
+ if (putout)
+ putp (p);
+ if (xpi_changes_res) {
+ if (*output_res_inch_p != -1)
+ *output_res_inch_p = R(*output_res_p * xpi);
+ } else {
+ if (*output_res_p != -1)
+ *output_res_p = R(*output_res_inch_p / xpi);
+ }
+ return (E_SUCCESS);
+
+ } else if (
+ change_res
+ && *output_res_inch_p != -1
+ && (p = tparm(change_res, R(*output_res_inch_p / xpi)))
+ && *p
+ ) {
+
+ if (putout)
+ putp (p);
+ if (*output_res_p != -1)
+ *output_res_p = R(*output_res_inch_p / xpi);
+ return (E_SUCCESS);
+
+ } else
+
+ return (E_FAILURE);
+}
diff --git a/usr/src/cmd/lp/lib/lp/set_size.c b/usr/src/cmd/lp/lib/lp/set_size.c
new file mode 100644
index 0000000000..d2fec5a842
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/set_size.c
@@ -0,0 +1,428 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.13 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "lp.set.h"
+
+#if defined(__STDC__)
+
+char * tparm ( char * , ... );
+int putp ( char * );
+int tidbit ( char * , char * , ... );
+
+#else
+
+extern char *tparm();
+int putp();
+int tidbit();
+
+#endif
+
+extern short output_res_char,
+ output_res_line,
+ output_res_horz_inch,
+ output_res_vert_inch;
+
+/**
+ ** set_size()
+ **/
+
+int
+#if defined(__STDC__)
+set_size (
+ char * str,
+ int which,
+ int putout
+)
+#else
+set_size (str, which, putout)
+ char *str;
+ int which,
+ putout;
+#endif
+{
+ static int cleared_margins_already = 0;
+
+ double size;
+
+ int i,
+ isize,
+ ret;
+
+ short curval,
+ output_res,
+ output_res_inch;
+
+ char *rest,
+ *set_margin1,
+ *set_margin2,
+ *set_margin1_parm,
+ *set_margin2_parm,
+ *set_both_margins = 0,
+ *move1,
+ *move2,
+ *step2,
+ *p1,
+ *p2,
+ *sp1,
+ *sp2,
+ *carriage_return,
+ *parm_right_cursor,
+ *column_address,
+ *repeat_char,
+ *cursor_right,
+ *parm_down_cursor,
+ *row_address,
+ *cursor_down,
+ *clear_margins,
+ *finale,
+ *slines;
+
+
+ if (which == 'W') {
+
+ tidbit ((char *)0, "cols", &curval);
+
+ if (output_res_char == -1)
+ tidbit ((char *)0, "orc", &output_res_char);
+ output_res = output_res_char;
+
+ if (output_res_horz_inch == -1)
+ tidbit ((char *)0, "orhi", &output_res_horz_inch);
+ output_res_inch = output_res_horz_inch;
+
+ } else {
+
+ tidbit ((char *)0, "lines", &curval);
+
+ if (output_res_line == -1)
+ tidbit ((char *)0, "orl", &output_res_line);
+ output_res = output_res_line;
+
+ if (output_res_vert_inch == -1)
+ tidbit ((char *)0, "orvi", &output_res_vert_inch);
+ output_res_inch = output_res_vert_inch;
+
+ }
+
+ size = strtod(str, &rest);
+ if (size <= 0)
+ return (E_BAD_ARGS);
+
+ switch (*rest) {
+ case ' ':
+ case 0:
+ break;
+ case 'c':
+ /*
+ * Convert to inches.
+ */
+ size /= 2.54;
+ /* fall through */
+ case 'i':
+ /*
+ * Convert to lines/columns.
+ */
+ if (output_res == -1 || output_res_inch == -1)
+ return (E_FAILURE);
+ size *= output_res_inch / output_res;
+ break;
+ default:
+ return (E_BAD_ARGS);
+ }
+
+
+ if ((isize = R(size)) == curval)
+ return (E_SUCCESS);
+
+ /*
+ * We number things 0 through N (e.g. an 80 column
+ * page is numbered 0 to 79). Thus if we are asked
+ * to set a width of 132, we set the left margin at
+ * 0 and the right at 131.
+ * Of course, if we're using the "slines" string,
+ * we give the length as N+1.
+ */
+ isize--;
+
+ /*
+ * When the width or length is set using the set-margin-at-
+ * current-position caps (e.g. smgl and smgr, smgt, smgb):
+ * If a parameterized motion capability exists, then we'll try
+ * to use it. However, if the instantiation of the capability
+ * (through tparm()) gives nothing, assume this means the motion
+ * is not allowed--don't try the next choice. This is the only
+ * way we have of checking for a width or length beyond the
+ * limits of the printer. If a parameterized motion capability
+ * doesn't exist, we have no way to check out-of-bounds width
+ * and length, sorry.
+ *
+ * When the width or length is set using parameterized caps
+ * (e.g. smglp and smgrp, or slines for length), the above is not
+ * a problem, of course.
+ */
+ if (which == 'W') {
+
+ tidbit ((char *)0, "smgl", &set_margin1);
+ tidbit ((char *)0, "smgr", &set_margin2);
+ tidbit ((char *)0, "smglp", &set_margin1_parm);
+ tidbit ((char *)0, "smgrp", &set_margin2_parm);
+ tidbit ((char *)0, "smglr", &set_both_margins);
+
+ tidbit ((char *)0, "cr", &carriage_return);
+ tidbit ((char *)0, "cuf", &parm_right_cursor);
+ tidbit ((char *)0, "hpa", &column_address);
+ tidbit ((char *)0, "rep", &repeat_char);
+ tidbit ((char *)0, "cuf1", &cursor_right);
+
+ if (OKAY(carriage_return))
+ move1 = carriage_return;
+ else
+ move1 = "\r";
+
+ if (OKAY(parm_right_cursor)) {
+ move2 = tparm(parm_right_cursor, isize);
+ step2 = 0;
+
+ } else if (OKAY(column_address)) {
+ move2 = tparm(column_address, isize);
+ step2 = 0;
+
+ } else if (OKAY(repeat_char)) {
+ move2 = tparm(repeat_char, ' ', isize);
+ step2 = 0;
+
+ } else if (OKAY(cursor_right)) {
+ move2 = 0;
+ step2 = cursor_right;
+
+ } else {
+ move2 = 0;
+ step2 = " ";
+ }
+
+ finale = move1; /* i.e. carriage return */
+
+ } else {
+
+ tidbit ((char *)0, "smgt", &set_margin1);
+ tidbit ((char *)0, "smgb", &set_margin2);
+ tidbit ((char *)0, "smgtp", &set_margin1_parm);
+ tidbit ((char *)0, "smgbp", &set_margin2_parm);
+ tidbit ((char *)0, "smgtb", &set_both_margins);
+
+ /*
+ * For compatibility with SVR3.2 era Terminfo files,
+ * we check "u9" as an alias for "slines" IF a check
+ * of "slines" comes up empty.
+ */
+ slines = 0; /* (in case compiled with old tidbit) */
+ tidbit ((char *)0, "slines", &slines);
+ if (!OKAY(slines))
+ tidbit ((char *)0, "u9", &slines);
+
+ tidbit ((char *)0, "cud", &parm_down_cursor);
+ tidbit ((char *)0, "vpa", &row_address);
+ tidbit ((char *)0, "cud1", &cursor_down);
+
+ move1 = ""; /* Assume we're already at top-of-page */
+
+ if (OKAY(parm_down_cursor)) {
+ move2 = tparm(parm_down_cursor, isize);
+ step2 = 0;
+
+ } else if (OKAY(row_address)) {
+ move2 = tparm(row_address, isize);
+ step2 = 0;
+
+ } else if (OKAY(cursor_down)) {
+ move2 = 0;
+ step2 = cursor_down;
+
+ } else {
+ move2 = 0;
+ step2 = "\n";
+ }
+
+ /*
+ * This has to be smarter, but we don't have the
+ * smarts ourselves, yet; i.e. what do we do if
+ * there is no "ff"?
+ */
+ tidbit ((char *)0, "ff", &finale);
+
+ }
+
+ /*
+ * For a short while we needed a kludge in Terminfo
+ * whereby if only one of the left/right or top/bottom
+ * parameterized margin setters was defined, it was
+ * a parm-string that could set BOTH margins. We now have
+ * separate strings for setting both margins, but we still
+ * allow the kludge.
+ */
+ if (!OKAY(set_both_margins)) {
+ if (OKAY(set_margin1_parm) && !OKAY(set_margin2_parm))
+ set_both_margins = set_margin1_parm;
+ else if (OKAY(set_margin2_parm) && !OKAY(set_margin1_parm))
+ set_both_margins = set_margin2_parm;
+ }
+
+ sp1 = sp2 = 0;
+
+ if (
+ which == 'L'
+ && OKAY(slines)
+ && (p1 = tparm(slines, isize + 1))
+ ) {
+ if (putout)
+ putp (p1);
+ finale = 0;
+ ret = E_SUCCESS;
+
+ } else if (
+ OKAY(set_both_margins)
+ && (p1 = tparm(set_both_margins, 0, isize))
+ && *p1
+ && (sp1 = Strdup(p1))
+ ) {
+
+ if (putout) {
+
+ if (!cleared_margins_already) {
+ tidbit ((char *)0, "mgc", &clear_margins);
+ if (OKAY(clear_margins)) {
+ cleared_margins_already = 1;
+ putp (clear_margins);
+ }
+ }
+
+ putp (sp1);
+
+ }
+ ret = E_SUCCESS;
+
+ /*
+ * The "smgbp" string takes two parameters; each defines the
+ * position of the margin, the first counting lines from the top
+ * of the page, the second counting lines from the bottom of the
+ * page. This shows the flaw in using the set-margin commands
+ * for setting the page length, because BY DEFINITION the second
+ * parameter must be 0 for us. But giving 0 won't cause a change
+ * in the page length, will it!
+ *
+ * Anyway, the "smgrp" expects just one parameter (thus will
+ * ignore a second parameter) so we can safely give the second
+ * parameter without caring which of width or length we're
+ * setting.
+ */
+ } else if (
+ OKAY(set_margin1_parm)
+ && (p1 = tparm(set_margin1_parm, 0))
+ && *p1
+ && (sp1 = Strdup(p1))
+ && OKAY(set_margin2_parm)
+ && (p2 = tparm(set_margin2_parm, isize, 0))
+ && *p2
+ && (sp2 = Strdup(p2))
+ ) {
+
+ if (putout) {
+
+ if (!cleared_margins_already) {
+ tidbit ((char *)0, "mgc", &clear_margins);
+ if (OKAY(clear_margins)) {
+ cleared_margins_already = 1;
+ putp (clear_margins);
+ }
+ }
+
+ putp (sp1);
+ putp (sp2);
+
+ }
+ ret = E_SUCCESS;
+
+ } else if (
+ OKAY(set_margin1)
+ && OKAY(set_margin2)
+ && (OKAY(move2) || OKAY(step2))
+ ) {
+
+ register char *p,
+ *q;
+
+ register int free_it = 0;
+
+ if (putout) {
+
+ if (!cleared_margins_already) {
+ tidbit ((char *)0, "mgc", &clear_margins);
+ if (OKAY(clear_margins)) {
+ cleared_margins_already = 1;
+ putp (clear_margins);
+ }
+ }
+
+ putp (move1);
+ putp (set_margin1);
+
+ if (!move2) {
+ move2 = Malloc(isize * strlen(step2) + 1);
+ if (!move2)
+ return (E_MALLOC);
+ for (p = move2, i = 0; i < isize; i++)
+ for (q = step2; *q; )
+ *p++ = *q++;
+ *p = 0;
+ free_it = 1;
+ }
+
+ putp (move2);
+ putp (set_margin2);
+
+ if (free_it)
+ Free (move2);
+ }
+ ret = E_SUCCESS;
+
+ } else
+ ret = E_FAILURE;
+
+ if (putout && OKAY(finale))
+ putp (finale);
+
+ if (sp1)
+ Free (sp1);
+ if (sp2)
+ Free (sp2);
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/lp/sop.c b/usr/src/cmd/lp/lib/lp/sop.c
new file mode 100644
index 0000000000..bf2121908c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/sop.c
@@ -0,0 +1,82 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** sop_up_rest() - READ REST OF FILE INTO STRING
+ **/
+char *
+sop_up_rest(int fd, char *endsop)
+{
+ register int size,
+ add_size,
+ lenendsop;
+
+ register char *str;
+
+ char buf[BUFSIZ];
+
+
+ str = 0;
+ size = 0;
+ if (endsop)
+ lenendsop = strlen(endsop);
+
+ errno = 0;
+ while (fdgets(buf, BUFSIZ, fd)) {
+ if (endsop && STRNEQU(endsop, buf, lenendsop))
+ break;
+ add_size = strlen(buf);
+ if (str)
+ str = Realloc(str, size + add_size + 1);
+ else
+ str = Malloc(size + add_size + 1);
+ if (!str) {
+ errno = ENOMEM;
+ return (0);
+ }
+ strcpy (str + size, buf);
+ size += add_size;
+ }
+ if (errno != 0) {
+ Free (str);
+ return (0);
+ }
+ return (str);
+}
diff --git a/usr/src/cmd/lp/lib/lp/sprintlist.c b/usr/src/cmd/lp/lib/lp/sprintlist.c
new file mode 100644
index 0000000000..2faf7a811f
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/sprintlist.c
@@ -0,0 +1,80 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** sprintlist() - FLATTEN (char **) LIST INTO (char *) LIST
+ **/
+
+char *
+#if defined(__STDC__)
+sprintlist (
+ char ** list
+)
+#else
+sprintlist (list)
+ char **list;
+#endif
+{
+ register char **plist,
+ *p,
+ *q;
+
+ char *ret;
+
+ int len = 0;
+
+
+ if (!list || !*list)
+ return (0);
+
+ for (plist = list; *plist; plist++)
+ len += strlen(*plist) + 1;
+
+ if (!(ret = Malloc(len))) {
+ errno = ENOMEM;
+ return (0);
+ }
+
+ q = ret;
+ for (plist = list; *plist; plist++) {
+ p = *plist;
+ while (*q++ = *p++)
+ ;
+ q[-1] = ' ';
+ }
+ q[-1] = 0;
+
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/lp/strip.c b/usr/src/cmd/lp/lib/lp/strip.c
new file mode 100644
index 0000000000..d1a4c0b1b6
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/strip.c
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+
+/**
+ ** strip() - STRIP LEADING AND TRAILING BLANKS
+ **/
+
+char *
+#if defined(__STDC__)
+strip (
+ char * str
+)
+#else
+strip (str)
+ register char *str;
+#endif
+{
+ register char *p;
+
+ if (!str || !*str)
+ return (0);
+
+ str += strspn(str, " ");
+ for (p = str; *p; p++)
+ ;
+ p--;
+ for (; p >= str && *p == ' '; p--)
+ ;
+ *++p = 0;
+ return (str);
+}
diff --git a/usr/src/cmd/lp/lib/lp/syntax.c b/usr/src/cmd/lp/lib/lp/syntax.c
new file mode 100644
index 0000000000..98e5838641
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/syntax.c
@@ -0,0 +1,172 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "ctype.h"
+#include "string.h"
+#include "sys/param.h"
+
+#include "lp.h"
+
+int
+#if defined(__STDC__)
+syn_name (
+ char * str
+)
+#else
+syn_name (str)
+ char *str;
+#endif
+{
+ register char *p;
+
+ if (!str || !*str)
+ return(0);
+
+ if (strlen(str) > (size_t) MAXPATHLEN)
+ return (0);
+
+ for (p = str; *p; p++)
+ if (!isalnum(*p) && *p != '_' && *p != '-' && *p != '.')
+ return (0);
+
+ return (1);
+}
+
+int
+#if defined(__STDC__)
+syn_type (
+ char * str
+)
+#else
+syn_type (str)
+ char *str;
+#endif
+{
+ register char *p;
+
+ if (!str)
+ return(0);
+
+ if (strlen(str) > (size_t) MAXPATHLEN)
+ return (0);
+
+ for (p = str; *p; p++)
+ if (!isalnum(*p) && *p != '-')
+ return (0);
+
+ return (1);
+}
+
+int
+#if defined(__STDC__)
+syn_text (
+ char * str
+)
+#else
+syn_text (str)
+ char *str;
+#endif
+{
+ register char *p;
+
+ if (!str)
+ return(0);
+
+ for (p = str; *p; p++)
+ if (!isgraph(*p) && *p != '\t' && *p != ' ')
+ return (0);
+
+ return (1);
+}
+
+int
+#if defined(__STDC__)
+syn_comment (
+ char * str
+)
+#else
+syn_comment (str)
+ char *str;
+#endif
+{
+ register char *p;
+
+ if (!str)
+ return(0);
+
+ for (p = str; *p; p++)
+ if (!isgraph(*p) && *p != '\t' && *p != ' ' && *p != '\n')
+ return (0);
+
+ return (1);
+}
+
+int
+#if defined(__STDC__)
+syn_machine_name (
+ char * str
+)
+#else
+syn_machine_name (str)
+ char *str;
+#endif
+{
+ if (!str)
+ return(0);
+
+ if (strlen(str) > (size_t) 8)
+ return (0);
+
+ return (1);
+}
+
+int
+#if defined(__STDC__)
+syn_option (
+ char * str
+)
+#else
+syn_option (str)
+ char *str;
+#endif
+{
+ register char *p;
+
+ if (!str)
+ return(0);
+
+ for (p = str; *p; p++)
+ if (!isprint(*p))
+ return (0);
+
+ return (1);
+}
diff --git a/usr/src/cmd/lp/lib/lp/tidbit.c b/usr/src/cmd/lp/lib/lp/tidbit.c
new file mode 100644
index 0000000000..22b58941e7
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/tidbit.c
@@ -0,0 +1,458 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include "errno.h"
+#include "string.h"
+#include "sys/types.h"
+#include "sys/stat.h"
+
+#if defined(__STDC__)
+#include "stdarg.h"
+#else
+#include "varargs.h"
+#endif
+
+#include "lp.h"
+
+extern char *boolnames[],
+ *numnames[],
+ *strnames[];
+
+extern char *getenv();
+
+ushort_t tidbit_boolean = 0;
+
+short tidbit_number = 0;
+
+char *tidbit_string = 0;
+
+#if defined(__STDC__)
+static int open_terminfo_file(char *, char *);
+#else
+static int open_terminfo_file();
+#endif
+
+/*
+ * _Getsh() - GET TWO-BYTE SHORT FROM "char *" POINTER PORTABLY
+ */
+
+/*
+ * "function" to get a short from a pointer. The short is in a standard
+ * format: two bytes, the first is the low order byte, the second is
+ * the high order byte (base 256). The only negative number allowed is
+ * -1, which is represented as 255, 255. This format happens to be the
+ * same as the hardware on the pdp-11 and vax, making it fast and
+ * convenient and small to do this on a pdp-11.
+ */
+
+#if vax || pdp11 || i386
+#define _Getsh(ip) (*((short *)((char *)(ip))))
+#endif /* vax || pdp11 || i386 */
+
+/*
+ * The following macro is partly due to Mike Laman, laman@sdcsvax
+ * NCR @ Torrey Pines. - Tony Hansen
+ */
+#if u3b || u3b15 || u3b2 || m68000 || sparc
+#define _Getsh(ip) ((short)(*((unsigned char *) ip) | (*(ip+1) << 8)))
+#endif /* u3b || u3b15 || u3b2 || m68000 || sparc */
+
+#ifndef _Getsh
+/*
+ * Here is a more portable version, which does not assume byte ordering
+ * in shorts, sign extension, etc. It does assume that the C preprocessor
+ * does sign-extension the same as on the machine being compiled for.
+ * When ANSI C comes along, this should be changed to check <limits.h>
+ * to see if the low character value is negative.
+ */
+
+static int
+#if defined(__STDC__)
+_Getsh(
+ register char *p
+)
+#else
+_Getsh(p)
+ register char *p;
+#endif
+{
+ register int rv,
+ rv2;
+
+#if -1 == '\377' /* sign extension occurs */
+ rv = (*p++) & 0377;
+ rv2 = (*p) & 0377;
+#else /* -1 == '\377' */ /* no sign extension */
+ rv = *p++;
+ rv2 = *p;
+#endif /* -1 == '\377' */
+ if ((rv2 == 0377) && ((rv == 0377) || (rv == 0376)))
+ return (-1);
+ return (rv + (rv2 * 256));
+}
+#endif /* _Getsh */
+
+#define MAX_TIDBS 32
+
+static struct tidb {
+
+ int snames,
+ nbools,
+ nints,
+ nstrs;
+
+ char *term,
+ *tiebuf,
+ *boolean_offset,
+ *number_offset,
+ *string_offset,
+ *string_table;
+
+} tidbs[MAX_TIDBS + 1]; /* one for last ditch */
+
+/*
+ * tidbit() - TERMINFO DATABASE LOOKUP
+ */
+
+/*
+ * Four forms of calling:
+ *
+ * tidbit ("term-type", "boolean-cap-name", &ushort)
+ * tidbit ("term-type", "numeric-cap-name", &short)
+ * tidbit ("term-type", "string-cap-name", &charstar)
+ * tidbit ("term-type", "any-cap-name", (char *)0)
+ *
+ * The last one is chancy, because of the pointer alignment
+ * problem, but hey--what the heck. Anyway, the last one
+ * causes the value to be stored in one of
+ *
+ * ushort tidbit_boolean;
+ * short tidbit_number;
+ * char *tidbit_string;
+ *
+ * as appropriate, and returns one of 1, 2, or 3 as the type
+ * of the capability is boolean, numeric, or string.
+ *
+ * For example, to extract the size of the screen for a 5410:
+ *
+ * short cols, lines;
+ *
+ * tidbit ("5410", "cols", &cols);
+ * tidbit ("5410", "lines", &lines);
+ *
+ * Note that for the lines and columns, this does NOT check
+ * the LINES and COLUMNS environment variables nor the window
+ * size, if running on a windowing terminal. That can be done
+ * by the caller.
+ *
+ * If first argument is (char *)0, "tidbit()" uses the same TERM
+ * used in the last call, or the TERM environment variable if this
+ * is the first call.
+ * If second argument is (char *)0, no lookup just verification
+ * of terminal type.
+ *
+ * Return is 0 (or 1, 2, 3 as above) if successful, otherwise -1
+ * with "errno" set:
+ *
+ * ENOENT can't open Terminfo file for terminal type
+ * EBADF Terminfo file is corrupted
+ * ENOMEM malloc failed
+ */
+
+/*VARARGS2*/
+int
+#if defined(__STDC__)
+tidbit(
+ char *term,
+ char *cap,
+ ...
+)
+#else
+tidbit(term, cap, va_alist)
+ char *term,
+ *cap;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ int rc;
+
+ register int i;
+
+ register char **pp;
+
+ register struct tidb *pt;
+
+ static char *last_term;
+
+
+ if (!term)
+ if (last_term)
+ term = last_term;
+ else {
+ term = getenv("TERM");
+ if (!term || !*term)
+ term = NAME_UNKNOWN;
+ }
+ if (term != last_term) {
+ if (last_term)
+ Free(last_term);
+ last_term = Strdup(term);
+ }
+
+ for (i = 0; i < MAX_TIDBS; i++)
+ if (tidbs[i].term && STREQU(tidbs[i].term, term)) {
+ pt = &tidbs[i];
+ break;
+ }
+
+ /*
+ * Not cached, so read the file and cache it.
+ */
+ if (i >= MAX_TIDBS) {
+
+ register int n,
+ tfd;
+
+ register char *terminfo;
+
+ struct stat statbuf;
+
+
+ /*
+ * If no empty spot can be found, "i" will index the
+ * last spot, a spare reserved to avoid problems with
+ * a full cache.
+ */
+ for (i = 0; i < MAX_TIDBS; i++)
+ if (!tidbs[i].term)
+ break;
+ pt = &tidbs[i];
+
+ tfd = -1;
+ if ((terminfo = getenv("TERMINFO")) && *terminfo)
+ tfd = open_terminfo_file(terminfo, term);
+#if defined(TERMINFO)
+ if (tfd < 0)
+ tfd = open_terminfo_file(TERMINFO, term);
+#endif
+ if (tfd >= 0)
+ (void) Fstat(tfd, &statbuf);
+
+ if (tfd < 0 || !statbuf.st_size) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ if (pt->tiebuf)
+ Free(pt->tiebuf);
+ if (!(pt->tiebuf = Malloc(statbuf.st_size))) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ n = Read(tfd, pt->tiebuf, statbuf.st_size);
+ (void) Close(tfd);
+ if (n <= 0 || n >= 4096 || _Getsh(pt->tiebuf) != 0432) {
+ Free(pt->tiebuf);
+ pt->tiebuf = 0;
+ errno = EBADF;
+ return (-1);
+ }
+
+ if (pt->term)
+ Free(pt->term);
+ if (!(pt->term = Strdup(term))) {
+ Free(pt->tiebuf);
+ pt->tiebuf = 0;
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ pt->snames = _Getsh(pt->tiebuf + 2);
+ pt->nbools = _Getsh(pt->tiebuf + 4);
+ pt->nints = _Getsh(pt->tiebuf + 6);
+ pt->nstrs = _Getsh(pt->tiebuf + 8);
+
+ pt->boolean_offset = pt->tiebuf + 6 * 2 + pt->snames;
+
+ pt->number_offset = pt->boolean_offset + pt->nbools;
+ if ((unsigned int)pt->number_offset & 1)
+ pt->number_offset++;
+
+ pt->string_offset = pt->number_offset + pt->nints * 2;
+
+ pt->string_table = pt->string_offset + pt->nstrs * 2;
+
+ }
+
+ rc = 0;
+
+#if defined(__STDC__)
+ va_start(ap, cap);
+#else
+ va_start(ap);
+#endif
+
+ if (!cap || !*cap)
+ ;
+
+ else if ((pp = wherelist(cap, boolnames))) {
+ register ushort_t *ushort_p;
+
+ register char *ip;
+
+ register int index = pp - boolnames;
+
+ if (!(ushort_p = va_arg(ap, ushort_t *))) {
+ ushort_p = &tidbit_boolean;
+ rc = 1;
+ }
+
+ if (index >= pt->nbools)
+ *ushort_p = 0;
+ else {
+ ip = pt->boolean_offset + index;
+ *ushort_p = (*ip & 01);
+ }
+
+ } else if ((pp = wherelist(cap, numnames))) {
+ register short *short_p;
+
+ register char *ip;
+
+ register int index = pp - numnames;
+
+ if (!(short_p = va_arg(ap, short *))) {
+ short_p = &tidbit_number;
+ rc = 2;
+ }
+
+ if (index >= pt->nints)
+ *short_p = -1;
+ else {
+ ip = pt->number_offset + index * 2;
+ *short_p = _Getsh(ip);
+ if (*short_p == -2)
+ *short_p = -1;
+ }
+
+ } else if ((pp = wherelist(cap, strnames))) {
+ register char **charstar_p;
+
+ register char *ip;
+
+ register int index = pp - strnames;
+
+ register short sindex;
+
+
+ if (!(charstar_p = va_arg(ap, char **))) {
+ charstar_p = &tidbit_string;
+ rc = 3;
+ }
+
+ if (index >= pt->nstrs)
+ *charstar_p = 0;
+ else {
+ ip = pt->string_offset + index * 2;
+ if ((sindex = _Getsh(ip)) >= 0)
+ *charstar_p = pt->string_table + sindex;
+ else
+ *charstar_p = 0;
+ }
+ }
+
+ va_end(ap);
+ return (rc);
+}
+
+/*
+ * untidbit() - FREE SPACE ASSOCIATED WITH A TERMINFO ENTRY
+ */
+
+void
+#if defined(__STDC__)
+untidbit(
+ char *term
+)
+#else
+untidbit(term)
+ char *term;
+#endif
+{
+ register int i;
+
+
+ for (i = 0; i < MAX_TIDBS; i++)
+ if (tidbs[i].term && STREQU(tidbs[i].term, term)) {
+ if (tidbs[i].tiebuf) {
+ Free(tidbs[i].tiebuf);
+ tidbs[i].tiebuf = 0;
+ }
+ Free(tidbs[i].term);
+ tidbs[i].term = 0;
+ break;
+ }
+}
+
+/*
+ * open_terminfo_file() - OPEN FILE FOR TERM ENTRY
+ */
+
+static int
+#if defined(__STDC__)
+open_terminfo_file(
+ char *terminfo,
+ char *term
+)
+#else
+open_terminfo_file(terminfo, term)
+ char *terminfo,
+ *term;
+#endif
+{
+ char first_letter[] = "X",
+ *path;
+
+ int fd;
+
+ first_letter[0] = term[0];
+ path = makepath(terminfo, first_letter, term, (char *)0);
+
+ /* start fix for bugid 1109709 */
+ if (path == NULL) {
+ return (-1);
+ }
+ /* end fix for bugid 1109709 */
+
+ fd = Open(path, 0);
+ Free(path);
+ return (fd);
+}
diff --git a/usr/src/cmd/lp/lib/lp/tx.c b/usr/src/cmd/lp/lib/lp/tx.c
new file mode 100644
index 0000000000..7f440aea3e
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/tx.c
@@ -0,0 +1,151 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <sys/zone.h>
+#include <syslog.h>
+#include <strings.h>
+
+#include <ucred.h>
+#include "tsol/label.h"
+/* lpsched include files */
+#if defined PS_FAULTED
+#undef PS_FAULTED
+#endif /* PS_FAULTED */
+#include "lp.h"
+#include <sys/tsol/label_macro.h>
+
+/*
+ * get_labeled_zonename - gets the the zonename with the same label.
+ *
+ * Input:
+ * slabel - USER_CLEAR label to match
+ *
+ * Output:
+ * -1 - zonename with that label could not be found
+ * or no memory for zonename
+ * 0 - label was GLOBAL_ZONENAME
+ * addr - zonename of zone matching USER_CLEAR label
+ * must be retuened by calling Free(addr)
+ *
+ */
+
+char *
+get_labeled_zonename(char *slabel)
+{
+ m_label_t *bsl = NULL;
+ int err = 0;
+ ssize_t zonename_size = -1;
+ zoneid_t zid = -1;
+ char *zname = NULL;
+
+ syslog(LOG_DEBUG, "lpsched: get_labeled_zonename %s", slabel);
+ /*
+ * convert the label to binary.
+ */
+ if (str_to_label(slabel, &bsl, USER_CLEAR,
+ L_NO_CORRECTION, &err) == -1) {
+ /* label could not be converted, error */
+ syslog(LOG_WARNING,
+ "lpsched: %s: label not recognized (error==%d)",
+ slabel, err);
+ return ((char *)-1);
+ }
+ if ((zid = getzoneidbylabel(bsl)) < 0) {
+ /* no zone with that label, cannot send mail */
+ syslog(LOG_WARNING,
+ "lpsched: cannot send mail, no zone with %s label",
+ slabel);
+ m_label_free(bsl);
+ return ((char *)-1);
+ }
+ zname = Malloc(ZONENAME_MAX + 1);
+ if ((zonename_size = getzonenamebyid(zid, zname, ZONENAME_MAX + 1))
+ == -1) {
+ /* cannot get zone name, cannot send mail */
+ syslog(LOG_WARNING,
+ "lpsched: cannot send mail, no zone name for %s",
+ slabel);
+ m_label_free(bsl);
+ Free(zname);
+ return ((char *)-1);
+ } else {
+ m_label_free(bsl);
+ if (strcmp(zname, GLOBAL_ZONENAME) == 0) {
+ Free(zname);
+ zname = NULL;
+ }
+ }
+ return (zname);
+}
+
+int
+get_peer_label(int fd, char **slabel)
+{
+ if (is_system_labeled()) {
+ ucred_t *uc = NULL;
+ m_label_t *sl;
+ m_label_t admin_low;
+ m_label_t admin_high;
+ char *pslabel = NULL; /* peer's slabel */
+
+ if ((fd < 0) || (slabel == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bsllow(&admin_low);
+ bslhigh(&admin_high);
+
+ if (getpeerucred(fd, &uc) == -1)
+ return (-1);
+
+ sl = ucred_getlabel(uc);
+
+ /*
+ * Remote print requests from the global zone
+ * arrive at admin_low, make them admin_high to
+ * avoid downgrade.
+ */
+ if (blequal(sl, &admin_low)) {
+ sl = &admin_high;
+ syslog(LOG_DEBUG, "get_peer_label(): upgrade"
+ " admin_low label to admin_high");
+ }
+
+ if (label_to_str(sl, &pslabel, M_INTERNAL, DEF_NAMES) != 0)
+ syslog(LOG_WARNING, "label_to_str(): %m");
+ ucred_free(uc);
+
+ if (pslabel != NULL) {
+ syslog(LOG_DEBUG, "get_peer_label(%d, %s): becomes %s",
+ fd, (*slabel ? *slabel : "NULL"), pslabel);
+ if (*slabel != NULL)
+ free(*slabel);
+ *slabel = strdup(pslabel);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/wherelist.c b/usr/src/cmd/lp/lib/lp/wherelist.c
new file mode 100644
index 0000000000..37d45b71b6
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/wherelist.c
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+
+#include "lp.h"
+
+/**
+ ** wherelist() - RETURN POINTER TO ITEM IN LIST
+ **/
+
+char **
+#if defined(__STDC__)
+wherelist (
+ char * item,
+ char ** list
+)
+#else
+wherelist (item, list)
+ register char *item;
+ register char **list;
+#endif
+{
+ if (!list || !*list)
+ return (0);
+
+ while (*list) {
+ if (STREQU(*list, item))
+ return (list);
+ list++;
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/lp/which.c b/usr/src/cmd/lp/lib/lp/which.c
new file mode 100644
index 0000000000..8464a45eda
--- /dev/null
+++ b/usr/src/cmd/lp/lib/lp/which.c
@@ -0,0 +1,168 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "ctype.h"
+#include "string.h"
+#include "stdlib.h"
+#include "unistd.h"
+
+#include "lp.h"
+
+/**
+ ** isprinter() - SEE IF ARGUMENT IS A REAL PRINTER
+ **/
+
+int
+#if defined(__STDC__)
+isprinter (
+ char * str
+)
+#else
+isprinter (str)
+ char *str;
+#endif
+{
+ char *path = 0;
+
+ int bool;
+
+ bool = (
+ str
+ && *str
+ && (path = getprinterfile(str, CONFIGFILE))
+ && Access(path, F_OK) == 0
+ );
+ if (path)
+ Free (path);
+ return (bool);
+}
+
+/**
+ ** isclass() - SEE IF ARGUMENT IS A REAL CLASS
+ **/
+
+int
+#if defined(__STDC__)
+isclass (
+ char * str
+)
+#else
+isclass (str)
+ char *str;
+#endif
+{
+ char *path = 0;
+
+ int bool;
+
+ bool = (
+ str
+ && *str
+ && (path = getclassfile(str))
+ && Access(path, F_OK) == 0
+ );
+ if (path)
+ Free (path);
+ return (bool);
+}
+
+/**
+ ** isrequest() - SEE IF ARGUMENT LOOKS LIKE A REAL REQUEST
+ **/
+
+int
+#if defined(__STDC__)
+isrequest (
+ char * str
+)
+#else
+isrequest (str)
+ char *str;
+#endif
+{
+ char *dashp;
+
+ /*
+ * Valid print requests have the form
+ *
+ * dest-NNN
+ *
+ * where ``dest'' looks like a printer or class name.
+ * An earlier version of this routine checked to see if
+ * the ``dest'' was an EXISTING printer or class, but
+ * that caused problems with valid requests moved from
+ * a deleted printer or class (the request ID doesn't
+ * change in the new LP).
+ */
+
+ if (!str || !*str)
+ return (0);
+
+ if (!(dashp = strrchr(str, '-')))
+ return (0);
+
+ if (dashp == str)
+ return(0);
+
+ *dashp = 0;
+ if (!syn_name(str)) {
+ *dashp = '-';
+ return (0);
+ }
+ *dashp++ = '-';
+
+ if (!isnumber(dashp))
+ return (0);
+
+ return (1);
+}
+
+int
+#if defined(__STDC__)
+isnumber (
+ char * s
+)
+#else
+isnumber (s)
+ char *s;
+#endif
+{
+ register int c;
+
+ if (!s || !*s)
+ return (0);
+ while ((c = *(s++)) != '\0')
+ if (!isdigit(c))
+ return (0);
+ return (1);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/Makefile b/usr/src/cmd/lp/lib/msgs/Makefile
new file mode 100644
index 0000000000..a73baebb49
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/Makefile
@@ -0,0 +1,86 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/msgs/Makefile
+#
+
+LIBRARY = liblpmsg.a
+
+OBJECTS = _getmessage.o \
+ _putmessage.o \
+ getmessage.o \
+ hslconv.o \
+ putmessage.o \
+ msgfmts.o \
+ mclose.o \
+ mconnect.o \
+ mdisconnect.o \
+ mgetputm.o \
+ mlisten.o \
+ mcreate.o \
+ mdestroy.o \
+ mneeds.o \
+ mopen.o \
+ mread.o \
+ mrecv.o \
+ msend.o \
+ mwrite.o \
+ streamio.o \
+ fifo_buffs.o \
+ read_fifo.o \
+ write_fifo.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master) $(C_PICFLAGS) -D_TS_ERRNO
+
+POFILE = lp_lib_msgs.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpmsg.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+LINT_CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+lint: lintlib
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) -o lpmsg llib-llpmsg
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/msgs/_getmessage.c b/usr/src/cmd/lp/lib/msgs/_getmessage.c
new file mode 100644
index 0000000000..ae4d62374c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/_getmessage.c
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+/* LINTLIBRARY */
+
+# include <stdarg.h>
+# include <string.h>
+# include <errno.h>
+
+# include "msgs.h"
+
+extern char *_lp_msg_fmts[];
+extern int errno;
+
+/* VARARGS */
+#if defined(__STDC__)
+int _getmessage ( char * buf, short rtype, va_list arg )
+#else
+int _getmessage (buf, rtype, arg)
+ char *buf;
+ short rtype;
+ va_list arg;
+#endif
+{
+ char *endbuf;
+ char *fmt;
+ char **t_string;
+ int temp = 0;
+ long *t_long;
+ short *t_short;
+ short etype;
+
+ if (buf == (char *)0)
+ {
+ errno = ENOSPC;
+ return(-1);
+ }
+
+ /*
+ * We assume that we're given a buffer big enough to hold
+ * the header.
+ */
+
+ endbuf = buf + (long)stoh(buf);
+ if ((buf + MESG_DATA) > endbuf)
+ {
+ errno = ENOMSG;
+ return(-1);
+ }
+
+ etype = stoh(buf + MESG_TYPE);
+ if (etype < 0 || etype > LAST_MESSAGE)
+ {
+ errno = EBADMSG;
+ return(-1);
+ }
+
+ if (etype != rtype)
+ {
+ if (rtype > 0 && rtype <= LAST_MESSAGE)
+ fmt = _lp_msg_fmts[rtype];
+ else
+ {
+ errno = EINVAL;
+ return(-1);
+ }
+ }
+ else
+ fmt = _lp_msg_fmts[etype];
+
+ buf += MESG_LEN;
+
+ while (*fmt != '\0')
+ switch(*fmt++)
+ {
+ case 'H':
+ if ((buf + 4) > endbuf)
+ {
+ errno = ENOMSG;
+ return(-1);
+ }
+
+ t_short = va_arg(arg, short *);
+ *t_short = stoh(buf);
+ buf += 4;
+ break;
+
+ case 'L':
+ if ((buf + 8) > endbuf)
+ {
+ errno = ENOMSG;
+ return(-1);
+ }
+
+ t_long = va_arg(arg, long *);
+ *t_long = stol(buf);
+ buf += 8;
+ break;
+
+ case 'D':
+ if ((buf + 4) > endbuf)
+ {
+ errno = ENOMSG;
+ return(-1);
+ }
+
+ t_short = va_arg(arg, short *);
+ *t_short = stoh(buf);
+ buf += 4;
+ t_string = va_arg(arg, char **);
+ if ((buf + *t_short) > endbuf)
+ {
+ errno = ENOMSG;
+ return(-1);
+ }
+ (*t_short)--; /* Don't mention the null we added */
+ *t_string = buf;
+ buf += *t_short;
+ break;
+
+ case 'S':
+ if ((buf + 4) > endbuf)
+ {
+ errno = ENOMSG;
+ return(-1);
+ }
+
+ t_string = va_arg(arg, char **);
+ temp = stoh(buf);
+ buf += 4;
+ if ((buf + temp) > endbuf)
+ {
+ errno = ENOMSG;
+ return(-1);
+ }
+
+ *t_string = buf;
+ buf += temp;
+ break;
+ }
+ return(etype);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/_putmessage.c b/usr/src/cmd/lp/lib/msgs/_putmessage.c
new file mode 100644
index 0000000000..66a6796f5d
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/_putmessage.c
@@ -0,0 +1,136 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10 */
+/* LINTLIBRARY */
+
+# include <stdarg.h>
+# include <string.h>
+# include <errno.h>
+
+# include "msgs.h"
+
+extern char *_lp_msg_fmts[];
+extern int errno;
+
+/* VARARGS */
+#if defined(__STDC__)
+int _putmessage ( char * buf, short type, va_list arg )
+#else
+int _putmessage (buf, type, arg)
+ char *buf;
+ short type;
+ va_list arg;
+#endif
+{
+ char *fmt;
+ char *t_string;
+ int size = 0;
+ long t_long;
+ short t_short;
+
+ if (type < 0 || type > LAST_MESSAGE)
+ {
+ errno = EBADMSG;
+ return(-1);
+ }
+
+ if (buf)
+ (void) htos(buf + MESG_TYPE, type);
+
+ size = MESG_LEN;
+
+ fmt = _lp_msg_fmts[type];
+
+ while (*fmt != '\0')
+ switch(*fmt++)
+ {
+ case 'H':
+ t_short = (short) va_arg(arg, int);
+ if (buf)
+ (void) htos(buf + size, t_short);
+
+ size += 4;
+ break;
+
+ case 'L':
+ t_long = (long) va_arg(arg, int);
+ if (buf)
+ (void) ltos(buf + size, t_long);
+
+ size += 8;
+ break;
+
+ case 'S':
+ t_string = (char *) va_arg(arg, char *);
+ t_short = (t_string? strlen(t_string) : 0) + 1;
+
+ if (buf)
+ (void) htos(buf + size, t_short);
+
+ size += 4;
+
+ if (buf)
+ if (t_string)
+ (void) memcpy(buf + size, t_string, t_short);
+ else
+ (buf + size)[0] = 0;
+
+ size += t_short;
+ break;
+
+ case 'D':
+ t_short = (short) va_arg(arg, int) + 1;
+ t_string = (char *) va_arg(arg, char *);
+
+ if (buf)
+ (void) htos(buf + size, t_short);
+
+ size += 4;
+
+ if (buf)
+ if (t_string)
+ {
+ (void) memcpy(buf + size, t_string, t_short);
+ buf[size + t_short - 1] = '\0';
+ }
+ else
+ *(buf + size) = '\0';
+
+ size += t_short;
+ break;
+ }
+
+
+ if (buf)
+ *(buf + size) = '\0';
+
+ size++; /* Add a null, just on general principle */
+
+ if (buf)
+ (void) htos(buf + MESG_SIZE, size);
+
+ return(size);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/fifo_buffs.c b/usr/src/cmd/lp/lib/msgs/fifo_buffs.c
new file mode 100644
index 0000000000..bf5621bcab
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/fifo_buffs.c
@@ -0,0 +1,149 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+/* LINTLIBRARY */
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include "lp.h"
+#include "msgs.h"
+
+static fifobuffer_t **FifoBufferTable = NULL;
+static int FifoBufferTableSize = 0;
+
+/*
+** Local functions
+*/
+static int InitFifoBufferTable (void);
+static int GrowFifoBufferTable (int);
+static fifobuffer_t *NewFifoBuffer (int);
+
+
+int
+ResetFifoBuffer(int fd)
+{
+ if ((!FifoBufferTableSize) && (InitFifoBufferTable () < 0))
+ return -1;
+
+ if (fd >= FifoBufferTableSize)
+ return 0;
+
+ if (FifoBufferTable [fd]) {
+ FifoBufferTable [fd]->full = 0;
+ FifoBufferTable [fd]->psave =
+ FifoBufferTable [fd]->psave_end =
+ FifoBufferTable [fd]->save;
+ }
+ return 0;
+}
+
+
+fifobuffer_t *
+GetFifoBuffer(int fd)
+{
+ if (fd < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if ((fd >= FifoBufferTableSize) && (GrowFifoBufferTable (fd) < 0))
+ return NULL;
+
+ if (!FifoBufferTable [fd]) {
+ if (!NewFifoBuffer (fd))
+ return NULL;
+
+ FifoBufferTable [fd]->full = 0;
+ FifoBufferTable [fd]->psave =
+ FifoBufferTable [fd]->psave_end =
+ FifoBufferTable [fd]->save;
+ }
+
+ return FifoBufferTable [fd];
+}
+
+
+static int
+InitFifoBufferTable()
+{
+ if (FifoBufferTableSize)
+ return 0;
+
+ FifoBufferTable = (fifobuffer_t **)
+ Calloc (100, sizeof (fifobuffer_t *));
+ if (!FifoBufferTable)
+ return -1; /* ENOMEM is already set. */
+
+ FifoBufferTableSize = 100;
+
+ return 0;
+}
+
+
+static int
+GrowFifoBufferTable (int fd)
+{
+ fifobuffer_t **newpp;
+
+ newpp = (fifobuffer_t **)
+ Realloc ((void*)FifoBufferTable,
+ (fd+10)*sizeof (fifobuffer_t *));
+ if (!newpp)
+ return -1; /* ENOMEM is already set. */
+
+ FifoBufferTableSize = fd+10;
+
+ return 0;
+}
+
+
+static fifobuffer_t *
+NewFifoBuffer(int fd)
+{
+ int i;
+
+ for (i=0; i < FifoBufferTableSize; i++)
+ {
+ if (FifoBufferTable [i] &&
+ Fcntl (i, F_GETFL) < 0 &&
+ errno == EBADF)
+ {
+ FifoBufferTable [fd] = FifoBufferTable [i];
+ FifoBufferTable [i] = NULL;
+ return FifoBufferTable [fd];
+ }
+ }
+ FifoBufferTable [fd] = (fifobuffer_t *)
+ Calloc (1, sizeof (fifobuffer_t));
+
+ return FifoBufferTable [fd];
+}
diff --git a/usr/src/cmd/lp/lib/msgs/getmessage.c b/usr/src/cmd/lp/lib/msgs/getmessage.c
new file mode 100644
index 0000000000..4af175d0bc
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/getmessage.c
@@ -0,0 +1,60 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* LINTLIBRARY */
+/*
+*/
+
+#if defined(__STDC__)
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+/* VARARGS */
+#if defined(__STDC__)
+int getmessage ( char * buf, short type, ... )
+#else
+int getmessage (buf, type, va_alist)
+ char *buf;
+ short type;
+ va_dcl
+#endif
+{
+ va_list arg;
+ int rval;
+ int _getmessage();
+
+#if defined(__STDC__)
+ va_start(arg, type);
+#else
+ va_start(arg);
+#endif
+
+ rval = _getmessage(buf, type, arg);
+ va_end(arg);
+ return(rval);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/hslconv.c b/usr/src/cmd/lp/lib/msgs/hslconv.c
new file mode 100644
index 0000000000..4fa0143a86
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/hslconv.c
@@ -0,0 +1,105 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* LINTLIBRARY */
+
+# include <string.h>
+
+static char _lp_hextable[17] = "0123456789ABCDEF";
+
+#if defined(__STDC__)
+char * ltos ( char * s, unsigned long l)
+#else
+char * ltos (s, l)
+ char *s;
+ unsigned long l;
+#endif
+{
+ int i = 7;
+
+ while (i >= 0)
+ {
+ s[i--] = _lp_hextable[l % 16];
+ l /= 16;
+ }
+ s += 8;
+ return(s);
+}
+
+#if defined(__STDC__)
+char * htos ( char * s, unsigned short h)
+#else
+char * htos (s, h)
+ char *s;
+ unsigned short h;
+#endif
+{
+ int i = 3;
+
+ while (i >= 0)
+ {
+ s[i--] = _lp_hextable[(long)h % 16];
+ h = (long) h / 16;
+ }
+ s += 4;
+ return(s);
+}
+
+#if defined(__STDC__)
+unsigned long stol ( char * s )
+#else
+unsigned long stol (s)
+ char *s;
+#endif
+{
+ int i = 0;
+ unsigned long l = 0;
+
+ while (i < 8)
+ {
+ l <<= 4;
+ l += strchr(_lp_hextable, s[i++]) - _lp_hextable;
+ }
+ return(l);
+}
+
+#if defined(__STDC__)
+unsigned short stoh ( char * s )
+#else
+unsigned short stoh (s)
+ char *s;
+#endif
+{
+ int i = 0;
+ unsigned short h = 0;
+
+ while (i < 4)
+ {
+ h <<= 4;
+ h += strchr(_lp_hextable, s[i++]) - _lp_hextable;
+ }
+ return(h);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/llib-llpmsg b/usr/src/cmd/lp/lib/msgs/llib-llpmsg
new file mode 100644
index 0000000000..84d1fa3b1c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/llib-llpmsg
@@ -0,0 +1,116 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+# include <sys/types.h>
+# include <poll.h>
+# include <stdarg.h>
+# include <stropts.h>
+
+
+typedef struct strbuf strbuf_t; /* STREAMS buffer */
+
+typedef struct mque
+{
+ struct mque *next;
+ struct strbuf *dat;
+} MQUE;
+
+typedef struct
+{
+ short type; /* type of connection */
+ int readfd; /* STREAM fd to read from */
+ int writefd; /* STREAM fd to write to */
+ int wait; /* number of systems waiting for */
+ char *file; /* pipe name if type==MD_FIFO */
+ short state; /* Current state of client */
+ short admin; /* Non zero if admin */
+ short event; /* Event returned from poll */
+ MQUE * mque; /* backlogged message ptr */
+ uid_t uid; /* Clients UID */
+ gid_t gid; /* Clients GID */
+ void (**on_discon)(); /* Clean up functions */
+} MESG;
+
+#define MSGMAX 2048
+typedef struct
+{
+ int full;
+ char save [MSGMAX],
+ *psave,
+ *psave_end;
+} fifobuffer_t;
+
+MESG * mcreate ( char * );
+int mlisteninit ( MESG * );
+MESG * mlisten ( void );
+int mlistenadd ( MESG *, short );
+int mon_discon ( MESG *, void (*)());
+MESG * mlistenreset ( void );
+int mdestroy ( MESG * );
+
+MESG * mconnect ( char *, int, int );
+int mgetm ( MESG *, int, ... );
+int mwrite ( MESG *, char * );
+int mputm ( MESG *, int, ... );
+int mread ( MESG *, char *, int );
+short msize ( char * );
+short mpeek ( MESG * );
+int mdisconnect ( MESG * );
+
+void __mbfree ( void );
+
+int mclose ( void );
+int mneeds ( void );
+int mopen ( void );
+int mrecv ( char *, int );
+int msend ( char * );
+
+int Putmsg (MESG *, strbuf_t *, strbuf_t *, int);
+int Getmsg (MESG *, strbuf_t *, strbuf_t *, int *);
+int read3_2 (MESG * md, char *msgbuf, int size);
+int write3_2 (MESG *, char *, int);
+int read_fifo (int, char *, unsigned int);
+int write_fifo (int, char *, unsigned int);
+int ResetFifoBuffer (int);
+fifobuffer_t *GetFifoBuffer (int);
+
+char * htos ( char *, unsigned short );
+char * ltos ( char *, unsigned long );
+unsigned long stol ( char * );
+unsigned short stoh ( char * );
+int _getmessage ( char *, short, va_list );
+int _putmessage ( char *, short, va_list );
+int getmessage ( char *, short, ... );
+int putmessage ( char *, short, ... );
diff --git a/usr/src/cmd/lp/lib/msgs/mclose.c b/usr/src/cmd/lp/lib/msgs/mclose.c
new file mode 100644
index 0000000000..4a9260bb36
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mclose.c
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+/* LINTLIBRARY */
+
+#include "lp.h"
+#include "msgs.h"
+
+extern MESG *lp_Md;
+
+int mclose()
+{
+ MESG *md = lp_Md;
+
+ lp_Md = 0;
+
+ return(mdisconnect(md));
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mconnect.c b/usr/src/cmd/lp/lib/msgs/mconnect.c
new file mode 100644
index 0000000000..139c9d8ccb
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mconnect.c
@@ -0,0 +1,204 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* LINTLIBRARY */
+
+# include <unistd.h>
+# include <fcntl.h>
+# include <errno.h>
+# include <sys/utsname.h>
+# include <stdlib.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+
+#include "lp.h"
+#include "msgs.h"
+
+#define TURN_OFF(X,F) (void)Fcntl(X, F_SETFL, (Fcntl(X, F_GETFL, 0) & ~(F)))
+
+#if defined(__STDC__)
+static int checklock ( void );
+#else
+static int checklock();
+#endif
+
+/*
+** mconnect() - OPEN A MESSAGE PATH
+*/
+
+#if defined(__STDC__)
+MESG * mconnect ( char * path, int id1, int id2 )
+#else
+MESG * mconnect ()
+ char *path;
+ int id1;
+ int id2;
+#endif
+{
+ int fd;
+ int wronly = 0;
+ int count = 0;
+ MESG *md;
+ struct stat stbuf;
+
+ /*
+ ** invoked as mconnect(path, 0, 0)
+ **
+ ** Open <path>, if isastream() is true for the returned file
+ ** descriptor, then we're done.
+ */
+
+ if (path)
+ {
+ /*
+ ** Verify that the spooler is running and that the
+ ** <path> identifies a pipe.
+ ** This prevents us from getting hung in the open
+ ** and from thinking the <path> is a non-streams pipe.
+ */
+ if (checklock() == -1)
+ return(NULL);
+Again: if (stat(path, &stbuf) == -1)
+ return(NULL);
+ if ((stbuf.st_mode & S_IFMT) != S_IFIFO) {
+ if (count++ > 20)
+ return (NULL);
+ sleep(1);
+ goto Again;
+ }
+
+ if ((fd = Open(path, O_RDWR, 0)) == -1)
+ if ((fd = Open(path, O_WRONLY, 0)) == -1)
+ return(NULL);
+ else
+ wronly = 1;
+
+ if (isastream(fd) && !wronly)
+ {
+#if defined(NOCONNLD)
+ int fds[2];
+
+ if (pipe(fds) != 0)
+ return(NULL);
+
+ if (ioctl(fd, I_SENDFD, fds[1]) != 0)
+ return(NULL);
+
+ (void)_Close(fd);
+
+ fd = fds[0];
+ (void)_Close(fds[1]);
+#endif
+
+ if ((md = (MESG *)Malloc(MDSIZE)) == NULL)
+ {
+ errno = ENOMEM;
+ return(NULL);
+ }
+
+ memset(md, 0, sizeof (MESG));
+ md->gid = getgid();
+ md->on_discon = NULL;
+ md->readfd = fd;
+ md->state = MDS_IDLE;
+ md->type = MD_STREAM;
+ md->uid = getuid();
+ md->writefd = fd;
+
+ ResetFifoBuffer (md->readfd);
+ return(md);
+ }
+
+ return(NULL);
+ }
+
+ if (id1 > 0 && id2 > 0)
+ {
+ if ((md = (MESG *)Malloc(MDSIZE)) == NULL)
+ {
+ errno = ENOMEM;
+ return(NULL);
+ }
+
+ memset(md, 0, sizeof (MESG));
+ md->gid = getgid();
+ md->on_discon = NULL;
+ md->readfd = id1;
+ md->state = MDS_IDLE;
+ md->type = MD_BOUND;
+ md->uid = getuid();
+ md->writefd = id2;
+
+ ResetFifoBuffer (md->readfd);
+
+ return(md);
+ }
+
+ errno = EINVAL;
+ return(NULL);
+}
+
+#if defined(__STDC__)
+static int checklock ( void )
+#else
+static int checklock()
+#endif
+{
+ int fd;
+ struct flock lock;
+
+ if ((fd = Open(Lp_Schedlock, O_RDONLY, 0666)) == -1)
+ return (-1);
+
+ /*
+ * Now, we try to read-lock the lock file. This can only succeed if
+ * the Spooler (lpsched) is down.
+ */
+
+ lock.l_type = F_RDLCK;
+ lock.l_whence = 0;
+ lock.l_start = 0;
+ lock.l_len = 0; /* till end of file */
+
+ if (Fcntl(fd, F_SETLK, &lock) != -1 || errno != EAGAIN)
+ {
+ (void)Close (fd);
+ return (-1);
+ }
+
+ /*
+ * We can get here only when fcntl() == -1 && errno == EAGAIN,
+ * i.e., spooler (lpsched) is running.
+ */
+
+ (void)Close (fd);
+
+ return(0);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mcreate.c b/usr/src/cmd/lp/lib/msgs/mcreate.c
new file mode 100644
index 0000000000..445d9e24a7
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mcreate.c
@@ -0,0 +1,82 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1996 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+
+# include <unistd.h>
+# include <string.h>
+# include <stropts.h>
+# include <errno.h>
+# include <stdlib.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+#if defined(__STDC__)
+MESG * mcreate ( char * path )
+#else
+MESG * mcreate (path)
+ char *path;
+#endif
+{
+ int fds[2];
+ MESG *md;
+
+ if (pipe(fds) != 0)
+ return(NULL);
+
+#if !defined(NOCONNLD)
+ if (ioctl(fds[1], I_PUSH, "connld") != 0)
+ return(NULL);
+#endif
+
+ if (fattach(fds[1], path) != 0)
+ return(NULL);
+
+ if ((md = (MESG *)Malloc(MDSIZE)) == NULL)
+ return(NULL);
+
+ memset(md, 0, sizeof (MESG));
+ md->admin = 1;
+ md->file = Strdup(path);
+ md->gid = getgid();
+ md->readfd = fds[0];
+ md->state = MDS_IDLE;
+ md->type = MD_MASTER;
+ md->uid = getuid();
+#if 1
+ md->writefd = fds[1];
+#else
+ md->writefd = fds[0];
+ close(fds[1]);
+#endif
+
+ return(md);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mdestroy.c b/usr/src/cmd/lp/lib/msgs/mdestroy.c
new file mode 100644
index 0000000000..eb029bb170
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mdestroy.c
@@ -0,0 +1,73 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1996 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+# include <string.h>
+# include <stropts.h>
+# include <errno.h>
+# include <stdlib.h>
+# include <unistd.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+int mdestroy(MESG *md)
+{
+ struct pollfd pfd;
+ struct strrecvfd recbuf;
+
+ if (!md || md->type != MD_MASTER || md->file == NULL) {
+ errno = EINVAL;
+ return(-1);
+ }
+
+ if (fdetach(md->file) != 0)
+ return(-1);
+
+ pfd.fd = md->readfd;
+ pfd.events = POLLIN;
+ while (poll(&pfd, 1, 500) > 0) {
+ if (ioctl(md->readfd, I_RECVFD, &recbuf) == 0)
+ close(recbuf.fd);
+ }
+
+ /*
+ * Pop connld module
+ */
+ if (ioctl(md->writefd, I_POP, 0) != 0)
+ return(-1);
+
+ Free(md->file);
+ md->file = NULL;
+
+ (void) mdisconnect(md);
+
+ return(0);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mdisconnect.c b/usr/src/cmd/lp/lib/msgs/mdisconnect.c
new file mode 100644
index 0000000000..b2230ccf5a
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mdisconnect.c
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* LINTLIBRARY */
+
+# include <stropts.h>
+# include <errno.h>
+# include <stdlib.h>
+
+#include "lp.h"
+#include "msgs.h"
+
+#if defined(__STDC__)
+static void disconnect3_2 ( MESG * );
+#else
+static void disconnect3_2();
+#endif
+
+#if defined(__STDC__)
+int mdisconnect ( MESG * md )
+#else
+int mdisconnect (md)
+ MESG *md;
+#endif
+{
+ int retvalue = 0;
+ void (**fnp)();
+ MQUE *p;
+
+ if (!md)
+ {
+ errno = ENXIO;
+ return(-1);
+ }
+
+ switch(md->type)
+ {
+ case MD_CHILD:
+ case MD_STREAM:
+ case MD_BOUND:
+ if (md->writefd >= 0)
+ (void) Close(md->writefd);
+ if (md->readfd >= 0)
+ (void) Close(md->readfd);
+ break;
+
+ case MD_USR_FIFO:
+ case MD_SYS_FIFO:
+ disconnect3_2(md);
+ break;
+ }
+
+ if (md->on_discon)
+ {
+ for (fnp = md->on_discon; *fnp; fnp++)
+ {
+ (*fnp)(md);
+ retvalue++;
+ }
+ Free(md->on_discon);
+ }
+
+ if (md->file)
+ Free(md->file);
+
+ if (md->mque)
+ {
+ while ((p = md->mque) != NULL)
+ {
+ md->mque = p->next;
+ Free(p->dat->buf);
+ Free(p->dat);
+ Free(p);
+ }
+ }
+ Free(md);
+
+ return(retvalue);
+}
+
+int discon3_2_is_running = 0;
+
+#if defined(__STDC__)
+static void disconnect3_2 ( MESG * md )
+#else
+static void disconnect3_2 (md)
+ MESG *md;
+#endif
+{
+ char *msgbuf = 0;
+ int size;
+
+ discon3_2_is_running = 1;
+
+ if (md->writefd != -1)
+ {
+ size = putmessage((char *)0, S_GOODBYE);
+ if ((msgbuf = (char *)Malloc((unsigned)size)))
+ {
+ (void)putmessage (msgbuf, S_GOODBYE);
+ (void)msend (msgbuf);
+ Free (msgbuf);
+ }
+
+ (void) Close (md->writefd);
+ }
+
+ if (md->readfd != -1)
+ (void) Close (md->readfd);
+
+ if (md->file)
+ {
+ (void) Unlink (md->file);
+ Free (md->file);
+ }
+
+ discon3_2_is_running = 0;
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mgetputm.c b/usr/src/cmd/lp/lib/msgs/mgetputm.c
new file mode 100644
index 0000000000..0322087751
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mgetputm.c
@@ -0,0 +1,186 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1994 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+
+# include <unistd.h>
+# include <errno.h>
+# include <stdlib.h>
+
+#if defined(__STDC__)
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+# include "lp.h"
+# include "msgs.h"
+
+
+/*
+** Size and pointer for mgetm()
+*/
+static int MBGSize = 0;
+static char * MBG = NULL;
+
+/*
+** Size and pointer for mputm()
+*/
+static int MBPSize = 0;
+static char * MBP = NULL;
+
+int peek3_2();
+
+#if defined(__STDC__)
+int mgetm ( MESG * md, int type, ... )
+#else
+int mgetm (md, type, va_alist)
+ MESG *md;
+ int type;
+ va_dcl
+#endif
+{
+ va_list vp;
+ int ret;
+ int needsize;
+
+#if defined(__STDC__)
+ va_start(vp, type);
+#else
+ va_start(vp);
+#endif
+
+ needsize = mpeek(md);
+ if (needsize <=0 || needsize > MSGMAX)
+ needsize = MSGMAX;
+ if (needsize > MBGSize)
+ {
+ if (MBG)
+ Free(MBG);
+ if ((MBG = (char *)Malloc(needsize)) == NULL)
+ {
+ MBGSize = 0;
+ MBG = NULL;
+ errno = ENOMEM;
+ return(-1);
+ }
+ MBGSize = needsize;
+ }
+ if (mread(md, MBG, MBGSize) < 0)
+ return(-1);
+
+ ret = _getmessage(MBG, type, vp);
+
+ va_end(vp);
+
+ return(ret);
+}
+
+#if defined(__STDC__)
+int mputm ( MESG * md, int type, ... )
+#else
+int mputm (md, type, va_alist)
+ MESG *md;
+ int type;
+ va_dcl
+#endif
+{
+ va_list vp;
+ int needsize;
+
+#if defined(__STDC__)
+ va_start(vp, type);
+#else
+ va_start(vp);
+#endif
+ needsize = _putmessage(NULL, type, vp);
+ va_end(vp);
+ if (needsize <= 0)
+ return(-1);
+
+ if (needsize > MBPSize)
+ {
+ if (MBP)
+ Free(MBP);
+ if ((MBP = (char *)Malloc(needsize)) == NULL)
+ {
+ MBPSize = 0;
+ MBP = NULL;
+ errno = ENOMEM;
+ return(-1);
+ }
+ MBPSize = needsize;
+ }
+
+#if defined(__STDC__)
+ va_start(vp, type);
+#else
+ va_start(vp);
+#endif
+ needsize = _putmessage(MBP, type, vp);
+ va_end(vp);
+ if (needsize <= 0)
+ return(-1);
+
+
+ return(mwrite(md, MBP));
+}
+
+#if defined(__STDC__)
+void __mbfree ( void )
+#else
+void __mbfree ()
+#endif
+{
+ MBGSize = MBPSize = 0;
+ if (MBG)
+ Free (MBG);
+ if (MBP)
+ Free (MBP);
+ MBG = MBP = NULL;
+}
+
+#if defined(__STDC__)
+short mpeek ( MESG * md )
+#else
+short mpeek (md)
+ MESG *md;
+#endif
+{
+ int size;
+
+ if (md->type == MD_USR_FIFO || md->type == MD_SYS_FIFO)
+ return(peek3_2(md->readfd) - EXCESS_3_2_LEN);
+
+ if (ioctl(md->readfd, I_NREAD, &size))
+ return((short)size);
+
+ return(-1);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mlisten.c b/usr/src/cmd/lp/lib/msgs/mlisten.c
new file mode 100644
index 0000000000..b792801ccf
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mlisten.c
@@ -0,0 +1,555 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.9 */
+# include <unistd.h>
+# include <stdlib.h>
+# include <string.h>
+# include <poll.h>
+# include <stropts.h>
+# include <fcntl.h>
+# include <errno.h>
+#include <syslog.h>
+#include <user_attr.h>
+#include <secdb.h>
+#include <pwd.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+#define TURN_ON(X,F) (void)Fcntl(X, F_SETFL, (Fcntl(X, F_GETFL, 0)|(F)))
+
+static int NumEvents = 0;
+static int NumCons = 0;
+static int ConsSize= 0;
+static int NumNewCons = 0;
+static MESG ** Connections = NULL;
+static struct pollfd * PollFdList = NULL;
+
+int
+mlisteninit(MESG * md)
+{
+ if (md == NULL)
+ {
+ errno = EINVAL;
+ return(-1);
+ }
+
+ if (ConsSize > 0)
+ {
+ errno = EBUSY;
+ return(-1);
+ }
+
+ ConsSize = 20;
+ Connections = (MESG **) Malloc(ConsSize * MDSIZE);
+ PollFdList = (struct pollfd*) Malloc(ConsSize * sizeof(struct pollfd));
+ if (Connections == NULL || PollFdList == NULL)
+ {
+ errno = ENOMEM;
+ return(-1);
+ }
+ Connections[0] = md;
+ PollFdList[0].fd = md->readfd;
+ PollFdList[0].events = POLLIN;
+ PollFdList[0].revents = 0;
+ NumCons = 1;
+ return(0);
+}
+
+int
+mlistenadd(MESG * md, short events)
+{
+ int slack;
+ struct pollfd * fdp;
+
+ /*
+ ** See if we have room in the connection table.
+ ** Realloc(3) the table if the number of connections
+ ** changes by more than 20.
+ */
+
+ slack = ConsSize - (NumCons + NumNewCons + 1);
+
+ if (slack < 0)
+ {
+ ConsSize += 20;
+ Connections = (MESG **) Realloc(Connections, ConsSize * MDSIZE);
+ PollFdList = (struct pollfd*) Realloc(PollFdList, ConsSize * sizeof(struct pollfd));
+ if (Connections == NULL || PollFdList == NULL)
+ {
+ errno = ENOMEM;
+ return(-1);
+ }
+ }
+
+ if (slack > 20)
+ {
+ ConsSize -= 20;
+ Connections = (MESG **) Realloc(Connections, ConsSize * MDSIZE);
+ PollFdList = (struct pollfd*) Realloc(PollFdList, ConsSize * sizeof(struct pollfd));
+ if (Connections == NULL || PollFdList == NULL)
+ {
+ errno = ENOMEM;
+ return(-1);
+ }
+ }
+
+ fdp = PollFdList + (NumCons + NumNewCons);
+ fdp->fd = md->readfd;
+ fdp->events = events;
+ fdp->revents = 0;
+
+ /*
+ ** Now add the entry to the connection table
+ ** NumCons will be updated above.
+ */
+ Connections[NumCons + NumNewCons++] = md;
+ return(0);
+}
+
+MESG *
+mlistenreset ( void ) /* funcdef */
+{
+ int x;
+ MESG * md;
+
+ if (ConsSize == 0)
+ return(NULL);
+
+ ConsSize = 0;
+
+ for (x = 1; x < NumCons; x++)
+ (void) mdisconnect(Connections[x]);
+
+ md = Connections[0];
+
+ Free(Connections);
+ Free(PollFdList);
+
+ Connections = NULL;
+ PollFdList = NULL;
+ NumCons = 0;
+ NumNewCons = 0;
+ NumEvents = 0;
+ return(md);
+}
+
+MESG *
+mlisten()
+{
+ extern uid_t Lp_Uid;
+
+ MESG * mdp;
+ MESG * md;
+ MQUE * p;
+ int flag = 0;
+ int disconacts;
+ int x;
+ int y;
+ struct pollfd * fdp;
+ struct strrecvfd recbuf;
+#if defined(NOCONNLD)
+ struct strbuf ctl;
+ char cbuff[MSGMAX];
+#endif
+
+#if defined(NOCONNLD)
+ /*
+ ** Set up buffer for receiving messages.
+ */
+ ctl.buf = cbuff;
+ ctl.maxlen = sizeof (cbuff);
+#endif
+
+ /*
+ ** This loop exists to return control to poll after the
+ ** result of poll yeilds no new connections or serviceable
+ ** messages.
+ */
+ for (;;)
+ {
+ /*
+ ** If there are no unserviced events pending, call poll(2)
+ ** and wait for a message or connection.
+ ** NumEvents may be -1 in the event of an interrupt, hence
+ ** <= 0
+ */
+ if (NumEvents <= 0)
+ {
+ /*
+ ** Add new connections, if any, reset connection counter
+ */
+ NumCons += NumNewCons;
+ NumNewCons = 0;
+
+ if (NumCons <= 0)
+ {
+ errno = EINTR;
+ return(NULL);
+ }
+
+ /*
+ ** Scan the connection table and remove any holes
+ */
+ for (x = 0; x < NumCons; x++)
+ {
+ mdp = Connections[x];
+
+ /*
+ ** Disconnected, clear the node and compress the
+ ** tables. If the disconnect called any
+ ** on_discon functions (disconacts > 0), return
+ ** because there may be something to clean up.
+ ** Finally, decrement <x> so that the next node
+ ** doesn't get missed.
+ */
+ if (mdp->readfd == -1)
+ {
+ disconacts = mdisconnect(mdp);
+ NumCons--;
+ for (y = x; y < (NumCons + NumNewCons); y++)
+ {
+ Connections[y] = Connections[y + 1];
+ PollFdList[y] = PollFdList[y + 1];
+ }
+ if (disconacts > 0)
+ {
+ errno = EINTR;
+ return(NULL);
+ }
+ else
+ x--;
+ } else {
+ /*
+ * We are in "mlisten", POLLIN is always set. We'll look
+ * at POLLOUT possibility when mque is non-NULL.
+ */
+ PollFdList[x].events = POLLIN;
+ if (mdp->mque)
+ PollFdList[x].events |= POLLOUT;
+ }
+ }
+
+ /*
+ ** Wait for a message or a connection.
+ ** This call may be interrupted by alarms used
+ ** elsewhere, so if poll fails, return NULL and
+ ** set errno to EAGAIN.
+ */
+ if ((NumEvents = poll(PollFdList, NumCons, -1)) < 0)
+ {
+ errno = EAGAIN;
+ return(NULL);
+ }
+ }
+
+ for (x = 0; x < NumCons; x++)
+ {
+ mdp = Connections[x];
+ fdp = PollFdList + x;
+
+ if (fdp->revents == 0)
+ continue;
+
+ switch (mdp->type) {
+ case MD_MASTER:
+ /*
+ ** Only valid revent is: POLLIN
+ */
+ if (fdp->revents != POLLIN)
+ {
+ errno = EINVAL;
+ return(NULL);
+ }
+
+ /*
+ ** Retrieve the file descriptor
+ */
+ if (ioctl(mdp->readfd, I_RECVFD, &recbuf) != 0)
+ {
+ if (errno == EINTR)
+ {
+ errno = EAGAIN;
+ return(NULL);
+ }
+ if (errno == ENXIO)
+ {
+ fdp->revents = 0;
+ NumEvents--;
+ continue;
+ }
+#if defined(NOCONNLD)
+ if (errno == EBADMSG)
+ while (Getmsg(mdp, &ctl, &ctl, &flag) >= 0);
+#endif
+ return(NULL);
+ }
+
+ TURN_ON(recbuf.fd, O_NDELAY);
+ /*
+ ** Now, create the message descriptor
+ ** and populate it with what we know.
+ */
+ if ((md = (MESG *)Malloc(MDSIZE)) == NULL)
+ {
+ errno = ENOMEM;
+ return(NULL);
+ }
+
+ memset(md, 0, sizeof (MESG));
+ md->gid = recbuf.gid;
+ md->readfd = md->writefd = recbuf.fd;
+ md->state = MDS_IDLE;
+ md->type = MD_UNKNOWN;
+ md->uid = recbuf.uid;
+
+ /*
+ * Determine if a print administrator is contacting lpsched.
+ * currently, root, lp and users with the "solaris.print.admin"
+ * privilege are print administrators
+ */
+ md->admin = (md->uid == 0 || md->uid == Lp_Uid);
+ if (md->admin == 0) {
+ struct passwd *pw = NULL;
+
+ if ((pw = getpwuid(md->uid)) != NULL)
+ md->admin = chkauthattr("solaris.print.admin",
+ pw->pw_name);
+ }
+
+ get_peer_label(md->readfd, &md->slabel);
+
+ if (mlistenadd(md, POLLIN) != 0)
+ return(NULL);
+
+ ResetFifoBuffer (md->readfd);
+ /*
+ ** Reset fdp because mlistenadd may have
+ ** realloc()ed PollFdList and changed its
+ ** physical location.
+ */
+ fdp = PollFdList + x;
+
+ /*
+ ** Clear the event that brought us here,
+ ** decrement the event counter, and get the
+ ** next event.
+ */
+ fdp->revents = 0;
+ NumEvents--;
+ break;
+
+ case MD_CHILD:
+ /*
+ ** If this connection is a child process, just
+ ** save the event and return the message descriptor
+ */
+
+ if (fdp->revents & POLLOUT) {
+ if (mdp->mque) {
+ if (mflush(mdp) < 0) {
+ syslog(LOG_DEBUG,
+ "MD_CHILD mflush failed");
+ }
+ }
+ }
+
+ if (fdp->revents & POLLIN) {
+ mdp->event = fdp->revents;
+ NumEvents--;
+ fdp->revents = 0;
+ return (mdp); /* we are in listening mode */
+ }
+
+ NumEvents--;
+ fdp->revents = 0;
+ break;
+
+ default:
+ /*
+ ** POLLNVAL means this client disconnected and
+ ** all messages have been processed.
+ */
+ if (fdp->revents & POLLNVAL) /* disconnected & no msg */
+ {
+ if (mdp->readfd >= 0) {
+ Close (mdp->readfd);
+ if (mdp->writefd == mdp->readfd)
+ mdp->writefd = -1;
+ mdp->readfd = -1;
+ }
+ fdp->revents = 0;
+ NumEvents--;
+ continue;
+ }
+
+ /*
+ ** POLLERR means an error message is on the
+ ** stream. Since this is totally unexpected,
+ ** the assumption is made that this stream will
+ ** be flagged POLLNVAL next time through poll
+ ** and will be removed at that time.
+ */
+ if (fdp->revents & POLLERR) /* uh, oh! */
+ {
+ if (mdp->readfd >= 0) {
+ Close (mdp->readfd);
+ if (mdp->writefd == mdp->readfd)
+ mdp->writefd = -1;
+ mdp->readfd = -1;
+ }
+ NumEvents--;
+ fdp->revents = 0;
+ continue;
+ }
+
+
+ /*
+ ** POLLHUP means the client aborted the call.
+ ** The client is not removed, because there may
+ ** still be messages on the stream.
+ */
+ if (fdp->revents & POLLHUP) /* disconnected */
+ {
+ NumEvents--;
+ fdp->revents = 0;
+ /*
+ * MORE: This is odd. Why are we closing the
+ * stream if there ``may still be messages''???
+ */
+ if (mdp->readfd >= 0) {
+ Close (mdp->readfd);
+ if (mdp->writefd == mdp->readfd)
+ mdp->writefd = -1;
+ mdp->readfd = -1;
+ }
+ continue;
+
+ /*
+ * MORE: Why is this here??
+ *
+ if (mdp->type == MD_SYS_FIFO)
+ (void) Close(mdp->writefd);
+
+ mdp->writefd = -1;
+
+ if (fdp->revents == POLLHUP)
+ {
+ NumEvents--;
+ fdp->revents = 0;
+ (void) Close(mdp->readfd);
+ mdp->readfd = -1;
+ continue;
+ }
+ *
+ */
+ }
+ /*
+ ** POLLOUT means that the client had a full
+ ** stream and messages became backlogged and
+ ** now the stream is empty. So the queued msgs
+ ** are sent with putmsg(2)
+ */
+ if (fdp->revents & POLLOUT)
+ {
+ if (mdp->mque == NULL)
+ {
+ NumEvents--;
+ fdp->revents = 0;
+ continue;
+ }
+ while (mdp->mque) {
+ if (Putmsg(mdp, NULL, mdp->mque->dat, 0))
+ break; /* failed for some reason */
+ p = mdp->mque;
+ mdp->mque = p->next;
+ Free(p->dat->buf);
+ Free(p->dat);
+ Free(p);
+ }
+ NumEvents--;
+ fdp->revents = 0;
+ continue;
+ }
+
+ /*
+ ** POLLIN means that there is a message on the
+ ** stream.
+ ** Return the message descriptor to the caller
+ ** so that the message may be received and
+ ** processed.
+ */
+ if (fdp->revents & POLLIN) /* got a message */
+ {
+ NumEvents--;
+ mdp->event = fdp->revents;
+ fdp->revents = 0;
+ if (mdp->type == MD_UNKNOWN)
+ mdp->type = MD_STREAM;
+ return(mdp);
+ }
+ break;
+ }
+ }
+ }
+}
+
+# define VOID_FUNC_PTR void (*)()
+# define PTR_TO_VOID_FUNC_PTR void (**)()
+
+int
+mon_discon(MESG * md, void (*fn)())
+{
+ int size = 2;
+ void (**fnp) ();
+
+ if (md->on_discon)
+ {
+ for (fnp = md->on_discon; *fnp; fnp++)
+ size++;
+ if ((md->on_discon = (PTR_TO_VOID_FUNC_PTR) Realloc (md->on_discon, size * sizeof(VOID_FUNC_PTR))) == NULL)
+ {
+ errno = ENOMEM;
+ return(-1);
+ }
+ }
+ else
+ if ((md->on_discon = (PTR_TO_VOID_FUNC_PTR) Malloc (size * sizeof(VOID_FUNC_PTR))) == NULL)
+ {
+ errno = ENOMEM;
+ return(-1);
+ }
+
+ size--;
+ md->on_discon[size] = NULL;
+ size--;
+ md->on_discon[size] = fn;
+ return(0);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mneeds.c b/usr/src/cmd/lp/lib/msgs/mneeds.c
new file mode 100644
index 0000000000..a1f48b78bb
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mneeds.c
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/* LINTLIBRARY */
+
+/**
+ ** mneeds() - RETURN NUMBER OF FILE DESCRIPTORS NEEDED BY mopen()
+ **/
+
+int mneeds ( )
+{
+ /*
+ * This is the expected number of file descriptors needed.
+ */
+ return (4);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mopen.c b/usr/src/cmd/lp/lib/msgs/mopen.c
new file mode 100644
index 0000000000..8ae14e27cc
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mopen.c
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* LINTLIBRARY */
+
+# include <errno.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+
+MESG *lp_Md = 0;
+
+/*
+** mopen() - OPEN A MESSAGE PATH
+*/
+
+int
+mopen ()
+{
+ if (lp_Md != NULL)
+ {
+ errno = EEXIST;
+ return (-1);
+ }
+
+ if ((lp_Md = mconnect(Lp_FIFO, 0, 0)) == NULL)
+ return(-1);
+
+ return(0);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mread.c b/usr/src/cmd/lp/lib/msgs/mread.c
new file mode 100644
index 0000000000..754b884bbd
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mread.c
@@ -0,0 +1,124 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* LINTLIBRARY */
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stropts.h>
+
+#include "lp.h"
+#include "msgs.h"
+
+extern int Lp_prio_msg;
+
+/*
+** Function: int mread( MESG *, char *, int)
+** Args: message descriptor
+** message buffer (var)
+** buffer size
+** Return: The size of the message in message buffer.
+** or -1 on error. Possible errnos are:
+** EINVAL Bad value for md or msgbuf.
+** E2BIG Not enough space for message.
+** EPIPE Far end dropped the connection.
+** ENOMSG No valid message available on fifo.
+**
+** mread examines message descriptor and either calls read3_2
+** to read 3.2 HPI messages or getmsg(2) to read 4.0 HPI messages.
+** If a message is read, it is returned in message buffer.
+*/
+
+#if defined(__STDC__)
+int mread ( MESG * md, char * msgbuf, int size )
+#else
+int mread ( md, msgbuf, size )
+MESG *md;
+char *msgbuf;
+int size;
+#endif
+{
+ int flag = 0;
+ char buff [MSGMAX];
+ struct strbuf dat;
+ struct strbuf ctl;
+
+ if (md == NULL || msgbuf == NULL)
+ {
+ errno = EINVAL;
+ return(-1);
+ }
+
+ switch(md->type)
+ {
+ case MD_CHILD:
+ case MD_STREAM:
+ case MD_BOUND:
+ if (size <= 0)
+ {
+ errno = E2BIG;
+ return(-1);
+ }
+ dat.buf = msgbuf;
+ dat.maxlen = size;
+ dat.len = 0;
+ ctl.buf = buff;
+ ctl.maxlen = sizeof (buff);
+ ctl.len = 0;
+ flag = Lp_prio_msg;
+ Lp_prio_msg = 0; /* clean this up so there are no surprises */
+
+ if (Getmsg(md, &ctl, &dat, &flag) < 0)
+ {
+ if (errno == EBADF)
+ errno = EPIPE;
+ return(-1);
+ }
+
+ if (dat.len == 0)
+ {
+ (void) Close(md->readfd);
+ return(0);
+ }
+ break;
+
+ case MD_USR_FIFO:
+ case MD_SYS_FIFO:
+ if (size < CONTROL_LEN)
+ {
+ errno = E2BIG;
+ return(-1);
+ }
+
+ if (read3_2(md, msgbuf, size) < 0)
+ return(-1);
+ break;
+ }
+
+ return((int)msize(msgbuf));
+}
diff --git a/usr/src/cmd/lp/lib/msgs/mrecv.c b/usr/src/cmd/lp/lib/msgs/mrecv.c
new file mode 100644
index 0000000000..9708cc1e61
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mrecv.c
@@ -0,0 +1,63 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.3 */
+/* LINTLIBRARY */
+# include <errno.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+extern MESG *lp_Md;
+
+/*
+** mrecv() - RECEIVE A MESSAGE
+*/
+
+int
+mrecv (msgbuf, size)
+char *msgbuf;
+int size;
+{
+ int n;
+
+ /*
+ ** Restart interrupted reads for binary compatibility.
+ */
+ do
+ n = mread(lp_Md, msgbuf, size);
+ while (n < 0 && errno == EINTR);
+
+ /*
+ ** Return EIDRM on disconnect for binary compatibility.
+ */
+ if (errno == EPIPE)
+ errno = EIDRM;
+
+ if (n <= 0)
+ return(-1);
+
+ return(getmessage(msgbuf, I_GET_TYPE));
+}
diff --git a/usr/src/cmd/lp/lib/msgs/msend.c b/usr/src/cmd/lp/lib/msgs/msend.c
new file mode 100644
index 0000000000..63cdb30a35
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/msend.c
@@ -0,0 +1,69 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+/* LINTLIBRARY */
+# include <errno.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+extern MESG *lp_Md;
+extern int discon3_2_is_running;
+
+/*
+** msend() - SEND A MESSAGE VIA FIFOS
+*/
+
+#if defined(__STDC__)
+int msend ( char * msgbuf )
+#else
+int msend (msgbuf)
+ char *msgbuf;
+#endif
+{
+ int rval;
+
+ do
+ {
+ if ((rval = mwrite(lp_Md, msgbuf)) < 0)
+ {
+ /*
+ ** "mclose()" will try to say goodbye to the Spooler,
+ ** and that, of course, will fail. But we'll call
+ ** "mclose()" anyway, for the other cleanup it does.
+ */
+ if (errno == EPIPE)
+ {
+ if (!discon3_2_is_running)
+ (void)mclose ();
+ errno = EIDRM;
+ }
+ }
+ }
+ while (rval < 0 && errno == EINTR);
+
+ return(rval);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/msgfmts.c b/usr/src/cmd/lp/lib/msgs/msgfmts.c
new file mode 100644
index 0000000000..100f0b9730
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/msgfmts.c
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* LINTLIBRARY */
+
+char *_lp_msg_fmts[] =
+{
+ "", /* 0 - R_BAD_MESSAGE */
+ "HSS", /* 1 - S_NEW_QUEUE */
+ "H", /* 2 - R_NEW_QUEUE */
+ "H", /* 3 - S_ALLOC_FILES */
+ "HS", /* 4 - R_ALLOC_FILES */
+ "S", /* 5 - S_PRINT_REQUEST */
+ "HSL", /* 6 - R_PRINT_REQUEST */
+ "S", /* 7 - S_START_CHANGE_REQUEST */
+ "HS", /* 8 - R_START_CHANGE_REQUEST */
+ "S", /* 9 - S_END_CHANGE_REQUEST */
+ "HL", /* 10 - R_END_CHANGE_REQUEST */
+ "S", /* 11 - S_CANCEL_REQUEST */
+ "H", /* 12 - R_CANCEL_REQUEST */
+ "SSSSS", /* 13 - S_INQUIRE_REQUEST */
+ "HSSSLLHSSSS", /* 14 - R_INQUIRE_REQUEST */
+ "S", /* 15 - S_LOAD_PRINTER */
+ "H", /* 16 - R_LOAD_PRINTER */
+ "S", /* 17 - S_UNLOAD_PRINTER */
+ "H", /* 18 - R_UNLOAD_PRINTER */
+ "S", /* 19 - S_INQUIRE_PRINTER_STATUS */
+ "HSSSSSHSLL", /* 20 - R_INQUIRE_PRINTER_STATUS */
+ "S", /* 21 - S_LOAD_CLASS */
+ "H", /* 22 - R_LOAD_CLASS */
+ "S", /* 23 - S_UNLOAD_CLASS */
+ "H", /* 24 - R_UNLOAD_CLASS */
+ "S", /* 25 - S_INQUIRE_CLASS */
+ "HSHSL", /* 26 - R_INQUIRE_CLASS */
+ "SSS", /* 27 - S_MOUNT */
+ "H", /* 28 - R_MOUNT */
+ "SSS", /* 29 - S_UNMOUNT */
+ "H", /* 30 - R_UNMOUNT */
+ "SS", /* 31 - S_MOVE_REQUEST */
+ "HL", /* 32 - R_MOVE_REQUEST */
+ "SS", /* 33 - S_MOVE_DEST */
+ "HSH", /* 34 - R_MOVE_DEST */
+ "S", /* 35 - S_ACCEPT_DEST */
+ "H", /* 36 - R_ACCEPT_DEST */
+ "SS", /* 37 - S_REJECT_DEST */
+ "H", /* 38 - R_REJECT_DEST */
+ "S", /* 39 - S_ENABLE_DEST */
+ "H", /* 40 - R_ENABLE_DEST */
+ "SSH", /* 41 - S_DISABLE_DEST */
+ "HS", /* 42 - R_DISABLE_DEST */
+ "", /* 43 - S_LOAD_FILTER_TABLE */
+ "H", /* 44 - R_LOAD_FILTER_TABLE */
+ "", /* 45 - S_UNLOAD_FILTER_TABLE */
+ "H", /* 46 - R_UNLOAD_FILTER_TABLE */
+ "S", /* 47 - S_LOAD_PRINTWHEEL */
+ "H", /* 48 - R_LOAD_PRINTWHEEL */
+ "S", /* 49 - S_UNLOAD_PRINTWHEEL */
+ "H", /* 50 - R_UNLOAD_PRINTWHEEL */
+ "", /* 51 - S_LOAD_USER_FILE */
+ "H", /* 52 - R_LOAD_USER_FILE */
+ "", /* 53 - S_UNLOAD_USER_FILE */
+ "H", /* 54 - R_UNLOAD_USER_FILE */
+ "S", /* 55 - S_LOAD_FORM */
+ "H", /* 56 - R_LOAD_FORM */
+ "S", /* 57 - S_UNLOAD_FORM */
+ "H", /* 58 - R_UNLOAD_FORM */
+ "S", /* 59 - S_GETSTATUS */
+ "S", /* 60 - R_GETSTATUS */
+ "SH", /* 61 - S_QUIET_ALERT */
+ "H", /* 62 - R_QUIET_ALERT */
+ "SLS", /* 63 - S_SEND_FAULT */
+ "H", /* 64 - R_SEND_FAULT */
+ "H", /* 65 - S_SHUTDOWN */
+ "H", /* 66 - R_SHUTDOWN */
+ "", /* 67 - S_GOODBYE */
+ "LHH", /* 68 - S_CHILD_DONE */
+ "", /* 69 - I_GET_TYPE */
+ "", /* 70 - I_QUEUE_CHK */
+ "SH", /* 71 - R_CONNECT */
+ "SSHH", /* 72 - S_GET_STATUS */
+ "HSHH", /* 73 - R_GET_STATUS */
+ "HSSSSS", /* 74 - S_INQUIRE_REQUEST_RANK */
+ "HSSSLLHSSSHS", /* 75 - R_INQUIRE_REQUEST_RANK */
+ "SSS", /* 76 - S_CANCEL */
+ "HLS", /* 77 - R_CANCEL */
+ "S", /* 78 - S_NEW_CHILD */
+ "SSH", /* 79 - R_NEW_CHILD */
+ "SHSD", /* 80 - S_SEND_JOB */
+ "SHD", /* 81 - R_SEND_JOB */
+ "HSS", /* 82 - S_JOB_COMPLETED */
+ "H", /* 83 - R_JOB_COMPLETED */
+ "S", /* 84 - S_INQUIRE_REMOTE_PRINTER */
+/* "", */ /* - the R_INQUIRE_REMOTE_STATUS uses format 20 */
+ "H", /* 85 - S_CHILD_SYNC */
+ "S", /* 86 - S_LOAD_SYSTEM */
+ "H", /* 87 - R_LOAD_SYSTEM */
+ "S", /* 88 - S_UNLOAD_SYSTEM */
+ "H", /* 89 - R_UNLOAD_SYSTEM */
+ "SLS", /* 90 - S_CLEAR_FAULT */
+ "H", /* 91 - R_CLEAR_FAULT */
+ "SSSH", /* 92 - S_MOUNT_TRAY */
+ "H", /* 93 - R_MOUNT_TRAY */
+ "SSSH", /* 94 - S_UNMOUNT_TRAY */
+ "H", /* 95 - R_UNMOUNT_TRAY */
+ "SH", /* 96 - S_MAX_TRAYS */
+ "H", /* 97 - R_MAX_TRAY */
+ "SHSHH", /* 98 - S_PAPER_CHANGED */
+ "H", /* 99 - R_PAPER_CHANGED */
+ "S", /* 100 - S_PAPER_ALLOWED */
+ "HSS", /* 101 - R_PAPER_ALLOWED */
+ "", /* 102 - S_PASS_PEER_CONNECTION */
+ "H", /* 103 - R_PASS_PEER_CONNECTION */
+ 0,
+};
diff --git a/usr/src/cmd/lp/lib/msgs/mwrite.c b/usr/src/cmd/lp/lib/msgs/mwrite.c
new file mode 100644
index 0000000000..b19a4bbb68
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/mwrite.c
@@ -0,0 +1,209 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+/* LINTLIBRARY */
+
+# include <errno.h>
+# include <string.h>
+# include <stropts.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+int Lp_prio_msg = 0;
+
+static int _mwrite ( MESG * md , char * msgbuf , int );
+
+/*
+ * mflush()
+ * return 0
+ * if it successfully writes all the queued message(s), or
+ * if some of them (errno is EAGAIN in this case).
+ * return -1 (with errno) when it failed.
+ */
+
+int
+mflush(MESG *md)
+{
+ MQUE *p;
+
+ errno = 0;
+ if (md == NULL || md->mque == NULL) {
+ errno = ENXIO;
+ return (-1);
+ }
+
+ while ((p = md->mque) != NULL) {
+ if (_mwrite(md, p->dat->buf, p->dat->len) != 0)
+ return (errno == EAGAIN ? 0 : -1);
+
+ /* mwrite successful, get the next and free this entry */
+ md->mque = p->next;
+ Free(p->dat->buf);
+ Free(p->dat);
+ Free(p);
+ }
+
+ return (0);
+}
+
+/*
+ * mwrite()
+ * return 0
+ * if it successfully writes the messages, or
+ * if it has been queued (errno is EAGAIN in this case)
+ * and md->mque is updated.
+ * return -1 (with errno) when it failed.
+ */
+
+int mwrite ( MESG * md, char * msgbuf )
+{
+ short size;
+ MQUE * p;
+ MQUE * q;
+
+ errno = 0;
+ if (md == NULL)
+ {
+ errno = ENXIO;
+ return(-1);
+ }
+ if (msgbuf == NULL)
+ {
+ errno = EINVAL;
+ return(-1);
+ }
+
+ size = stoh(msgbuf);
+
+ if (LAST_MESSAGE < stoh(msgbuf + MESG_TYPE))
+ {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (md->mque)
+ goto queue; /* if there is a queue already, try to write all */
+
+ if (_mwrite(md, msgbuf, size) == 0)
+ return(0);
+
+ if (errno != EAGAIN)
+ return(-1);
+
+ /*
+ * fall through to queue the messages that cannot be sent now.
+ */
+
+queue:
+ if ((p = (MQUE *)Malloc(sizeof(MQUE))) == NULL
+ || (p->dat = (struct strbuf *)Malloc(sizeof(struct strbuf))) == NULL
+ || (p->dat->buf = (char *)Malloc(size)) == NULL)
+ {
+ errno = ENOMEM;
+ return(-1);
+ }
+ (void) memcpy(p->dat->buf, msgbuf, size);
+ p->dat->len = size;
+ p->next = 0;
+
+ if ((q = md->mque) != NULL)
+ {
+ /* insert the new one to tail */
+ while (q->next)
+ q = q->next;
+ q->next = p;
+
+ while ((p = md->mque) != NULL)
+ {
+ if (_mwrite(md, p->dat->buf, p->dat->len) != 0) {
+ return (errno == EAGAIN ? 0 : -1);
+ }
+
+ /* mwrite successful, get the next and free this entry */
+ md->mque = p->next;
+ Free(p->dat->buf);
+ Free(p->dat);
+ Free(p);
+ }
+ }
+ else
+ md->mque = p;
+
+ return(0);
+}
+
+int _mwrite ( MESG * md, char * msgbuf , int size )
+{
+ int flag = 0;
+ struct strbuf ctl;
+ struct strbuf dat;
+
+ switch (md->type)
+ {
+ case MD_CHILD:
+ case MD_STREAM:
+ case MD_BOUND:
+ if (size <= 0 || size > MSGMAX)
+ {
+ errno = EINVAL;
+ return(-1);
+ }
+
+ ctl.buf = "xyzzy";
+ ctl.maxlen = ctl.len = strlen(ctl.buf)+1;
+ dat.buf = msgbuf;
+ dat.maxlen = dat.len = size;
+ flag = Lp_prio_msg;
+ Lp_prio_msg = 0; /* clean this up so there are no surprises */
+
+ if (Putmsg(md, &ctl, &dat, flag) == 0)
+ return(0);
+ return(-1);
+
+ case MD_SYS_FIFO:
+ case MD_USR_FIFO:
+ switch (write3_2(md, msgbuf, size))
+ {
+ case -1:
+ return(-1);
+ case 0:
+ break;
+ default:
+ return(0);
+ }
+ break;
+
+ default:
+ errno = EINVAL;
+ return(-1);
+ }
+ return 0;
+}
diff --git a/usr/src/cmd/lp/lib/msgs/putmessage.c b/usr/src/cmd/lp/lib/msgs/putmessage.c
new file mode 100644
index 0000000000..0c50487c21
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/putmessage.c
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+/* LINTLIBRARY */
+
+#if defined(__STDC__)
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+/* VARARGS */
+#if defined(__STDC__)
+int putmessage(char * buf, short type, ... )
+#else
+int putmessage(buf, type, va_alist)
+ char *buf;
+ short type;
+ va_dcl
+#endif
+{
+ int size;
+ va_list arg;
+ int _putmessage();
+
+#if defined(__STDC__)
+ va_start(arg, type);
+#else
+ va_start(arg);
+#endif
+
+ size = _putmessage(buf, type, arg);
+ va_end(arg);
+ return(size);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/read_fifo.c b/usr/src/cmd/lp/lib/msgs/read_fifo.c
new file mode 100644
index 0000000000..c30e39ba97
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/read_fifo.c
@@ -0,0 +1,366 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+
+# include <errno.h>
+# include <string.h>
+#include <syslog.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+extern char Resync[];
+extern char Endsync[];
+static int Had_Full_Buffer = 1;
+int Garbage_Bytes = 0;
+int Garbage_Messages= 0;
+
+static int _buffer(int);
+
+/*
+** A real message is written in one piece, and the write
+** is atomic. Thus, even if the O_NDELAY flag is set,
+** if we read part of the real message, we can continue
+** to read the rest of it in as many steps as we want
+** (up to the size of the message, of course!) without
+** UNIX returning 0 because no data is available.
+** So, a real message doesn't have to be read in one piece,
+** which is good since we don't know how much to read!
+**
+** Fake messages, or improperly written messages, don't
+** have this nice property.
+**
+** INTERRUPTED READS:
+**
+** If a signal occurs during an attempted read, we can exit.
+** The caller can retry the read and we will correctly restart
+** it. The correctness of this assertion can be seen by noticing
+** that at the beginning of each READ below, we can go back
+** to the first statement executed (the first READ below)
+** and correctly reexecute the code.
+**
+** If the last writer closed the fifo, we'll read 0 bytes
+** (at least on the subsequent read). If we were in the
+** middle of reading a message, we were reading a bogus
+** message (but see below).
+**
+** If we read less than we expect, it's because we were
+** reading a fake message (but see below).
+**
+** HOWEVER: In the last two cases, we may have ONE OR MORE
+** REAL MESSAGES snuggled in amongst the trash!
+**
+** All this verbal rambling is preface to let you understand why we
+** buffer the data (which is a shame, but necessary).
+*/
+
+/*
+** As long as we get real messages, we can avoid needless function calls.
+** The SYNC argument in this macro should be set if the resynch. bytes
+** have been read--i.e. if the rest of the message is trying to be read.
+** In this case, if we had not read a full buffer last time, then we
+** must be in the middle of a bogus message.
+*/
+
+#define UNSYNCHED_READ(N) \
+ if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \
+ { \
+ switch (_buffer(fifo)) \
+ { \
+ case -1: \
+ return (-1); \
+ case 0: \
+ if (fbp->psave_end > fbp->psave) \
+ goto SyncUp; \
+ return (0); \
+ } \
+ }
+
+#define SYNCHED_READ(N) \
+ if (fbp->psave_end - fbp->psave < N || fbp->psave >= fbp->psave_end) \
+ { \
+ switch (_buffer(fifo)) \
+ { \
+ case -1: \
+ return (-1); \
+ case 0: \
+ if (fbp->psave_end > fbp->psave) \
+ goto SyncUp; \
+ return (0); \
+ } \
+ if (!Had_Full_Buffer) \
+ goto SyncUp; \
+ }
+
+/*
+** read_fifo() - READ A BUFFER WITH HEADER AND CHECKSUM
+*/
+int
+read_fifo (fifo, buf, size)
+int fifo;
+char *buf;
+unsigned int size;
+{
+ register fifobuffer_t *fbp;
+ register unsigned int real_chksum,
+ chksum,
+ real_size;
+
+ /*
+ ** Make sure we start on a message boundary. The first
+ ** line of defense is to look for the resync. bytes.
+ **
+ ** The "SyncUp" label is global to this routine (below this point)
+ ** and is called whenever we determine that we're out
+ ** of sync. with the incoming bytes.
+ */
+
+ if (!(fbp=GetFifoBuffer (fifo)))
+ return -1;
+
+ UNSYNCHED_READ (HEAD_RESYNC_LEN);
+ while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1])
+ {
+SyncUp:
+#if defined(TRACE_MESSAGES)
+ if (trace_messages)
+ syslog(LOG_DEBUG, "DISCARD %c\n", *fbp->psave);
+#endif
+ fbp->psave++;
+ Garbage_Bytes++;
+ UNSYNCHED_READ (HEAD_RESYNC_LEN);
+ }
+
+
+ /*
+ ** We're sync'd, so read the full header.
+ */
+
+ SYNCHED_READ (HEAD_LEN);
+
+
+ /*
+ ** If the header size is smaller than the minimum size for a header,
+ ** or larger than allowed, we must assume that we really aren't
+ ** synchronized.
+ */
+
+ real_size = stoh(fbp->psave + HEAD_SIZE);
+ if (real_size < CONTROL_LEN || MSGMAX < real_size)
+ {
+#if defined(TRACE_MESSAGES)
+ if (trace_messages)
+ syslog(LOG_DEBUG, "BAD SIZE\n");
+#endif
+ goto SyncUp;
+ }
+
+ /*
+ ** We have the header. Now we can finally read the rest of the
+ ** message...
+ */
+
+ SYNCHED_READ (real_size);
+
+
+ /*
+ ** ...but did we read a real message?...
+ */
+
+ if
+ (
+ *(fbp->psave + TAIL_ENDSYNC(real_size)) != Endsync[0]
+ || *(fbp->psave + TAIL_ENDSYNC(real_size) + 1) != Endsync[1]
+ )
+ {
+#if defined(TRACE_MESSAGES)
+ if (trace_messages)
+ syslog(LOG_DEBUG, "BAD ENDSYNC\n");
+#endif
+ Garbage_Messages++;
+ goto SyncUp;
+ }
+
+ chksum = stoh(fbp->psave + TAIL_CHKSUM(real_size));
+ CALC_CHKSUM (fbp->psave, real_size, real_chksum);
+ if (real_chksum != chksum)
+ {
+#if defined(TRACE_MESSAGES)
+ if (trace_messages)
+ syslog(LOG_DEBUG, "BAD CHKSUM\n");
+#endif
+ Garbage_Messages++;
+ goto SyncUp;
+ }
+
+ /*
+ ** ...yes!...but can the caller handle the message?
+ */
+
+ if (size < real_size)
+ {
+ errno = E2BIG;
+ return (-1);
+ }
+
+
+ /*
+ ** Yes!! We can finally copy the message into the caller's buffer
+ ** and remove it from our buffer. That wasn't so bad, was it?
+ */
+
+#if defined(TRACE_MESSAGES)
+ if (trace_messages)
+ syslog(LOG_DEBUG, "MESSAGE: %-.*s", real_size, fbp->psave);
+#endif
+ (void)memcpy (buf, fbp->psave, real_size);
+ fbp->psave += real_size;
+ return (real_size);
+}
+
+int
+peek3_2 (fifo)
+int fifo;
+{
+ register fifobuffer_t *fbp;
+ register unsigned int real_size;
+
+ /*
+ ** Make sure we start on a message boundary. The first
+ ** line of defense is to look for the resync. bytes.
+ **
+ ** The "SyncUp" label is global to this routine (below this point)
+ ** and is called whenever we determine that we're out
+ ** of sync. with the incoming bytes.
+ */
+
+ if (!(fbp=GetFifoBuffer (fifo)))
+ return -1;
+ UNSYNCHED_READ (HEAD_RESYNC_LEN);
+ while (*fbp->psave != Resync[0] || *(fbp->psave + 1) != Resync[1])
+ {
+SyncUp:
+ fbp->psave++;
+ Garbage_Bytes++;
+ UNSYNCHED_READ (HEAD_RESYNC_LEN);
+ }
+
+
+ /*
+ ** We're sync'd, so read the full header.
+ */
+
+ SYNCHED_READ (HEAD_LEN);
+
+
+ /*
+ ** If the header size is smaller than the minimum size for a header,
+ ** or larger than allowed, we must assume that we really aren't
+ ** synchronized.
+ */
+
+ real_size = stoh(fbp->psave + HEAD_SIZE);
+ if (real_size < CONTROL_LEN || MSGMAX < real_size)
+ {
+ goto SyncUp;
+ }
+
+ return(real_size);
+}
+
+static int
+_buffer(int fifo)
+{
+ int n, nbytes, count = 0;
+ register fifobuffer_t *fbp;
+
+ /*
+ ** As long as we get real messages, and if we chose
+ ** SAVE_SIZE well, we shouldn't have to move the data
+ ** in the "else" branch below: Each time we call "read"
+ ** we aren't likely to get as many bytes as we ask for,
+ ** just as many as are in the fifo, AND THIS SHOULD
+ ** REPRESENT AN INTEGRAL NUMBER OF MESSAGES. Since
+ ** the "read_fifo" routine reads complete messages,
+ ** it will end its read at the end of the message,
+ ** which (eventually) will make "psave_end" == "psave".
+ */
+
+ /*
+ ** If the buffer is empty, there's nothing to move.
+ */
+ if (!(fbp = GetFifoBuffer (fifo)))
+ return -1;
+ if (fbp->psave_end == fbp->psave)
+ fbp->psave = fbp->psave_end = fbp->save; /* sane pointers! */
+
+ /*
+ ** If the buffer has data at the high end, move it down.
+ */
+ else
+ if (fbp->psave != fbp->save) /* sane pointers! */
+ {
+ /*
+ ** Move the data still left in the buffer to the
+ ** front, so we can read as much as possible into
+ ** buffer after it.
+ */
+
+ memmove(fbp->save, fbp->psave, fbp->psave_end - fbp->psave);
+
+ fbp->psave_end = fbp->save + (fbp->psave_end - fbp->psave);
+ fbp->psave = fbp->save; /* sane pointers! */
+ }
+
+ /*
+ ** The "fbp->psave" and "fbp->psave_end" pointers must be in a sane
+ ** state when we get here, in case the "read()" gets interrupted.
+ ** When that happens, we return to the caller who may try
+ ** to restart us! Sane: fbp->psave == fbp->save (HERE!)
+ */
+
+ nbytes = MSGMAX - (fbp->psave_end - fbp->save);
+
+ while ((n = read(fifo, fbp->psave_end, nbytes)) == 0 && count < 60)
+ {
+ (void) sleep ((unsigned) 1);
+ count++;
+ }
+
+ if (n > 0)
+ fbp->psave_end += n;
+
+ Had_Full_Buffer = fbp->full;
+ fbp->full = (nbytes == n);
+
+ return (n);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/streamio.c b/usr/src/cmd/lp/lib/msgs/streamio.c
new file mode 100644
index 0000000000..58ce7a9871
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/streamio.c
@@ -0,0 +1,172 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+#include <unistd.h>
+#include <signal.h>
+#include <stropts.h>
+#include <errno.h>
+#include "lp.h"
+#include "msgs.h"
+
+extern int errno;
+
+/*
+ * Putmsg() function
+ * Return 0: success,
+ * non-zero: return code of the failed putmsg() system call.
+ * plus errno for caller to check.
+ * NOTE: cannot do TRACE* calls if errno is expected to be returned!
+ * TRACE* uses fprintf and destroys the content of errno.
+ * Save errno before the TRACE* calls.
+ */
+
+int
+Putmsg (MESG *mdp, strbuf_t *ctlp, strbuf_t *datap, int flags)
+{
+ int i;
+ int rtncode;
+ int count;
+ struct pollfd fds;
+
+ fds.fd = mdp->writefd;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+
+ (void) poll(&fds, 1, 1000);
+ if (fds.revents & (POLLHUP | POLLERR | POLLNVAL)) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ if (!(fds.revents & POLLOUT)) {
+ errno = EAGAIN;
+ return (-1);
+ }
+
+ rtncode = putmsg (mdp->writefd, ctlp, datap, flags);
+ return (rtncode);
+}
+
+int
+Getmsg (MESG *mdp, strbuf_t *ctlp, strbuf_t *datap, int *flagsp)
+{
+ int rtncode;
+
+ rtncode = getmsg (mdp->readfd, ctlp, datap, flagsp);
+ return (rtncode);
+}
+
+char AuthCode[HEAD_AUTHCODE_LEN];
+static void (*callers_sigpipe_trap)() = SIG_DFL;
+
+
+/*
+** Function: static int read3_2( MESG *, char *, int)
+** Args: message descriptor
+** message buffer (var)
+** buffer size
+** Return: 0 for sucess, -1 for failure
+**
+** This performs a 3.2 HPI style read_fifo on the pipe referanced
+** in the message descriptor. If a message is found, it is returned
+** in message buffer.
+*/
+int read3_2 ( MESG * md, char *msgbuf, int size )
+{
+ short type;
+
+ if (md->type == MD_USR_FIFO)
+ (void) Close (Open(md->file, O_RDONLY, 0));
+
+ do
+ {
+ switch (read_fifo(md->readfd, msgbuf, size))
+ {
+ case -1:
+ return (-1);
+
+ case 0:
+ /*
+ ** The fifo was empty and we have O_NDELAY set,
+ ** or the Spooler closed our FIFO.
+ ** We don't set O_NDELAY in the user process,
+ ** so that should never happen. But be warned
+ ** that we can't tell the difference in some versions
+ ** of the UNIX op. sys.!!
+ **
+ */
+ errno = EPIPE;
+ return (-1);
+ }
+
+ if ((type = stoh(msgbuf + HEAD_TYPE)) < 0 || LAST_MESSAGE < type)
+ {
+ errno = ENOMSG;
+ return (-1);
+ }
+ }
+ while (type == I_QUEUE_CHK);
+
+ (void)memcpy (AuthCode, msgbuf + HEAD_AUTHCODE, HEAD_AUTHCODE_LEN);
+
+ /*
+ ** Get the size from the 3.2 HPI message
+ ** minus the size of the control data
+ ** Copy the actual message
+ ** Reset the message size.
+ */
+ size = stoh(msgbuf + HEAD_SIZE) - EXCESS_3_2_LEN;
+ memmove(msgbuf, msgbuf + HEAD_SIZE, size);
+ (void) htos(msgbuf + MESG_SIZE, size);
+ return(0);
+}
+
+int write3_2 ( MESG * md, char * msgbuf, int size )
+{
+ char tmpbuf [MSGMAX + EXCESS_3_2_LEN];
+ int rval;
+
+
+ (void) memmove(tmpbuf + HEAD_SIZE, msgbuf, size);
+ (void) htos(tmpbuf + HEAD_SIZE, size + EXCESS_3_2_LEN);
+ (void) memcpy (tmpbuf + HEAD_AUTHCODE, AuthCode, HEAD_AUTHCODE_LEN);
+
+ callers_sigpipe_trap = signal(SIGPIPE, SIG_IGN);
+
+ rval = write_fifo(md->writefd, tmpbuf, size + EXCESS_3_2_LEN);
+
+ (void) signal(SIGPIPE, callers_sigpipe_trap);
+
+
+ return (rval);
+}
diff --git a/usr/src/cmd/lp/lib/msgs/write_fifo.c b/usr/src/cmd/lp/lib/msgs/write_fifo.c
new file mode 100644
index 0000000000..b2454f476c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/msgs/write_fifo.c
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.10 */
+/* LINTLIBRARY */
+
+# include <unistd.h>
+# include <errno.h>
+# include <string.h>
+
+# include "lp.h"
+# include "msgs.h"
+
+/*
+** Choose at least one byte that won't appear in the body or header
+** of a message.
+*/
+unsigned char Resync[HEAD_RESYNC_LEN] = { 0x01, 0xFE };
+unsigned char Endsync[HEAD_RESYNC_LEN] = { 0x02, 0xFD };
+
+
+/*
+** write_fifo() - WRITE A BUFFER WITH HEADER AND CHECKSUM
+*/
+
+#if defined(__STDC__)
+int write_fifo ( int fifo, char * buf, unsigned int size )
+#else
+int write_fifo (fifo, buf, size)
+ int fifo;
+ char *buf;
+ unsigned int size;
+#endif
+{
+ unsigned short chksum = 0;
+ int wbytes = 0;
+
+ (void)memcpy (buf + HEAD_RESYNC, Resync, HEAD_RESYNC_LEN);
+ (void)memcpy (buf + TAIL_ENDSYNC(size), Endsync, TAIL_ENDSYNC_LEN);
+
+ CALC_CHKSUM (buf, size, chksum);
+ (void)htos (buf + TAIL_CHKSUM(size), chksum);
+
+
+ /*
+ ** A message must be written in one call, to avoid interleaving
+ ** messages from several processes.
+ **
+ ** The caller is responsible for trapping SIGPIPE, so
+ ** we just return what the "write()" system call does.
+ **
+ ** Well, almost. If the pipe was almost full, we may have
+ ** written a partial message. If this is the case, we lie
+ ** and say the pipe was full, so the caller can try again.
+ **
+ ** read_fifo can deal with a truncated message, so we let it
+ ** do the grunt work associated with partial messages.
+ **
+ ** NOTE: Writing the remainder of the message is not feasible
+ ** as someone else may have written something to the fifo
+ ** while we were setting up to retry.
+ */
+
+ if ((wbytes = write(fifo, buf, size)) > 0)
+ if (wbytes != size)
+ return(0);
+
+ return(wbytes);
+}
diff --git a/usr/src/cmd/lp/lib/oam/Makefile b/usr/src/cmd/lp/lib/oam/Makefile
new file mode 100644
index 0000000000..531a504f7f
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/Makefile
@@ -0,0 +1,107 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1990-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/oam/Makefile
+#
+include ../../Makefile.lp
+
+LIBRARY = liblpoam.a
+
+TEXTOBJS = e_adm__msgs.o \
+ e_can__msgs.o \
+ e_cmb__msgs.o \
+ e_fl__msgs.o \
+ e_for__msgs.o \
+ e_lp__msgs.o \
+ e_lpp__msgs.o \
+ e_lpu__msgs.o \
+ e_mov__msgs.o \
+ e_sht__msgs.o \
+ e_stat__msgs.o \
+ e_sys__msgs.o
+
+OBJECTS = agettxt.o \
+ buffers.o \
+ fmtmsg.o \
+ $(TEXTOBJS)
+
+# see the comment below about the '+' signs in TEXTTARG
+#
+TEXTSRCS = $(TEXTOBJS:%.o=%.c)
+TEXTTARG = $(TEXTSRCS:%=+ %)
+
+TFILES = msg.source gen-defs gen-text
+
+TXTFILES= $(TFILES)
+
+LPINC = ../../include
+OAMDEF_H = $(LPINC)/oam_def.h
+
+CLEANFILES = $(TEXTSRCS) $(OAMDEF_H) xx??
+
+include ../../../../lib/Makefile.lib
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I$(LPINC) $(CPPFLAGS.master)
+
+.KEEP_STATE:
+
+all install : $(TXTFILES) $(LIBS)
+
+# derived source files
+# and their dependencies
+#
+# beware of the hidden ordering requirement in the target source
+# macros. TEXTTARG contains '+' signs to tell make that this is a
+# target group. Without this syntax, an infinite build loop occurs.
+#
+$(OAMDEF_H) $(TEXTTARG) :$(TFILES)
+ sh gen-defs > $(OAMDEF_H)
+ sh gen-text
+
+# dependencies slightly overstated but necessarily explicit
+$(OBJS) $(PICS) : $(OAMDEF_H) $$(@F:.o=.c)
+
+include ../../../../lib/Makefile.targ
+
+POFILE = lp_lib_oam.po
+XGETFLAGS += -a -x lp_lib_oam.xcl
+
+CLEANFILES += llib-llpoam.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+
+lint: lintlib
+ $(LINT.c) $(LINTFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT.c) $(LINTFLAGS) -o lpoam llib-llpoam
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/oam/agettxt.c b/usr/src/cmd/lp/lib/oam/agettxt.c
new file mode 100644
index 0000000000..0e389c6435
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/agettxt.c
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+
+#include "oam.h"
+#include <string.h>
+#include <locale.h>
+
+char **_oam_msg_base_ = 0;
+
+char *
+#if defined(__STDC__)
+agettxt (
+ long msg_id,
+ char * buf,
+ int buflen
+)
+#else
+agettxt (msg_id, buf, buflen)
+ long msg_id;
+ char *buf;
+ int buflen;
+#endif
+{
+ if (_oam_msg_base_)
+ strncpy (buf, gettext(_oam_msg_base_[msg_id]), buflen-1);
+ else
+ strncpy (buf, gettext("No message defined--get help!"), buflen-1);
+ buf[buflen-1] = 0;
+ return (buf);
+}
diff --git a/usr/src/cmd/lp/lib/oam/buffers.c b/usr/src/cmd/lp/lib/oam/buffers.c
new file mode 100644
index 0000000000..1bbf071a26
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/buffers.c
@@ -0,0 +1,34 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+/* LINTLIBRARY */
+
+#include "oam.h"
+
+char _m_[MSGSIZ],
+ _a_[MSGSIZ],
+ _f_[MSGSIZ],
+ *_t_ = "999999";
diff --git a/usr/src/cmd/lp/lib/oam/fmtmsg.c b/usr/src/cmd/lp/lib/oam/fmtmsg.c
new file mode 100644
index 0000000000..6f47c82166
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/fmtmsg.c
@@ -0,0 +1,248 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+
+#include "stdio.h"
+#include "string.h"
+
+#include "oam.h"
+#include <stdlib.h>
+#include <widec.h>
+#include <libintl.h>
+#include <locale.h>
+
+#define LINE_LEN 70
+
+#define SHORT_S 80
+#define LONG_S 2000
+
+static char *severity_names[MAX_SEVERITY-MIN_SEVERITY+1] = {
+ "HALT",
+ "ERROR",
+ "WARNING",
+ "INFO"
+};
+
+static const char *TOFIX = "TO FIX";
+
+static int wrap(wchar_t *, wchar_t *, int, wchar_t *);
+
+/**
+ ** fmtmsg()
+ **/
+
+void
+fmtmsg(char *label, int severity, char *text, char *action)
+{
+ int tofix_len, indent_len;
+ wchar_t wtofix[SHORT_S], wlabel[SHORT_S], wsev[SHORT_S], wtext[LONG_S],
+ null[1] = {0};
+
+ /*
+ * Return if the severity isn't recognized.
+ */
+ if (severity < MIN_SEVERITY || MAX_SEVERITY < severity)
+ return;
+
+ mbstowcs(wtofix, gettext(TOFIX), SHORT_S);
+ mbstowcs(wlabel, label, SHORT_S);
+ mbstowcs(wsev, gettext(severity_names[severity]), SHORT_S);
+ mbstowcs(wtext, text, LONG_S);
+
+ tofix_len = wscol(wtofix),
+ indent_len = wscol(wlabel) + wscol(wsev) + 2;
+ if (indent_len < tofix_len)
+ indent_len = tofix_len;
+
+ if (wrap(wlabel, wsev, indent_len, wtext) <= 0)
+ return;
+
+ if (action && *action) {
+ if (fputc('\n', stderr) == EOF)
+ return;
+
+ mbstowcs(wtext, action, LONG_S);
+ if (wrap(wtofix, null, indent_len, wtext) <= 0)
+ return;
+ }
+
+ if (fputc('\n', stderr) == EOF)
+ return;
+
+ fflush (stderr);
+}
+
+/**
+ ** wrap() - PUT OUT "STUFF: string", WRAPPING string AS REQUIRED
+ **/
+
+static int
+wrap(wchar_t *prefix, wchar_t *suffix, int indent_len, wchar_t *str)
+{
+ int len, n, col;
+ int maxlen, tmpcol;
+ wchar_t *p, *pw, *ppw;
+ static const wchar_t eol[] = {L'\r', L'\n', L'\0'};
+
+ /*
+ * Display the initial stuff followed by a colon.
+ */
+ if ((len = wscol(suffix)))
+ n = fprintf(stderr, gettext("%*ws: %ws: "),
+ indent_len - len - 2, prefix, suffix);
+ else
+ n = fprintf(stderr, gettext("%*ws: "), indent_len, prefix);
+ if (n <= 0)
+ return (-1);
+
+ maxlen = LINE_LEN - indent_len - 1;
+
+ /* Check for bogus indent_len */
+ if (maxlen < 1) {
+ return (-1);
+ }
+
+ /*
+ * Loop once for each line of the string to display.
+ */
+ for (p = str; *p; ) {
+
+ /*
+ * Display the next "len" bytes of the string, where
+ * "len" is the smallest of:
+ *
+ * - LINE_LEN
+ * - # bytes before control character
+ * - # bytes left in string
+ *
+ */
+
+ len = wcscspn(p, eol);
+ /* calc how many columns the string will take */
+ col = wcswidth(p, len);
+ if (col > maxlen) {
+ /*
+ * How many characters fit into our desired line length
+ */
+ pw = p;
+ tmpcol = 0;
+ while (*pw) {
+ if (iswprint(*pw))
+ tmpcol += wcwidth(*pw);
+ if (tmpcol > maxlen)
+ break;
+ else
+ pw++;
+ }
+ /*
+ * At this point, pw may point to:
+ * A null character: EOL found (should never happen, though)
+ * The character that just overruns the maxlen.
+ */
+ if (!*pw) {
+ /*
+ * Found a EOL.
+ * This should never happen.
+ */
+ len = pw - p;
+ goto printline;
+ }
+ ppw = pw;
+ /*
+ * Don't split words
+ *
+ * Bugid 4202307 - liblpoam in lp internal library doesn't
+ * handle multibyte character.
+ */
+ while (pw > p) {
+ if (iswspace(*pw) ||
+ (wdbindf(*(pw - 1), *pw, 1) < 5)) {
+ break;
+ } else {
+ pw--;
+ }
+ }
+ if (pw != p) {
+ len = pw - p;
+ } else {
+ /*
+ * Failed to find the best place to fold.
+ * So, prints as much characters as maxlen allows
+ */
+ len = ppw - p;
+ }
+ }
+
+printline:
+ for (n = 0; n < len; n++, p++) {
+ if (iswprint(*p)) {
+ if (fputwc(*p, stderr) == WEOF) {
+ return (-1);
+ }
+ }
+ }
+
+ /*
+ * If we displayed up to a control character,
+ * put out the control character now; otherwise,
+ * put out a newline unless we've put out all
+ * the text.
+ */
+
+ if (*p == L'\r' || *p == L'\n') {
+ while (*p == L'\r' || *p == L'\n') {
+ if (fputwc(*p, stderr) == WEOF)
+ return (-1);
+ p++;
+ }
+ } else if (*p) {
+ if (fputwc(L'\n', stderr) == WEOF)
+ return (-1);
+ }
+
+ while (iswspace(*p))
+ p++;
+
+ /*
+ * If the loop won't end this time (because we
+ * have more stuff to display) put out leading
+ * blanks to align the next line with the previous
+ * lines.
+ */
+ if (*p) {
+ for (n = 0; n < indent_len + 2; n++)
+ (void) fputwc(L' ', stderr);
+ }
+ }
+
+ return (1);
+}
diff --git a/usr/src/cmd/lp/lib/oam/gen-defs b/usr/src/cmd/lp/lib/oam/gen-defs
new file mode 100644
index 0000000000..ad8e72db71
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/gen-defs
@@ -0,0 +1,63 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+##########
+#
+# Generate ../../include/oam_def.h
+##########
+
+echo "/*This file is automatically generated from msg.source.*/"
+
+csplit -k -s msg.source /E_.*__MSGS/ {99} 2>/dev/null
+
+sed -n -e '/^[ ]*#/p' xx00
+rm xx00
+
+echo 'extern char **_oam_msg_base_;'
+for x in xx??
+do
+ BASE=`line <${x}`
+ base=`echo ${BASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ echo 'extern char *'${base}'[];'
+done
+
+for x in xx??
+do
+
+ (
+ BASE=`line`
+ base=`echo ${BASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+
+ echo "${BASE}"
+
+ sed -e '/^[ ]*$/d' \
+ | sed -n \
+ -e 's/^[ ]*\(E_.*\)$/\1:(_oam_msg_base_='${base}',(long)(:-'${BASE}'))/p' \
+ -e '/^[ ]*#/p'
+ ) <${x}
+
+done \
+| nl -bp"^E_" -v0 -i2 -s: \
+| sed \
+ -e 's/^[ ]*\([0-9]*\):\(E_.*\):\(.*\):\(.*\)$/#define \2 \3\1\4/' \
+ -e 's/^[ ]*\([0-9]*\):\(E_.*\)$/#define \2 (\1+2)/' \
+| sed -e 's/^[ ]*//'
diff --git a/usr/src/cmd/lp/lib/oam/gen-text b/usr/src/cmd/lp/lib/oam/gen-text
new file mode 100644
index 0000000000..31299d3dc5
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/gen-text
@@ -0,0 +1,46 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+##########
+#
+# Generate e_xxx__base.c files
+#
+# THE ../../oam_def.h FILE MUST BE GENERATED FIRST
+##########
+
+for x in xx??
+do
+
+ (
+ base=`line | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ echo "generating ${base}.c"
+
+ (
+ echo "/*This file is automatically generated from msg.source.*/"
+ echo 'char *'${base}'[] = {'
+ sed -n -e 's/^[ ]*".*"$/&,/p'
+ echo '};'
+ ) >${base}.c
+
+ ) <${x}
+
+done
diff --git a/usr/src/cmd/lp/lib/oam/llib-llpoam b/usr/src/cmd/lp/lib/oam/llib-llpoam
new file mode 100644
index 0000000000..b2a06901ee
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/llib-llpoam
@@ -0,0 +1,39 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+char *agettxt(long msg_id, char *buf, int buflen);
+
+void fmtmsg(char * label, int severity, char * text, char * action);
+
+
diff --git a/usr/src/cmd/lp/lib/oam/lp_lib_oam.xcl b/usr/src/cmd/lp/lib/oam/lp_lib_oam.xcl
new file mode 100644
index 0000000000..ccc0fa8c6d
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/lp_lib_oam.xcl
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+msgid ""
+msgid "999999"
diff --git a/usr/src/cmd/lp/lib/oam/msg.source b/usr/src/cmd/lp/lib/oam/msg.source
new file mode 100644
index 0000000000..d0650c00cf
--- /dev/null
+++ b/usr/src/cmd/lp/lib/oam/msg.source
@@ -0,0 +1,981 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/**
+ **
+ ** This file contains definitions for the E_... symbols
+ ** used with the LP_ERRMSG routines. The definitions are
+ ** linked with the text in this file, but they have to be split:
+ ** The E_... symbols go into a header file, and the text
+ ** go into separate, compilable files.
+ **/
+
+/*
+ *
+ * Format of lines in this file:
+ *
+ * E_...
+ * "text-for-error-message"
+ * "text-for-TO-FIX-statement"
+ *
+ * Lines that DON'T begin with E_..., " (double quote), or #
+ * (after leading spaces or tabs) are skipped. Thus these comment
+ * lines are ignored, but the C preprocessor directives are kept.
+ *
+ * Note: The preprocessor directives DO NOT keep text from being
+ * generated, nor do they keep the E_... symbols from being numbered
+ * (which is consistent). The directives ARE useful for keeping them
+ * from being needlessly defined in a program that includes "oam.h"
+ */
+
+#define I_AM_CANCEL 1
+#define I_AM_COMB 2
+#define I_AM_LP 3
+#define I_AM_LPADMIN 4
+#define I_AM_LPFILTER 5
+#define I_AM_LPFORMS 6
+#define I_AM_LPMOVE 7
+#define I_AM_LPNETWORK 8
+#define I_AM_LPPRIVATE 9
+#define I_AM_LPSCHED 10
+#define I_AM_LPSHUT 11
+#define I_AM_LPSTAT 12
+#define I_AM_LPUSERS 13
+#define I_AM_LPSYSTEM 14
+#define I_AM_OZ 99
+
+/**
+ ** COMMON MESSAGES USED BY ALL PROGRAMS
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_LP__MSGS
+
+E_LP_OPTION
+ "Unrecognized option \"%s\"."
+ ""
+E_LP_MALLOC
+ "Not enough memory."
+ "Try again later or give a simpler\ncommand."
+E_LP_AGAIN
+ "Another process is using the file\n\"%s\"."
+ "Try again later."
+E_LP_ANYNONE
+ "The names \"any\" and \"none\" are reserved."
+ "You must use a different name."
+E_LP_ACCESS
+ "Can't access the file\n\"%s\"."
+ "Check its file permissions."
+E_LP_NOTNAME
+ "\"%s\" doesn't have the correct syntax."
+ "Give a name that has 1 to 14 letters,\ndigits, dashes, or underscores."
+E_LP_OPTARG
+ "The option %s requires an argument."
+ ""
+E_LP_UNKREQID
+ "Request \"%s\" doesn't exist."
+ ""
+E_LP_MSEND
+ "Can't send message to the LP print service."
+ "The LP print service apparently has been\nstopped. Get help from your system\nadministrator."
+E_LP_MRECV
+ "Can't receive message from the LP print service."
+ "The LP print service apparently has been\nstopped. Get help from your system\nadministrator."
+E_LP_BADSTATUS
+ "Received unexpected status %d in a reply from the\nLP print service."
+ "It's likely there is an error in this\nsoftware. Please get help from your\nsystem administrator."
+E_LP_PGONE
+ "Printer \"%s\" has disappeared!"
+ "The administrator should completely\nremove the printer."
+E_LP_PNBUSY
+ "Printer \"%s\" was not busy."
+ ""
+E_LP_MOPEN
+ "Can't establish contact with the LP print service."
+ "Either the LP print service has stopped,\nor all message channels are busy. If the\nproblem continues, get help from your\nsystem administrator."
+E_LP_MLATER
+ "All message channels busy."
+ "Try again later."
+E_LP_AMBIG
+ "Ambiguous or invalid combination of\n%s and %s options."
+ "Give only one of the two options."
+E_LP_2MANY
+ "Multiple -%c options given."
+ "The last one will be used;\nprocessing continues."
+E_LP_BADREPLY
+ "Received unexpected message %d from the LP print service."
+ "It's likely there is an error in this\nsoftware. Please get help from your\nsystem administrator."
+E_LP_DSTUNK
+ "Destination \"%s\" is unknown to the\nLP print service."
+ ""
+E_LP_NOTADM
+ "You aren't allowed to do that."
+ "You must be logged in as \"lp\" or \"root\"."
+E_LP_NODEST
+ "No destinations specified."
+ ""
+E_LP_BADFILE
+ "Cannot access the file:\n%s."
+ "Make sure file names are valid."
+E_LP_EMPTY
+ "\"%s\" is empty."
+ ""
+E_LP_NOFILES
+ "No (or empty) input files."
+ ""
+E_LP_OPTCOMB
+ "Illegal combination of options."
+ "Check the manual for proper usage."
+E_LP_NOSPACE
+ "No space to allocate temp files."
+ "Clean up disk, or try again later."
+E_LP_ISDIR
+ "\"%s\" is a directory."
+ "A regular file is needed here; check the\nname."
+E_LP_BADSCALE
+ "Improper scaled decimal number."
+ "Number must be greater than zero. You\ncan use only 'i' and 'c' for scaling\nnumbers ('i' inches, 'c' centimeters).\nFor setting cpi (horizontal pitch),\nsynonyms \"pica\", \"elite\", \"compressed\"\nare allowed."
+E_LP_EXTRA
+ "Extra command line arguments starting with\n\"%s\"."
+ "Processing continues, but check for a\nmissing option. Use the -? option to see\na list of valid options."
+E_LP_BADPRI
+ "Bad priority value \"%s\"."
+ "Use an integer value from 0 to 39."
+E_LP_2LATE
+ "Request \"%s\" is done."
+ "It is too late to do anything with it."
+E_LP_BUSY
+ "Request \"%s\" is busy."
+ "If the request is printing, disable the\nprinter and resubmit this command."
+E_LP_NULLARG
+ "Null argument given for %s option."
+ "You have to give a non-empty value for\nthis option."
+E_LP_BADOARG
+ "Argument to option -%c is invalid: \"%s\"."
+ "Re-enter with valid option arguments."
+E_LP_NEEDSCHED
+ "The LP print service isn't running or can't be\nreached."
+ "Your request can't be completely handled\nwithout the LP print service. If this\nproblem continues, get help from your\nsystem administrator."
+E_LP_BADDEST
+ "Destination \"%s\" does not exist."
+ "Use a printer or class that exists on\nthis system."
+E_LP_PUTCLASS
+ "Error writing class \"%s\" to disk\n(%s)."
+ ""
+E_LP_GETCLASS
+ "Error reading class \"%s\" from disk\n(%s)."
+ ""
+E_LP_DELCLASS
+ "Error deleting class \"%s\" from disk\n(%s)."
+ ""
+E_LP_GETPRINTER
+ "Error reading printer information for \"%s\"\n(%s)."
+ ""
+E_LP_PUTPRINTER
+ "Error writing printer information for \"%s\"\n(%s)."
+ ""
+E_LP_DELPRINTER
+ "Error deleting printer information for \"%s\"\n(%s)."
+ ""
+E_LP_GETFORM
+ "Error reading form information for \"%s\"\n(%s)."
+ ""
+E_LP_PUTFORM
+ "Error writing form information for \"%s\"\n(%s)."
+ ""
+E_LP_DELFORM
+ "Error deleting form information for \"%s\"\n(%s)."
+ ""
+E_LP_GETREQUEST
+ "Error reading request file.\n(%s)."
+ ""
+E_LP_PUTREQUEST
+ "Error writing request file.\n(%s)."
+ ""
+E_LP_NOCLASS
+ "Class \"%s\" does not exist."
+ "Use the \"lpstat -c all\" command to list\nall known classes."
+E_LP_NOPRINTER
+ "Printer \"%s\" does not exist."
+ "Use the \"lpstat -p all\" command to list\nall known printers."
+E_LP_NOFORM
+ "Form \"%s\" does not exist."
+ "Use the \"lpstat -f all\" command to list\nall known forms."
+E_LP_GETMSG
+ "Failed to parse message from the LP print service.\n(%s)"
+ ""
+E_LP_HAVEREQS
+ "The LP print service isn't running."
+ "Your request may affect print jobs, but\nthe LP print service isn't running to\nevaluate this. Start it by running the\n/usr/lib/lp/lpsched command."
+E_LP_DENYDEST
+ "You are not allowed to use the destination\n\"%s\"."
+ "Use the lpstat -p command to list all\nknown printers; you can use those marked\n\"available\"."
+E_LP_NOFILTER
+ "There is no filter to convert the file content."
+ "Use the lpstat -p -l command to find a\nprinter that can handle the file type\n directly, check your filters using lpfilter -f all -l, or consult with your system\nadministrator."
+E_LP_REQDENY
+ "Requests for destination \"%s\" aren't\nbeing accepted."
+ "Use the \"lpstat -a\" command to see why\nthis destination is not accepting\nrequests."
+E_LP_PTRCHK
+ "The following options can't be handled:\n%s"
+ "The printer(s) that otherwise qualify\nfor printing your request can't handle\none or more of these options. Try\nanother printer, or change the options."
+E_LP_MNOMEM
+ "No room for this request!"
+ "The spooling directory is full, or the\nLP print service can't allocate enough\nmemory for this request."
+E_LP_UALLOWDENY
+ "Invalid argument to the -u option."
+ "The argument must begin with either\n\"allow:\" or \"deny:\" and be followed with\na list of user names."
+E_LP_NOQUIET
+ "No alerts are active for \"%s\"."
+ ""
+E_LP_GARBNMB
+ "Illegal value for the -%c option."
+ "Give an integer value with this option."
+E_LP_NEGARG
+ "Illegal value for the -%c option."
+ "This must be a non-negative number, that\nis also small enough to be interpreted\ncorrectly (numbers too large might be\nconverted to negative values)."
+E_LP_GONEREMOTE
+ "Request %s is on the remote system."
+ "The LP print service currently does not\nallow you to change or move a request,\nonce it is on the remote system."
+E_LP_ZEROARG
+ "Illegal value for the -%c option."
+ "Give a positive value for the option."
+E_LP_MISSING
+ "No list given after the \"%s:\"."
+ "You seem to have left something out;\nhowever, processing of the rest of the\ncommand line options continues."
+E_LP_ACCESSINFO
+ "Error writing access information to disk\n(%s)."
+ ""
+E_LP_GARBAGE
+ "Too many bad input lines."
+ "Fix the input and try again."
+E_LP_USAGE
+ "Unrecognized option \"%s\".\nEnter command with -? option for proper usage."
+ ""
+E_LP_NOREQ
+ "No request ids available."
+ "Check for faulted or disabled printer(s) with \n\"lpstat -a\"."
+E_LP_LARGEFILE
+ "Large File encountered, can't print:\n%s."
+ "Make sure the file is not a Large File."
+/**
+ ** MESSAGES FOR THE LPFILTER PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_FL__MSGS
+
+#if WHO_AM_I == I_AM_LPFILTER || WHO_AM_I == I_AM_OZ
+#define E_FL_IGNORE E_LP_EXTRA
+#define E_FL_GARBAGE E_LP_GARBAGE
+
+E_FL_ACCESS
+ "Can't access filter table\n\"%s\"."
+ "Check its file permissions."
+E_FL_ACCESSI
+ "Can't access archived filter table\n\"%s\"."
+ "Check its file permissions."
+E_FL_NOCMD
+ "No command specified."
+ "You must give a command or program name."
+E_FL_NOFACTY
+ "No filters are archived."
+ "See if any were installed originally."
+E_FL_FACTYNM
+ "No filter by that name was archived."
+ "Check the name again."
+E_FL_NOFILT
+ "No filter name given."
+ "You must specify a filter name;\nuse the -f option."
+E_FL_OPEN
+ "Can't open the file for reading: \"%s\""
+ "Check that it exists and that you\ncan read it."
+E_FL_READ
+ "Error reading input."
+ ""
+E_FL_UNKFILT
+ "No filter by the name \"%s\" exists."
+ "Check the name again."
+E_FL_UNKNOWN
+ "Error accessing filter table\n\"%s\"\n(%s)."
+ ""
+E_FL_HEADING
+ "Input line %d can not be used."
+ "Fix the input if necessary;\nprocessing continues."
+E_FL_NOACT
+ "Nothing to do."
+ "You must give one of these options:\n-F, -, -x, -l."
+E_FL_NOTALL
+ "Can't add a filter named \"all\"."
+ "You must use another name."
+E_FL_STRANGE
+ "Could not read all filters from table\n\"%s\"."
+ ""
+E_FL_NOSPLOAD
+ "The LP print service didn't load the filter table."
+ "Try restarting the LP print service by\nrunning the /usr/lib/lp/lpsched command."
+E_FL_BADTEMPLATE
+ "Missing option template."
+ "There appears to be an incomplete option\ntemplate. This can be caused by a double\ncomma in the option list. Resubmit the\nentire input."
+E_FL_BADKEY
+ "Unrecognized keyword in option template."
+ "Resubmit the entire input. Check the\nlpfilter(1M) manual page for the list of\nvalid keywords."
+E_FL_BADPATT
+ "Missing pattern in option template."
+ "Resubmit the entire input; make sure all\noption templates include a keyword,\npattern, and replacement:\nkeyword pattern = replacement\n(e.g. MODES * = -m *)."
+E_FL_BADRESULT
+ "Missing replacement in option template."
+ "Resubmit the entire input; make sure all\noption templates include a keyword,\npattern, and replacement:\nkeyword pattern = replacement\n(e.g. MODES * = -m *)."
+E_FL_BADREGEX
+ "Error in regular expression:\n %s"
+ "Resubmit the entire input with the\ncorrect regular expression."
+#endif
+
+/**
+ ** MESSAGES FOR THE CANCEL PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_CAN__MSGS
+
+#if WHO_AM_I == I_AM_CANCEL || WHO_AM_I == I_AM_OZ
+
+E_CAN_BADARG
+ "\"%s\" is not a request id or a printer."
+ "Cancel requests by id or by\nname of printer where printing."
+E_CAN_CANT
+ "Can't cancel request \"%s\"."
+ "You are not allowed to cancel\nanother's request."
+E_CAN_NOUSERP
+ "No jobs on printer %s for user(s) %s."
+ "Use the lpstat -o or lpstat -u commands\nto see what requests have been queued."
+E_CAN_ANYUSERP
+ "No user has a job on printer %s."
+ "Use the lpstat -o or lpstat -u commands\nto see what requests have been queued."
+E_CAN_NOUSERANYP
+ "No jobs on any printer for user(s) %s."
+ "Use the lpstat -o command to see what\nrequests have been queued."
+E_CAN_ANYUSERANYP
+ "No requests queued."
+ ""
+E_CAN_NOACT
+ "Nothing to do."
+ "You need to give a request ID or printer\nname, or the -u option to specify a user."
+
+#endif
+
+/**
+ ** MESSAGES FOR THE ACCEPT, REJECT, ENABLE, DISABLE PROGRAMS
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_CMB__MSGS
+
+#if WHO_AM_I == I_AM_COMB || WHO_AM_I == I_AM_OZ
+
+E_REJ_2TIME
+ "Destination \"%s\" was already\nnot accepting requests."
+ ""
+
+E_ACC_2TIME
+ "Destination \"%s\" was already accepting\nrequests."
+ ""
+
+E_DIS_2TIME
+ "Destination \"%s\" was already disabled."
+ ""
+E_DIS_CLASS
+ "\"%s\" is a class."
+ "You can only disable printers, not\nclasses. If you want to prevent people\nfrom submitting requests to this class,\nuse the /usr/sbin/reject command."
+
+E_ENA_2TIME
+ "Destination \"%s\" was already enabled."
+ ""
+E_ENA_CLASS
+ "\"%s\" is a class."
+ "You can only enable printers, not\nclasses. If you want to allow people to\nsubmit requests to this class, use the\n/usr/sbin/accept command."
+
+#endif
+
+/**
+ ** MESSAGES FOR THE LPMOVE PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_MOV__MSGS
+
+#if WHO_AM_I == I_AM_LPMOVE || WHO_AM_I == I_AM_OZ
+
+E_MOV_BADDEST
+ "Request \"%s\" cannot be moved."
+ ""
+E_MOV_NOMEDIA
+ "Request \"%s\" cannot be moved."
+ "The form or character set needed by the\nrequest no longer exists. You should\ncancel this request."
+E_MOV_DENYMEDIA
+ "Request \"%s\" cannot be moved."
+ "The form needed by the request is no\nlonger available to the user. You should\ncancel this request."
+E_MOV_NOMOUNT
+ "Request \"%s\" cannot be moved."
+ "The form needed by the request can't be\nmounted on the destined printer. Try\nanother destination, or wait for the\nrequest to finish printing or cancel it."
+E_MOV_PTRCHK
+ "Request \"%s\" cannot be moved\nbecause the following options can't be handled:\n%s"
+ "Try moving the request to another\ndestination, or wait for the request to\nfinish printing or cancel it."
+E_MOV_DENYDEST
+ "Request \"%s\" cannot be moved."
+ "The person who submitted the request is\nnot allowed to use the printer(s). Try\nanother destination, or wait for the\nrequest to finish printing or cancel it."
+E_MOV_NOFILTER
+ "Request \"%s\" cannot be moved."
+ "There is no filter to convert the file\ncontent for the printer(s). Try another\ndestination, or wait for the request to\nfinish printing or cancel it."
+
+#endif
+
+/**
+ ** MESSAGES FOR THE LPUSERS PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_LPU__MSGS
+
+#if WHO_AM_I == I_AM_LPUSERS || WHO_AM_I == I_AM_OZ
+
+E_LPU_BADFILE
+ "Bad file: %s, errno=%d."
+ ""
+E_LPU_BADFORM
+ "Bad user profile:\n\"%s\"."
+ ""
+E_LPU_DEFTWICE
+ "Default listed twice."
+ ""
+E_LPU_NOLOAD
+ "The LP print service did not load new priority\ndefinitions."
+ "Try restarting the LP print service."
+E_LPU_BADU
+ "Bad user specified: %s"
+ ""
+E_LPU_NOUSER
+ "User \"%s\" did not have a limit set\n(or is illegal)"
+ ""
+
+#endif
+
+/**
+ ** MESSAGES FOR THE LP PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_LPP__MSGS
+
+#if WHO_AM_I == I_AM_LP || WHO_AM_I == I_AM_OZ
+#define E_LPP_BADDEST E_LP_BADDEST
+
+E_LPP_ILLARG
+ "Illegal file arguments with change request."
+ "To change which files should be printed,\ncancel this request and resubmit it."
+E_LPP_NOSTART
+ "End change received, but no start."
+ "Internal error, report to administrator."
+E_LPP_FPUTREQ
+ "Could not write request."
+ ""
+E_LPP_FGETREQ
+ "Could not read request \"%s\"."
+ "Check argument to -i option."
+E_LPP_NODEST
+ "No default destination."
+ "You must identify which printer should\nhandle your request by naming it or a\nclass of printers (-d name) or by naming\na type of printer (-T type)."
+E_LPP_NOMEDIA
+ "Form or character set not available."
+ "Check the spelling of the form/character\nset name. Use the lpstat -f -S command\nto list all known forms and character\nsets."
+E_LPP_DENYMEDIA
+ "You are not allowed to use the form\n\"%s\"."
+ "Use the lpstat -f command to list all\nknown forms; you can use those marked\n\"available\"."
+E_LPP_NOMOUNT
+ "The form or print wheel can't be used."
+ "The printer(s) that otherwise qualify\nfor printing your request are not\nallowed to have the form or print wheel\nmounted. Use the lpstat -p -l command\nto list printers where it (they) can be\nmounted."
+E_LPP_COMBMW
+ "Illegal combination of -w and -m options."
+ "Notification will be by mail only;\nthe \"-w\" option is ignored."
+E_LPP_NOOPEN
+ "The LP print service could not read your request\nfile."
+ "See if the spooling file system is full.\nGet help from your system administrator."
+E_LPP_FORMCHARSET
+ "The character set can't be used with the form."
+ "Since the form is defined as needing a\nparticular character set, just resubmit\nthe command without the -S option."
+E_LPP_CURDIR
+ "Can't determine the current directory."
+ "The LP print service can not determine\nwhere all your files are located because\nit doesn't have the same current\ndirectory. Give the -c option to copy\nthe file(s)."
+E_LPP_ODDFILE
+ "One or more files can't be used or found."
+ "Either the files are illegal (fifos,\nblock devices, etc.), or can't be found\nby the LP print service. The latter\ntypically happens when your files are on\nlocal resources not accessible over RFS."
+
+#endif
+
+/**
+ ** MESSAGES FOR THE LPSHUT PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_SHT__MSGS
+
+#if WHO_AM_I == I_AM_LPSHUT || WHO_AM_I == I_AM_OZ
+
+E_SHT_CANT
+ "You can't shut down the LP print service."
+ "You must be logged in as \"lp\" or \"root\"."
+
+#endif
+
+/**
+ ** MESSAGES FOR THE LPADMIN PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_ADM__MSGS
+
+#if WHO_AM_I == I_AM_LPADMIN || WHO_AM_I == I_AM_OZ
+#define E_ADM_ZEROARG E_LP_ZEROARG
+#define E_ADM_MISSING E_LP_MISSING
+#define E_ADM_ACCESSINFO E_LP_ACCESSINFO
+
+E_ADM_NOTLOCAL
+ "You have specified a remote printer\nand supplied one or more of the following\noptions: A,a,e,F,H,h,i,l,m,M,o,U,v,Q,W."
+ ""
+E_ADM_ANYALLSYS
+ "The names \"any\" and \"all\" are reserved."
+ "You must use a system name that has\nbeen defined with the lpsystem command."
+E_ADM_DALONE
+ "Other options given with -d option."
+ "Give only the -d option to define\na default destination."
+E_ADM_XALONE
+ "Other options given with -x option."
+ "Give only the -x option to delete a\nprinter."
+E_ADM_SALONE
+ "Confusing options given."
+ "You are either missing the -p option or\nhave given extraneous options while\ntrying to define alerting for a\nprint wheel."
+E_ADM_JALONE
+ "Wrong combination of options."
+ "The -j option should not be given when\nadding a new printer."
+E_ADM_MNTNONE
+ "Nothing to mount."
+ "Give the -f or -S option to identify\nform or print wheel to mount."
+E_ADM_PNOQ
+ "Illegal use of the -Q option."
+ "Don't give the -Q option when setting\na printer fault alert."
+E_ADM_NODEST
+ "Destination \"%s\" doesn't exist."
+ "Check the name again. Use the lpstat -p\nor lpstat -c command to see if the\nprinter or class exists."
+E_ADM_NOACT
+ "Nothing to do."
+ "You must give one of these options:\n-p, -d, -x, -S."
+E_ADM_CNOU
+ "No -u option given."
+ "Give the -C option only with the\n-u option."
+E_ADM_JNOF
+ "No -F option given."
+ "Give the -j option only with the\n-F option."
+E_ADM_2MANY
+ "Multiple -o %s options given."
+ "The last one will be used;\nprocessing continues."
+E_ADM_QUOTES
+ "Missing right %c quote in stty= argument."
+ ""
+E_ADM_BADTYPE
+ "Printer type \"%s\" is not in the\nTerminfo database."
+ "Check the name again; if it is correct\nyou have to make an entry for it in the\nTerminfo database."
+E_ADM_MIXEDTYPES
+ "Inconsistent printer types."
+ "The printer types do not agree on\nwhether the printer takes print wheels\nor not. Check the printer types or the\nTerminfo database."
+E_ADM_MUNKNOWN
+ "\"unknown\" not allowed with multiple printer types."
+ "Your list of printer types includes the\ntype \"unknown\"; either remove that type\nfrom the list or give just the type\n\"unknown\"."
+E_ADM_BADCAP
+ "\"%s\" setting impossible."
+ ""
+E_ADM_BADCAPS
+ "The printer can't handle all the above setting(s)."
+ "Check the manual for the printer to make\nsure each value is correct; check that\nthe Terminfo entry/entries are correct."
+E_ADM_NBADCAPS
+ "Settings won't work on these printer types:\n %s"
+ "The incompatible settings won't be\napplied when these types are used to\nprint a request. Change the settings or\nlist of types, if you want."
+E_ADM_PRCL
+ "Can't create the printer \"%s\"."
+ "This is an existing class name;\nchoose another name."
+E_ADM_NOUV
+ "Missing -U or -v option."
+ "Local printers must have\na port defined (-v option) or\nhave dial-out instructions (-U option)."
+E_ADM_BOTHUV
+ "Both -U and -v given."
+ "Give only one of these options, the\n-v option to name the direct connect\nport or the -U to identify the dial-out\nmethod."
+E_ADM_NOTMEM
+ "The printer \"%s\" is not a member of\nthe class \"%s\"."
+ "Use the lpstat -c command to find the\ncorrect class."
+E_ADM_TOPT
+ "No printer type (-T option) given."
+ "The printer type must be known:\n* to set default cpi, lpi, length, width\n* to define character sets, print wheels\n* to allow forms."
+E_ADM_INTCONF
+ "The options -e, -i and -m are mutually exclusive."
+ "Give just one of these options to define\nan interface program."
+E_ADM_NOPR
+ "The printer \"%s\" does not exist."
+ "You must give the name of an existing\nprinter in the -e option."
+E_ADM_SAMEPE
+ "The -p and -e options have the same value."
+ "You must name a different printer\nin the -e option."
+E_ADM_SAMECR
+ "The -c and -r options have the same value."
+ "Don't try to remove the printer from the\nsame class to which you are adding it."
+E_ADM_NOMODEL
+ "The model \"%s\" does not exist."
+ "Use the command\n ls /usr/lib/lp/model\nto find the list of known models."
+E_ADM_CONFLICT
+ "The options \"-%c\" and \"-%c\" are contradictory."
+ "Give the -l option if the printer is\nalso a login terminal, give the\n-h option if it is not."
+E_ADM_ISDIR
+ "\"%s\" is a directory."
+ "If this is not what you intended, enter\nthe command again with the correct name."
+E_ADM_ISBLK
+ "\"%s\" is a block device."
+ "If this is not what you intended, enter\nthe command again with the correct name."
+E_ADM_ISMISMATCH
+ "\"%s\" is a symlink that points to a file with a different owner."
+ "Retry this operation with a new device."
+E_ADM_ISNOTROOTOWNED
+ "\"%s\" is a symlink owned by an unprivileged user.\nThis introduces a potential security hole in your configuration."
+ "If this is not what you intended, enter\nthe command again with the correct name."
+E_ADM_DEVACCESS
+ "\"%s\" is accessible by others."
+ "If other users can access it you may get\nunwanted output. If this is not what you\nwant change the owner to \"lp\" and change\nthe mode to 0600.\nProcessing continues."
+E_ADM_NOENT
+ "\"%s\" doesn't exist."
+ "Create the file, special device, or FIFO\nfor the -v option before running this\ncommand."
+E_ADM_INCLASS
+ "The printer \"%s\" is already a member\nof the class \"%s\"."
+ "If you made a mistake, rerun the command\nwith the correct names;\nprocessing continues."
+E_ADM_GETCLASSES
+ "Error reading all classes from disk\n(%s)."
+ ""
+E_ADM_GETPRINTERS
+ "Error reading all printers from disk\n(%s)."
+ ""
+E_ADM_FALLOWDENY
+ "Invalid argument to the -f option."
+ "The argument must begin with either\n\"allow:\" or \"deny:\" and be followed with\na list of form names. On the other hand,\nperhaps you forgot the -M option?"
+E_ADM_ICKFORM
+ "Form \"%s\" is not listed as available\nfor the printer \"%s\"."
+ "Check the name; if wrong enter the\ncommand again.\nProcessing continues."
+E_ADM_PWHEELS
+ "-S must not give a character set map."
+ "The printer takes only print wheels.\nFix the type or change the value in the\n-S option."
+E_ADM_CHARSETS
+ "-S must give a character set map."
+ "The printer has only selectable\ncharacter sets. Fix the type or change\nthe value in the -S option."
+E_ADM_BADSET
+ "Illegal character set \"%s\"."
+ ""
+E_ADM_NBADSET
+ "Character set \"%s\" won't work with\nthese printer types:\n %s"
+ ""
+E_ADM_BADSETS
+ "The printer's type(s) don't have the\nabove character sets defined."
+ "Check the manual for the printer to make\nsure each name is correct; check that\nthe Terminfo entry/entries are correct."
+E_ADM_NOPWHEEL
+ "The printer doesn't take print wheels."
+ "Check that you named the right printer.\nCheck that the Terminfo database is\ncorrect; if wrong, fix it and add the\nprint wheel list for the printer."
+E_ADM_ICKPWHEEL
+ "Print wheel \"%s\" is not listed as\navailable for the printer \"%s\"."
+ "Check the name; if wrong enter the\ncommand again with the correct name.\nProcessing continues."
+E_ADM_MNTLATER
+ "The printer is busy; can't mount/unmount now."
+ "Wait until the current job(s) are\nfinished, or disable the printer."
+E_ADM_NOMEDIA
+ "Can't mount/unmount the form or print wheel."
+ "Check the name. The one you gave isn't\nrecognized."
+E_ADM_DELSTRANGE
+ "Strange, the LP print service took the request to\ndelete printer or class \"%s\" but the disk copy\ncan't be deleted.\n(%s)"
+ ""
+E_ADM_DESTBUSY
+ "There are jobs currently queued for destination\n\"%s\""
+ "Use the /usr/sbin/lpmove command to\nassign them to another destination,\nor wait for them to finish printing."
+E_ADM_WRDEFAULT
+ "Error writing default destination\n(%s)."
+ ""
+E_ADM_PUTPWHEEL
+ "Error writing print wheel information for \"%s\"\n(%s)."
+ ""
+E_ADM_FBAD
+ "Illegal value for the -F option"
+ "You must give one of the values\n\"continue\", \"wait\", or \"beginning\"."
+#if defined(J_OPTION)
+E_ADM_FBADJ
+ "Illegal value for the -F option"
+ "You must give one of the values\n\"wait\" or \"beginning\".\n(\"continue\" is not allowed if you also\ngive the -j option.)"
+#endif
+E_ADM_BADO
+ "\"%s\" is an illegal value for the\n-o option"
+ "You must give one of the values\nbanner, nobanner,\ncpi=X, lpi=X, width=X, length=X,\nstty=... (if ... is a list, surround IT\nwith single quotes (') and put the whole\nthing in double quotes (\")),\nor filebreak or nofilebreak (with -a)."
+E_ADM_FORMCAP
+ "The form \"%s\" requires capabilities\nnot provided by the printer."
+ ""
+E_ADM_FORMCAPS
+ "Can't allow one or more forms."
+ "You have to adjust each form definition,\nif possible. Leave each form out of the\nallow list to continue defining the\nprinter."
+E_ADM_BADINTF
+ "Can't access the file \"%s\"\nto copy the interface program."
+ "Make sure the name is correct;\nmake sure the file exists."
+E_ADM_CLPR
+ "Can't create class \"%s\"."
+ "This is an existing printer name;\nchoose another name."
+E_ADM_BADQUIETORLIST
+ "Illegal -A option for printer/print wheel\n\"%s\"."
+ "You can't give the -A quiet or the\n-A list option for a printer or print\nwheel that doesn't exist yet."
+E_ADM_PLONELY
+ "Nothing to do."
+ "The -p option identifies a printer; give\nother options to do something with it."
+E_ADM_NOAWQ
+ "Nothing to do."
+ "The -S option identifies a print wheel;\ngive a -A, -W, and/or -Q option to set\nor change the alerting for it."
+E_ADM_MALIGN
+ "Missing the -M or -f option"
+ "The -a option asks for an alignment\npattern, but you need to tell what form\nto mount."
+E_ADM_NOALIGN
+ "No alignment pattern has been registered with\nthe form \"%s\"."
+ "The form will be mounted anyway. If you\nneed to check the alignment of the form,\nregister an alignment pattern using the\nlpforms command, unmount the form, then\nissue this command again."
+E_ADM_LISTWQ
+ "Illegal combination of options."
+ "Don't give the \"-A list\" option with the\n-W or -Q options."
+E_ADM_NOPSPACE
+ "The LP print service can't take another printer."
+ "The printer configuration has been saved\non disk nonetheless. Stop the LP print\nservice (/usr/sbin/lpshut) and restart it\n(/usr/lib/lp/lpsched) to have it recognize\nthe new printer."
+E_ADM_NOCSPACE
+ "The LP print service can't take another class."
+ "The class configuration has been saved\non disk nonetheless. Stop the LP print\nservice (/usr/sbin/lpshut) and restart it\n(/usr/lib/lp/lpsched) to have it\nrecognize the new class."
+E_ADM_NOPWSPACE
+ "The LP print service can't take in another print\nwheel alert."
+ "The alert configuration has been saved\non disk nonetheless. Stop the LP print\nservice (/usr/sbin/lpshut) and restart it\n(/usr/lib/lp/lpsched) to have it\nrecognize the new print wheel alert."
+E_ADM_BADMOUNT
+ "Shouldn't mount the form."
+ "You may want to adjust the form\ndefinition, if possible. Check that the\nTerminfo database gives correct\nattributes for the printer type.\nThe form is considered mounted anyway."
+E_ADM_NBADMOUNT
+ "The form \"%s\" won't work with these\nprinter types:\n %s"
+ ""
+E_ADM_CLNPR
+ "Can't create both class and printer \"%s\"."
+ "Make the two names different."
+E_ADM_GETSYS
+ "Error reading system information for \"%s\"\n(%s)."
+ ""
+E_ADM_NOSYS
+ "System \"%s\" does not exist."
+ "Use the \"lpsystem -l\" command to list\nall known systems."
+E_ADM_NAMEONLOCAL
+ "You may not specify a remote printer\nname with a local system name."
+ "Either specify a remote system name\nor omit the remote printer name."
+E_ADM_ANYALLNONE
+ "The names \"any\", \"all\" and \"none\" are reserved."
+ "Use a different name when adding a\nprinter. The name \"all\" can be used with\nthe -A, -x, -r, or -c options."
+E_ADM_NFIFO
+ "Can't open FIFO to print alignment pattern.\n(%s)"
+ ""
+E_ADM_NFILTER
+ "No filter to convert the alignment pattern."
+ "The printer can't print the alignment\npattern directly, and there's no filter\nthat will convert it. Check the form\ndefinition. Check the printer type."
+E_ADM_NPAGES
+ "There may be extra lines in the alignment pattern."
+ "If the printed alignment pattern is too\nlong, either add a filter that can print\na subset of pages or redefine the form\nwith a manually truncated pattern.\nProcessing continues."
+E_ADM_FILEBREAK
+ "Ignoring the -o filebreak option."
+ "This is only used with the -a option\nwhen mounting a form, to insert a page\nbreak between alignment patterns.\nPerhaps you left out the -a option?"
+E_ADM_UNALIGN
+ "Ignoring the -a option."
+ "This is only used when MOUNTING a form,\nto print a pattern to help you align it.\nUnmounting a form means you're replacing\nit with blank paper, which needs no\nalignment."
+E_ADM_ERRDEST
+ "The LP print service could not read the disk file\ncontaining this configuration information."
+ "This is probably due to a full spooling\nfile system. If it is, clean out files\nto free up space, then resubmit this\ncommand."
+E_ADM_MANDCHSET
+ "The form requires the character set\n\"%s\"."
+ "Check the form name and form definition.\nSince a particular character set is\nmandatory with this form but the printer\ncan't select that character set, you\ncan't mount the form on this printer."
+E_ADM_MANDPWHEEL1
+ "The form requires the print wheel\n\"%s\"."
+ "This print wheel has been listed as\nmandatory for the form, but it is not\ncurrently mounted. If you don't want the\ncurrent print wheel used, enter the\ncommand again, and identify the print\nwheel to be mounted."
+E_ADM_MANDPWHEEL2
+ "The form requires the print wheel\n\"%s\"."
+ "This print wheel has been listed as\nmandatory for the form. If you made a\nmistake, enter the command again and\nchange the print wheel to be mounted."
+E_ADM_ASINGLES
+ "Only one print wheel at a time, please."
+ "You can only give a single print wheel\nname, not a list of names, when defining\na print wheel alert. Only the first\nprint wheel will be defined. (Maybe you\nleft out the -p option?)"
+E_ADM_MSINGLES
+ "Only one print wheel at a time, please."
+ "You can only give a single print wheel\nname, not a list of names, when mounting\na print wheel. Only the first one will\nbe mounted."
+E_ADM_ONLYSIMPLE
+ "Input types not allowed with multiple printer\ntypes."
+ "The LP print service currently doesn't\nallow input types other than \"simple\"\nwhen more than one printer type is\ngiven. You have to change the printer\ntypes or input types."
+E_ADM_SIGNORE
+ "Certain options ignored for remote printer\n %s."
+ "When you try to change the configuration\nof all printers at once some options are\nignored for remote printers."
+E_ADM_BADPWHEEL
+ "There are no alerts defined for the print wheel\n\"%s\"."
+ "Check the name again."
+E_ADM_BADTRAY
+ "The printer does not have the tray number you specified."
+ "Try using the -t option with -M to set the total number of trays."
+E_ADM_MAXTRAY
+ "The number of trays specified with the -t option must between 1 and 100."
+ ""
+E_ADM_ALSO_SEP_FORM
+ "`%s' cannot be used as a paper name because it\nis already defined as an old style form."
+ "Either use another name, or remove the conflicting form using `lpforms'."
+E_ADM_NOPPD
+ "The ppd \"%s\" does not exist."
+ "Use the command\n find <PPD file repository> -type f\n"
+ "where <PPD file repository> is one or more of the following:\n"
+ " /usr/share/ppd/*/*/\n /usr/share/local/ppd/*/*/\n"
+ " /opt/share/ppd/*/*/\n /var/lp/ppd/*/*/\n"
+ "to find the list of known printer ppd definitions."
+
+#endif
+
+/**
+ ** MESSAGES FOR THE LPFORMS PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_FOR__MSGS
+
+#if WHO_AM_I == I_AM_LPFORMS || WHO_AM_I == I_AM_OZ
+#define E_FOR_MOPENREQX E_LP_HAVEREQS
+#define E_FOR_UALLOWDENY E_LP_UALLOWDENY
+#define E_FOR_EXTRAARG E_LP_EXTRA
+
+E_FOR_FORMNAME
+ "No form name given."
+ "You must specify a form name using the\n-f option."
+E_FOR_NOACT
+ "Nothing to do."
+ "You must give one of these options:\n- -F (new form)\n- -F -l -x -u -A -W -Q (existing form)"
+E_FOR_EMPTYFILE
+ "Empty form description file given."
+ "All defaults will be used; resubmit the\ncommand if this is not what you want.\nProcessing continues."
+E_FOR_DELSTRANGE
+ "Strange, the LP print service accepted\nthe delete form request but the disk\ncopy can't be deleted."
+ ""
+E_FOR_CTMPFILE
+ "Unable to create temporary file."
+ "Set the TMPDIR environment variable to a\nsuitable temporary directory name."
+E_FOR_OPEN
+ "Can't open \"%s\" for reading."
+ "Check that it exists and that you\ncan read it."
+E_FOR_ANYNONE
+ "Reserved words \"any\" and \"none\" are not\nappropriate in this context."
+ ""
+E_FOR_NOFORMS
+ "No forms currently defined."
+ ""
+E_FOR_NOSHCMDERR
+ "No alert given."
+ "You must give a shell command to use as\nthe alert."
+E_FOR_NOSHCMDWARN
+ "No alert defined for form \"%s\"."
+ "Use the -A option to define a shell\ncommand to use as the alert.\nProcessing continues."
+E_FOR_BADHDR
+ "Bad input header in form description file on\nline %d."
+ ""
+E_FOR_BADSCALE
+ "Improper scaled decimal number on line %d."
+ "You can use only 'i' and 'c' for scaling numbers."
+E_FOR_BADINT
+ "Invalid integer given on line %d."
+ "You must give a positive non-zero\ninteger value."
+E_FOR_BADCHSETQUALIFIER
+ "Bad qualifier given after character set on\nline %d."
+ "The only legal qualifier immediately\nfollowing a character set name is\n\",mandatory\"."
+E_FOR_TRAILIN
+ "Bad input follows legal input on line %d."
+ "Check to the System Administrator's\nReference manual for the correct syntax."
+E_FOR_NOTNAME
+ "Incorrect syntax for name on line %d."
+ "Give a name that has 1 to 14 letters,\ndigits, or underscores."
+E_FOR_NOTCTYPE
+ "Incorrect syntax for content type on line %d."
+ "Give a content type that has 1 to 14\nletters, digits, or dashes."
+E_FOR_UNKNOWN
+ "Error accessing form \"%s\"\n(%s)."
+ ""
+E_FOR_FORMBUSY
+ "There are jobs currently queued for form\n\"%s\""
+ "Either wait for the requests to finish\nprinting or cancel them. Use the\nlpstat -o -l command to find out which\nneed this form."
+E_FOR_NOSPACE
+ "The LP print service can't take in another form."
+ "The form definition has been saved on\ndisk nonetheless. Stop the LP print\nservice (/usr/sbin/lpshut) and restart it\n(/usr/lib/lp/lpsched) to have it\nrecognize the new form."
+E_FOR_ANYDEL
+ "Nothing will happen."
+ "The \"-f any\" option is used to set an\nalert for those forms without an alert,\nbut \"-A none\" defines no alert."
+E_FOR_ALSO_SEP_FORM
+ "The form `%s' cannot be defined with\npaper `%s' because `%s' is already\ndefined as an old style form. "
+ "Either use another name, or remove the\nconflicting form using `lpforms'."
+
+#endif
+
+/**
+ ** MESSAGES FOR THE LPSTAT PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_STAT__MSGS
+
+#if WHO_AM_I == I_AM_LPSTAT || WHO_AM_I == I_AM_OZ
+
+E_STAT_BADSET
+ "Non-existent character set \"%s\"."
+ "Check the name again; use the\n\"lpstat -S all\" command to get a list of\nall known character sets."
+E_STAT_BADSTAT
+ "\"%s\" isn't a request ID or destination"
+ "Use the \"lpstat -p all -c all\" command\nto get a list of valid destinations.\nUse the \"lpstat -o all\" command to get a\nlist of all outstanding print requests."
+E_STAT_DONE
+ "\"%s\" already printed."
+ "You can't get any information about this\nrequest, since no record of it remains."
+E_STAT_USER
+ "\"%s\" is not currently a user on this system."
+ "Check the spelling of the name.\nUse the \"lpstat -u all\" command to get a\nlist of outstanding print requests."
+
+#endif
+
+/**
+ ** MESSAGES FOR THE LPSYSTEM PROGRAM
+ **/
+
+/* DON'T TOUCH THE NEXT LINE */
+E_SYS__MSGS
+
+#if WHO_AM_I == I_AM_LPSYSTEM || WHO_AM_I == I_AM_OZ
+
+E_SYS_NOTCPIP
+ "TCP/IP is not installed on this system."
+ ""
+#endif
diff --git a/usr/src/cmd/lp/lib/papi/Makefile b/usr/src/cmd/lp/lib/papi/Makefile
new file mode 100644
index 0000000000..0db8138e89
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/Makefile
@@ -0,0 +1,81 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = psm-lpsched.a
+VERS=.1
+
+LPSCHED_OBJS = lpsched-msgs.o lpsched-service.o lpsched-printers.o \
+ lpsched-jobs.o lpsched-misc.o
+OBJECTS = $(LPSCHED_OBJS) service.o printer.o job.o ppd.o library.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+ROOTLIBDIR= $(ROOT)/usr/lib/print
+
+CPPFLAGS = -I.
+CPPFLAGS += -I$(LPINC)
+CPPFLAGS += -I$(SRC)/lib/print/libpapi-common/common
+CPPFLAGS += -D_REENTRANT
+CPPFLAGS += $(ENVCPPFLAGS1)
+CPPFLAGS += $(ENVCPPFLAGS2)
+LDLIBS += -lcurses -lc
+LDLIBS += -L$(SRC)/cmd/lp/lib/msgs -llpmsg
+LDLIBS += -L$(SRC)/cmd/lp/lib/printers -llpprt
+LDLIBS += -L$(SRC)/cmd/lp/lib/class -llpcls
+LDLIBS += -L$(SRC)/cmd/lp/lib/requests -llpreq
+LDLIBS += -L$(SRC)/cmd/lp/lib/secure -llpsec
+LDLIBS += -L$(SRC)/cmd/lp/lib/forms -llpfrm
+LDLIBS += -L$(SRC)/cmd/lp/lib/access -llpacc
+LDLIBS += -L$(SRC)/cmd/lp/lib/lp -llp
+
+MAPFILES = mapfile
+
+LIBS = $(DYNLIB)
+SRCS= $(OBJECTS:%.o=%.c)
+
+#${ROOTLIBDIR}:
+# $(INS.dir)
+
+POFILE = lp_lib_papi_psm.po
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+_msg: $(POFILE)
+
+install: $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS)
+
+cstyle:
+ $(CSTYLE) $(SRCS)
+
+lint: lintcheck
+
+include ../../../../lib/Makefile.targ
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/papi/job.c b/usr/src/cmd/lp/lib/papi/job.c
new file mode 100644
index 0000000000..aafce80d0c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/job.c
@@ -0,0 +1,1420 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <papi_impl.h>
+
+/*
+ * for an older application that may have been linked with a pre-v1.0
+ * PAPI implementation.
+ */
+papi_status_t
+papiAttributeListAdd(papi_attribute_t ***attrs, int flags, char *name,
+ papi_attribute_value_type_t type, papi_attribute_value_t *value)
+{
+ return (papiAttributeListAddValue(attrs, flags, name, type, value));
+}
+
+#ifdef LP_USE_PAPI_ATTR
+static papi_status_t psm_modifyAttrsFile(papi_attribute_t **attrs, char *file);
+static papi_status_t psm_modifyAttrsList(char *file, papi_attribute_t **attrs,
+ papi_attribute_t ***newAttrs);
+#endif
+
+int32_t
+check_job_id(papi_service_t svc, char *printer, int32_t id)
+{
+ papi_job_t *jobs = NULL;
+ papi_status_t status;
+ int ret = -1;
+ char *jattrs[] = { "job-id",
+ "job-id-requested", NULL };
+
+ status = papiPrinterListJobs(svc, printer, jattrs, PAPI_LIST_JOBS_ALL,
+ 0, &jobs);
+
+ if (status != PAPI_OK) {
+ detailed_error(svc,
+ gettext("Failed to query service for %s: %s\n"),
+ printer, lpsched_status_string(status));
+ return (-1);
+ }
+
+ if (jobs != NULL) {
+ int i = 0;
+
+ for (i = 0; jobs[i] != NULL; i++) {
+ int32_t rid = -1;
+ int32_t jid = -1;
+ papi_attribute_t **list =
+ papiJobGetAttributeList(jobs[i]);
+
+ papiAttributeListGetInteger(list, NULL,
+ "job-id-requested", &rid);
+ papiAttributeListGetInteger(list, NULL,
+ "job-id", &jid);
+
+ /*
+ * check if id matches with either rid or jid
+ */
+ if (rid == id) {
+ /* get the actual id and return it */
+ papiAttributeListGetInteger(list, NULL,
+ "job-id", &id);
+ return (id);
+ } else if (jid == id) {
+ if (rid != -1) {
+ /*
+ * It is a remote lpd job.
+ * It cannot be modified based on job-id
+ * or spool number
+ */
+ return (-1);
+ } else {
+ /*
+ * It is either local job or
+ * remote ipp job
+ */
+ return (id);
+ }
+ }
+ }
+ }
+ return (id);
+}
+
+void
+papiJobFree(papi_job_t job)
+{
+ job_t *tmp = (job_t *)job;
+
+ if (tmp != NULL) {
+ papiAttributeListFree(tmp->attributes);
+ free(tmp);
+ }
+}
+
+void
+papiJobListFree(papi_job_t *jobs)
+{
+ if (jobs != NULL) {
+ int i;
+
+ for (i = 0; jobs[i] != NULL; i++) {
+ papiJobFree(jobs[i]);
+ }
+ free(jobs);
+ }
+}
+
+papi_attribute_t **
+papiJobGetAttributeList(papi_job_t job)
+{
+ job_t *tmp = (job_t *)job;
+
+ if (tmp != NULL)
+ return (tmp->attributes);
+
+ return (NULL);
+}
+
+char *
+papiJobGetPrinterName(papi_job_t job)
+{
+ job_t *tmp = (job_t *)job;
+ char *result = NULL;
+
+ if (tmp != NULL)
+ papiAttributeListGetString(tmp->attributes, NULL,
+ "printer-name", &result);
+
+ return (result);
+}
+
+int32_t
+papiJobGetId(papi_job_t job)
+{
+ job_t *tmp = (job_t *)job;
+ int result = -1;
+
+ if (tmp != NULL)
+ papiAttributeListGetInteger(tmp->attributes, NULL, "job-id",
+ &result);
+
+ return (result);
+}
+
+static REQUEST *
+create_request(papi_service_t svc, char *printer, papi_attribute_t **attributes)
+{
+ REQUEST *r;
+
+ if ((r = calloc(1, sizeof (*r))) != NULL) {
+ char *hostname = NULL;
+
+ r->priority = -1;
+ r->destination = printer_name_from_uri_id(printer, -1);
+
+ papiAttributeListGetString(attributes, NULL,
+ "job-originating-host-name", &hostname);
+
+ if (hostname == NULL) {
+ char host[BUFSIZ];
+
+ if (gethostname(host, sizeof (host)) == 0)
+ papiAttributeListAddString(&attributes,
+ PAPI_ATTR_REPLACE,
+ "job-originating-host-name",
+ host);
+ }
+
+ job_attributes_to_lpsched_request(svc, r, attributes);
+ }
+
+ return (r);
+}
+
+static papi_status_t
+authorized(service_t *svc, int32_t id)
+{
+ papi_status_t result = PAPI_NOT_AUTHORIZED; /* assume the worst */
+ char file[32];
+ REQUEST *r;
+
+ snprintf(file, sizeof (file), "%d-0", id);
+ if ((r = getrequest(file)) != NULL) {
+ uid_t uid = getuid();
+ struct passwd *pw = NULL;
+ char *user = "intruder"; /* assume an intruder */
+
+ if ((pw = getpwuid(uid)) != NULL)
+ user = pw->pw_name; /* use the process owner */
+
+ if ((uid == 0) || (uid == 71)) { /* root/lp can forge this */
+ papi_status_t s;
+ s = papiAttributeListGetString(svc->attributes, NULL,
+ "user-name", &user);
+ if (s != PAPI_OK) /* true root/lp are almighty */
+ result = PAPI_OK;
+ }
+
+ if (result != PAPI_OK) {
+ if (strcmp(user, r->user) == 0)
+ result = PAPI_OK;
+ else {
+ /*
+ * user and r->user might contain the
+ * host info also
+ */
+ char *token1 = strtok(r->user, "@");
+ char *token2 = strtok(NULL, "@");
+ char *token3 = strtok(user, "@");
+ char *token4 = strtok(NULL, "@");
+
+ /*
+ * token1 and token3 contain usernames
+ * token2 and token4 contain hostnames
+ */
+ if ((token1 == NULL) || (token3 == NULL))
+ result = PAPI_NOT_AUTHORIZED;
+ else if ((token4 != NULL) &&
+ (strcmp(token4, "localhost") == 0) &&
+ (strcmp(token3, "root") == 0) ||
+ (strcmp(token3, "lp") == 0)) {
+ /*
+ * root/lp user on server can
+ * cancel any requset
+ */
+ result = PAPI_OK;
+ } else if (strcmp(token1, token3) == 0) {
+ /*
+ * usernames are same
+ * compare the hostnames
+ */
+ if ((token4 != NULL) &&
+ (token2 != NULL) &&
+ (strcmp(token4, "localhost") ==
+ 0)) {
+ /*
+ * Its server machine
+ */
+ static char host[256];
+ if (gethostname(host,
+ sizeof (host)) == 0) {
+ if ((host != NULL) &&
+ (strcmp(host,
+ token2) == 0))
+ result =
+ PAPI_OK;
+ }
+
+ } else if ((token4 != NULL) &&
+ (token2 != NULL) &&
+ (strcmp(token4, token2) == 0)) {
+ result = PAPI_OK;
+ } else if ((token4 == NULL) &&
+ (token2 != NULL)) {
+ /*
+ * When the request is sent from
+ * client to server using ipp
+ * token4 is NULL
+ */
+ result = PAPI_OK;
+ }
+ }
+ }
+ }
+
+ freerequest(r);
+ } else
+ result = PAPI_NOT_FOUND;
+
+ return (result);
+}
+
+static papi_status_t
+copy_file(char *from, char *to)
+{
+ int ifd, ofd;
+ char buf[BUFSIZ];
+ int rc;
+
+ if ((ifd = open(from, O_RDONLY)) < 0)
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+
+ if ((ofd = open(to, O_WRONLY)) < 0) {
+ close(ifd);
+ return (PAPI_NOT_POSSIBLE);
+ }
+
+ while ((rc = read(ifd, buf, sizeof (buf))) > 0)
+ write(ofd, buf, rc);
+
+ close(ifd);
+ close(ofd);
+
+ return (PAPI_OK);
+}
+
+
+#ifdef LP_USE_PAPI_ATTR
+/*
+ * *****************************************************************************
+ *
+ * Description: Create a file containing all the attributes in the attribute
+ * list passed to this function.
+ * This file is then passed through lpsched and given to either
+ * a slow-filter or to the printer's interface script to process
+ * the attributes.
+ *
+ * Parameters: attrs - list of attributes and their values
+ * file - file pathname to create and put the attributes into.
+ *
+ * *****************************************************************************
+ */
+
+static papi_status_t
+psm_copy_attrsToFile(papi_attribute_t **attrs, char *file)
+
+{
+ papi_status_t result = PAPI_OK;
+
+ if ((attrs != NULL) && (*attrs != NULL)) {
+ FILE *out = NULL;
+
+ if ((out = fopen(file, "w")) != NULL) {
+ papiAttributeListPrint(out, attrs, "");
+ fclose(out);
+ } else {
+ result = PAPI_NOT_POSSIBLE;
+ }
+ }
+
+ return (result);
+} /* psm_copy_attrsToFile */
+
+
+/*
+ * *****************************************************************************
+ *
+ * Description: Modify the given attribute 'file' with the attributes from the
+ * 'attrs' list. Attributes already in the file will be replaced
+ * with the new value. New attributes will be added into the file.
+ *
+ * Parameters: attrs - list of attributes and their values
+ * file - file pathname to create and put the attributes into.
+ *
+ * *****************************************************************************
+ */
+
+static papi_status_t
+psm_modifyAttrsFile(papi_attribute_t **attrs, char *file)
+
+{
+ papi_status_t result = PAPI_OK;
+ papi_attribute_t **newAttrs = NULL;
+ struct stat tmpBuf;
+ FILE *fd = NULL;
+
+ if ((attrs != NULL) && (*attrs != NULL) && (file != NULL)) {
+
+ /*
+ * check file exist before try to modify it, if it doesn't
+ * exist assume there is an error
+ */
+ if (stat(file, &tmpBuf) == 0) {
+ /*
+ * if file is currently empty just write the given
+ * attributes to the file otherwise exact the attributes
+ * from the file and modify them accordingly before
+ * writing them back to the file
+ */
+ if (tmpBuf.st_size == 0) {
+ newAttrs = (papi_attribute_t **)attrs;
+
+ fd = fopen(file, "w");
+ if (fd != NULL) {
+ papiAttributeListPrint(fd,
+ newAttrs, "");
+ fclose(fd);
+ } else {
+ result = PAPI_NOT_POSSIBLE;
+ }
+ } else {
+ result =
+ psm_modifyAttrsList(file, attrs, &newAttrs);
+
+ fd = fopen(file, "w");
+ if (fd != NULL) {
+ papiAttributeListPrint(fd,
+ newAttrs, "");
+ fclose(fd);
+ } else {
+ result = PAPI_NOT_POSSIBLE;
+ }
+
+ papiAttributeListFree(newAttrs);
+ }
+ } else {
+ result = PAPI_NOT_POSSIBLE;
+ }
+ }
+
+ return (result);
+} /* psm_modifyAttrsFile */
+
+
+/*
+ * *****************************************************************************
+ *
+ * Description: Extracts the attributes in the given attribute 'file' and
+ * creates a new list 'newAttrs' containing the modified list of
+ * attributes.
+ *
+ * Parameters: file - pathname of file containing attributes to be modified
+ * attrs - list of attributes and their values to modify
+ * newAttrs - returns the modified list of attributes
+ *
+ * *****************************************************************************
+ */
+
+static papi_status_t
+psm_modifyAttrsList(char *file, papi_attribute_t **attrs,
+ papi_attribute_t ***newAttrs)
+
+{
+ papi_status_t result = PAPI_OK;
+ papi_attribute_t *nextAttr = NULL;
+ papi_attribute_value_t **values = NULL;
+ void *iter = NULL;
+ FILE *fd = NULL;
+ register int fD = 0;
+ char aBuff[200];
+ char *a = NULL;
+ char *p = NULL;
+ int count = 0;
+ int n = 0;
+
+ fd = fopen(file, "r");
+ if (fd != NULL) {
+ fD = fileno(fd);
+ a = &aBuff[0];
+ p = &aBuff[0];
+ count = read(fD, &aBuff[0], sizeof (aBuff) - 1);
+ while ((result == PAPI_OK) && (count > 0)) {
+ aBuff[count+n] = '\0';
+ if (count == sizeof (aBuff) - n - 1) {
+ p = strrchr(aBuff, '\n');
+ if (p != NULL) {
+ /* terminate at last complete line */
+ *p = '\0';
+ }
+ }
+ result = papiAttributeListFromString(
+ newAttrs, PAPI_ATTR_EXCL, aBuff);
+
+ if (result == PAPI_OK) {
+ /*
+ * handle any part lines and then read the next
+ * buffer from the file
+ */
+ n = 0;
+ if (p != a) {
+ p++; /* skip NL */
+ n = sizeof (aBuff) - 1 - (p - a);
+ strncpy(aBuff, p, n);
+ }
+ count = read(fD, &aBuff[n],
+ sizeof (aBuff) - n - 1);
+ p = &aBuff[0];
+ }
+ }
+ fclose(fd);
+ }
+
+ /* now modify the attribute list with the new attributes in 'attrs' */
+
+ nextAttr = papiAttributeListGetNext((papi_attribute_t **)attrs, &iter);
+ while ((result == PAPI_OK) && (nextAttr != NULL)) {
+ values = nextAttr->values;
+
+ if ((values != NULL) && (*values != NULL)) {
+ result = papiAttributeListAddValue(newAttrs,
+ PAPI_ATTR_REPLACE,
+ nextAttr->name,
+ nextAttr->type, *values);
+ values++;
+ }
+
+ while ((result == PAPI_OK) &&
+ (values != NULL) && (*values != NULL)) {
+ result = papiAttributeListAddValue(newAttrs,
+ PAPI_ATTR_APPEND,
+ nextAttr->name,
+ nextAttr->type, *values);
+ values++;
+ }
+ nextAttr =
+ papiAttributeListGetNext((papi_attribute_t **)attrs, &iter);
+ }
+
+ return (result);
+} /* papi_modifyAttrsList() */
+#endif
+
+
+papi_status_t
+papiJobSubmit(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ char **files, papi_job_t *job)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+ struct stat statbuf;
+ job_t *j;
+ int file_no;
+ char *request_id = NULL;
+ REQUEST *request;
+ int i;
+ char *c;
+ char *tmp = NULL;
+ char lpfile[BUFSIZ];
+
+ if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
+ (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (job_ticket != NULL)
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+
+ if (files != NULL)
+ for (file_no = 0; files[file_no] != NULL; file_no++) {
+ if (access(files[file_no], R_OK) < 0) {
+ detailed_error(svc,
+ gettext("Cannot access file: %s: %s"),
+ files[file_no], strerror(errno));
+ return (PAPI_BAD_ARGUMENT);
+ }
+ if (stat(files[file_no], &statbuf) < 0) {
+ detailed_error(svc,
+ gettext("Cannot access file: %s: %s"),
+ files[file_no], strerror(errno));
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+ if (statbuf.st_size == 0) {
+ detailed_error(svc,
+ gettext("Zero byte (empty) file: %s"),
+ files[file_no]);
+ return (PAPI_BAD_ARGUMENT);
+ }
+ }
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ /* file_no + 1 for the control file (-0) */
+ status = lpsched_alloc_files(svc, file_no + 1, &request_id);
+ if (status != PAPI_OK)
+ return (status);
+
+ request = create_request(svc, (char *)printer,
+ (papi_attribute_t **)job_attributes);
+
+ for (i = 0; files[i] != NULL; i++) {
+ papi_status_t status;
+ snprintf(lpfile, sizeof (lpfile), "%s%s-%d",
+ "/var/spool/lp/temp/", request_id, i+1);
+ status = copy_file(files[i], lpfile);
+ if (status != PAPI_OK) {
+ detailed_error(svc,
+ gettext("unable to copy: %s -> %s: %s"),
+ files[i], lpfile, strerror(errno));
+ freerequest(request);
+ return (PAPI_DEVICE_ERROR);
+ }
+ addlist(&(request->file_list), lpfile);
+ }
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * store the job attributes in the PAPI job attribute file that was
+ * created by lpsched_alloc_files(), the attributes will then pass
+ * through lpsched and be given to the slow-filters and the printer's
+ * interface script to process them
+ */
+ snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
+ "/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
+ status = psm_copy_attrsToFile(job_attributes, lpfile);
+ if (status != PAPI_OK) {
+ detailed_error(svc, "unable to copy attributes to file: %s: %s",
+ lpfile, strerror(errno));
+ return (PAPI_DEVICE_ERROR);
+ }
+#endif
+
+ /* store the meta-data file */
+ snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
+ if (putrequest(lpfile, request) < 0) {
+ detailed_error(svc, gettext("unable to save request: %s: %s"),
+ lpfile, strerror(errno));
+ freerequest(request);
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ status = lpsched_commit_job(svc, lpfile, &tmp);
+ if (status != PAPI_OK) {
+ unlink(lpfile);
+ freerequest(request);
+ return (status);
+ }
+
+ lpsched_request_to_job_attributes(request, j);
+ freerequest(request);
+
+ if ((c = strrchr(tmp, '-')) != NULL)
+ c++;
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-id", atoi(c));
+ papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-uri", tmp);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiJobSubmitByReference(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ char **files, papi_job_t *job)
+{
+ service_t *svc = handle;
+ struct stat statbuf;
+ job_t *j;
+ int file_no;
+ short status;
+ char *request_id = NULL;
+ REQUEST *request;
+ char *c;
+ char *tmp = NULL;
+ char lpfile[BUFSIZ];
+ char **file_list = NULL;
+
+ if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
+ (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (job_ticket != NULL)
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+
+ if (files != NULL)
+ for (file_no = 0; files[file_no] != NULL; file_no++) {
+ if (access(files[file_no], R_OK) < 0) {
+ detailed_error(svc,
+ gettext("Cannot access file: %s: %s"),
+ files[file_no], strerror(errno));
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+ if (stat(files[file_no], &statbuf) < 0) {
+ detailed_error(svc,
+ gettext("Cannot access file: %s: %s"),
+ files[file_no], strerror(errno));
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+ if (statbuf.st_size == 0) {
+ detailed_error(svc,
+ gettext("Zero byte (empty) file: %s"),
+ files[file_no]);
+ return (PAPI_BAD_ARGUMENT);
+ }
+
+ if (files[file_no][0] != '/') {
+ char path[MAXPATHLEN];
+
+ if (getcwd(path, sizeof (path)) == NULL) {
+ detailed_error(svc, gettext(
+ "getcwd for file: %s: %s"),
+ files[file_no],
+ strerror(errno));
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+ strlcat(path, "/", sizeof (path));
+ if (strlcat(path, files[file_no], sizeof (path))
+ >= sizeof (path)) {
+ detailed_error(svc, gettext(
+ "pathname too long: %s"),
+ files[file_no]);
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+ addlist(&file_list, path);
+ } else
+ addlist(&file_list, (char *)files[file_no]);
+ }
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ /* 1 for the control file (-0) */
+ status = lpsched_alloc_files(svc, 1, &request_id);
+ if (status != PAPI_OK)
+ return (status);
+
+ request = create_request(svc, (char *)printer,
+ (papi_attribute_t **)job_attributes);
+ request->file_list = file_list;
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * store the job attributes in the PAPI job attribute file that was
+ * created by lpsched_alloc_files(), the attributes will then pass
+ * through lpsched and be given to the slow-filters and the printer's
+ * interface script to process them
+ */
+ snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
+ "/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
+ status = psm_copy_attrsToFile(job_attributes, lpfile);
+ if (status != PAPI_OK) {
+ detailed_error(svc, "unable to copy attributes to file: %s: %s",
+ lpfile, strerror(errno));
+ return (PAPI_DEVICE_ERROR);
+ }
+#endif
+
+ /* store the meta-data file */
+ snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
+ if (putrequest(lpfile, request) < 0) {
+ detailed_error(svc, gettext("unable to save request: %s: %s"),
+ lpfile, strerror(errno));
+ freerequest(request);
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ status = lpsched_commit_job(svc, lpfile, &tmp);
+ if (status != PAPI_OK) {
+ unlink(lpfile);
+ freerequest(request);
+ return (status);
+ }
+
+ lpsched_request_to_job_attributes(request, j);
+
+ freerequest(request);
+
+ if ((c = strrchr(tmp, '-')) != NULL)
+ c++;
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-id", atoi(c));
+ papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-uri", tmp);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiJobValidate(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ char **files, papi_job_t *job)
+{
+ papi_status_t status;
+ papi_attribute_t **attributes = NULL;
+ int i;
+
+ papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
+ "job-hold-until", "indefinite");
+ for (i = 0; job_attributes[i]; i++)
+ list_append(&attributes, job_attributes[i]);
+
+ status = papiJobSubmitByReference(handle, printer,
+ (papi_attribute_t **)attributes,
+ job_ticket, files, job);
+ if (status == PAPI_OK) {
+ int id = papiJobGetId(*job);
+
+ if (id != -1)
+ papiJobCancel(handle, printer, id);
+ }
+
+ attributes[1] = NULL; /* after attr[0], they are in another list */
+ papiAttributeListFree(attributes);
+
+ return (status);
+}
+
+papi_status_t
+papiJobStreamOpen(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, papi_stream_t *stream)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+ job_stream_t *s = NULL;
+ char *request_id = NULL;
+ char lpfile[BUFSIZ];
+
+ if ((svc == NULL) || (printer == NULL) || (stream == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (job_ticket != NULL)
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+
+ if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ /* 1 for data, 1 for the meta-data (-0) */
+ status = lpsched_alloc_files(svc, 2, &request_id);
+ if (status != PAPI_OK)
+ return (status);
+
+ papiAttributeListAddString(&job_attributes, PAPI_ATTR_EXCL,
+ "job-name", "standard input");
+
+ s->request = create_request(svc, (char *)printer,
+ (papi_attribute_t **)job_attributes);
+ snprintf(lpfile, sizeof (lpfile), "/var/spool/lp/temp/%s-1",
+ request_id);
+ s->fd = open(lpfile, O_WRONLY);
+ addlist(&(s->request->file_list), lpfile);
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * store the job attributes in the PAPI job attribute file that was
+ * created by lpsched_alloc_files(), the attributes will then pass
+ * through lpsched and be given to the slow-filters and the printer's
+ * interface script to process them
+ */
+ snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
+ "/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
+ status = psm_copy_attrsToFile(job_attributes, lpfile);
+ if (status != PAPI_OK) {
+ detailed_error(svc, "unable to copy attributes to file: %s: %s",
+ lpfile, strerror(errno));
+ close(s->fd);
+ free(s);
+ return (PAPI_DEVICE_ERROR);
+ }
+#endif
+
+ /* store the meta-data file */
+ snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
+ s->meta_data_file = strdup(lpfile);
+ if (putrequest(lpfile, s->request) < 0) {
+ detailed_error(svc, gettext("unable to save request: %s: %s"),
+ lpfile, strerror(errno));
+ s->request = NULL;
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiJobStreamWrite(papi_service_t handle,
+ papi_stream_t stream, void *buffer, size_t buflen)
+{
+ service_t *svc = handle;
+ job_stream_t *s = stream;
+
+ if ((svc == NULL) || (stream == NULL) || (buffer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (write(s->fd, buffer, buflen) != buflen)
+ return (PAPI_DEVICE_ERROR);
+
+ return (PAPI_OK);
+}
+papi_status_t
+papiJobStreamClose(papi_service_t handle,
+ papi_stream_t stream, papi_job_t *job)
+{
+ papi_status_t status = PAPI_OK;
+ service_t *svc = handle;
+ job_stream_t *s = stream;
+ job_t *j = NULL;
+ char *tmp = NULL, *c;
+
+ if ((svc == NULL) || (stream == NULL) || (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ close(s->fd);
+
+ lpsched_request_to_job_attributes(s->request, j);
+
+ if (s->meta_data_file != NULL) {
+ status = lpsched_commit_job(svc, s->meta_data_file, &tmp);
+ if (status != PAPI_OK) {
+ unlink(s->meta_data_file);
+ return (status);
+ }
+ if ((c = strrchr(tmp, '-')) != NULL)
+ c++;
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-id", atoi(c));
+ papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-uri", tmp);
+ free(s->meta_data_file);
+ }
+ freerequest(s->request);
+ free(s);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiJobQuery(papi_service_t handle, char *printer, int32_t job_id,
+ char **requested_attrs,
+ papi_job_t *job)
+{
+ service_t *svc = handle;
+ job_t *j;
+ char *dest;
+ char req_id[32];
+ short rc;
+ char *form = NULL,
+ *request_id = NULL,
+ *charset = NULL,
+ *user = NULL,
+ *slabel = NULL,
+ *file = NULL;
+ time_t date = 0;
+ size_t size = 0;
+ short rank = 0,
+ state = 0;
+
+ if ((handle == NULL) || (printer == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(printer, job_id);
+ snprintf(req_id, sizeof (req_id), "%s-%d", dest, job_id);
+ free(dest);
+
+ rc = snd_msg(svc, S_INQUIRE_REQUEST_RANK, 0, "", "", req_id, "", "");
+ if (rc < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ if (rcv_msg(svc, R_INQUIRE_REQUEST_RANK, &rc, &request_id,
+ &user, &slabel, &size, &date, &state, &dest, &form,
+ &charset, &rank, &file) < 0) {
+ detailed_error(svc,
+ gettext("failed to read response from scheduler"));
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ if ((request_id == NULL) || (request_id[0] == NULL))
+ return (PAPI_NOT_FOUND);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ snprintf(req_id, sizeof (req_id), "%d-0", job_id);
+ lpsched_read_job_configuration(svc, j, req_id);
+
+ job_status_to_attributes(j, request_id, user, slabel, size, date, state,
+ dest, form, charset, rank, file);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiJobMove(papi_service_t handle, char *printer, int32_t job_id,
+ char *destination)
+{
+ papi_status_t result = PAPI_OK;
+ long bits;
+ service_t *svc = handle;
+ char req_id[64];
+ char *queue;
+ char *user = NULL;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
+ (destination == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ queue = printer_name_from_uri_id(printer, job_id);
+ snprintf(req_id, sizeof (req_id), "%s-%d", queue, job_id);
+ free(queue);
+
+ if (papiAttributeListGetString(svc->attributes, NULL, "user-name",
+ &user) == PAPI_OK) {
+ REQUEST *r = getrequest(req_id);
+
+ if ((r != NULL) && (r->user != NULL) &&
+ (strcmp(r->user, user) != 0))
+ result = PAPI_NOT_AUTHORIZED;
+ freerequest(r);
+ }
+
+ if (result == PAPI_OK) {
+ short status = MOK;
+ char *dest = printer_name_from_uri_id(destination, -1);
+
+ if ((snd_msg(svc, S_MOVE_REQUEST, req_id, dest) < 0) ||
+ (rcv_msg(svc, R_MOVE_REQUEST, &status, &bits) < 0))
+ status = MTRANSMITERR;
+
+ free(dest);
+
+ result = lpsched_status_to_papi_status(status);
+ }
+
+ return (result);
+}
+
+papi_status_t
+papiJobCancel(papi_service_t handle, char *printer, int32_t job_id)
+{
+ papi_status_t result = PAPI_OK;
+ service_t *svc = handle;
+ char req_id[64];
+ char *dest;
+ char *user = NULL;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(printer, job_id);
+ snprintf(req_id, sizeof (req_id), "%s-%d", dest, job_id);
+ free(dest);
+
+ if (papiAttributeListGetString(svc->attributes, NULL, "user-name",
+ &user) == PAPI_OK) {
+ REQUEST *r = getrequest(req_id);
+
+ if ((result = authorized(handle, job_id)) != PAPI_OK)
+ result = PAPI_NOT_AUTHORIZED;
+
+ if ((r != NULL) && (r->user != NULL) &&
+ (strcmp(r->user, user) != 0))
+ result = PAPI_NOT_AUTHORIZED;
+ freerequest(r);
+ }
+
+ if (result == PAPI_OK) {
+ short status = MOK;
+
+ if ((snd_msg(svc, S_CANCEL_REQUEST, req_id) < 0) ||
+ (rcv_msg(svc, R_CANCEL_REQUEST, &status) < 0))
+ status = MTRANSMITERR;
+
+ result = lpsched_status_to_papi_status(status);
+ }
+
+ return (result);
+}
+
+papi_status_t
+hold_release_job(papi_service_t handle, char *printer,
+ int32_t job_id, int flag)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+ REQUEST *r = NULL;
+ char *file;
+ char *dest;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((status = authorized(svc, job_id)) != PAPI_OK)
+ return (status);
+
+ dest = printer_name_from_uri_id(printer, job_id);
+ status = lpsched_start_change(svc, dest, job_id, &file);
+ if (status != PAPI_OK)
+ return (status);
+
+ if ((r = getrequest(file)) != NULL) {
+ r->actions &= ~ACT_RESUME;
+ switch (flag) {
+ case 0:
+ r->actions |= ACT_HOLD;
+ break;
+ case 1:
+ r->actions |= ACT_RESUME;
+ break;
+ case 2:
+ r->actions |= ACT_IMMEDIATE;
+ break;
+ }
+ if (putrequest(file, r) < 0) {
+ detailed_error(svc,
+ gettext("failed to write job: %s: %s"),
+ file, strerror(errno));
+ freerequest(r);
+ return (PAPI_DEVICE_ERROR);
+ }
+ freerequest(r);
+ } else {
+ detailed_error(svc, gettext("failed to read job: %s: %s"),
+ file, strerror(errno));
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ status = lpsched_end_change(svc, dest, job_id);
+
+ return (status);
+}
+
+papi_status_t
+papiJobHold(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (hold_release_job(handle, printer, job_id, 0));
+}
+
+papi_status_t
+papiJobRelease(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (hold_release_job(handle, printer, job_id, 1));
+}
+
+papi_status_t
+papiJobPromote(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (hold_release_job(handle, printer, job_id, 2));
+}
+
+papi_status_t
+papiJobModify(papi_service_t handle, char *printer, int32_t job_id,
+ papi_attribute_t **attributes, papi_job_t *job)
+{
+ papi_status_t status;
+ job_t *j = NULL;
+ service_t *svc = handle;
+ char *file = NULL;
+ char *dest;
+ REQUEST *r = NULL;
+ char lpfile[BUFSIZ];
+ int32_t job_id_actual;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
+ (attributes == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ dest = printer_name_from_uri_id(printer, job_id);
+
+ /*
+ * job-id might be job-id-requested
+ * If it is job-id-requested then we need to
+ * look for corresponding job-id
+ */
+ job_id_actual = check_job_id(svc, printer, job_id);
+
+ if (job_id_actual < 0) {
+ status = PAPI_NOT_FOUND;
+ detailed_error(svc,
+ "failed to initiate change for job (%s-%d): %s",
+ dest, job_id, "no such resource");
+ return (status);
+ }
+
+ status = lpsched_start_change(svc, dest, job_id_actual, &file);
+ if (status != PAPI_OK)
+ return (status);
+
+ if ((r = getrequest(file)) != NULL) {
+ job_attributes_to_lpsched_request(handle, r,
+ (papi_attribute_t **)attributes);
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * store the job attributes in the PAPI job attribute file
+ * that was created by the original job request. We need to
+ * modify the attributes in the file as per the new attributes
+ */
+ snprintf(lpfile, sizeof (lpfile), "%s%d-%s",
+ "/var/spool/lp/temp/", job_id_actual, LP_PAPIATTRNAME);
+ status = psm_modifyAttrsFile(attributes, lpfile);
+ if (status != PAPI_OK) {
+ detailed_error(svc,
+ "unable to modify the attributes file: %s: %s",
+ lpfile, strerror(errno));
+ return (PAPI_DEVICE_ERROR);
+ }
+#endif
+
+ if (putrequest(file, r) < 0) {
+ detailed_error(svc,
+ gettext("failed to write job: %s: %s"),
+ file, strerror(errno));
+ freerequest(r);
+ return (PAPI_DEVICE_ERROR);
+ }
+ } else {
+ detailed_error(svc, gettext("failed to read job: %s: %s"),
+ file, strerror(errno));
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ status = lpsched_end_change(svc, dest, job_id_actual);
+ lpsched_request_to_job_attributes(r, j);
+
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-id", job_id_actual);
+
+ freerequest(r);
+
+ return (status);
+}
+
+/*
+ * Extension to PAPI, a variation of this is slated for post-1.0
+ */
+#define DUMMY_FILE "/var/spool/lp/fifos/FIFO"
+
+papi_status_t
+papiJobCreate(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, papi_job_t *job)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ REQUEST *request;
+ char *request_id = NULL;
+ char *c;
+ char *tmp = NULL;
+ char metadata_file[MAXPATHLEN];
+
+ if ((svc == NULL) || (printer == NULL) || (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (job_ticket != NULL)
+ return (PAPI_JOB_TICKET_NOT_SUPPORTED);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ /* 1 for the control file (-0) */
+ status = lpsched_alloc_files(svc, 1, &request_id);
+ if (status != PAPI_OK)
+ return (status);
+
+ /* convert the attributes to an lpsched REQUEST structure */
+ request = create_request(svc, (char *)printer,
+ (papi_attribute_t **)job_attributes);
+ if (request == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+ addlist(&request->file_list, DUMMY_FILE); /* add a dummy file */
+ request->actions |= ACT_HOLD; /* hold the job */
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * store the job attributes in the PAPI job attribute file that was
+ * created by lpsched_alloc_files(), the attributes will then pass
+ * through lpsched and be given to the slow-filters and the printer's
+ * interface script to process them
+ */
+ snprintf(metadata_file, sizeof (metadata_file), "%s%s-%s",
+ "/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
+ status = psm_copy_attrsToFile(job_attributes, metadata_file);
+ if (status != PAPI_OK) {
+ detailed_error(svc, "unable to copy attributes to file: %s: %s",
+ metadata_file, strerror(errno));
+ free(request_id);
+ return (PAPI_DEVICE_ERROR);
+ }
+#endif
+
+ /* store the REQUEST on disk */
+ snprintf(metadata_file, sizeof (metadata_file), "%s-0", request_id);
+ free(request_id);
+ if (putrequest(metadata_file, request) < 0) {
+ detailed_error(svc, gettext("unable to save request: %s: %s"),
+ metadata_file, strerror(errno));
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ status = lpsched_commit_job(svc, metadata_file, &tmp);
+ if (status != PAPI_OK) {
+ unlink(metadata_file);
+ return (status);
+ }
+
+ lpsched_request_to_job_attributes(request, j);
+
+ if ((c = strrchr(tmp, '-')) != NULL)
+ c++;
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-id", atoi(c));
+ papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-uri", tmp);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiJobCommit(papi_service_t handle, char *printer, int32_t id)
+{
+ papi_status_t status = PAPI_OK;
+ service_t *svc = handle;
+ REQUEST *r = NULL;
+ char *metadata_file;
+ char *dest;
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(printer, id);
+ /* tell the scheduler that we want to change the job */
+ status = lpsched_start_change(svc, dest, id, &metadata_file);
+ if (status != PAPI_OK)
+ return (status);
+
+ if ((r = getrequest(metadata_file)) != NULL) {
+ r->actions &= ~ACT_RESUME;
+ r->actions |= ACT_RESUME;
+ dellist(&r->file_list, DUMMY_FILE);
+
+ if (putrequest(metadata_file, r) < 0) {
+ detailed_error(svc,
+ gettext("failed to write job: %s: %s"),
+ metadata_file, strerror(errno));
+ freerequest(r);
+ return (PAPI_DEVICE_ERROR);
+ }
+ } else {
+ detailed_error(svc, gettext("failed to read job: %s: %s"),
+ metadata_file, strerror(errno));
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ status = lpsched_end_change(svc, dest, id);
+ freerequest(r);
+
+ return (status);
+}
+
+papi_status_t
+papiJobStreamAdd(papi_service_t handle, char *printer, int32_t id,
+ papi_stream_t *stream)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+ job_stream_t *s = NULL;
+ char *metadata_file = NULL;
+ char *dest;
+ char path[MAXPATHLEN];
+
+ /* allocate space for the stream */
+ if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ dest = printer_name_from_uri_id(printer, id);
+ /* create/open data file (only root or lp can really do this */
+ snprintf(path, sizeof (path), "/var/spool/lp/temp/%d-XXXXXX", id);
+ if ((s->fd = mkstemp(path)) < 0) {
+ detailed_error(svc, gettext("unable to create sink (%s): %s"),
+ path, strerror(errno));
+ free(s);
+ return (PAPI_NOT_AUTHORIZED);
+ }
+
+ /* add data file to job */
+ status = lpsched_start_change(svc, dest, id, &metadata_file);
+ if (status != PAPI_OK) {
+ close(s->fd);
+ free(s);
+ unlink(path);
+ return (status);
+ }
+
+ if ((s->request = getrequest(metadata_file)) == NULL) {
+ detailed_error(svc, gettext("unable to load request: %s: %s"),
+ metadata_file, strerror(errno));
+ close(s->fd);
+ free(s);
+ unlink(path);
+ return (PAPI_NOT_POSSIBLE);
+ }
+
+ addlist(&(s->request->file_list), path);
+
+ if (putrequest(metadata_file, s->request) < 0) {
+ detailed_error(svc, gettext("unable to save request: %s: %s"),
+ metadata_file, strerror(errno));
+ close(s->fd);
+ free(s);
+ unlink(path);
+ return (PAPI_NOT_POSSIBLE);
+ }
+
+ status = lpsched_end_change(svc, dest, id);
+
+ if (status != PAPI_OK)
+ return (status);
+
+ return (PAPI_OK);
+}
diff --git a/usr/src/cmd/lp/lib/papi/library.c b/usr/src/cmd/lp/lib/papi/library.c
new file mode 100644
index 0000000000..53c3a956a6
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/library.c
@@ -0,0 +1,98 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <string.h>
+#include <papi.h>
+
+static char *calls[] = {
+ /* Attribute Calls */
+ "papiAttributeListAddValue",
+ "papiAttributeListAddBoolean", "papiAttributeListAddCollection",
+ "papiAttributeListAddDatetime", "papiAttributeListAddInteger",
+ "papiAttributeListAddMetadata", "papiAttributeListAddRange",
+ "papiAttributeListAddResolution", "papiAttributeListAddString",
+ "papiAttributeListDelete",
+ "papiAttributeListGetValue", "papiAttributeListGetNext",
+ "papiAttributeListFind",
+ "papiAttributeListGetBoolean", "papiAttributeListGetCollection",
+ "papiAttributeListGetDatetime", "papiAttributeListGetInteger",
+ "papiAttributeListGetMetadata", "papiAttributeListGetRange",
+ "papiAttributeListGetResolution", "papiAttributeListGetString",
+ "papiAttributeListFromString", "papiAttributeListToString",
+ "papiAttributeListFree",
+ /* Job Calls */
+ "papiJobSubmit", "papiJobSubmitByReference", "papiJobValidate",
+ "papiJobStreamOpen", "papiJobStreamWrite", "papiJobStreamClose",
+ "papiJobQuery", "papiJobModify", "papiJobCancel", "papiJobPromote",
+ "papiJobGetAttributeList", "papiJobGetId", "papiJobGetPrinterName",
+ "papiJobFree", "papiJobListFree",
+ "papiJobHold", "papiJobRelease",
+ /* Printer Calls */
+ "papiPrintersList", "papiPrinterQuery", "papiPrinterModify",
+ "papiPrinterAdd", "papiPrinterRemove",
+ "papiPrinterPause", "papiPrinterResume",
+ "papiPrinterDisable", "papiPrinterEnable",
+ "papiPrinterPurgeJobs", "papiPrinterListJobs",
+ "papiPrinterGetAttributeList",
+ "papiPrinterFree", "papiPrinterListFree",
+ /* Service Calls */
+ "papiServiceCreate", "papiServiceDestroy",
+ "papiServiceGetAppData",
+ "papiServiceGetEncryption", "papiServiceGetPassword",
+ "papiServiceGetServiceName", "papiServiceGetUserName",
+ "papiServiceSetAppData", "papiServiceSetAuthCB",
+ "papiServiceSetEncryption", "papiServiceSetPassword",
+ "papiServiceSetUserName",
+ "papiServiceGetAttributeList", "papiServiceGetStatusMessage",
+ /* Misc Calls */
+ "papiStatusString",
+ "papiLibrarySupportedCall", "papiLibrarySupportedCalls",
+ NULL
+};
+
+char **
+papiLibrarySupportedCalls()
+{
+ return (calls);
+}
+
+char
+papiLibrarySupportedCall(const char *name)
+{
+ int i;
+
+ for (i = 0; calls[i] != NULL; i++)
+ if (strcmp(name, calls[i]) == 0)
+ return (PAPI_TRUE);
+
+ return (PAPI_FALSE);
+}
diff --git a/usr/src/cmd/lp/lib/papi/lpsched-jobs.c b/usr/src/cmd/lp/lib/papi/lpsched-jobs.c
new file mode 100644
index 0000000000..0713de64c2
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/lpsched-jobs.c
@@ -0,0 +1,535 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <pwd.h>
+
+/* lpsched include files */
+#include "lp.h"
+#include "requests.h"
+#include "printers.h"
+
+#include <papi_impl.h>
+
+papi_status_t
+job_attributes_to_lpsched_request(papi_service_t svc, REQUEST *r,
+ papi_attribute_t **attributes)
+{
+ papi_status_t status = PAPI_OK;
+ papi_attribute_t *attr;
+ papi_attribute_t **unmapped = NULL;
+ papi_attribute_t *tmp[2];
+ int i;
+ char *s;
+
+ char **options = NULL;
+ char **modes = NULL;
+
+ char pr_filter = 0;
+ char *pr_title = NULL;
+ int pr_width = -1;
+ int pr_indent = -1;
+ int numberUp = 0;
+ int orientation = 0;
+ int lower = 0;
+ int upper = 0;
+ char buf[256];
+ void *iterator = NULL;
+ char *mapped_keys[] = { "copies", "document-format", "form",
+ "job-class", "job-hold-until", "job-host", "job-name",
+ "job-originating-user-name", "job-printer",
+ "job-sheets", "lp-charset", "lp-modes", "number-up",
+ "orienttation-requested", "page-ranges", "pr-filter",
+ "pr-indent", "pr-title", "pr-width", "job-priority",
+ "requesting-user-name", "job-originating-host-name",
+ NULL };
+
+ if (attributes == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ /* replace the current destination */
+ papiAttributeListGetLPString(attributes,
+ "job-printer", &r->destination);
+
+ /* set the copies. We need at least 1 */
+ i = r->copies;
+ papiAttributeListGetInteger(attributes, NULL, "copies", &i);
+ if (i <= 0)
+ i = 1;
+ r->copies = i;
+
+ /*
+ * set the priority. PAPI/IPP uses 1-100, lpsched use 0-39, so we
+ * have to convert it.
+ */
+ if (papiAttributeListGetInteger(attributes, NULL, "job-priority", &i)
+ == PAPI_OK) {
+ if ((i < 1) || (i > 100))
+ i = 50;
+ i = 40 - (i / 2.5);
+ r->priority = i;
+ }
+ if ((r->priority < 0) || (r->priority > 39))
+ r->priority = 20;
+
+ /* set the requested form to print on */
+ papiAttributeListGetLPString(attributes, "form", &r->form);
+
+ /* set the page range */
+ memset(tmp, NULL, sizeof (tmp));
+ tmp[0] = papiAttributeListFind(attributes, "page-ranges");
+ if (tmp[0] != NULL) {
+ char buf[BUFSIZ];
+
+ papiAttributeListToString(tmp, " ", buf, sizeof (buf));
+ if ((s = strchr(buf, '=')) != NULL)
+ r->pages = (char *)strdup(++s);
+ }
+
+ /*
+ * set the document format, converting to old format names as
+ * as needed.
+ */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "document-format", &s);
+ if (s != NULL)
+ r->input_type = strdup(mime_type_to_lp_type(s));
+
+
+ /*
+ * If we don't have an owner, set one.
+ */
+ if (r->user == NULL) {
+ uid_t uid = getuid();
+ struct passwd *pw;
+ char *user = "intruder";
+ char *host = NULL;
+ char buf[256];
+
+ if ((pw = getpwuid(uid)) != NULL)
+ user = pw->pw_name; /* default to the process owner */
+
+ papiAttributeListGetString(attributes, NULL,
+ "job-originating-host-name", &host);
+ papiAttributeListGetString(attributes, NULL,
+ "job-host", &host);
+ papiAttributeListGetString(attributes, NULL,
+ "job-originating-user-name", &user);
+ papiAttributeListGetString(attributes, NULL,
+ "requesting-user-name", &user);
+
+ snprintf(buf, sizeof (buf), "%s%s%s", user,
+ (host ? "@" : ""), (host ? host : ""));
+ user = buf;
+
+ r->user = strdup(user);
+ }
+
+ /* set any held state */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "job-hold-until", &s);
+ if (s != NULL) {
+ r->actions &= ~(ACT_SPECIAL); /* strip immediate/hold/resume */
+ if (strcmp(s, "resume") == 0)
+ r->actions |= ACT_RESUME;
+ else if ((strcmp(s, "immediate") == 0) ||
+ (strcmp(s, "no-hold") == 0))
+ r->actions |= ACT_IMMEDIATE;
+ else if ((strcmp(s, "indefinite") == 0) ||
+ (strcmp(s, "hold") == 0))
+ r->actions |= ACT_HOLD;
+ }
+
+ /* set lp charset/printwheel */
+ papiAttributeListGetLPString(attributes, "lp-charset", &r->charset);
+
+ /* legacy pr(1) filter related garbage "lpr -p" */
+ papiAttributeListGetBoolean(attributes, NULL, "pr-filter", &pr_filter);
+ papiAttributeListGetString(attributes, NULL, "pr-title", &pr_title);
+ papiAttributeListGetInteger(attributes, NULL, "pr-width", &pr_width);
+ papiAttributeListGetInteger(attributes, NULL, "pr-indent", &pr_indent);
+
+ if (pr_filter != 0) {
+ char buf[128];
+
+ if (pr_title != NULL) {
+ snprintf(buf, sizeof (buf), "prtitle='%s'", pr_title);
+ appendlist(&modes, buf);
+ }
+
+ if (pr_width > 0) {
+ snprintf(buf, sizeof (buf), "prwidth=%d", pr_width);
+ appendlist(&modes, buf);
+ }
+
+ if (pr_indent > 0) {
+ snprintf(buf, sizeof (buf), "indent=%d", pr_indent);
+ appendlist(&modes, buf);
+ }
+ } else if ((pr_title != NULL) || (pr_width >= 0) || (pr_indent >= 0))
+ detailed_error(svc, gettext(
+ "pr(1) filter options specified without enabling pr(1) filter"));
+
+ /* add burst page information */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "job-sheets", &s);
+ if ((s != NULL) && (strcasecmp(s, "none") != 0)) {
+ char buf[128];
+ char *class = NULL;
+ char *job_name = NULL;
+
+ papiAttributeListGetLPString(attributes, "job-class", &class);
+ papiAttributeListGetLPString(attributes, "job-name", &job_name);
+
+ /* burst page is enabled by default, add the title */
+ snprintf(buf, sizeof (buf), "%s%s%s",
+ (job_name ? job_name : ""),
+ (job_name && class ? "\\n#####\\n#####\\t\\t " : ""),
+ (class ? class : ""));
+ if (buf[0] != '\0') {
+ if (r->title != NULL)
+ free(r->title);
+ r->title = strdup(buf);
+ }
+ } else if ((s != NULL) && (strcasecmp(s, "none") == 0)) {
+ /* burst page is disabled via lp "option" */
+ appendlist(&options, "nobanner");
+ }
+
+ /* Convert attribute "number-up" to mode group=n */
+ papiAttributeListGetInteger(attributes, NULL, "number-up", &numberUp);
+ if ((numberUp >= 2) && ((numberUp % 2) == 0)) {
+ snprintf(buf, sizeof (buf), "group=%d", numberUp);
+ appendlist(&modes, buf);
+ }
+
+ /*
+ * Convert attribute "orientation-requested" to modes
+ * 'landscape', 'portrait', etc.
+ */
+ papiAttributeListGetInteger(attributes, NULL,
+ "orientation-requested", &orientation);
+ if ((orientation >= 3) && (orientation <= 6)) {
+ switch (orientation) {
+ case 4: /* landscape */
+ case 5: /* reverse-landscape, use landscape instead */
+ appendlist(&modes, "landscape");
+ break;
+ case 3: /* portrait */
+ case 6: /* reverse-portrait, use portrait instead */
+ default:
+ appendlist(&modes, "portrait");
+ break;
+ }
+ }
+
+ /* add "lp -y" modes */
+ attr = papiAttributeListFind(attributes, "lp-modes");
+ if ((attr != NULL) && (attr->type == PAPI_STRING) &&
+ (attr->values != NULL)) {
+ int i;
+
+ for (i = 0; attr->values[i] != NULL; i++)
+ appendlist(&modes, attr->values[i]->string);
+ }
+
+ if (modes != NULL) {
+ if (r->modes == NULL)
+ free(r->modes);
+ r->modes = sprintlist(modes);
+ freelist(modes);
+ }
+
+ /* add any unconsumed attributes to the "options" list */
+ split_and_copy_attributes(mapped_keys, attributes, NULL, &unmapped);
+ if (unmapped != NULL) { /* convert them to lp options */
+ char *buf = malloc(1024);
+ ssize_t size = 1024;
+
+ while (papiAttributeListToString(unmapped, " ", buf, size)
+ != PAPI_OK) {
+ size += 1024;
+ buf = realloc(buf, size);
+ }
+ appendlist(&options, buf);
+ free(buf);
+ papiAttributeListFree(unmapped);
+ }
+
+ if (options != NULL) {
+ if (r->options != NULL)
+ free(r->options);
+ r->options = sprintlist(options);
+ freelist(options);
+ }
+
+ return (PAPI_OK);
+}
+
+/*
+ * Convert REQUEST->outcome (or R_REQUEST_* state) to the equivalent
+ * PAPI attribute representation.
+ */
+static void
+lpsched_request_outcome_to_attributes(papi_attribute_t ***attributes,
+ unsigned short state)
+{
+ if (attributes == NULL)
+ return;
+
+ if (state & RS_NOTIFYING) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x0800); /* notifying user */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-notifying");
+ } else if (state & RS_HELD) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x0001); /* held */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-hold-until-specified");
+ } else if (state & RS_CANCELLED) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x0040); /* job cancelled */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-canceled-by-user");
+ } else if (state & RS_PRINTED) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x0010); /* finished printing job */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-complete");
+ } else if (state & RS_PRINTING) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x0008); /* printing job */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-printing");
+ } else if (state & RS_ADMINHELD) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x2000); /* held by admin */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-hold-until-specified");
+ } else if (state & RS_FILTERED) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x0004); /* filtered */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-filtered");
+ } else if (state & RS_CHANGING) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x0020); /* job held for changing */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-held-for-change");
+ } else if (state & RS_FILTERING) {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x0002); /* being filtered */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-being-filtered");
+ } else {
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-state", 0x4000); /* else */
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-state-reasons", "job-queued");
+ }
+
+
+
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-hold-until",
+ ((state & RS_HELD) ? "indefinite" : "no-hold"));
+}
+
+/*
+ * convert user[@host] to papi attributes
+ */
+static void
+lpsched_user_to_job_attributes(papi_attribute_t ***list, char *user)
+{
+ if ((list != NULL) && (user != NULL) && (user[0] != NULL)) {
+ char *host = strrchr(user, '@');
+
+ if (host != NULL) {
+ *host = NULL;
+ papiAttributeListAddString(list, PAPI_ATTR_REPLACE,
+ "job-originating-user-name", user);
+ papiAttributeListAddString(list, PAPI_ATTR_REPLACE,
+ "job-originating-host-name", host + 1);
+ *host = '@';
+ } else
+ papiAttributeListAddString(list, PAPI_ATTR_REPLACE,
+ "job-originating-user-name", user);
+ }
+}
+
+/*
+ * Convert REQUEST structure to the equivalent PAPI attribute representation.
+ */
+void
+lpsched_request_to_job_attributes(REQUEST *r, job_t *j)
+{
+ char *tmp;
+ int i;
+
+ /* copies */
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "copies", r->copies);
+
+ /* destination */
+ papiAttributeListAddLPString(&j->attributes, PAPI_ATTR_REPLACE,
+ "printer-name", r->destination);
+
+ /* form */
+ papiAttributeListAddLPString(&j->attributes, PAPI_ATTR_REPLACE,
+ "form", r->form);
+
+ /* options */
+ papiAttributeListFromString(&j->attributes, PAPI_ATTR_APPEND,
+ r->options);
+
+ tmp = (((r->options != NULL) && (strstr(r->options, "nobanner")
+ != NULL)) ? "none" : "standard");
+ papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-sheets", tmp);
+
+ tmp = (((r->options != NULL) && (strstr(r->options, "duplex")
+ != NULL)) ? "two-sized" : "one-sided");
+ papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
+ "sides", tmp);
+
+ i = (((r->options != NULL) && (strstr(r->options, "landscape")
+ != NULL)) ? 4 : 3);
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "orientation-requested", i);
+
+ /* priority (map 0-39 to 1-100) */
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-priority",
+ (int)(100 - (r->priority * 2.5)));
+
+ /* pages */
+ papiAttributeListAddLPString(&j->attributes, PAPI_ATTR_REPLACE,
+ "page-ranges", r->pages);
+
+ /* charset */
+ papiAttributeListAddLPString(&j->attributes, PAPI_ATTR_REPLACE,
+ "lp-charset", r->charset);
+
+ /* modes */
+ papiAttributeListAddLPString(&j->attributes, PAPI_ATTR_REPLACE,
+ "lp-modes", r->modes);
+
+ /* title */
+ papiAttributeListAddLPString(&j->attributes, PAPI_ATTR_REPLACE,
+ "job-name", r->title);
+
+ /* input_type */
+
+ /* user */
+ lpsched_user_to_job_attributes(&j->attributes, r->user);
+
+ /* outcome */
+ lpsched_request_outcome_to_attributes(&j->attributes, r->outcome);
+
+ /* constants, (should be derived from options) */
+ papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
+ "number-up", 1);
+
+ papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
+ "multiple-document-handling",
+ "seperate-documents-collated-copies");
+}
+
+/*
+ * Convert R_REQUEST_* results to the equivalent PAPI attribute representation.
+ */
+void
+job_status_to_attributes(job_t *job, char *req_id, char *user, char *slabel,
+ size_t size, time_t date, short state, char *destination,
+ char *form, char *charset, short rank, char *file)
+{
+ char buf[BUFSIZ];
+ char *p;
+
+ lpsched_user_to_job_attributes(&job->attributes, user);
+ papiAttributeListAddInteger(&job->attributes, PAPI_ATTR_REPLACE,
+ "job-k-octets", size/1024);
+ papiAttributeListAddInteger(&job->attributes, PAPI_ATTR_REPLACE,
+ "job-octets", size);
+ if ((p = strrchr(req_id, '-')) != NULL) {
+ papiAttributeListAddInteger(&job->attributes, PAPI_ATTR_REPLACE,
+ "job-id", atoi(++p));
+ }
+ snprintf(buf, sizeof (buf), "lpsched://localhost/printers/%s/%d",
+ destination, atoi(p));
+ papiAttributeListAddString(&job->attributes, PAPI_ATTR_REPLACE,
+ "job-uri", buf);
+ snprintf(buf, sizeof (buf), "lpsched://localhost/printers/%s",
+ destination);
+ papiAttributeListAddString(&job->attributes, PAPI_ATTR_REPLACE,
+ "job-printer-uri", buf);
+ papiAttributeListAddInteger(&job->attributes, PAPI_ATTR_REPLACE,
+ "job-printer-up-time", time(NULL));
+ papiAttributeListAddString(&job->attributes, PAPI_ATTR_REPLACE,
+ "output-device-assigned", destination);
+ papiAttributeListAddString(&job->attributes, PAPI_ATTR_REPLACE,
+ "printer-name", destination);
+ papiAttributeListAddLPString(&job->attributes, PAPI_ATTR_REPLACE,
+ "form", form);
+
+ lpsched_request_outcome_to_attributes(&job->attributes, state);
+
+ papiAttributeListAddInteger(&job->attributes, PAPI_ATTR_REPLACE,
+ "time-at-creation", date);
+ papiAttributeListAddLPString(&job->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-request-id", req_id);
+ papiAttributeListAddLPString(&job->attributes, PAPI_ATTR_REPLACE,
+ "lp-charset", charset);
+ papiAttributeListAddInteger(&job->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-job-state", state);
+ papiAttributeListAddInteger(&job->attributes, PAPI_ATTR_REPLACE,
+ "number-of-intervening-jobs", rank - 1);
+ papiAttributeListAddLPString(&job->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-file", file);
+ papiAttributeListAddLPString(&job->attributes, PAPI_ATTR_EXCL,
+ "job-name", file);
+ papiAttributeListAddLPString(&job->attributes, PAPI_ATTR_EXCL,
+ "tsol-sensitivity-label", slabel);
+}
+
+void
+lpsched_read_job_configuration(service_t *svc, job_t *j, char *file)
+{
+ REQUEST *r;
+
+ if ((r = getrequest(file)) == NULL) {
+ detailed_error(svc, gettext("unable to read job data: %s"),
+ file);
+ return;
+ }
+
+ lpsched_request_to_job_attributes(r, j);
+}
diff --git a/usr/src/cmd/lp/lib/papi/lpsched-misc.c b/usr/src/cmd/lp/lib/papi/lpsched-misc.c
new file mode 100644
index 0000000000..ce45d1aa5c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/lpsched-misc.c
@@ -0,0 +1,189 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <papi_impl.h>
+
+
+papi_status_t
+papiAttributeListAddLPString(papi_attribute_t ***list, int flags, char *name,
+ char *value)
+{
+ papi_status_t result = PAPI_BAD_ARGUMENT;
+
+ if ((list != NULL) && (name != NULL) && (value != NULL) &&
+ (value[0] != NULL))
+ result = papiAttributeListAddString(list, flags, name, value);
+ return (result);
+}
+
+papi_status_t
+papiAttributeListAddLPStrings(papi_attribute_t ***list, int flags, char *name,
+ char **values)
+{
+ papi_status_t result = PAPI_OK;
+ int i, flgs = flags;
+
+ if ((list == NULL) || (name == NULL) || (values == NULL))
+ result = PAPI_BAD_ARGUMENT;
+
+ for (i = 0; ((result == PAPI_OK) && (values[i] != NULL));
+ i++, flgs = PAPI_ATTR_APPEND)
+ result = papiAttributeListAddString(list, flgs, name,
+ values[i]);
+
+ return (result);
+}
+
+void
+papiAttributeListGetLPString(papi_attribute_t **attributes, char *key,
+ char **string)
+{
+ char *value = NULL;
+
+ papiAttributeListGetString(attributes, NULL, key, &value);
+ if (value != NULL) {
+ if (*string != NULL)
+ free(*string);
+ *string = strdup(value);
+ }
+}
+
+void
+papiAttributeListGetLPStrings(papi_attribute_t **attributes, char *key,
+ char ***strings)
+{
+ papi_status_t status;
+ char **values = NULL;
+ char *value = NULL;
+ void *iter = NULL;
+
+ for (status = papiAttributeListGetString(attributes, &iter,
+ key, &value);
+ status == PAPI_OK;
+ status = papiAttributeListGetString(attributes, &iter,
+ NULL, &value))
+ addlist(&values, value);
+
+ if (values != NULL) {
+ if (*strings != NULL)
+ freelist(*strings);
+ *strings = values;
+ }
+}
+
+char *
+printer_name_from_uri_id(char *uri, int32_t id)
+{
+ REQUEST *request = NULL;
+ char *result = "";
+
+ if (uri != NULL) {
+ if ((result = strrchr(uri, '/')) != NULL) {
+ result += 1;
+ } else
+ result = (char *)uri;
+
+ if ((strcmp(result, "jobs") == 0) ||
+ (strcmp(result, "any") == 0) ||
+ (strcmp(result, "all") == 0))
+ result = "";
+ }
+
+ if ((result[0] == NULL) && (id != -1)) {
+ char path[32];
+
+ snprintf(path, sizeof (path), "%d-0", id);
+ if ((request = getrequest(path)) != NULL)
+ result = request->destination;
+ }
+
+ result = strdup(result);
+
+ if (request != NULL)
+ freerequest(request);
+
+ return (result);
+}
+
+/*
+ * LP content type <-> MIME type conversion table. (order dependent)
+ */
+static struct {
+ char *mime_type;
+ char *lp_type;
+} type_map[] = {
+ { "text/plain", "simple" },
+ { "application/octet-stream", "raw" },
+ { "application/octet-stream", "any" },
+ { "application/postscript", "postscript" },
+ { "application/postscript", "ps" },
+ { "application/x-cif", "cif" },
+ { "application/x-dvi", "dvi" },
+ { "application/x-plot", "plot" },
+ { "application/x-ditroff", "troff" },
+ { "application/x-troff", "otroff" },
+ { "application/x-pr", "pr" },
+ { "application/x-fortran", "fortran" },
+ { "application/x-raster", "raster" },
+ { NULL, NULL}
+};
+
+char *
+mime_type_to_lp_type(char *mime_type)
+{
+ int i;
+
+ if (mime_type == NULL)
+ return ("simple");
+
+ for (i = 0; type_map[i].mime_type != NULL; i++)
+ if (strcasecmp(type_map[i].mime_type, mime_type) == 0)
+ return (type_map[i].lp_type);
+
+ return (mime_type);
+}
+
+char *
+lp_type_to_mime_type(char *lp_type)
+{
+ int i;
+
+ if (lp_type == NULL)
+ return ("text/plain");
+
+ for (i = 0; type_map[i].lp_type != NULL; i++)
+ if (strcasecmp(type_map[i].lp_type, lp_type) == 0)
+ return (type_map[i].mime_type);
+
+ return (lp_type);
+}
diff --git a/usr/src/cmd/lp/lib/papi/lpsched-msgs.c b/usr/src/cmd/lp/lib/papi/lpsched-msgs.c
new file mode 100644
index 0000000000..2d64912d08
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/lpsched-msgs.c
@@ -0,0 +1,623 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <libintl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+
+/* lpsched include files */
+#include "lp.h"
+#include "msgs.h"
+#include "printers.h"
+#include "class.h"
+
+#include <papi_impl.h>
+
+
+/*
+ * Format and send message to lpsched (die if any errors occur)
+ */
+/*VARARGS1*/
+int
+snd_msg(service_t *svc, int type, ...)
+{
+ int rc = -1;
+ va_list ap;
+
+ if (svc == NULL)
+ return (-1);
+
+ /* fill the message buffer */
+ va_start(ap, type);
+ rc = _putmessage(svc->msgbuf, type, ap);
+ va_end(ap);
+ if (rc < 0) {
+ detailed_error(svc,
+ gettext("unable to build message for scheduler: %s"),
+ strerror(errno));
+ return (rc);
+ }
+
+ /* write the message */
+ while (((rc = mwrite(svc->md, svc->msgbuf)) < 0) && (errno == EINTR)) {
+ }
+
+ if (rc < 0)
+ detailed_error(svc,
+ gettext("unable to send message to scheduler: %s"),
+ strerror(errno));
+ return (rc);
+}
+
+/*
+ * Receive message from lpsched (die if any errors occur)
+ */
+int
+rcv_msg(service_t *svc, int type, ...)
+{
+ int rc = -1;
+
+ if (svc == NULL)
+ return (-1);
+
+ /* read the message */
+ while (((rc = mread(svc->md, svc->msgbuf, svc->msgbuf_size)) < 0) &&
+ (errno == EINTR)) {
+ }
+
+ if (rc < 0)
+ detailed_error(svc,
+ gettext("unable to read message from scheduler: %s"),
+ strerror(errno));
+ else {
+ va_list ap;
+
+ va_start(ap, type);
+ rc = _getmessage(svc->msgbuf, type, ap);
+ va_end(ap);
+
+ if (rc < 0)
+ detailed_error(svc,
+ gettext("unable to parse message from scheduler: %s"),
+ strerror(errno));
+ }
+
+ return (rc);
+}
+
+papi_status_t
+lpsched_status_to_papi_status(int status)
+{
+ switch (status) {
+ case MNOMEM:
+ return (PAPI_TEMPORARY_ERROR);
+ case MNOFILTER:
+ return (PAPI_DOCUMENT_FORMAT_ERROR);
+ case MNOOPEN:
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ case MERRDEST:
+ case MDENYDEST:
+ return (PAPI_NOT_ACCEPTING);
+ case MNOMEDIA:
+ return (PAPI_PRINT_SUPPORT_FILE_NOT_FOUND);
+ case MDENYMEDIA:
+ case MNOPERM:
+ return (PAPI_NOT_AUTHORIZED);
+ case MUNKNOWN:
+ case MNODEST:
+ case MNOINFO:
+ return (PAPI_NOT_FOUND);
+ case MTRANSMITERR:
+ return (PAPI_SERVICE_UNAVAILABLE);
+ case M2LATE:
+ return (PAPI_GONE);
+ case MBUSY:
+ return (PAPI_PRINTER_BUSY);
+ case MOK:
+ case MOKMORE:
+ return (PAPI_OK);
+ }
+
+ return (PAPI_INTERNAL_ERROR);
+}
+
+char *
+lpsched_status_string(short status)
+{
+ switch (status) {
+ case MNOMEM:
+ return (gettext("lpsched: out of memory"));
+ case MNOFILTER:
+ return (gettext("No filter available to convert job"));
+ case MNOOPEN:
+ return (gettext("lpsched: could not open request"));
+ case MERRDEST:
+ return (gettext("queue disabled"));
+ case MDENYDEST:
+ return (gettext("destination denied request"));
+ case MNOMEDIA:
+ return (gettext("unknown form specified in job"));
+ case MDENYMEDIA:
+ return (gettext("access denied to form specified in job"));
+ case MUNKNOWN:
+ return (gettext("no such resource"));
+ case MNODEST:
+ return (gettext("unknown destination"));
+ case MNOPERM:
+ return (gettext("permission denied"));
+ case MNOINFO:
+ return (gettext("no information available"));
+ case MTRANSMITERR:
+ return (gettext("failure to communicate with lpsched"));
+ default: {
+ static char result[16];
+
+ snprintf(result, sizeof (result), gettext("status: %d"),
+ status);
+ return (result);
+ }
+ }
+}
+
+papi_status_t
+lpsched_alloc_files(papi_service_t svc, int number, char **prefix)
+{
+ papi_status_t result = PAPI_OK;
+ short status = MOK;
+
+ if ((svc == NULL) || (prefix == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((snd_msg(svc, S_ALLOC_FILES, number) < 0) ||
+ (rcv_msg(svc, R_ALLOC_FILES, &status, prefix) < 0))
+ status = MTRANSMITERR;
+
+ if (status != MOK) {
+ detailed_error(svc,
+ gettext("failed to allocate %d file(s) for request: %s"),
+ number, lpsched_status_string(status));
+ result = lpsched_status_to_papi_status(status);
+ }
+
+ return (result);
+}
+
+papi_status_t
+lpsched_commit_job(papi_service_t svc, char *job, char **tmp)
+/* job is host/req-id */
+{
+ papi_status_t result = PAPI_OK;
+ short status = MOK;
+ long bits;
+
+ if ((svc == NULL) || (job == NULL) || (tmp == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((snd_msg(svc, S_PRINT_REQUEST, job) < 0) ||
+ (rcv_msg(svc, R_PRINT_REQUEST, &status, tmp, &bits) < 0))
+ status = MTRANSMITERR;
+
+ if (status != MOK) {
+ detailed_error(svc, gettext("failed to commit job (%s): %s"),
+ job, lpsched_status_string(status));
+ result = lpsched_status_to_papi_status(status);
+ }
+
+ return (result);
+}
+
+papi_status_t
+lpsched_start_change(papi_service_t svc, char *printer, int32_t job_id,
+ char **tmp)
+{
+ papi_status_t result = PAPI_OK;
+ short status = MOK;
+ char req[BUFSIZ];
+ char *dest;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(printer, job_id);
+ snprintf(req, sizeof (req), "%s-%d", dest, job_id);
+ free(dest);
+
+ if ((snd_msg(svc, S_START_CHANGE_REQUEST, req) < 0) ||
+ (rcv_msg(svc, R_START_CHANGE_REQUEST, &status, tmp) < 0))
+ status = MTRANSMITERR;
+
+ if (status != MOK) {
+ detailed_error(svc,
+ gettext("failed to initiate change for job (%s-%d): %s"),
+ printer,
+ job_id, lpsched_status_string(status));
+ result = lpsched_status_to_papi_status(status);
+ }
+
+ return (result);
+}
+
+papi_status_t
+lpsched_end_change(papi_service_t svc, char *printer, int32_t job_id)
+{
+ papi_status_t result = PAPI_OK;
+ short status = MOK;
+ long bits;
+ char req[BUFSIZ];
+ char *dest;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(printer, job_id);
+ snprintf(req, sizeof (req), "%s-%d", dest, job_id);
+ free(dest);
+
+ if ((snd_msg(svc, S_END_CHANGE_REQUEST, req) < 0) ||
+ (rcv_msg(svc, R_END_CHANGE_REQUEST, &status, &bits) < 0))
+ status = MTRANSMITERR;
+
+ if (status != MOK) {
+ detailed_error(svc,
+ gettext("failed to commit change for job (%s-%d): %s"), printer,
+ job_id, lpsched_status_string(status));
+ result = lpsched_status_to_papi_status(status);
+ }
+
+ return (result);
+}
+
+papi_status_t
+lpsched_accept_printer(papi_service_t svc, char *printer)
+{
+ papi_status_t result = PAPI_OK;
+ short status = MOK;
+ char *req_id;
+ char *dest;
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(printer, -1);
+ if ((snd_msg(svc, S_ACCEPT_DEST, dest) < 0) ||
+ (rcv_msg(svc, R_ACCEPT_DEST, &status, &req_id) < 0))
+ status = MTRANSMITERR;
+ free(dest);
+
+ if ((status != MOK) && (status != MERRDEST)) {
+ detailed_error(svc, "%s: %s", printer,
+ lpsched_status_string(status));
+ }
+ result = lpsched_status_to_papi_status(status);
+
+ return (result);
+}
+
+papi_status_t
+lpsched_reject_printer(papi_service_t svc, char *printer, char *message)
+{
+ papi_status_t result = PAPI_OK;
+ short status = MOK;
+ char *req_id;
+ char *dest;
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (message == NULL)
+ message = "stopped by user";
+
+ dest = printer_name_from_uri_id(printer, -1);
+ if ((snd_msg(svc, S_REJECT_DEST, dest, message, 0) < 0) ||
+ (rcv_msg(svc, R_REJECT_DEST, &status, &req_id) < 0))
+ status = MTRANSMITERR;
+ free(dest);
+
+ if ((status != MOK) && (status != MERRDEST)) {
+ detailed_error(svc, "%s: %s", printer,
+ lpsched_status_string(status));
+ }
+ result = lpsched_status_to_papi_status(status);
+
+ return (result);
+}
+
+papi_status_t
+lpsched_enable_printer(papi_service_t svc, char *printer)
+{
+ papi_status_t result = PAPI_OK;
+ short status = MOK;
+ char *req_id;
+ char *dest;
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(printer, -1);
+ if ((snd_msg(svc, S_ENABLE_DEST, dest) < 0) ||
+ (rcv_msg(svc, R_ENABLE_DEST, &status, &req_id) < 0))
+ status = MTRANSMITERR;
+ free(dest);
+
+ if ((status != MOK) && (status != MERRDEST)) {
+ detailed_error(svc, "%s: %s", printer,
+ lpsched_status_string(status));
+ }
+ result = lpsched_status_to_papi_status(status);
+
+ return (result);
+}
+
+papi_status_t
+lpsched_disable_printer(papi_service_t svc, char *printer, char *message)
+{
+ papi_status_t result = PAPI_OK;
+ short status = MOK;
+ char *req_id;
+ char *dest;
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (message == NULL)
+ message = "stopped by user";
+
+ dest = printer_name_from_uri_id(printer, -1);
+ if ((snd_msg(svc, S_DISABLE_DEST, dest, message, 0) < 0) ||
+ (rcv_msg(svc, R_DISABLE_DEST, &status, &req_id) < 0))
+ status = MTRANSMITERR;
+ free(dest);
+
+ if ((status != MOK) && (status != MERRDEST)) {
+ detailed_error(svc, "%s: %s", printer,
+ lpsched_status_string(status));
+ }
+ result = lpsched_status_to_papi_status(status);
+
+ return (result);
+}
+
+papi_status_t
+lpsched_load_unload_dest(papi_service_t handle, char *dest, int type)
+{
+ service_t *svc = handle;
+ papi_status_t result;
+ short status = MOK;
+
+ /* tell the scheduler it's going */
+ if (snd_msg(svc, type, dest, "", "") < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ switch (type) {
+ case S_LOAD_PRINTER:
+ type = R_LOAD_PRINTER;
+ break;
+ case S_UNLOAD_PRINTER:
+ type = R_UNLOAD_PRINTER;
+ break;
+ case S_LOAD_CLASS:
+ type = R_LOAD_CLASS;
+ break;
+ case S_UNLOAD_CLASS:
+ type = R_UNLOAD_CLASS;
+ }
+
+ if (rcv_msg(svc, type, &status) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ result = lpsched_status_to_papi_status(status);
+
+ return (result);
+}
+
+papi_status_t
+lpsched_remove_class(papi_service_t handle, char *dest)
+{
+ papi_status_t result;
+
+ /* tell the scheduler it's going */
+ result = lpsched_load_unload_dest(handle, dest, S_UNLOAD_CLASS);
+
+ if (result == PAPI_OK) {
+ /* remove the scheduler config files */
+ if (delclass(dest) == -1)
+ result = PAPI_SERVICE_UNAVAILABLE;
+ }
+
+ return (result);
+}
+
+static void
+remove_from_class(papi_service_t handle, char *dest, CLASS *cls)
+{
+ if (dellist(&cls->members, dest) == 0) {
+ if (cls->members != NULL) {
+ if (putclass(cls->name, cls) == 0)
+ (void) lpsched_load_unload_dest(handle,
+ cls->name, S_LOAD_CLASS);
+ } else
+ (void) lpsched_remove_class(handle, cls->name);
+ }
+}
+
+papi_status_t
+lpsched_remove_printer(papi_service_t handle, char *dest)
+{
+
+ papi_status_t result;
+
+ /* tell the scheduler it's going */
+ result = lpsched_load_unload_dest(handle, dest, S_UNLOAD_PRINTER);
+
+ if (result == PAPI_OK) {
+ CLASS *cls;
+ char *dflt;
+
+ /* remove the scheduler config files */
+ if (delprinter(dest) == -1)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ /* remove from any classes */
+ while ((cls = getclass(NAME_ALL)) != NULL) {
+ if (searchlist(dest, cls->members) != 0)
+ remove_from_class(handle, dest, cls);
+ freeclass(cls);
+ }
+
+ /* reset the default if it needs to be done */
+ if (((dflt = getdefault()) != NULL) &&
+ (strcmp(dflt, dest) == 0))
+ putdefault(NAME_NONE);
+ }
+
+ return (result);
+}
+
+papi_status_t
+lpsched_add_modify_class(papi_service_t handle, char *dest,
+ papi_attribute_t **attributes)
+{
+ papi_status_t result;
+ void *iter = NULL;
+ char **members = NULL;
+ char *member;
+
+ /*
+ * The only attribute that we can modify for a class is the set of
+ * members. Anything else will be ignored.
+ */
+ for (result = papiAttributeListGetString(attributes, &iter,
+ "member-names", &member);
+ result == PAPI_OK;
+ result = papiAttributeListGetString(attributes, &iter,
+ NULL, &member))
+ addlist(&members, member);
+
+ if (members != NULL) {
+ /* modify the configuration file */
+ CLASS class;
+
+ memset(&class, 0, sizeof (class));
+ class.name = dest;
+ class.members = members;
+
+ if (putclass(dest, &class) == -1) {
+ if ((errno == EPERM) || (errno == EACCES))
+ result = PAPI_NOT_AUTHORIZED;
+ else
+ result = PAPI_NOT_POSSIBLE;
+ } else
+ result = PAPI_OK;
+
+ freelist(members);
+ } else
+ result = PAPI_ATTRIBUTES;
+
+ /* tell the scheduler about the changes */
+ if (result == PAPI_OK)
+ result = lpsched_load_unload_dest(handle, dest, S_LOAD_CLASS);
+
+ return (result);
+}
+
+papi_status_t
+lpsched_add_printer(papi_service_t handle, char *dest,
+ papi_attribute_t **attributes)
+{
+ PRINTER *p;
+ papi_status_t result = PAPI_TEMPORARY_ERROR;
+
+ if ((p = calloc(1, sizeof (*p))) != NULL) {
+ p->name = strdup(dest);
+ p->banner = BAN_ALWAYS;
+ p->interface = strdup("/usr/lib/lp/model/uri");
+ p->fault_alert.shcmd = strdup("mail");
+
+ attributes_to_printer(attributes, p);
+
+ if (putprinter(dest, p) == -1) {
+ if ((errno == EPERM) || (errno == EACCES))
+ result = PAPI_NOT_AUTHORIZED;
+ else
+ result = PAPI_NOT_POSSIBLE;
+ } else
+ result = PAPI_OK;
+
+ freeprinter(p);
+ }
+
+ /* tell the scheduler about the changes */
+ if (result == PAPI_OK)
+ result = lpsched_load_unload_dest(handle, dest, S_LOAD_PRINTER);
+
+ return (result);
+}
+
+papi_status_t
+lpsched_add_modify_printer(papi_service_t handle, char *dest,
+ papi_attribute_t **attributes, int type)
+{
+ PRINTER *p;
+ papi_status_t result;
+
+ if (type == 0) {
+ if ((p = calloc(1, sizeof (*p))) != NULL) {
+ p->name = strdup(dest);
+ p->banner = BAN_ALWAYS;
+ p->interface = strdup("/usr/lib/lp/model/uri");
+ p->fault_alert.shcmd = strdup("mail");
+ }
+ } else
+ p = getprinter(dest);
+
+ if (p != NULL) {
+ attributes_to_printer(attributes, p);
+
+ if (putprinter(dest, p) == -1) {
+ if ((errno == EPERM) || (errno == EACCES))
+ result = PAPI_NOT_AUTHORIZED;
+ else
+ result = PAPI_NOT_POSSIBLE;
+ } else
+ result = PAPI_OK;
+
+ freeprinter(p);
+ } else
+ result = PAPI_NOT_POSSIBLE;
+
+ /* tell the scheduler about the changes */
+ if (result == PAPI_OK)
+ result = lpsched_load_unload_dest(handle, dest, S_LOAD_PRINTER);
+
+ return (result);
+}
diff --git a/usr/src/cmd/lp/lib/papi/lpsched-printers.c b/usr/src/cmd/lp/lib/papi/lpsched-printers.c
new file mode 100644
index 0000000000..3765e21f66
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/lpsched-printers.c
@@ -0,0 +1,496 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <libintl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <papi_impl.h>
+
+#include "class.h"
+
+void
+lpsched_printer_status_to_attributes(papi_attribute_t ***attrs,
+ unsigned short status)
+{
+ if (attrs == NULL)
+ return;
+
+ if (!(status & (PS_DISABLED|PS_LATER))) {
+ if (status & PS_FAULTED) {
+ if (status & PS_BUSY)
+ /* faulted printing */
+ papiAttributeListAddInteger(attrs,
+ PAPI_ATTR_REPLACE,
+ "printer-state", 0x06);
+ else
+ /* faulted printer */
+ papiAttributeListAddInteger(attrs,
+ PAPI_ATTR_REPLACE,
+ "printer-state", 0x07);
+
+ papiAttributeListAddString(attrs, PAPI_ATTR_REPLACE,
+ "printer-state-reasons", "none");
+ } else if (status & PS_BUSY) {
+ papiAttributeListAddInteger(attrs, PAPI_ATTR_REPLACE,
+ "printer-state", 0x04); /* processing */
+ papiAttributeListAddString(attrs, PAPI_ATTR_REPLACE,
+ "printer-state-reasons", "moving-to-paused");
+ } else if (status & PS_FORM_FAULT) {
+ papiAttributeListAddInteger(attrs, PAPI_ATTR_REPLACE,
+ "printer-state", 0x05); /* stopped */
+ papiAttributeListAddString(attrs, PAPI_ATTR_REPLACE,
+ "printer-state-reasons",
+ "interpreter-resource-unavailable");
+ } else
+ papiAttributeListAddInteger(attrs, PAPI_ATTR_REPLACE,
+ "printer-state", 0x03); /* idle */
+ } else if (status & PS_DISABLED) {
+ papiAttributeListAddInteger(attrs, PAPI_ATTR_REPLACE,
+ "printer-state", 0x05); /* stopped */
+ papiAttributeListAddString(attrs, PAPI_ATTR_REPLACE,
+ "printer-state-reasons", "paused");
+ } else if (status & PS_LATER) {
+ papiAttributeListAddInteger(attrs, PAPI_ATTR_REPLACE,
+ "printer-state", 0x08); /* waiting for auto reply */
+ papiAttributeListAddString(attrs, PAPI_ATTR_REPLACE,
+ "printer-state-reasons", "moving-to-paused");
+ } else {
+ papiAttributeListAddInteger(attrs, PAPI_ATTR_REPLACE,
+ "printer-state", 0x03); /* idle */
+ }
+
+ papiAttributeListAddBoolean(attrs, PAPI_ATTR_REPLACE,
+ "printer-is-accepting-jobs",
+ ((status & PS_REJECTED) != PS_REJECTED));
+ papiAttributeListAddBoolean(attrs, PAPI_ATTR_REPLACE,
+ "printer-is-processing-jobs",
+ ((status & PS_DISABLED) != PS_DISABLED));
+}
+
+void
+lpsched_printer_defaults(papi_attribute_t ***attributes)
+{
+ if (attributes == NULL)
+ return;
+
+ papiAttributeListAddBoolean(attributes, PAPI_ATTR_REPLACE,
+ "multiple-document-jobs-supported", PAPI_TRUE);
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "multiple-document-handling-supported",
+ "seperate-documents-colated-copies");
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "pdl-override-supported", "not-attempted");
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-priority-supported", 40);
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-priority-default", 20);
+ papiAttributeListAddRange(attributes, PAPI_ATTR_REPLACE,
+ "copies-supported", 1, 65535);
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "copies-default", 1);
+ papiAttributeListAddBoolean(attributes, PAPI_ATTR_REPLACE,
+ "page-ranges-supported", PAPI_TRUE);
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "number-up-supported", 1);
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "number-up-default", 1);
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-hold-until-supported", "no-hold");
+ papiAttributeListAddString(attributes, PAPI_ATTR_APPEND,
+ "job-hold-until-supported", "indefinite");
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "job-hold-until-default", "no-hold");
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "document-format-default", "application/octet-stream");
+
+}
+
+papi_status_t
+lpsched_printer_configuration_to_attributes(service_t *svc, printer_t *p,
+ char *dest)
+{
+ PRINTER *tmp;
+ char buf[BUFSIZ+1];
+ struct utsname sysname;
+ char **allowed = NULL, **denied = NULL;
+ char **f_allowed = NULL, **f_denied = NULL;
+
+ if ((svc == NULL) || (p == NULL) || (dest == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* get the configuration DB data */
+ if ((tmp = getprinter(dest)) == NULL) {
+ detailed_error(svc,
+ gettext("unable to read configuration data"));
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ /* name */
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-name", tmp->name);
+ if (tmp->name != NULL) {
+ char uri[BUFSIZ];
+
+ snprintf(uri, sizeof (uri), "lpsched://localhost/printers/%s",
+ tmp->name);
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-uri-supported", uri);
+ }
+
+ /* banner */
+ if ((tmp->banner & BAN_OPTIONAL) == BAN_OPTIONAL)
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_APPEND,
+ "job-sheets-supported", "optional");
+ else if (tmp->banner & BAN_NEVER)
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_APPEND,
+ "job-sheets-supported", "none");
+ else if (tmp->banner & BAN_ALWAYS)
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_APPEND,
+ "job-sheets-supported", "standard");
+
+ /* input_types */
+ if (tmp->input_types != NULL) {
+ int i;
+
+ for (i = 0; tmp->input_types[i] != NULL; i++)
+ papiAttributeListAddLPString(&p->attributes,
+ PAPI_ATTR_APPEND, "document-format-supported",
+ lp_type_to_mime_type(tmp->input_types[i]));
+ }
+
+ /* description */
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-info", tmp->description);
+
+ /* add lpsched specific attributes */
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "device-uri", tmp->device);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-dial-info", tmp->dial_info);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-fault-recovery", tmp->fault_rec);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-interface-script", tmp->interface);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-data-rate", tmp->speed);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-stty", tmp->stty);
+ papiAttributeListAddBoolean(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-login-term", tmp->login);
+ papiAttributeListAddBoolean(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-daisy", tmp->daisy);
+ papiAttributeListAddLPStrings(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-charsets", tmp->char_sets);
+#ifdef CAN_DO_MODULES
+ papiAttributeListAddLPStrings(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-modules", tmp->modules);
+#endif /* CAN_DO_MODULES */
+ papiAttributeListAddLPStrings(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-options", tmp->options);
+ papiAttributeListAddLPStrings(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-printer-type", tmp->printer_types);
+ if (tmp->fault_alert.shcmd != NULL) {
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-fault-alert-command",
+ tmp->fault_alert.shcmd);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-fault-alert-threshold",
+ tmp->fault_alert.Q);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-fault-alert-interval",
+ tmp->fault_alert.W);
+ }
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-cpi-value", tmp->cpi.val);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-cpi-unit", tmp->cpi.sc);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-lpi-value", tmp->lpi.val);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-lpi-unit", tmp->lpi.sc);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-plen-value", tmp->plen.val);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-plen-unit", tmp->plen.sc);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-pwid-value", tmp->pwid.val);
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-pwid-unit", tmp->pwid.sc);
+
+ /* allow/deny list */
+ load_userprinter_access(dest, &allowed, &denied);
+ papiAttributeListAddLPStrings(&p->attributes, PAPI_ATTR_REPLACE,
+ "requesting-user-name-allowed", allowed);
+ papiAttributeListAddLPStrings(&p->attributes, PAPI_ATTR_REPLACE,
+ "requesting-user-name-denied", denied);
+
+ freelist(allowed);
+ freelist(denied);
+
+ /* forms allow/deny list */
+ load_formprinter_access(dest, &f_allowed, &f_denied);
+ papiAttributeListAddLPStrings(&p->attributes, PAPI_ATTR_REPLACE,
+ "form-supported", f_allowed);
+
+ /*
+ * All forms allowed case
+ * When all forms are allowed forms.allow does not get created but
+ * forms.deny file gets created with no entries
+ */
+ if ((f_allowed == NULL) && (f_denied != NULL) && (f_denied[0] == NULL))
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "form-supported", "all");
+
+ freelist(f_allowed);
+ freelist(f_denied);
+
+#ifdef LP_USE_PAPI_ATTR
+ if (tmp->ppd != NULL) {
+ int fd;
+ struct stat sbuf;
+
+ /* construct the two URIs for the printer's PPD file */
+ if (uname(&sysname) < 0) {
+ /* failed to get systen name */
+ sysname.nodename[0] = 0;
+ }
+ snprintf(buf, sizeof (buf), "file://%s%s/ppd/%s.ppd",
+ sysname.nodename, ETCDIR, tmp->name);
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_REPLACE,
+ "ppd-file-uri", buf);
+
+ snprintf(buf, sizeof (buf), "file://%s%s",
+ sysname.nodename, tmp->ppd);
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-printer-configure-ppd-uri", buf);
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-ppd-source-path", tmp->ppd);
+
+ snprintf(buf, sizeof (buf), "%s/ppd/%s.ppd", ETCDIR, tmp->name);
+
+ /*
+ * We don't return error on any of the error conditions, we just
+ * silently return without adding the attribute.
+ */
+ PPDFileToAttributesList(&p->attributes, buf);
+ }
+#endif
+
+ freeprinter(tmp);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+printer_status_to_attributes(printer_t *p, char *printer, char *form,
+ char *character_set, char *disable_reason, char *reject_reason,
+ short status, char *request_id,
+ long disable_date, long reject_date)
+{
+ if (p == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "form-ready", form);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-active-job", request_id);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-mounted-char-set", character_set);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-disable-reason", disable_reason);
+ papiAttributeListAddDatetime(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-disable-date", disable_date);
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-reject-reason", reject_reason);
+ papiAttributeListAddDatetime(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-reject-date", reject_date);
+
+ /* add the current system time */
+ papiAttributeListAddDatetime(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-current-time", time(NULL));
+
+ /* add the time since last enabled */
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-up-time", time(NULL));
+
+ /* add the status information */
+ lpsched_printer_status_to_attributes(&p->attributes, status);
+
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_EXCL,
+ "printer-state-reasons", "none");
+
+ lpsched_printer_defaults(&p->attributes);
+
+ return (PAPI_OK);
+}
+
+
+/*
+ * This puts the class information in only. It could create a hybrid
+ * printer object to return, but that is problematic at best.
+ */
+papi_status_t
+lpsched_class_configuration_to_attributes(service_t *svc, printer_t *p,
+ char *dest)
+{
+ CLASS *tmp;
+
+ if ((svc == NULL) || (p == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* get the configuration DB data */
+ if ((tmp = getclass(dest)) == NULL) {
+ detailed_error(svc,
+ gettext("unable to read configuration data"));
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ /* name */
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-name", tmp->name);
+ if (tmp->name != NULL) {
+ char uri[BUFSIZ];
+
+ snprintf(uri, sizeof (uri), "lpsched://localhost/printers/%s",
+ tmp->name);
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-uri-supported", uri);
+ }
+
+ if (tmp->members != NULL) {
+ char **members = tmp->members;
+ int i;
+
+ for (i = 0; members[i] != NULL; i++)
+ papiAttributeListAddString(&p->attributes,
+ PAPI_ATTR_APPEND,
+ "member-names", members[i]);
+ }
+
+ freeclass(tmp);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+class_status_to_attributes(printer_t *p, char *printer, short status,
+ char *reject_reason, long reject_date)
+{
+ if (p == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ papiAttributeListAddLPString(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-reject-reason", reject_reason);
+ papiAttributeListAddDatetime(&p->attributes, PAPI_ATTR_REPLACE,
+ "lpsched-reject-date", reject_date);
+
+ /* add the current system time */
+ papiAttributeListAddDatetime(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-current-time", time(NULL));
+
+ papiAttributeListAddInteger(&p->attributes, PAPI_ATTR_REPLACE,
+ "printer-up-time", time(NULL));
+
+ /* add the status information */
+ lpsched_printer_status_to_attributes(&p->attributes, status);
+
+ papiAttributeListAddString(&p->attributes, PAPI_ATTR_EXCL,
+ "printer-state-reasons", "none");
+
+ lpsched_printer_defaults(&p->attributes);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+attributes_to_printer(papi_attribute_t **attributes, PRINTER *tmp)
+{
+ papi_status_t status;
+ void *iter = NULL;
+ char *string = NULL;
+ int flags;
+ char **list = NULL;
+
+ /* banner needs some conversion to the bitfield */
+ iter = NULL, string = NULL; flags = 0;
+ for (status = papiAttributeListGetString(attributes, &iter,
+ "job-sheets-supported", &string);
+ status == PAPI_OK;
+ status = papiAttributeListGetString(attributes, &iter,
+ NULL, &string))
+ if (strcasecmp(string, "none") == 0)
+ flags |= BAN_NEVER;
+ else if (strcasecmp(string, "standard") == 0)
+ flags |= BAN_ALWAYS;
+ if (flags != 0)
+ tmp->banner = flags;
+
+ /* input_types needs mime-type conversion */
+ iter = NULL, string = NULL; list = NULL;
+ for (status = papiAttributeListGetString(attributes, &iter,
+ "document-format-supported", &string);
+ status == PAPI_OK;
+ status = papiAttributeListGetString(attributes, &iter,
+ NULL, &string))
+ addlist(&list, mime_type_to_lp_type(string));
+ if (list != NULL) {
+ if (tmp->input_types != NULL)
+ freelist(tmp->input_types);
+ tmp->input_types = list;
+ }
+
+ papiAttributeListGetLPString(attributes,
+ "device-uri", &tmp->device);
+ papiAttributeListGetLPString(attributes,
+ "printer-info", &tmp->description);
+ papiAttributeListGetLPString(attributes,
+ "lpsched-dial-info", &tmp->dial_info);
+ papiAttributeListGetLPString(attributes,
+ "lpsched-fault-recovery", &tmp->fault_rec);
+ papiAttributeListGetLPString(attributes,
+ "lpsched-interface-script", &tmp->interface);
+ papiAttributeListGetLPString(attributes,
+ "lpsched-data-rate", &tmp->speed);
+ papiAttributeListGetLPString(attributes,
+ "lpsched-stty", &tmp->stty);
+ papiAttributeListGetLPStrings(attributes,
+ "lpsched-charsets", &tmp->char_sets);
+ papiAttributeListGetLPStrings(attributes,
+ "lpsched-printer-types", &tmp->printer_types);
+ papiAttributeListGetLPStrings(attributes,
+ "lpsched-options", &tmp->options);
+ papiAttributeListGetLPStrings(attributes,
+ "lpsched-modules", &tmp->modules);
+#ifdef LP_USE_PAPI_ATTR
+ papiAttributeListGetLPString(attributes,
+ "lpsched-printer-ppd-uri", &tmp->ppd);
+#endif
+
+ return (PAPI_OK);
+}
diff --git a/usr/src/cmd/lp/lib/papi/lpsched-service.c b/usr/src/cmd/lp/lib/papi/lpsched-service.c
new file mode 100644
index 0000000000..33f0082944
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/lpsched-service.c
@@ -0,0 +1,47 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <libintl.h>
+#include <papi_impl.h>
+
+#include "form.h"
+
+
+void
+lpsched_service_information(papi_attribute_t ***attrs)
+{
+ FORM form;
+
+ while (getform(NAME_ALL, &form, (FALERT *)0, (FILE **)0) != -1) {
+ papiAttributeListAddString(attrs, PAPI_ATTR_APPEND,
+ "form-supported", form.name);
+ freeform(&form);
+ }
+}
diff --git a/usr/src/cmd/lp/lib/papi/mapfile b/usr/src/cmd/lp/lib/papi/mapfile
new file mode 100644
index 0000000000..a4eeffdaf6
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/mapfile
@@ -0,0 +1,273 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# Generic interface definition for usr/src/cmd/lp/lib/papi
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNW_1.0 {
+ global:
+ # PAPI Attribute Calls
+ papiAttributeListAdd;
+ papiAttributeListAddValue {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListAddBoolean {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListAddCollection {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListAddDatetime {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListAddInteger {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListAddMetadata {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListAddRange {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListAddResolution {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListAddString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListDelete {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetValue {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetNext {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListFind {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetBoolean {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetCollection {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetDatetime {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetInteger {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetMetadata {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetRange {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetResolution {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListGetString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListFromString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListToString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListFree {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+
+ # PAPI Service Calls
+ papiServiceCreate;
+ papiServiceDestroy;
+ papiServiceSetUserName;
+ papiServiceSetPassword;
+ papiServiceSetEncryption;
+ papiServiceSetAuthCB;
+ papiServiceSetAppData;
+ papiServiceGetUserName;
+ papiServiceGetPassword;
+ papiServiceGetEncryption;
+ papiServiceGetAppData;
+ papiServiceGetServiceName;
+ papiServiceGetAttributeList;
+ papiServiceGetStatusMessage;
+
+ # PAPI Printer Calls
+ papiPrintersList;
+ papiPrinterQuery;
+ papiPrinterAdd;
+ papiPrinterModify;
+ papiPrinterRemove;
+ papiPrinterDisable;
+ papiPrinterEnable;
+ papiPrinterPause;
+ papiPrinterResume;
+ papiPrinterPurgeJobs;
+ papiPrinterListJobs;
+ papiPrinterGetAttributeList;
+ papiPrinterFree;
+ papiPrinterListFree;
+
+ # PAPI Job Calls
+ papiJobSubmit;
+ papiJobSubmitByReference;
+ papiJobValidate;
+ papiJobStreamOpen;
+ papiJobStreamWrite;
+ papiJobStreamClose;
+ papiJobQuery;
+ papiJobModify;
+ papiJobMove;
+ papiJobCancel;
+ papiJobHold;
+ papiJobRelease;
+ papiJobRestart {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiJobPromote;
+ papiJobGetAttributeList;
+ papiJobGetPrinterName;
+ papiJobGetId;
+ papiJobGetJobTicket {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiJobFree;
+ papiJobListFree;
+
+ # Misc. PAPI Calls
+ papiStatusString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiLibrarySupportedCall;
+ papiLibrarySupportedCalls;
+};
+
+SYMBOL_VERSION SUNWprivate_1.0 {
+ global:
+ papiServiceSetPeer; # used by to pass peer connection
+ papiJobCreate;
+ papiJobStreamAdd;
+ papiJobCommit;
+
+ # Misc. supporting calls
+ # URI
+ uri_from_string {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ uri_to_string {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ uri_free {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ # list
+ list_remove {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ list_append {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ list_concatenate {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+
+ # NS
+ getprinterbyname {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ is_localhost {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+
+ # extra Attribute Calls
+ copy_attributes {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ split_and_copy_attributes {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+ papiAttributeListPrint {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ };
+
+ local:
+ *;
+};
diff --git a/usr/src/cmd/lp/lib/papi/papi_impl.h b/usr/src/cmd/lp/lib/papi/papi_impl.h
new file mode 100644
index 0000000000..5d13df73ee
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/papi_impl.h
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PAPI_IMPL_H
+#define _PAPI_IMPL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <papi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <sys/types.h>
+#include <stdarg.h>
+
+/* lpsched include files */
+#include <lp.h>
+#include <msgs.h>
+#include <printers.h>
+#include <requests.h>
+
+
+/*
+ * Implementation specific types/prototypes/definitions follow
+ *
+ *
+ * Ex:
+ */
+
+typedef struct {
+ papi_attribute_t **attributes;
+ int (*authCB)(papi_service_t svc, void *app_data);
+ void *app_data;
+ MESG *md;
+ char *msgbuf;
+ size_t msgbuf_size;
+} service_t;
+
+typedef struct job {
+ papi_attribute_t **attributes; /* job attributes */
+} job_t;
+
+typedef struct {
+ papi_attribute_t **attributes; /* queue attributes */
+} printer_t;
+
+typedef struct {
+ int fd;
+ REQUEST *request;
+ char *meta_data_file;
+ char added;
+} job_stream_t;
+
+extern void lpsched_read_job_configuration(service_t *svc, job_t *j,
+ char *file);
+extern void lpsched_request_to_job(REQUEST *r, job_t *j);
+
+extern void job_status_to_attributes(job_t *job, char *req_id, char *user,
+ char *slabel, size_t size, time_t date,
+ short state, char *destination, char *form,
+ char *charset, short rank, char *file);
+extern papi_status_t addLPString(papi_attribute_t ***list,
+ int flags, char *name, char *value);
+extern papi_status_t papiAttributeListAddLPStrings(papi_attribute_t ***list,
+ int flags, char *name, char **values);
+extern void papiAttributeListGetLPString(papi_attribute_t **attributes,
+ char *key, char **string);
+extern void papiAttributeListGetLPStrings(papi_attribute_t **attributes,
+ char *key, char ***string);
+
+extern papi_status_t lpsched_printer_configuration_to_attributes(
+ service_t *svc, printer_t *p, char *dest);
+extern papi_status_t lpsched_class_configuration_to_attributes(service_t *svc,
+ printer_t *p, char *dest);
+extern papi_status_t class_status_to_attributes(printer_t *p, char *printer,
+ short status, char *reject_reason, long reject_date);
+extern papi_status_t lpsched_reject_printer(papi_service_t svc,
+ char *printer, char *message);
+extern papi_status_t lpsched_accept_printer(papi_service_t svc,
+ char *printer);
+extern papi_status_t lpsched_disable_printer(papi_service_t svc,
+ char *printer, char *message);
+extern papi_status_t lpsched_enable_printer(papi_service_t svc,
+ char *printer);
+extern papi_status_t lpsched_status_to_papi_status(int status);
+extern papi_status_t job_attributes_to_lpsched_request(papi_service_t svc,
+ REQUEST *r, papi_attribute_t **attributes);
+extern papi_status_t lpsched_alloc_files(papi_service_t svc, int number,
+ char **prefix);
+extern papi_status_t lpsched_commit_job(papi_service_t svc, char *job,
+ char **tmp);
+extern papi_status_t lpsched_start_change(papi_service_t svc,
+ char *printer, int32_t job_id, char **tmp);
+extern papi_status_t lpsched_end_change(papi_service_t svc,
+ char *printer, int32_t job_id);
+extern papi_status_t printer_status_to_attributes(printer_t *p, char *printer,
+ char *form, char *character_set, char *reject_reason,
+ char *disable_reason, short status, char *request_id, long enable_date,
+ long reject_date);
+extern papi_status_t lpsched_remove_printer(papi_service_t svc, char *dest);
+extern papi_status_t lpsched_remove_class(papi_service_t svc, char *dest);
+extern papi_status_t lpsched_add_modify_printer(papi_service_t svc, char *dest,
+ papi_attribute_t **attributes, int type);
+extern papi_status_t lpsched_add_modify_class(papi_service_t svc, char *dest,
+ papi_attribute_t **attributes);
+
+extern void lpsched_service_information(papi_attribute_t ***attrs);
+extern void lpsched_request_to_job_attributes(REQUEST *r, job_t *j);
+extern void detailed_error(service_t *svc, char *fmt, ...);
+extern char *banner_type(unsigned short banner);
+extern char *mime_type_to_lp_type(char *mime_type);
+extern char *lp_type_to_mime_type(char *lp_type);
+extern char *fifo_name_from_uri(char *uri);
+extern char *printer_name_from_uri_id(char *uri, int32_t id);
+
+extern int snd_msg(service_t *svc, int type, ...);
+extern int rcv_msg(service_t *svc, int type, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PAPI_IMPL_H */
diff --git a/usr/src/cmd/lp/lib/papi/ppd.c b/usr/src/cmd/lp/lib/papi/ppd.c
new file mode 100644
index 0000000000..5facf902be
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/ppd.c
@@ -0,0 +1,164 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains an extremely rudimentary implementation of PPD file
+ * parsing support. The parsing done here converts the contents of a PPD
+ * file into a set of PAPI attributes that applications can use to build
+ * print panels.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <papi.h>
+
+static void
+process_line(char *line, char **key, char **value, char **comment)
+{
+ char *ptr, *ptr2;
+
+ *key = &line[1];
+ *value = NULL;
+ *comment = NULL;
+
+ if ((ptr = strchr(line, ':')) == NULL)
+ return;
+
+ /*
+ * line is in the form:
+ * *key: value/comment
+ * or
+ * *key value/comment: data
+ */
+ *ptr++ = NULL;
+ while (isspace(*ptr) != 0)
+ ptr++;
+
+ if ((ptr2 = strchr(line, ' ')) != NULL) {
+ ptr = ptr2;
+ /*
+ * line is in the form:
+ * *key value/comment: data
+ */
+ *ptr++ = NULL;
+ while (*ptr == ' ')
+ ptr++;
+ }
+
+ if (*ptr == '*')
+ ptr++;
+
+ *value = ptr;
+
+ if ((ptr = strchr(ptr, '/')) != NULL) {
+ *ptr++ = NULL;
+ *comment = ptr;
+ }
+}
+
+papi_status_t
+PPDFileToAttributesList(papi_attribute_t ***attributes, char *filename)
+{
+ papi_status_t status = PAPI_OK;
+ FILE *fp;
+ char line[256];
+ char capability[256];
+ char def[256];
+ char supported[256];
+ char *current_group_name = NULL;
+
+ int ui = 0;
+
+ if ((fp = fopen(filename, "r")) == NULL)
+ return (PAPI_NOT_POSSIBLE);
+
+ while ((status == PAPI_OK) &&
+ (fgets(line, sizeof (line), fp) != NULL)) {
+ char *key = NULL, *value = NULL, *text = NULL;
+
+ /* we want *key...: "value" */
+ if (line[0] != '*')
+ continue;
+
+ if (strchr(line, ':') == NULL)
+ continue;
+
+ if ((text = strrchr(line, '\n')) != NULL)
+ *text = NULL;
+
+ process_line(line, &key, &value, &text);
+
+ if ((strcasecmp(key, "PageSize") == 0) ||
+ (strcasecmp(key, "InputSlot") == 0))
+ key = "media";
+
+ if (strcasecmp(key, "OpenGroup") == 0) {
+ if (value == NULL)
+ value = "unknown";
+ current_group_name = strdup(value);
+ } else if (strcasecmp(key, "OpenUI") == 0) {
+ if ((strcasecmp(value, "PageSize") == 0) ||
+ (strcasecmp(value, "InputSlot") == 0))
+ value = "media";
+ snprintf(capability, sizeof (capability), "%s", value);
+ snprintf(def, sizeof (def),
+ "%s-default", value);
+ snprintf(supported, sizeof (supported),
+ "%s-supported", value);
+ ui = 1;
+ } else if (strcasecmp(key, "CloseGroup") == 0) {
+ /* do nothing */
+ } else if (strcasecmp(key, "CloseUI") == 0) {
+ ui = 0;
+ /* do nothing */
+ } else if (strcasecmp(key, "Manufacturer") == 0) {
+ status = papiAttributeListAddString(attributes,
+ PAPI_ATTR_EXCL,
+ "printer-make", value);
+ } else if (strcasecmp(key, "ModelName") == 0) {
+ status = papiAttributeListAddString(attributes,
+ PAPI_ATTR_EXCL,
+ "printer-model", value);
+ } else if (strcasecmp(key, "ShortNickName") == 0) {
+ status = papiAttributeListAddString(attributes,
+ PAPI_ATTR_EXCL,
+ "printer-make-and-model", value);
+ } else if ((strncasecmp(key, "Default", 7) == 0) && ui) {
+ status = papiAttributeListAddString(attributes,
+ PAPI_ATTR_EXCL,
+ def, value);
+ } else if ((strcasecmp(key, capability) == 0) && ui) {
+ status = papiAttributeListAddString(attributes,
+ PAPI_ATTR_APPEND,
+ supported, value);
+ }
+ }
+ fclose(fp);
+
+ return (status);
+}
diff --git a/usr/src/cmd/lp/lib/papi/printer.c b/usr/src/cmd/lp/lib/papi/printer.c
new file mode 100644
index 0000000000..5a3fba075a
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/printer.c
@@ -0,0 +1,516 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <libintl.h>
+#include <papi_impl.h>
+#include <lp.h>
+
+extern int isclass(char *);
+
+void
+papiPrinterFree(papi_printer_t printer)
+{
+ printer_t *tmp = printer;
+
+ if (tmp != NULL) {
+ papiAttributeListFree(tmp->attributes);
+ free(tmp);
+ }
+}
+
+void
+papiPrinterListFree(papi_printer_t *printers)
+{
+ if (printers != NULL) {
+ int i;
+
+ for (i = 0; printers[i] != NULL; i++)
+ papiPrinterFree(printers[i]);
+ free(printers);
+ }
+}
+
+papi_status_t
+papiPrintersList(papi_service_t handle, char **requested_attrs,
+ papi_filter_t *filter, papi_printer_t **printers)
+{
+ service_t *svc = handle;
+ printer_t *p = NULL;
+ short status = MOK;
+ char *printer = NULL,
+ *form = NULL,
+ *request_id = NULL,
+ *character_set = NULL,
+ *reject_reason = NULL,
+ *disable_reason = NULL;
+ short printer_status = 0;
+ long enable_date = 0, reject_date = 0;
+
+ if ((handle == NULL) || (printers == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((filter == NULL) ||
+ ((filter->filter.bitmask.mask & PAPI_PRINTER_LOCAL) ==
+ (filter->filter.bitmask.value & PAPI_PRINTER_LOCAL))) {
+ /* ask the spooler for the printer(s) and state */
+ if (snd_msg(svc, S_INQUIRE_PRINTER_STATUS, NAME_ALL) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ do {
+ if (rcv_msg(svc, R_INQUIRE_PRINTER_STATUS, &status,
+ &printer, &form, &character_set,
+ &disable_reason, &reject_reason,
+ &printer_status, &request_id,
+ &enable_date, &reject_date) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ if ((p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ lpsched_printer_configuration_to_attributes(svc, p,
+ printer);
+
+ printer_status_to_attributes(p, printer, form,
+ character_set, disable_reason,
+ reject_reason, printer_status,
+ request_id, enable_date, reject_date);
+
+ list_append(printers, p);
+
+ } while (status == MOKMORE);
+ }
+
+ if ((filter == NULL) ||
+ ((filter->filter.bitmask.mask & PAPI_PRINTER_CLASS) ==
+ (filter->filter.bitmask.value & PAPI_PRINTER_CLASS))) {
+ /* ask the spooler for the class(es) and state */
+ if (snd_msg(svc, S_INQUIRE_CLASS, NAME_ALL) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ do {
+ if (rcv_msg(svc, R_INQUIRE_CLASS, &status, &printer,
+ &printer_status, &reject_reason,
+ &reject_date) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ if ((p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ lpsched_class_configuration_to_attributes(svc, p,
+ printer);
+
+ class_status_to_attributes(p, printer, printer_status,
+ reject_reason, reject_date);
+
+ list_append(printers, p);
+
+ } while (status == MOKMORE);
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiPrinterQuery(papi_service_t handle, char *name,
+ char **requested_attrs,
+ papi_attribute_t **job_attrs,
+ papi_printer_t *printer)
+{
+ papi_status_t pst;
+ service_t *svc = handle;
+ printer_t *p = NULL;
+ char *dest;
+ short status = MOK;
+ char *pname = NULL,
+ *form = NULL,
+ *request_id = NULL,
+ *character_set = NULL,
+ *reject_reason = NULL,
+ *disable_reason = NULL;
+ short printer_status = 0;
+ long enable_date = 0, reject_date = 0;
+
+ if ((handle == NULL) || (name == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ dest = printer_name_from_uri_id(name, -1);
+
+ if (strcmp(dest, "_default") == 0) {
+ static char *_default;
+
+ if (_default == NULL) {
+ int fd;
+ static char buf[128];
+
+ if ((fd = open("/etc/lp/default", O_RDONLY)) >= 0) {
+ read(fd, buf, sizeof (buf));
+ close(fd);
+ _default = strtok(buf, " \t\n");
+ }
+ }
+ dest = _default;
+ }
+
+ if (isprinter(dest) != 0) {
+ pst = lpsched_printer_configuration_to_attributes(svc, p, dest);
+ if (pst != PAPI_OK)
+ return (pst);
+
+ /* get the spooler status data now */
+ if (snd_msg(svc, S_INQUIRE_PRINTER_STATUS, dest) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ if (rcv_msg(svc, R_INQUIRE_PRINTER_STATUS, &status, &pname,
+ &form, &character_set, &disable_reason,
+ &reject_reason, &printer_status, &request_id,
+ &enable_date, &reject_date) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ printer_status_to_attributes(p, pname, form, character_set,
+ disable_reason, reject_reason, printer_status,
+ request_id, enable_date, reject_date);
+ } else if (isclass(dest) != 0) {
+ pst = lpsched_class_configuration_to_attributes(svc, p, dest);
+ if (pst != PAPI_OK)
+ return (pst);
+
+ /* get the spooler status data now */
+ if (snd_msg(svc, S_INQUIRE_CLASS, dest) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ if (rcv_msg(svc, R_INQUIRE_CLASS, &status, &pname,
+ &printer_status, &reject_reason,
+ &reject_date) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ class_status_to_attributes(p, pname, printer_status,
+ reject_reason, reject_date);
+ } else if (strcmp(dest, "PrintService") == 0) {
+ /* fill the printer object with service information */
+ lpsched_service_information(&p->attributes);
+ } else
+ return (PAPI_NOT_FOUND);
+
+ free(dest);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiPrinterAdd(papi_service_t handle, char *name,
+ papi_attribute_t **attributes, papi_printer_t *result)
+{
+ papi_status_t status;
+ printer_t *p = NULL;
+ char *dest;
+
+ if ((handle == NULL) || (name == NULL) || (attributes == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(name, -1);
+
+ if (isprinter(dest) != 0) {
+ status = lpsched_add_modify_printer(handle, dest,
+ attributes, 0);
+
+ if ((*result = p = calloc(1, sizeof (*p))) != NULL)
+ lpsched_printer_configuration_to_attributes(handle, p,
+ dest);
+ else
+ status = PAPI_TEMPORARY_ERROR;
+
+ } else if (isclass(dest) != 0) {
+ status = lpsched_add_modify_class(handle, dest, attributes);
+
+ if ((*result = p = calloc(1, sizeof (*p))) != NULL)
+ lpsched_class_configuration_to_attributes(handle, p,
+ dest);
+ else
+ status = PAPI_TEMPORARY_ERROR;
+
+ } else
+ status = PAPI_NOT_FOUND;
+
+ free(dest);
+
+ return (status);
+}
+
+papi_status_t
+papiPrinterModify(papi_service_t handle, char *name,
+ papi_attribute_t **attributes, papi_printer_t *result)
+{
+ papi_status_t status;
+ printer_t *p = NULL;
+ char *dest;
+
+ if ((handle == NULL) || (name == NULL) || (attributes == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(name, -1);
+
+ if (isprinter(dest) != 0) {
+ status = lpsched_add_modify_printer(handle, dest,
+ attributes, 1);
+
+ if ((*result = p = calloc(1, sizeof (*p))) != NULL)
+ lpsched_printer_configuration_to_attributes(handle, p,
+ dest);
+ else
+ status = PAPI_TEMPORARY_ERROR;
+ } else if (isclass(dest) != 0) {
+ status = lpsched_add_modify_class(handle, dest, attributes);
+
+ if ((*result = p = calloc(1, sizeof (*p))) != NULL)
+ lpsched_class_configuration_to_attributes(handle, p,
+ dest);
+ else
+ status = PAPI_TEMPORARY_ERROR;
+ } else
+ status = PAPI_NOT_FOUND;
+
+ free(dest);
+
+ return (status);
+}
+
+papi_status_t
+papiPrinterRemove(papi_service_t handle, char *name)
+{
+ papi_status_t result;
+ char *dest;
+
+ if ((handle == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(name, -1);
+
+ if (isprinter(dest) != 0) {
+ result = lpsched_remove_printer(handle, dest);
+ } else if (isclass(dest) != 0) {
+ result = lpsched_remove_class(handle, dest);
+ } else
+ result = PAPI_NOT_FOUND;
+
+ free(dest);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterDisable(papi_service_t handle, char *name, char *message)
+{
+ papi_status_t result;
+
+ if ((handle == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ result = lpsched_disable_printer(handle, name, message);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterEnable(papi_service_t handle, char *name)
+{
+ papi_status_t result;
+
+ if ((handle == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ result = lpsched_enable_printer(handle, name);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterPause(papi_service_t handle, char *name, char *message)
+{
+ papi_status_t result;
+
+ if ((handle == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ result = lpsched_reject_printer(handle, name, message);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterResume(papi_service_t handle, char *name)
+{
+ papi_status_t result;
+
+ if ((handle == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ result = lpsched_accept_printer(handle, name);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterPurgeJobs(papi_service_t handle, char *name, papi_job_t **jobs)
+{
+ service_t *svc = handle;
+ papi_status_t result = PAPI_OK_SUBST;
+ short more;
+ long status;
+ char *dest;
+ char *req_id;
+
+ if ((handle == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(name, -1);
+ more = snd_msg(svc, S_CANCEL, dest, "", "");
+ free(dest);
+ if (more < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ do {
+ if (rcv_msg(svc, R_CANCEL, &more, &status, &req_id) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ switch (status) {
+ case MOK:
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_APPEND,
+ "canceled-jobs", req_id);
+ break;
+ case M2LATE:
+ case MUNKNOWN:
+ case MNOINFO:
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_APPEND,
+ "cancel-failed", req_id);
+ result = PAPI_DEVICE_ERROR;
+ break;
+ case MNOPERM:
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_APPEND,
+ "cancel-failed", req_id);
+ result = PAPI_NOT_AUTHORIZED;
+ break;
+ default:
+ detailed_error(svc, gettext("cancel failed, bad status (%d)\n"),
+ status);
+ return (PAPI_DEVICE_ERROR);
+ }
+ } while (more == MOKMORE);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterListJobs(papi_service_t handle, char *name,
+ char **requested_attrs, int type_mask,
+ int max_num_jobs, papi_job_t **jobs)
+{
+ service_t *svc = handle;
+ char *dest;
+ short rc;
+ int count = 1;
+
+ if ((handle == NULL) || (name == NULL) || (jobs == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ dest = printer_name_from_uri_id(name, -1);
+
+ rc = snd_msg(svc, S_INQUIRE_REQUEST_RANK, 0, "", dest, "", "", "");
+ free(dest);
+ if (rc < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ do {
+ job_t *job = NULL;
+ char *dest = NULL,
+ *ptr,
+ *form = NULL,
+ *req_id = NULL,
+ *charset = NULL,
+ *owner = NULL,
+ *slabel = NULL,
+ *file = NULL;
+ char request_file[128];
+ time_t date = 0;
+ size_t size = 0;
+ short rank = 0, state = 0;
+
+ if (rcv_msg(svc, R_INQUIRE_REQUEST_RANK, &rc, &req_id,
+ &owner, &slabel, &size, &date, &state, &dest,
+ &form, &charset, &rank, &file) < 0)
+ return (PAPI_SERVICE_UNAVAILABLE);
+
+ if ((rc != MOK) && (rc != MOKMORE))
+ continue;
+ /*
+ * at this point, we should check to see if the job matches the
+ * selection criterion defined in "type_mask".
+ */
+
+ /* too many yet? */
+ if ((max_num_jobs != 0) && (count++ > max_num_jobs))
+ continue;
+
+ if ((job = calloc(1, sizeof (*job))) == NULL)
+ continue;
+
+ /* Request file is <req_id>-0 */
+ if ((ptr = strrchr(req_id, '-')) != NULL) {
+ ++ptr;
+ snprintf(request_file, sizeof (request_file),
+ "%s-0", ptr);
+ }
+
+ lpsched_read_job_configuration(svc, job, request_file);
+
+ job_status_to_attributes(job, req_id, owner, slabel, size,
+ date, state, dest, form, charset, rank, file);
+
+ list_append(jobs, job);
+
+ } while (rc == MOKMORE);
+
+ if (rc == MNOINFO) /* If no jobs are found, it's still ok */
+ rc = MOK;
+
+ return (lpsched_status_to_papi_status(rc));
+}
+
+papi_attribute_t **
+papiPrinterGetAttributeList(papi_printer_t printer)
+{
+ printer_t *tmp = printer;
+
+ if (tmp == NULL)
+ return (NULL);
+
+ return (tmp->attributes);
+}
diff --git a/usr/src/cmd/lp/lib/papi/service.c b/usr/src/cmd/lp/lib/papi/service.c
new file mode 100644
index 0000000000..a15434fcfb
--- /dev/null
+++ b/usr/src/cmd/lp/lib/papi/service.c
@@ -0,0 +1,303 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <alloca.h>
+#include <libintl.h>
+#include <papi_impl.h>
+
+#include <tsol/label.h>
+
+papi_status_t
+papiServiceCreate(papi_service_t *handle, char *service_name,
+ char *user_name, char *password,
+ int (*authCB)(papi_service_t svc, void *app_data),
+ papi_encryption_t encryption, void *app_data)
+{
+ service_t *svc = NULL;
+ char *path = Lp_FIFO;
+
+ if (handle == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*handle = svc = calloc(1, sizeof (*svc))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ svc->md = mconnect(path, 0, 0);
+ if (svc->md == NULL) {
+ detailed_error(svc,
+ gettext("can't connect to spooler for %s: %s"),
+ (service_name ? service_name : ""), strerror(errno));
+ return (PAPI_SERVICE_UNAVAILABLE);
+ }
+
+ svc->msgbuf_size = MSGMAX;
+ if ((svc->msgbuf = calloc(1, svc->msgbuf_size)) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ if (service_name != NULL)
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_EXCL,
+ "service-name", service_name);
+
+ (void) papiServiceSetUserName(svc, user_name);
+ (void) papiServiceSetPassword(svc, password);
+ (void) papiServiceSetAuthCB(svc, authCB);
+ (void) papiServiceSetAppData(svc, app_data);
+ (void) papiServiceSetEncryption(svc, encryption);
+
+ return (PAPI_OK);
+}
+
+void
+papiServiceDestroy(papi_service_t handle)
+{
+ service_t *svc = handle;
+
+ if (svc != NULL) {
+ if (svc->md != NULL)
+ mdisconnect(svc->md);
+ if (svc->msgbuf != NULL)
+ free(svc->msgbuf);
+ papiAttributeListFree(svc->attributes);
+ free(svc);
+ }
+}
+
+/*
+ * interface for passing a peer's connection to gather sensitivity labeling
+ * from for Trusted Solaris.
+ */
+papi_status_t
+papiServiceSetPeer(papi_service_t handle, int peerfd)
+{
+ papi_status_t result = PAPI_OK;
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if (is_system_labeled()) {
+ short status;
+
+ if ((snd_msg(svc, S_PASS_PEER_CONNECTION) < 0) ||
+ (ioctl(svc->md->writefd, I_SENDFD, peerfd) < 0) ||
+ (rcv_msg(svc, R_PASS_PEER_CONNECTION, &status) < 0))
+ status = MTRANSMITERR;
+
+ if (status != MOK) {
+ detailed_error(svc,
+ gettext("failed to send peer connection: %s"),
+ lpsched_status_string(status));
+ result = lpsched_status_to_papi_status(status);
+ }
+ }
+
+ return (result);
+}
+
+papi_status_t
+papiServiceSetUserName(papi_service_t handle, char *user_name)
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ return (papiAttributeListAddString(&svc->attributes, PAPI_ATTR_REPLACE,
+ "user-name", user_name));
+}
+
+papi_status_t
+papiServiceSetPassword(papi_service_t handle, char *password)
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ return (papiAttributeListAddString(&svc->attributes, PAPI_ATTR_REPLACE,
+ "password", password));
+}
+
+papi_status_t
+papiServiceSetEncryption(papi_service_t handle,
+ papi_encryption_t encryption)
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ return (papiAttributeListAddInteger(&svc->attributes, PAPI_ATTR_REPLACE,
+ "encryption", (int)encryption));
+}
+
+papi_status_t
+papiServiceSetAuthCB(papi_service_t handle,
+ int (*authCB)(papi_service_t svc, void *app_data))
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ svc->authCB = (int (*)(papi_service_t svc, void *app_data))authCB;
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiServiceSetAppData(papi_service_t handle, void *app_data)
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ svc->app_data = (void *)app_data;
+
+ return (PAPI_OK);
+}
+
+char *
+papiServiceGetServiceName(papi_service_t handle)
+{
+ service_t *svc = handle;
+ char *result = NULL;
+
+ if (svc != NULL)
+ papiAttributeListGetString(svc->attributes, NULL,
+ "service-name", &result);
+
+ return (result);
+}
+
+char *
+papiServiceGetUserName(papi_service_t handle)
+{
+ service_t *svc = handle;
+ char *result = NULL;
+
+ if (svc != NULL)
+ papiAttributeListGetString(svc->attributes, NULL,
+ "user-name", &result);
+
+ return (result);
+}
+
+char *
+papiServiceGetPassword(papi_service_t handle)
+{
+ service_t *svc = handle;
+ char *result = NULL;
+
+ if (svc != NULL)
+ papiAttributeListGetString(svc->attributes, NULL,
+ "password", &result);
+
+ return (result);
+}
+
+papi_encryption_t
+papiServiceGetEncryption(papi_service_t handle)
+{
+ service_t *svc = handle;
+ papi_encryption_t result = PAPI_ENCRYPT_NEVER;
+
+ if (svc != NULL)
+ papiAttributeListGetInteger(svc->attributes, NULL,
+ "encryption", (int *)&result);
+
+ return (result);
+}
+
+void *
+papiServiceGetAppData(papi_service_t handle)
+{
+ service_t *svc = handle;
+ void *result = NULL;
+
+ if (svc != NULL)
+ result = svc->app_data;
+
+ return (result);
+}
+
+papi_attribute_t **
+papiServiceGetAttributeList(papi_service_t handle)
+{
+ service_t *svc = handle;
+ papi_attribute_t **result = NULL;
+
+ if (svc != NULL) {
+ lpsched_service_information(&svc->attributes);
+ result = svc->attributes;
+ }
+
+ return (result);
+}
+
+char *
+papiServiceGetStatusMessage(papi_service_t handle)
+{
+ service_t *svc = handle;
+ char *result = NULL;
+
+ if (svc != NULL)
+ papiAttributeListGetString(svc->attributes, NULL,
+ "detailed-status-message", &result);
+
+ return (result);
+}
+
+void
+detailed_error(service_t *svc, char *fmt, ...)
+{
+ if ((svc != NULL) && (fmt != NULL)) {
+ va_list ap;
+ size_t size;
+ char *message = alloca(BUFSIZ);
+
+ va_start(ap, fmt);
+ /*
+ * fill in the message. If the buffer is too small, allocate
+ * one that is large enough and fill it in.
+ */
+ if ((size = vsnprintf(message, BUFSIZ, fmt, ap)) >= BUFSIZ)
+ if ((message = alloca(size)) != NULL)
+ vsnprintf(message, size, fmt, ap);
+ va_end(ap);
+
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_APPEND,
+ "detailed-status-message", message);
+ }
+}
diff --git a/usr/src/cmd/lp/lib/printers/Makefile b/usr/src/cmd/lp/lib/printers/Makefile
new file mode 100644
index 0000000000..578ebee8e4
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/Makefile
@@ -0,0 +1,73 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/printers/Makefile
+#
+
+LIBRARY = liblpprt.a
+
+OBJECTS = chkprinter.o \
+ default.o \
+ delprinter.o \
+ freeprinter.o \
+ getprinter.o \
+ getpentry.o \
+ p_head.o \
+ okprinter.o \
+ printwheels.o \
+ putprinter.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master) $(C_PICFLAGS)
+
+POFILE = lp_lib_printers.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpprt.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+LINT_CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+lint: lintlib
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) -o lpprt llib-llpprt
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/printers/chkprinter.c b/usr/src/cmd/lp/lib/printers/chkprinter.c
new file mode 100644
index 0000000000..378f3a312c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/chkprinter.c
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.8 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+
+#include "lp.h"
+#include "lp.set.h"
+#include "printers.h"
+
+extern short output_res_char,
+ output_res_line,
+ output_res_horz_inch,
+ output_res_vert_inch;
+
+/**
+ ** chkprinter() - CHECK VALIDITY OF PITCH/SIZE/CHARSET FOR TERMINFO TYPE
+ **/
+
+unsigned long
+#if defined(__STDC__)
+chkprinter (
+ char * type,
+ char * cpi,
+ char * lpi,
+ char * len,
+ char * wid,
+ char * cs
+)
+#else
+chkprinter (type, cpi, lpi, len, wid, cs)
+ char *type,
+ *cpi,
+ *lpi,
+ *len,
+ *wid,
+ *cs;
+#endif
+{
+ register unsigned long retflags = 0;
+
+
+ if (tidbit(type, (char *)0) == -1)
+ return (retflags | PCK_TYPE);
+
+ output_res_char = -1;
+ output_res_line = -1;
+ output_res_horz_inch = -1;
+ output_res_vert_inch = -1;
+
+ if (cpi && *cpi && set_pitch(cpi, 'H', 0) != E_SUCCESS)
+ retflags |= PCK_CPI;
+
+ if (lpi && *lpi && set_pitch(lpi, 'V', 0) != E_SUCCESS)
+ retflags |= PCK_LPI;
+
+ if (len && *len && set_size(len, 'L', 0) != E_SUCCESS)
+ retflags |= PCK_LENGTH;
+
+ if (wid && *wid && set_size(wid, 'W', 0) != E_SUCCESS)
+ retflags |= PCK_WIDTH;
+
+ if (cs && *cs && set_charset(cs, 0, type) != E_SUCCESS)
+ retflags |= PCK_CHARSET;
+
+ return (retflags);
+}
diff --git a/usr/src/cmd/lp/lib/printers/default.c b/usr/src/cmd/lp/lib/printers/default.c
new file mode 100644
index 0000000000..29e8944c5a
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/default.c
@@ -0,0 +1,78 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "stdlib.h"
+
+#include "lp.h"
+
+/**
+ ** getdefault() - READ THE NAME OF THE DEFAULT DESTINATION FROM DISK
+ **/
+
+char *
+getdefault(void)
+{
+ return (loadline(Lp_Default));
+}
+
+/**
+ ** putdefault() - WRITE THE NAME OF THE DEFAULT DESTINATION TO DISK
+ **/
+
+int
+putdefault(char *dflt)
+{
+ int fd;
+
+ if (!dflt || !*dflt)
+ return (deldefault());
+
+ if ((fd = open_locked(Lp_Default, "w", MODE_READ)) < 0)
+ return (-1);
+
+ fdprintf(fd, "%s\n", dflt);
+
+ close(fd);
+ return (0);
+}
+
+/**
+ ** deldefault() - REMOVE THE NAME OF THE DEFAULT DESTINATION
+ **/
+
+int
+deldefault(void)
+{
+ return (rmfile(Lp_Default));
+}
diff --git a/usr/src/cmd/lp/lib/printers/delprinter.c b/usr/src/cmd/lp/lib/printers/delprinter.c
new file mode 100644
index 0000000000..a7a183e902
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/delprinter.c
@@ -0,0 +1,156 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "printers.h"
+
+#if defined(__STDC__)
+static int _delprinter ( char * );
+#else
+static int _delprinter();
+#endif
+
+/**
+ ** delprinter()
+ **/
+
+int
+#if defined(__STDC__)
+delprinter (
+ char * name
+)
+#else
+delprinter (name)
+ char *name;
+#endif
+{
+ long lastdir;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!Lp_A_Printers || !Lp_A_Interfaces) {
+ getadminpaths (LPUSER);
+ if (!Lp_A_Printers || !Lp_A_Interfaces)
+ return (0);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ lastdir = -1;
+ while ((name = next_dir(Lp_A_Printers, &lastdir)))
+ if (_delprinter(name) == -1)
+ return (-1);
+ return (0);
+ } else
+ return (_delprinter(name));
+}
+
+/**
+ ** _delprinter()
+ **/
+
+static int
+#if defined(__STDC__)
+_delprinter (
+ char * name
+)
+#else
+_delprinter (name)
+ char *name;
+#endif
+{
+ register char *path;
+#ifdef LP_USE_PAPI_ATTR
+ char ppdfile[BUFSIZ];
+#endif
+
+#define RMFILE(X) if (!(path = getprinterfile(name, X))) \
+ return (-1); \
+ if (rmfile(path) == -1) { \
+ Free (path); \
+ return (-1); \
+ } \
+ Free (path)
+ RMFILE (COMMENTFILE);
+ RMFILE (CONFIGFILE);
+ RMFILE (FALLOWFILE);
+ RMFILE (FDENYFILE);
+ RMFILE (UALLOWFILE);
+ RMFILE (UDENYFILE);
+ RMFILE (STATUSFILE);
+ RMFILE (FAULTMESSAGEFILE);
+
+ delalert (Lp_A_Printers, name);
+
+ if (!(path = makepath(Lp_A_Interfaces, name, (char *)0)))
+ return (-1);
+ if (rmfile(path) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+#ifdef LP_USE_PAPI_ATTR
+ /* Check if the printer has a ppd file, if it does delete it */
+ (void) snprintf(ppdfile, sizeof (ppdfile), "%s.ppd", name);
+
+ if (!(path = makepath(ETCDIR, "ppd", ppdfile, (char *)0)))
+ {
+ return (-1);
+ }
+ if (rmfile(path) == -1)
+ {
+ Free(path);
+ return (-1);
+ }
+ Free(path);
+#endif
+
+ if (!(path = getprinterfile(name, (char *)0)))
+ return (-1);
+ if (Rmdir(path) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/printers/freeprinter.c b/usr/src/cmd/lp/lib/printers/freeprinter.c
new file mode 100644
index 0000000000..e915885dd0
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/freeprinter.c
@@ -0,0 +1,89 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "printers.h"
+#include <syslog.h>
+
+/**
+ ** freeprinter() - FREE MEMORY ALLOCATED FOR PRINTER STRUCTURE
+ **/
+
+void freeprinter (pp)
+ PRINTER *pp;
+{
+ if (!pp)
+ return;
+
+ syslog(LOG_DEBUG, "freeprinter(%s)", pp->name ? pp->name : "");
+ if (pp->name)
+ Free (pp->name);
+ if (pp->char_sets)
+ freelist (pp->char_sets);
+ if (pp->input_types)
+ freelist (pp->input_types);
+ if (pp->options)
+ freelist (pp->options);
+ if (pp->device)
+ Free (pp->device);
+ if (pp->dial_info)
+ Free (pp->dial_info);
+ if (pp->fault_rec)
+ Free (pp->fault_rec);
+ if (pp->interface)
+ Free (pp->interface);
+ if (pp->printer_type)
+ Free (pp->printer_type);
+ if (pp->remote)
+ Free (pp->remote);
+ if (pp->speed)
+ Free (pp->speed);
+ if (pp->stty)
+ Free (pp->stty);
+ if (pp->description)
+ Free (pp->description);
+ if (pp->fault_alert.shcmd)
+ Free (pp->fault_alert.shcmd);
+#if defined(CAN_DO_MODULES)
+ if (pp->modules)
+ freelist (pp->modules);
+#endif
+ if (pp->printer_types)
+ freelist (pp->printer_types);
+ Free (pp);
+
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/printers/getpentry.c b/usr/src/cmd/lp/lib/printers/getpentry.c
new file mode 100644
index 0000000000..8eeb753d52
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/getpentry.c
@@ -0,0 +1,170 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "printers.h"
+
+extern struct {
+ char *v;
+ short len,
+ okremote;
+} prtrheadings[];
+
+/*
+ * getpentry() - EXTRACT ONE PRINTER ENTRY FROM DISK FILE
+ */
+
+char *
+getpentry(char *name, int want_fld)
+{
+ static long lastdir = -1;
+ char buf[BUFSIZ];
+ int fld;
+ int fd;
+ register char * p;
+ register char * path;
+ int isNameAll;
+ char * option_entry = NULL;
+
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ /*
+ * Getting ``all''? If so, jump into the directory
+ * wherever we left off.
+ */
+ isNameAll = STREQU(NAME_ALL, name);
+ for (; ; ) {
+ /*
+ * fix for bug 1117241
+ * occasionally when a printer is removed, a printer directory
+ * is left behind, but the CONFIGFILE is removed. In this
+ * case this directory terminates the search for additional
+ * printers as we have been returning 0 in this case.
+ * Now, we loop back and try the next directory until
+ * we have no more directories or we find a directory with
+ * a CONFIGFILE
+ */
+ if (isNameAll) {
+ if (!(name = next_dir(Lp_A_Printers, &lastdir)))
+ return (0);
+ } else
+ lastdir = -1;
+
+ /*
+ * Get the printer configuration information.
+ */
+
+ path = getprinterfile(name, CONFIGFILE);
+ if (!path) {
+ if (isNameAll)
+ Free(name);
+ return (0);
+ }
+
+ if ((fd = open_locked(path, "r", 0)) < 0) {
+ Free(path);
+
+ /*
+ * go around to loop again for
+ * NAME_ALL case
+ */
+
+ if (!isNameAll) /* fix for bug 1117241 */
+ return (0);
+ else
+ Free(name);
+ }
+ else
+ break;
+ }
+ Free(path);
+
+ /*
+ * Read the file.
+ */
+ errno = 0;
+ while (fdgets(buf, BUFSIZ, fd) != NULL) {
+
+ buf[strlen(buf) - 1] = 0;
+
+ for (fld = 0; fld < PR_MAX; fld++)
+ if (prtrheadings[fld].v &&
+ prtrheadings[fld].len &&
+ STRNEQU(
+ buf,
+ prtrheadings[fld].v,
+ prtrheadings[fld].len)) {
+
+ p = buf + prtrheadings[fld].len;
+ while (*p && *p == ' ')
+ p++;
+ break;
+ }
+
+ /*
+ * To allow future extensions to not impact applications
+ * using old versions of this routine, ignore strange
+ * fields.
+ */
+ if (fld >= PR_MAX)
+ continue;
+
+ if (fld == want_fld) {
+ if ((option_entry = strdup(p)) == NULL) {
+ return (0);
+ }
+ }
+
+
+ }
+ if (errno != 0) {
+ int save_errno = errno;
+ close(fd);
+ errno = save_errno;
+ return (0);
+ }
+ close(fd);
+
+ return (option_entry);
+}
diff --git a/usr/src/cmd/lp/lib/printers/getprinter.c b/usr/src/cmd/lp/lib/printers/getprinter.c
new file mode 100644
index 0000000000..058d1ae2d7
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/getprinter.c
@@ -0,0 +1,404 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+#include <syslog.h>
+
+#include "lp.h"
+#include "printers.h"
+
+extern struct {
+ char *v;
+ short len,
+ okremote;
+} prtrheadings[];
+
+/**
+ ** getprinter() - EXTRACT PRINTER STRUCTURE FROM DISK FILE
+ **/
+
+PRINTER *
+getprinter(char *name)
+{
+ static long lastdir = -1;
+
+ PRINTER *prp;
+
+ char buf[BUFSIZ];
+
+ short daisy;
+
+ int fld;
+
+ int fd;
+
+ FALERT *pa;
+
+ register char * p;
+ register char ** pp;
+ register char *** ppp;
+ register char * path;
+ int isNameAll;
+
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ syslog(LOG_DEBUG, "getprinter(%s)", name ? name : "");
+ /*
+ * Getting ``all''? If so, jump into the directory
+ * wherever we left off.
+ */
+ isNameAll = STREQU(NAME_ALL, name);
+ for (; ; ) {
+ /* fix for bug 1117241
+ * occasionally when a printer is removed, a printer directory
+ * is left behind, but the CONFIGFILE is removed. In this
+ * case this directory terminates the search for additional
+ * printers as we have been returning 0 in this case.
+ * Now, we loop back and try the next directory until
+ * we have no more directories or we find a directory with
+ * a CONFIGFILE
+ */
+ if (isNameAll) {
+ if (!(name = next_dir(Lp_A_Printers, &lastdir)))
+ return (0);
+ } else
+ lastdir = -1;
+
+ /*
+ * Get the printer configuration information.
+ */
+
+ path = getprinterfile(name, CONFIGFILE);
+ if (!path) {
+ if (isNameAll)
+ Free(name);
+ return (0);
+ }
+
+ if ((fd = open_locked(path, "r", 0)) < 0) {
+ Free(path); /*
+ * go around to loop again for
+ * NAME_ALL case
+ */
+
+ if (!isNameAll) /* fix for bug 1117241 */
+ return(0);
+ else
+ Free(name);
+ }
+ else
+ break;
+ }
+ Free (path);
+
+ /*
+ * Initialize the entire structure, to ensure no random
+ * values get in it. However, make sure some values won't
+ * be null or empty. Do the latter here as opposed to
+ * after reading the file, because sometimes the file
+ * contains an empty header to FORCE a null/empty value.
+ */
+ prp = calloc(sizeof (*prp), 1);
+ prp->name = Strdup(name);
+ if (isNameAll)
+ Free(name);
+ prp->printer_types = getlist(NAME_UNKNOWN, LP_WS, LP_SEP);
+ prp->input_types = getlist(NAME_SIMPLE, LP_WS, LP_SEP);
+#if defined(CAN_DO_MODULES)
+ prp->modules = getlist(NAME_DEFAULT, LP_WS, LP_SEP);
+#endif
+
+ /*
+ * Read the file.
+ */
+ errno = 0;
+ while (fdgets(buf, BUFSIZ, fd) != NULL) {
+
+ buf[strlen(buf) - 1] = 0;
+
+ for (fld = 0; fld < PR_MAX; fld++)
+ if (
+ prtrheadings[fld].v
+ && prtrheadings[fld].len
+ && STRNEQU(
+ buf,
+ prtrheadings[fld].v,
+ prtrheadings[fld].len
+ )
+ ) {
+ p = buf + prtrheadings[fld].len;
+ while (*p && *p == ' ')
+ p++;
+ break;
+ }
+
+ /*
+ * To allow future extensions to not impact applications
+ * using old versions of this routine, ignore strange
+ * fields.
+ */
+ if (fld >= PR_MAX)
+ continue;
+
+ switch (fld) {
+
+ case PR_BAN:
+ if ((pp = getlist(p, LP_WS, ":"))) {
+ if (pp[0] != NULL) {
+ if (strcmp(pp[0], NAME_OPTIONAL) == 0)
+ prp->banner = BAN_OPTIONAL;
+ else if (strcmp(pp[0], NAME_OFF) == 0)
+ prp->banner = BAN_NEVER;
+ else if (strcmp(pp[0], NAME_ON) == 0)
+ prp->banner = BAN_ALWAYS;
+ else /* default to the LP default */
+ prp->banner = BAN_ALWAYS;
+ }
+ if (pp[1] && CS_STREQU(pp[1], NAME_ALWAYS))
+ prp->banner |= BAN_ALWAYS;
+ freelist (pp);
+ }
+ break;
+
+ case PR_LOGIN:
+ prp->login = LOG_IN;
+ break;
+
+ case PR_CPI:
+ prp->cpi = getcpi(p);
+ break;
+
+ case PR_LPI:
+ prp->lpi = getsdn(p);
+ break;
+
+ case PR_LEN:
+ prp->plen = getsdn(p);
+ break;
+
+ case PR_WIDTH:
+ prp->pwid = getsdn(p);
+ break;
+
+ case PR_CS:
+ ppp = &(prp->char_sets);
+ goto CharStarStar;
+
+ case PR_ITYPES:
+ ppp = &(prp->input_types);
+CharStarStar: if (*ppp)
+ freelist (*ppp);
+ *ppp = getlist(p, LP_WS, LP_SEP);
+ break;
+
+ case PR_DEV:
+ pp = &(prp->device);
+ goto CharStar;
+
+ case PR_DIAL:
+ pp = &(prp->dial_info);
+ goto CharStar;
+
+ case PR_RECOV:
+ pp = &(prp->fault_rec);
+ goto CharStar;
+
+ case PR_INTFC:
+ pp = &(prp->interface);
+ goto CharStar;
+
+ case PR_PTYPE:
+ ppp = &(prp->printer_types);
+ goto CharStarStar;
+
+ case PR_REMOTE:
+ pp = &(prp->remote);
+ goto CharStar;
+
+ case PR_SPEED:
+ pp = &(prp->speed);
+ goto CharStar;
+
+ case PR_STTY:
+ pp = &(prp->stty);
+CharStar: if (*pp)
+ Free (*pp);
+ *pp = Strdup(p);
+ break;
+
+#if defined(CAN_DO_MODULES)
+ case PR_MODULES:
+ ppp = &(prp->modules);
+ goto CharStarStar;
+#endif
+
+ case PR_OPTIONS:
+ ppp = &(prp->options);
+ goto CharStarStar;
+ break;
+
+ case PR_PPD:
+ {
+ pp = &(prp->ppd);
+ goto CharStar;
+ }
+ }
+
+ }
+ if (errno != 0) {
+ int save_errno = errno;
+
+ freeprinter (prp);
+ close(fd);
+ errno = save_errno;
+ return (0);
+ }
+ close(fd);
+
+ /*
+ * Get the printer description (if it exists).
+ */
+ if (!(path = getprinterfile(prp->name, COMMENTFILE)))
+ return (0);
+ if (!(prp->description = loadstring(path)) && errno != ENOENT) {
+ Free (path);
+ freeprinter (prp);
+ return (0);
+ }
+ Free (path);
+
+ /*
+ * Get the information for the alert. Don't fail if we can't
+ * read it because of access permission UNLESS we're "root"
+ * or "lp"
+ */
+ if (!(pa = getalert(Lp_A_Printers, prp->name))) {
+ if (
+ errno != ENOENT
+ && (
+ errno != EACCES
+ || !getpid() /* we be root */
+ || STREQU(getname(), LPUSER) /* we be lp */
+ )
+ ) {
+ freeprinter (prp);
+ return (0);
+ }
+ } else
+ prp->fault_alert = *pa;
+
+ /*
+ * Now go through the structure and see if we have
+ * anything strange.
+ */
+ if (!okprinter(prp->name, prp, 0)) {
+ freeprinter (prp);
+ errno = EBADF;
+ return (0);
+ }
+
+ /*
+ * Just in case somebody tried to pull a fast one
+ * by giving a printer type header by itself....
+ */
+ if (!prp->printer_types)
+ prp->printer_types = getlist(NAME_UNKNOWN, LP_WS, LP_SEP);
+
+ /*
+ * If there are more than one printer type, then we can't
+ * have any input types, except perhaps ``simple''.
+ */
+ if (
+ lenlist(prp->printer_types) > 1
+ && prp->input_types
+ && (
+ lenlist(prp->input_types) > 1
+ || !STREQU(NAME_SIMPLE, *prp->input_types)
+ )
+ ) {
+ freeprinter (prp);
+ badprinter = BAD_ITYPES;
+ errno = EBADF;
+ return (0);
+ }
+
+ /*
+ * If there are more than one printer types, none can
+ * be ``unknown''.
+ */
+ if (
+ lenlist(prp->printer_types) > 1
+ && searchlist(NAME_UNKNOWN, prp->printer_types)
+ ) {
+ freeprinter (prp);
+ badprinter = BAD_PTYPES;
+ errno = EBADF;
+ return (0);
+ }
+
+ /*
+ * All the printer types had better agree on whether the
+ * printer takes print wheels!
+ */
+ prp->daisy = -1;
+ for (pp = prp->printer_types; *pp; pp++) {
+ tidbit (*pp, "daisy", &daisy);
+ if (daisy == -1)
+ daisy = 0;
+ if (prp->daisy == -1)
+ prp->daisy = daisy;
+ else if (prp->daisy != daisy) {
+ freeprinter (prp);
+ badprinter = BAD_DAISY;
+ errno = EBADF;
+ return (0);
+ }
+ }
+
+ /*
+ * Help out those who are still using the obsolete
+ * "printer_type" member.
+ */
+ prp->printer_type = Strdup(*prp->printer_types);
+
+ return (prp);
+}
diff --git a/usr/src/cmd/lp/lib/printers/llib-llpprt b/usr/src/cmd/lp/lib/printers/llib-llpprt
new file mode 100644
index 0000000000..f71ee5ff18
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/llib-llpprt
@@ -0,0 +1,99 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "../../include/lp.h"
+
+typedef struct PRINTER {
+ char *name; /* name of printer (redundant) */
+ unsigned short banner; /* banner page conditions */
+ SCALED cpi; /* default character pitch */
+ char **char_sets; /* list of okay char-sets/print-wheels */
+ char **input_types; /* list of types acceptable to printer */
+ char *device; /* printer port full path name */
+ char *dial_info; /* system name or phone # for dial-up */
+ char *fault_rec; /* printer fault recovery procedure */
+ char *interface; /* interface program full path name */
+ SCALED lpi; /* default line pitch */
+ SCALED plen; /* default page length */
+ unsigned short login; /* is/isn't a login terminal */
+ char *printer_type; /* Terminfo look-up value (obsolete) */
+ char *remote; /* remote machine!printer-name */
+ char *speed; /* baud rate for connection */
+ char *stty; /* space separated list of stty options */
+ SCALED pwid; /* default page width */
+ char *description; /* comment about printer */
+ FALERT fault_alert; /* how to alert on printer fault */
+ short daisy; /* 1/0 - printwheels/character-sets */
+#if defined(CAN_DO_MODULES)
+ char **modules; /* streams modules to push */
+#endif
+ char **printer_types; /* Terminfo look-up values */
+ char **options; /* space separated list of undefined -o options */
+
+ /*
+ * Adding new members to this structure? Check out
+ * cmd/lpadmin/do_printer.c, where we initialize
+ * each new printer structure.
+ */
+} PRINTER;
+
+typedef struct PWHEEL {
+ char *name; /* name of print wheel */
+ FALERT alert; /* how to alert when mount needed */
+} PWHEEL;
+
+extern unsigned long badprinter,
+ ignprinter;
+PRINTER * getprinter ( char * );
+
+PWHEEL * getpwheel ( char * );
+
+char * getdefault ( void );
+
+int putprinter ( char *, PRINTER *);
+int delprinter ( char * );
+int putdefault ( char * );
+int deldefault ( void );
+int putpwheel ( char * , PWHEEL * );
+int delpwheel ( char * );
+int okprinter ( char * , PRINTER * , int );
+
+unsigned long chkprinter (char *, char *, char *, char *, char *, char *);
+
+void freeprinter ( PRINTER * );
+void freepwheel ( PWHEEL * );
+
+char * getpentry(char *, int);
+
+
diff --git a/usr/src/cmd/lp/lib/printers/okprinter.c b/usr/src/cmd/lp/lib/printers/okprinter.c
new file mode 100644
index 0000000000..006bba00ab
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/okprinter.c
@@ -0,0 +1,155 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.19 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "sys/types.h"
+#include "stdlib.h"
+#include <unistd.h>
+
+#include "lp.h"
+#include "printers.h"
+
+unsigned long badprinter = 0;
+
+static int okinterface ( char * , PRINTER * );
+
+/**
+ ** okprinter() - SEE IF PRINTER STRUCTURE IS SOUND
+ **/
+
+int
+okprinter(char *name, PRINTER *prbufp, int isput)
+{
+ badprinter = 0;
+
+ /*
+ * A printer can't be remote and have device, interface,
+ * fault recovery, or alerts.
+ */
+ if (
+ prbufp->remote
+ && (
+ prbufp->device
+ || prbufp->interface
+ || (
+ prbufp->fault_alert.shcmd
+ && !STREQU(NAME_NONE, prbufp->fault_alert.shcmd)
+ )
+#if defined(CAN_DO_MODULES)
+# if defined(FIXED)
+/*
+ * This needs some work...getprinter() initializes this to "default"
+ */
+ || (
+ !emptylist(prbufp->modules)
+ && !STREQU(NAME_NONE, prbufp->modules[0])
+ )
+# endif
+#endif
+ )
+ )
+ badprinter |= BAD_REMOTE;
+
+ /*
+ * A local printer must have an interface program. This is
+ * for historical purposes (it let's someone know where the
+ * interface program came from) AND is used by "putprinter()"
+ * to copy the interface program. We must be able to read it.
+ */
+ if (!prbufp->remote && isput && !okinterface(name, prbufp))
+ badprinter |= BAD_INTERFACE;
+
+ /*
+ * A local printer must have device or dial info.
+ */
+ if (!prbufp->remote && !prbufp->device && !prbufp->dial_info)
+ badprinter |= BAD_DEVDIAL;
+
+ /*
+ * Fault recovery must be one of three kinds
+ * (or default).
+ */
+ if (
+ prbufp->fault_rec
+ && !STREQU(prbufp->fault_rec, NAME_CONTINUE)
+ && !STREQU(prbufp->fault_rec, NAME_BEGINNING)
+ && !STREQU(prbufp->fault_rec, NAME_WAIT)
+ )
+ badprinter |= BAD_FAULT;
+
+ /*
+ * Alert command can't be reserved word.
+ */
+ if (
+ prbufp->fault_alert.shcmd
+ && (
+ STREQU(prbufp->fault_alert.shcmd, NAME_QUIET)
+ || STREQU(prbufp->fault_alert.shcmd, NAME_LIST)
+ )
+ )
+ badprinter |= BAD_ALERT;
+
+ return ((badprinter & ~ignprinter)? 0 : 1);
+}
+
+/**
+ ** okinterface() - CHECK THAT THE INTERFACE PROGRAM IS OKAY
+ **/
+
+static int
+canread(char *path)
+{
+ return ((access(path, R_OK) < 0) ? 0 : 1);
+}
+
+static int
+okinterface(char *name, PRINTER *prbufp)
+{
+ int ret;
+
+ register char *path;
+
+
+ if (prbufp->interface)
+ ret = canread(prbufp->interface);
+
+ else
+ if (!(path = makepath(Lp_A_Interfaces, name, (char *)0)))
+ ret = 0;
+ else {
+ ret = canread(path);
+ Free (path);
+ }
+
+ return (ret);
+}
diff --git a/usr/src/cmd/lp/lib/printers/p_head.c b/usr/src/cmd/lp/lib/printers/p_head.c
new file mode 100644
index 0000000000..f7911435cc
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/p_head.c
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+
+#include "lp.h"
+#include "printers.h"
+
+struct {
+ char *v;
+ short len,
+ okremote;
+} prtrheadings[PR_MAX] = {
+
+#define ENTRY(X) X, sizeof(X)-1
+
+ ENTRY("Banner:"), 0, /* PR_BAN */
+ ENTRY("CPI:"), 0, /* PR_CPI */
+ ENTRY("Character sets:"), 1, /* PR_CS */
+ ENTRY("Content types:"), 1, /* PR_ITYPES */
+ ENTRY("Device:"), 0, /* PR_DEV */
+ ENTRY("Dial:"), 0, /* PR_DIAL */
+ ENTRY("Fault:"), 0, /* PR_RECOV */
+ ENTRY("Interface:"), 0, /* PR_INTFC */
+ ENTRY("LPI:"), 0, /* PR_LPI */
+ ENTRY("Length:"), 0, /* PR_LEN */
+ ENTRY("Login:"), 0, /* PR_LOGIN */
+ ENTRY("Printer type:"), 1, /* PR_PTYPE */
+ ENTRY("Remote:"), 1, /* PR_REMOTE */
+ ENTRY("Speed:"), 0, /* PR_SPEED */
+ ENTRY("Stty:"), 0, /* PR_STTY */
+ ENTRY("Width:"), 0, /* PR_WIDTH */
+#if defined(CAN_DO_MODULES)
+ ENTRY("Modules:"), 0, /* PR_MODULES */
+#endif
+ ENTRY("Options:"), 1, /* PR_OPTIONS */
+ ENTRY("PPD:"), 0, /* PR_PPD */
+
+#undef ENTRY
+
+};
diff --git a/usr/src/cmd/lp/lib/printers/printwheels.c b/usr/src/cmd/lp/lib/printers/printwheels.c
new file mode 100644
index 0000000000..e553404fc4
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/printwheels.c
@@ -0,0 +1,249 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "printers.h"
+
+/**
+ ** getpwheel() - GET PRINT WHEEL INFO FROM DISK
+ **/
+
+PWHEEL *
+#if defined(__STDC__)
+getpwheel (
+ char * name
+)
+#else
+getpwheel (name)
+ char *name;
+#endif
+{
+ static long lastdir = -1;
+
+ PWHEEL *pwp;
+
+ register FALERT *pa;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (0);
+ }
+
+ /*
+ * Getting ``all''? If so, jump into the directory
+ * wherever we left off.
+ */
+ if (STREQU(NAME_ALL, name)) {
+ if (!(name = next_dir(Lp_A_PrintWheels, &lastdir)))
+ return (0);
+ } else
+ lastdir = -1;
+
+ /*
+ * Get the information for the alert.
+ */
+ if (!(pa = getalert(Lp_A_PrintWheels, name))) {
+
+ /*
+ * Unless the world has turned weird, we shouldn't
+ * get ENOTDIR if we're doing the ``all'' case--because
+ * getting here in the all case meant the printwheel
+ * directory exists, but ENOTDIR means it doesn't!
+ */
+ if (errno == ENOTDIR)
+ errno = ENOENT; /* printwheel doesn't exist */
+
+ return (0);
+ }
+
+ pwp = calloc(1, sizeof (*pwp));
+ pwp->alert = *pa;
+ pwp->name = Strdup(name);
+
+ return (pwp);
+}
+
+/**
+ ** putpwheel() - PUT PRINT WHEEL INFO TO DISK
+ **/
+
+int
+#if defined(__STDC__)
+putpwheel (
+ char * name,
+ PWHEEL * pwheelp
+)
+#else
+putpwheel (name, pwheelp)
+ char *name;
+ PWHEEL *pwheelp;
+#endif
+{
+ register char *path;
+
+ struct stat statbuf;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(name, NAME_ALL)) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /*
+ * Create the parent directory for this printer
+ * if it doesn't yet exist.
+ */
+ if (!(path = makepath(Lp_A_PrintWheels, name, (char *)0)))
+ return (-1);
+ if (Stat(path, &statbuf) == 0) {
+ if (!S_ISDIR(statbuf.st_mode)) {
+ Free (path);
+ errno = ENOTDIR;
+ return (-1);
+ }
+ } else if (errno != ENOENT || mkdir_lpdir(path, MODE_DIR) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ /*
+ * Now write out the alert condition.
+ */
+ if (putalert(Lp_A_PrintWheels, name, &(pwheelp->alert)) == -1)
+ return (-1);
+
+ return (0);
+}
+
+/**
+ ** delpwheel() - DELETE PRINT WHEEL INFO FROM DISK
+ **/
+
+#if defined(__STDC__)
+static int _delpwheel ( char * );
+#else
+static int _delpwheel();
+#endif
+
+int
+#if defined(__STDC__)
+delpwheel (
+ char * name
+)
+#else
+delpwheel (name)
+ char *name;
+#endif
+{
+ long lastdir;
+
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ lastdir = -1;
+ while ((name = next_dir(Lp_A_PrintWheels, &lastdir)))
+ if (_delpwheel(name) == -1)
+ return (-1);
+ return (0);
+ } else
+ return (_delpwheel(name));
+}
+
+/**
+ ** _delpwheel()
+ **/
+
+static int
+#if defined(__STDC__)
+_delpwheel (
+ char * name
+)
+#else
+_delpwheel (name)
+ char *name;
+#endif
+{
+ register char *path;
+
+ if (delalert(Lp_A_PrintWheels, name) == -1)
+ return (-1);
+ if (!(path = makepath(Lp_A_PrintWheels, name, (char *)0)))
+ return (-1);
+ if (Rmdir(path)) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+ return (0);
+}
+
+/**
+ ** freepwheel() - FREE MEMORY ALLOCATED FOR PRINT WHEEL STRUCTURE
+ **/
+
+void
+#if defined(__STDC__)
+freepwheel (
+ PWHEEL * ppw
+)
+#else
+freepwheel (ppw)
+ PWHEEL *ppw;
+#endif
+{
+ if (!ppw)
+ return;
+ if (ppw->name)
+ Free (ppw->name);
+ if (ppw->alert.shcmd)
+ Free (ppw->alert.shcmd);
+ Free (ppw);
+
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/printers/putprinter.c b/usr/src/cmd/lp/lib/printers/putprinter.c
new file mode 100644
index 0000000000..f7214dfe65
--- /dev/null
+++ b/usr/src/cmd/lp/lib/printers/putprinter.c
@@ -0,0 +1,794 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "sys/stat.h"
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "printers.h"
+
+#include <unistd.h>
+#include <sys/wait.h>
+
+#define SHELL "/bin/sh"
+#define PPDZIP ".gz"
+
+extern struct {
+ char *v;
+ short len,
+ okremote;
+} prtrheadings[];
+
+#if defined(__STDC__)
+
+static void print_sdn (int, char *, SCALED);
+static void print_l (int, char *, char **);
+static void print_str (int, char *, char *);
+
+#ifdef LP_USE_PAPI_ATTR
+static int addPrintersPPD(char *name, PRINTER *prbufp);
+static int copyPPDFile(char *ppd, char *printersPPD);
+static int unzipPPDFile(char *ppd, char *printersPPD);
+#endif
+
+#else
+
+static void print_sdn(),
+ print_l(),
+ print_str();
+
+#ifdef LP_USE_PAPI_ATTR
+static int addPrintersPPD();
+static int copyPPDFile();
+static int unzipPPDFile();
+#endif
+
+#endif
+
+unsigned long ignprinter = 0;
+int ppdopt = 0;
+
+/**
+ ** putprinter() - WRITE PRINTER STRUCTURE TO DISK FILES
+ **/
+
+int
+putprinter(char *name, PRINTER *prbufp)
+{
+ register char * path;
+ register char * stty;
+ register char * speed;
+
+ int fdin, fdout;
+
+ int fld;
+
+ char buf[BUFSIZ];
+
+ struct stat statbuf1,
+ statbuf2;
+
+
+ badprinter = 0;
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (STREQU(NAME_ALL, name)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * First go through the structure and see if we have
+ * anything strange.
+ */
+ if (!okprinter(name, prbufp, 1)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (!Lp_A_Printers || !Lp_A_Interfaces) {
+ getadminpaths (LPUSER);
+ if (!Lp_A_Printers || !Lp_A_Interfaces)
+ return (0);
+ }
+
+ /*
+ * Create the parent directory for this printer
+ * if it doesn't yet exist.
+ */
+ if (!(path = getprinterfile(name, (char *)0)))
+ return (-1);
+ if (Stat(path, &statbuf1) == 0) {
+ if (!S_ISDIR(statbuf1.st_mode)) {
+ Free (path);
+ errno = ENOTDIR;
+ return (-1);
+ }
+ } else if (errno != ENOENT || mkdir_lpdir(path, MODE_DIR) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ /*
+ * Create the copy of the interface program, unless
+ * that would be silly or not desired.
+ * Conversely, make sure the interface program doesn't
+ * exist for a remote printer.
+ */
+ if (prbufp->remote) {
+ if (!(path = makepath(Lp_A_Interfaces, name, (char *)0)))
+ return (-1);
+ (void)rmfile (path);
+ Free (path);
+ }
+ if (prbufp->interface && (ignprinter & BAD_INTERFACE) == 0) {
+ if (Stat(prbufp->interface, &statbuf1) == -1)
+ return (-1);
+ if (!(path = makepath(Lp_A_Interfaces, name, (char *)0)))
+ return (-1);
+ if (
+ Stat(path, &statbuf2) == -1
+ || statbuf1.st_dev != statbuf2.st_dev
+ || statbuf1.st_ino != statbuf2.st_ino
+ ) {
+ register int n;
+
+ if ((fdin = open_locked(prbufp->interface, "r", 0)) < 0) {
+ Free (path);
+ return (-1);
+ }
+ if ((fdout = open_locked(path, "w", MODE_EXEC)) < 0) {
+ Free (path);
+ close(fdin);
+ return (-1);
+ }
+ while ((n = read(fdin, buf, BUFSIZ)) > 0)
+ write (fdout, buf, n);
+ close(fdout);
+ close(fdin);
+ }
+ Free (path);
+ }
+
+#ifdef LP_USE_PAPI_ATTR
+ /*
+ * Handle PPD (Postscript Printer Definition) file for printer
+ * if this printer has been configured with one
+ */
+ if ((prbufp->ppd != NULL) && (ppdopt))
+ {
+ if (addPrintersPPD(name, prbufp) != 0)
+ {
+ /* failed to added the printers PPD file */
+ return (-1);
+ }
+ }
+#endif
+
+ /*
+ * If this printer is dialed up, remove any baud rates
+ * from the stty option list and move the last one to
+ * the ".speed" member if the ".speed" member isn't already
+ * set. Conversely, if this printer is directly connected,
+ * move any value from the ".speed" member to the stty list.
+ */
+
+ stty = (prbufp->stty? Strdup(prbufp->stty) : 0);
+ if (prbufp->speed)
+ speed = Strdup(prbufp->speed);
+ else
+ speed = 0;
+
+ if (prbufp->dial_info && stty) {
+ register char *newstty,
+ *p,
+ *q;
+
+ register int len;
+
+ if (!(q = newstty = Malloc(strlen(stty) + 1))) {
+ Free (stty);
+ errno = ENOMEM;
+ return (-1);
+ }
+ newstty[0] = 0; /* start with empty copy */
+
+ for (
+ p = strtok(stty, " ");
+ p;
+ p = strtok((char *)0, " ")
+ ) {
+ len = strlen(p);
+ if (strspn(p, "0123456789") == len) {
+ /*
+ * If "prbufp->speed" isn't set, then
+ * use the speed we just found. Don't
+ * check "speed", because if more than
+ * one speed was given in the list, we
+ * want the last one.
+ */
+ if (!prbufp->speed) {
+ if (speed)
+ Free (speed);
+ speed = Strdup(p);
+ }
+
+ } else {
+ /*
+ * Not a speed, so copy it to the
+ * new stty string.
+ */
+ if (q != newstty)
+ *q++ = ' ';
+ strcpy (q, p);
+ q += len;
+ }
+ }
+
+ Free (stty);
+ stty = newstty;
+
+ } else if (!prbufp->dial_info && speed) {
+ register char *newstty;
+
+ newstty = Malloc(strlen(stty) + 1 + strlen(speed) + 1);
+ if (!newstty) {
+ if (stty)
+ Free (stty);
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ if (stty) {
+ strcpy (newstty, stty);
+ strcat (newstty, " ");
+ strcat (newstty, speed);
+ Free (stty);
+ } else
+ strcpy (newstty, speed);
+ Free (speed);
+ speed = 0;
+
+ stty = newstty;
+
+ }
+
+ /*
+ * Open the configuration file and write out the printer
+ * configuration.
+ */
+
+ if (!(path = getprinterfile(name, CONFIGFILE))) {
+ if (stty)
+ Free (stty);
+ if (speed)
+ Free (speed);
+ return (-1);
+ }
+ if ((fdout = open_locked(path, "w", MODE_READ)) < 0) {
+ Free (path);
+ if (stty)
+ Free (stty);
+ if (speed)
+ Free (speed);
+ return (-1);
+ }
+ Free (path);
+
+ errno = 0;
+ for (fld = 0; fld < PR_MAX; fld++) {
+ if (prbufp->remote && !prtrheadings[fld].okremote)
+ continue;
+
+ switch (fld) {
+
+#define HEAD prtrheadings[fld].v
+
+ case PR_BAN:
+ {
+ char *ptr = NAME_ON;
+
+ switch (prbufp->banner) {
+ case BAN_ALWAYS:
+ ptr = NAME_ON;
+ break;
+ case BAN_NEVER:
+ ptr = NAME_OFF;
+ break;
+ case BAN_OPTIONAL:
+ ptr = NAME_OPTIONAL;
+ break;
+ }
+ (void)fdprintf(fdout, "%s %s\n", HEAD, ptr);
+ }
+ break;
+
+ case PR_CPI:
+ print_sdn(fdout, HEAD, prbufp->cpi);
+ break;
+
+ case PR_CS:
+ if (!emptylist(prbufp->char_sets))
+ print_l(fdout, HEAD, prbufp->char_sets);
+ break;
+
+ case PR_ITYPES:
+ /*
+ * Put out the header even if the list is empty,
+ * to distinguish no input types from the default.
+ */
+ print_l(fdout, HEAD, prbufp->input_types);
+ break;
+
+ case PR_DEV:
+ print_str(fdout, HEAD, prbufp->device);
+ break;
+
+ case PR_DIAL:
+ print_str(fdout, HEAD, prbufp->dial_info);
+ break;
+
+ case PR_RECOV:
+ print_str(fdout, HEAD, prbufp->fault_rec);
+ break;
+
+ case PR_INTFC:
+ print_str(fdout, HEAD, prbufp->interface);
+ break;
+
+ case PR_LPI:
+ print_sdn(fdout, HEAD, prbufp->lpi);
+ break;
+
+ case PR_LEN:
+ print_sdn(fdout, HEAD, prbufp->plen);
+ break;
+
+ case PR_LOGIN:
+ if (prbufp->login & LOG_IN)
+ (void)fdprintf(fdout, "%s\n", HEAD);
+ break;
+
+ case PR_PTYPE:
+ {
+ char **printer_types;
+
+ /*
+ * For backward compatibility for those who
+ * use only "->printer_type", we have to play
+ * some games here.
+ */
+ if (prbufp->printer_type && !prbufp->printer_types)
+ printer_types = getlist(
+ prbufp->printer_type,
+ LP_WS,
+ LP_SEP
+ );
+ else
+ printer_types = prbufp->printer_types;
+
+ if (!printer_types || !*printer_types)
+ print_str(fdout, HEAD, NAME_UNKNOWN);
+ else
+ print_l(fdout, HEAD, printer_types);
+
+ if (printer_types != prbufp->printer_types)
+ freelist (printer_types);
+ break;
+ }
+
+ case PR_REMOTE:
+ print_str(fdout, HEAD, prbufp->remote);
+ break;
+
+ case PR_SPEED:
+ print_str(fdout, HEAD, speed);
+ break;
+
+ case PR_STTY:
+ print_str(fdout, HEAD, stty);
+ break;
+
+ case PR_WIDTH:
+ print_sdn(fdout, HEAD, prbufp->pwid);
+ break;
+
+#if defined(CAN_DO_MODULES)
+ case PR_MODULES:
+ /*
+ * Put out the header even if the list is empty,
+ * to distinguish no modules from the default.
+ */
+ print_l(fdout, HEAD, prbufp->modules);
+ break;
+#endif
+
+ case PR_OPTIONS:
+ print_l(fdout, HEAD, prbufp->options);
+ break;
+
+ case PR_PPD:
+ {
+ print_str(fdout, HEAD, prbufp->ppd);
+ break;
+ }
+ }
+
+ }
+ if (stty)
+ Free (stty);
+ if (speed)
+ Free (speed);
+ if (errno != 0) {
+ close(fdout);
+ return (-1);
+ }
+ close(fdout);
+
+ /*
+ * If we have a description of the printer,
+ * write it out to a separate file.
+ */
+ if (prbufp->description) {
+
+ if (!(path = getprinterfile(name, COMMENTFILE)))
+ return (-1);
+
+ if (dumpstring(path, prbufp->description) == -1) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ }
+
+ /*
+ * Now write out the alert condition.
+ */
+ if (
+ prbufp->fault_alert.shcmd
+ && putalert(Lp_A_Printers, name, &(prbufp->fault_alert)) == -1
+ )
+ return (-1);
+
+ return (0);
+}
+
+/**
+ ** print_sdn() - PRINT SCALED DECIMAL NUMBER WITH HEADER
+ ** print_l() - PRINT (char **) LIST WITH HEADER
+ ** print_str() - PRINT STRING WITH HEADER
+ **/
+
+static void
+print_sdn(int fd, char *head, SCALED sdn)
+{
+ if (sdn.val <= 0)
+ return;
+
+ (void)fdprintf (fd, "%s ", head);
+ fdprintsdn (fd, sdn);
+
+ return;
+}
+
+static void
+print_l(int fd, char *head, char **list)
+{
+ (void)fdprintf (fd, "%s ", head);
+ printlist_setup (0, 0, LP_SEP, 0);
+ fdprintlist (fd, list);
+ printlist_unsetup ();
+
+ return;
+}
+
+static void
+print_str(int fd, char *head, char *str)
+{
+ if (!str || !*str)
+ return;
+
+ (void)fdprintf (fd, "%s %s\n", head, str);
+
+ return;
+}
+
+
+#ifdef LP_USE_PAPI_ATTR
+/*
+ * Function: addPrintersPPD()
+ *
+ * Description: Handle PPD (Postscript Printer Definition) file for this
+ * printer if it has been configured with one
+ *
+ */
+
+static int
+addPrintersPPD(char *name, PRINTER *prbufp)
+
+{
+ int result = 0;
+ char *path = NULL;
+ char *ppd = NULL;
+ char buf[BUFSIZ];
+ struct stat statbuf;
+
+ (void) snprintf(buf, sizeof (buf), "%s.ppd", name);
+ if (prbufp->remote)
+ {
+ /* make sure the PPD file doesn't exist for a remote printer */
+ if (!(path = makepath(ETCDIR, "ppd", buf, (char *)0)))
+ {
+ result = -1;
+ }
+ else
+ {
+ (void) rmfile(path);
+ }
+ }
+
+ if ((result == 0) && (prbufp->ppd != NULL))
+ {
+ ppd = strdup(prbufp->ppd);
+
+ if (ppd == NULL)
+ {
+ result = -1;
+ }
+ else
+ {
+ /* Check the PPD file given exists */
+
+ if (Stat(ppd, &statbuf) == -1)
+ {
+ /*
+ * The given ppd files does not exist, but
+ * check if there is a zipped version of the
+ * file that we can use instead
+ */
+ if (strstr(ppd, PPDZIP) != NULL)
+ {
+ /* this is a zipped file so exit */
+ result = -1;
+ }
+ else
+ {
+ ppd = Realloc(ppd,
+ strlen(ppd)+strlen(PPDZIP)+2);
+ if (ppd != NULL)
+ {
+ ppd = strcat(ppd, PPDZIP);
+ if (Stat(ppd, &statbuf) == -1)
+ {
+ /*
+ * this zipped version
+ * of the file does not
+ * exist either
+ */
+ result = -1;
+ }
+ }
+ else
+ {
+ result = -1;
+ }
+ }
+ }
+ }
+
+ /*
+ * Create the copy of the PPD file for this printer
+ * unless that would be silly or not desired
+ */
+
+ if (result == 0)
+ {
+ if (!(path = makepath(ETCDIR, "ppd", buf, (char *)0)))
+ {
+ result = -1;
+ }
+ }
+
+ /*
+ * At this point we may have a zipped or unzipped ppd file, if
+ * it's unzipped just copy it otherwise unzip it to the
+ * printer's ppd file (/etc/lp/ppd/<printer>.ppd)
+ */
+
+ if (result == 0)
+ {
+ if (strstr(ppd, PPDZIP) == NULL)
+ {
+ result = copyPPDFile(ppd, path);
+ }
+ else
+ {
+ result = unzipPPDFile(ppd, path);
+ }
+
+ (void) chown_lppath(path);
+ (void) chmod(path, 0644);
+ }
+
+ if (ppd != NULL)
+ {
+ Free(ppd);
+ }
+ if (path != NULL)
+ {
+ Free(path);
+ }
+ }
+
+ return (result);
+} /* addPrintersPPD() */
+
+
+/*
+ * Function: copyPPDFile()
+ *
+ * Description: Copy the given ppd file to the printer's file in /etc/lp/ppd
+ *
+ */
+
+static int
+copyPPDFile(char *ppd, char *printersPPD)
+
+{
+ int result = 0;
+ register int n = 0;
+ int fdin = 0;
+ int fdout = 0;
+ char buf[BUFSIZ];
+
+ if ((ppd != NULL) && (printersPPD != NULL))
+ {
+ if ((fdin = open_locked(ppd, "r", 0)) < 0)
+ {
+ result = -1;
+ }
+ else
+ {
+ fdout = open_locked(printersPPD, "w", MODE_EXEC);
+ if (fdout < 0)
+ {
+ close(fdin);
+ result = -1;
+ }
+ }
+
+ if (result == 0)
+ {
+ while ((n = read(fdin, buf, BUFSIZ)) > 0)
+ {
+ write(fdout, buf, n);
+ }
+ close(fdout);
+ close(fdin);
+ }
+ }
+ else
+ {
+ result = -1;
+ }
+
+ return (result);
+} /* copyPPDFile() */
+
+
+
+/*
+ * Function: unzipPPDFile()
+ *
+ * Description: Unzip the given ppd file to the printer's file in /etc/lp/ppd.
+ * This is done by forking and running the unzip utility on the
+ * zipped ppd file.
+ *
+ */
+
+static int
+unzipPPDFile(char *ppd, char *printersPPD)
+
+{
+ int result = -1;
+ char *cmdLine = NULL;
+ pid_t childPID = 0;
+ int stat = 0;
+ int clSize = 0;
+
+
+ if ((ppd != NULL) && (printersPPD != NULL))
+ {
+ childPID = fork();
+
+ switch (childPID)
+ {
+ case -1:
+ {
+ /* return error */
+ break;
+ }
+
+ case 0:
+ {
+ /* child process - so execute something */
+
+ clSize = strlen("/usr/bin/rm -f ") +
+ strlen(printersPPD) +
+ strlen("/usr/bin/gzip -dc ") +
+ strlen(ppd) +
+ strlen(printersPPD) + 20;
+ cmdLine = malloc(clSize);
+ if (cmdLine != NULL)
+ {
+
+ (void) snprintf(cmdLine, clSize,
+ "/usr/bin/rm -f %s; /usr/bin/gzip -dc %s > %s",
+ printersPPD, ppd,
+ printersPPD);
+ result = execl(SHELL, SHELL, "-c",
+ cmdLine, NULL);
+ exit(result);
+ }
+ break;
+ }
+
+ default:
+ {
+ /* parent process, child pid is in childPID */
+
+ while (wait(&stat) != childPID);
+
+ if ((stat & 0xff00) == 0)
+ {
+ result = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ return (result);
+} /* unzipPPDFile() */
+#endif
diff --git a/usr/src/cmd/lp/lib/requests/Makefile b/usr/src/cmd/lp/lib/requests/Makefile
new file mode 100644
index 0000000000..06cabd5cb3
--- /dev/null
+++ b/usr/src/cmd/lp/lib/requests/Makefile
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/requests/Makefile
+#
+
+LIBRARY = liblpreq.a
+
+OBJECTS = anyrequests.o \
+ freerequest.o \
+ getrequest.o \
+ r_head.o \
+ putrequest.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master) $(C_PICFLAGS)
+
+POFILE = lp_lib_requests.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpreq.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+LINT_CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+lint: lintlib
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) -o lpreq llib-llpreq
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/requests/anyrequests.c b/usr/src/cmd/lp/lib/requests/anyrequests.c
new file mode 100644
index 0000000000..ec61529c54
--- /dev/null
+++ b/usr/src/cmd/lp/lib/requests/anyrequests.c
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+
+#include "lp.h"
+
+/**
+ ** anyrequests() - SEE IF ANY REQUESTS ARE ``QUEUED''
+ **/
+
+int
+#if defined(__STDC__)
+anyrequests (
+ void
+)
+#else
+anyrequests ()
+#endif
+{
+ long lastdir = -1;
+
+ char * name;
+
+
+ /*
+ * This routine walks through the requests (secure)
+ * directory looking for files, descending one level
+ * into each sub-directory, if any. Finding at least
+ * one file means that a request is queued.
+ */
+ while ((name = next_dir(Lp_Requests, &lastdir))) {
+
+ long lastfile = -1;
+
+ char * subdir;
+
+
+ if (!(subdir = makepath(Lp_Requests, name, (char *)0)))
+ return (1); /* err on safe side */
+
+ if (next_file(subdir, &lastfile)) {
+ Free (subdir);
+ return (1);
+ }
+
+ Free (subdir);
+ }
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/requests/freerequest.c b/usr/src/cmd/lp/lib/requests/freerequest.c
new file mode 100644
index 0000000000..cff15480ac
--- /dev/null
+++ b/usr/src/cmd/lp/lib/requests/freerequest.c
@@ -0,0 +1,81 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "requests.h"
+
+/**
+ ** freerequest() - FREE STRUCTURE ALLOCATED FOR A REQUEST STRUCTURE
+ **/
+
+void
+#if defined(__STDC__)
+freerequest (
+ REQUEST * reqbufp
+)
+#else
+freerequest (reqbufp)
+ register REQUEST *reqbufp;
+#endif
+{
+ if (!reqbufp)
+ return;
+ if (reqbufp->destination)
+ Free (reqbufp->destination);
+ if (reqbufp->file_list)
+ freelist (reqbufp->file_list);
+ if (reqbufp->form)
+ Free (reqbufp->form);
+ if (reqbufp->alert)
+ Free (reqbufp->alert);
+ if (reqbufp->options)
+ Free (reqbufp->options);
+ if (reqbufp->pages)
+ Free (reqbufp->pages);
+ if (reqbufp->charset)
+ Free (reqbufp->charset);
+ if (reqbufp->modes)
+ Free (reqbufp->modes);
+ if (reqbufp->title)
+ Free (reqbufp->title);
+ if (reqbufp->input_type)
+ Free (reqbufp->input_type);
+ if (reqbufp->user)
+ Free (reqbufp->user);
+ Free (reqbufp);
+
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/requests/getrequest.c b/usr/src/cmd/lp/lib/requests/getrequest.c
new file mode 100644
index 0000000000..7aa5933395
--- /dev/null
+++ b/usr/src/cmd/lp/lib/requests/getrequest.c
@@ -0,0 +1,266 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "requests.h"
+
+extern struct {
+ char *v;
+ short len;
+} reqheadings[];
+
+/**
+ ** getrequest() - EXTRACT REQUEST STRUCTURE FROM DISK FILE
+ **/
+
+REQUEST *
+#if defined(__STDC__)
+getrequest (
+ char * file
+)
+#else
+getrequest (file)
+ char *file;
+#endif
+{
+ REQUEST *reqp;
+
+ char buf[BUFSIZ],
+ *path,
+ *p;
+
+ int fd;
+
+ int fld;
+
+
+ /*
+ * Full pathname? If so the file must lie in LP's
+ * regular temporary directory.
+ */
+ if (*file == '/') {
+ if (!STRNEQU(file, Lp_Tmp, strlen(Lp_Tmp))) {
+ errno = EINVAL;
+ return (0);
+ }
+ path = Strdup(file);
+
+ /*
+ * A relative pathname (such as system/name)?
+ * If so we'll locate it under LP's regular temporary
+ * directory.
+ */
+ } else if (strchr(file, '/')) {
+ if (!(path = makepath(Lp_Tmp, file, (char *)0)))
+ return (0);
+
+ /*
+ * It must be a simple name. Locate this under the
+ * special temporary directory that is linked to the
+ * regular place for the local system.
+ */
+ } else if (!(path = makepath(Lp_Temp, file, (char *)0)))
+ return (0);
+
+
+ if ((fd = open_locked(path, "r", 0)) < 0) {
+ Free (path);
+ return (0);
+ }
+ Free (path);
+
+ reqp = calloc(sizeof (*reqp), 1);
+ reqp->copies = 1;
+ reqp->priority = -1;
+
+ errno = 0;
+ while (fdgets(buf, BUFSIZ, fd)) {
+
+ buf[strlen(buf) - 1] = 0;
+
+ for (fld = 0; fld < RQ_MAX; fld++)
+ if (
+ reqheadings[fld].v
+ && reqheadings[fld].len
+ && STRNEQU(
+ buf,
+ reqheadings[fld].v,
+ reqheadings[fld].len
+ )
+ ) {
+ p = buf + reqheadings[fld].len;
+ break;
+ }
+
+ /*
+ * To allow future extensions to not impact applications
+ * using old versions of this routine, ignore strange
+ * fields.
+ */
+ if (fld >= RQ_MAX)
+ continue;
+
+ switch (fld) {
+
+ case RQ_COPIES:
+ reqp->copies = atoi(p);
+ break;
+
+ case RQ_DEST:
+ reqp->destination = Strdup(p);
+ break;
+
+ case RQ_FILE:
+ appendlist (&reqp->file_list, p);
+ break;
+
+ case RQ_FORM:
+ if (!STREQU(p, NAME_ANY))
+ reqp->form = Strdup(p);
+ break;
+
+ case RQ_HANDL:
+ if (STREQU(p, NAME_RESUME))
+ reqp->actions |= ACT_RESUME;
+ else if (STREQU(p, NAME_HOLD))
+ reqp->actions |= ACT_HOLD;
+ else if (STREQU(p, NAME_IMMEDIATE))
+ reqp->actions |= ACT_IMMEDIATE;
+ break;
+
+ case RQ_NOTIFY:
+ if (STREQU(p, "M"))
+ reqp->actions |= ACT_MAIL;
+ else if (STREQU(p, "W"))
+ reqp->actions |= ACT_WRITE;
+ else if (STREQU(p, "N"))
+ reqp->actions |= ACT_NOTIFY;
+ else
+ reqp->alert = Strdup(p);
+ break;
+
+ case RQ_OPTS:
+ reqp->options = Strdup(p);
+ break;
+
+ case RQ_PRIOR:
+ reqp->priority = atoi(p);
+ break;
+
+ case RQ_PAGES:
+ reqp->pages = Strdup(p);
+ break;
+
+ case RQ_CHARS:
+ if (!STREQU(p, NAME_ANY))
+ reqp->charset = Strdup(p);
+ break;
+
+ case RQ_TITLE:
+ reqp->title = Strdup(p);
+ break;
+
+ case RQ_MODES:
+ reqp->modes = Strdup(p);
+ break;
+
+ case RQ_TYPE:
+ reqp->input_type = Strdup(p);
+ break;
+
+ case RQ_USER:
+ reqp->user = Strdup(p);
+ break;
+
+ case RQ_RAW:
+ reqp->actions |= ACT_RAW;
+ break;
+
+ case RQ_FAST:
+ reqp->actions |= ACT_FAST;
+ break;
+
+ case RQ_STAT:
+ reqp->outcome = (ushort)strtol(p, (char **)0, 16);
+ break;
+
+ }
+
+ }
+ if (errno != 0) {
+ int save_errno = errno;
+
+ close(fd);
+ errno = save_errno;
+ return (0);
+ }
+ close(fd);
+
+ /*
+ * Now go through the structure and see if we have
+ * anything strange.
+ */
+ if (
+ reqp->copies <= 0
+ || !reqp->file_list || !*(reqp->file_list)
+ || reqp->priority < -1 || 39 < reqp->priority
+ || STREQU(reqp->input_type, NAME_ANY)
+ || STREQU(reqp->input_type, NAME_TERMINFO)
+ ) {
+ freerequest (reqp);
+ errno = EBADF;
+ return (0);
+ }
+
+ /*
+ * Guarantee some return values won't be null or empty.
+ */
+ if (!reqp->destination || !*reqp->destination) {
+ if (reqp->destination)
+ Free (reqp->destination);
+ reqp->destination = Strdup(NAME_ANY);
+ }
+ if (!reqp->input_type || !*reqp->input_type) {
+ if (reqp->input_type)
+ Free (reqp->input_type);
+ reqp->input_type = Strdup(NAME_SIMPLE);
+ }
+
+ return (reqp);
+}
diff --git a/usr/src/cmd/lp/lib/requests/llib-llpreq b/usr/src/cmd/lp/lib/requests/llib-llpreq
new file mode 100644
index 0000000000..ec8a5f0250
--- /dev/null
+++ b/usr/src/cmd/lp/lib/requests/llib-llpreq
@@ -0,0 +1,59 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+
+typedef struct REQUEST {
+ short copies; /* number of copies of request to print */
+ char *destination; /* printer or class name */
+ char **file_list; /* list of files to print: req. content */
+ char *form; /* preprinted form to print on */
+ ushort actions; /* mail/write, immediate/hold/resume, raw */
+ char *alert; /* program to run to alert user when done */
+ char *options; /* print options; space separated list */
+ short priority; /* priority level, 0-39, of the request */
+ char *pages; /* list of pages to print (uniq. please!) */
+ char *charset; /* character set to select or mount */
+ char *modes; /* mode(s) of operation; space sep. list */
+ char *title; /* optional title for banner page */
+ char *input_type; /* type of content */
+ char *user; /* user name of person submitting */
+ ushort outcome; /* success/fauilure */
+ ushort version; /* version of system sending job*/
+} REQUEST;
+
+REQUEST * getrequest ( char * );
+int putrequest ( char *, REQUEST * );
+void freerequest ( REQUEST * );
+
diff --git a/usr/src/cmd/lp/lib/requests/putrequest.c b/usr/src/cmd/lp/lib/requests/putrequest.c
new file mode 100644
index 0000000000..a426562057
--- /dev/null
+++ b/usr/src/cmd/lp/lib/requests/putrequest.c
@@ -0,0 +1,225 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "stdio.h"
+#include "string.h"
+#include "errno.h"
+#include "sys/types.h"
+#include "sys/utsname.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "requests.h"
+
+extern struct {
+ char *v;
+ short len;
+} reqheadings[];
+
+/**
+ ** putrequest() - WRITE REQUEST STRUCTURE TO DISK FILE
+ **/
+
+int
+#if defined(__STDC__)
+putrequest (
+ char * file,
+ REQUEST * reqbufp
+)
+#else
+putrequest (file, reqbufp)
+ char *file;
+ REQUEST *reqbufp;
+#endif
+{
+ char **pp,
+ *path;
+
+ int fd;
+
+ int fld;
+
+ /*
+ * First go through the structure and see if we have
+ * anything strange.
+ */
+ if (
+ reqbufp->copies <= 0
+ || !(reqbufp->destination)
+ || !reqbufp->file_list || !*(reqbufp->file_list)
+ || (reqbufp->actions & (ACT_MAIL|ACT_WRITE))
+ && (reqbufp->alert && *(reqbufp->alert))
+ || reqbufp->priority < -1 || 39 < reqbufp->priority
+ ) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /*
+ * Now open the file and write out the request.
+ */
+
+ /*
+ * Full pathname? If so the file must lie in LP's
+ * regular temporary directory.
+ */
+ if (*file == '/') {
+ if (!STRNEQU(file, Lp_Tmp, strlen(Lp_Tmp))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ path = Strdup(file);
+
+ /*
+ * A relative pathname (such as system/name)?
+ * If so we'll locate it under LP's regular temporary
+ * directory.
+ */
+ } else if (strchr(file, '/')) {
+ if (!(path = makepath(Lp_Tmp, file, (char *)0)))
+ return (-1);
+
+ /*
+ * If must be a simple name. Locate this under the
+ * special temporary directory that is linked to the
+ * regular place for the local system.
+ */
+ } else if (!(path = makepath(Lp_Temp, file, (char *)0)))
+ return (-1);
+
+ if ((fd = open_locked(path, "w", MODE_NOREAD)) < 0) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ for (fld = 0; fld < RQ_MAX; fld++) switch (fld) {
+
+#define HEAD reqheadings[fld].v
+
+ case RQ_COPIES:
+ (void)fdprintf(fd, "%s%d\n", HEAD, reqbufp->copies);
+ break;
+
+ case RQ_DEST:
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->destination);
+ break;
+
+ case RQ_FILE:
+ for (pp = reqbufp->file_list; *pp; pp++)
+ (void)fdprintf(fd, "%s%s\n", HEAD, *pp);
+ break;
+
+ case RQ_FORM:
+ if (reqbufp->form)
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->form);
+ break;
+
+ case RQ_HANDL:
+ if ((reqbufp->actions & ACT_SPECIAL) == ACT_IMMEDIATE)
+ (void)fdprintf(fd, "%s%s\n", HEAD, NAME_IMMEDIATE);
+ else if ((reqbufp->actions & ACT_SPECIAL) == ACT_RESUME)
+ (void)fdprintf(fd, "%s%s\n", HEAD, NAME_RESUME);
+ else if ((reqbufp->actions & ACT_SPECIAL) == ACT_HOLD)
+ (void)fdprintf(fd, "%s%s\n", HEAD, NAME_HOLD);
+ break;
+
+ case RQ_NOTIFY:
+ if (reqbufp->actions & ACT_MAIL)
+ (void)fdprintf(fd, "%sM\n", HEAD);
+ else if (reqbufp->actions & ACT_WRITE)
+ (void)fdprintf(fd, "%sW\n", HEAD);
+ else if (reqbufp->actions & ACT_NOTIFY)
+ (void)fdprintf(fd, "%sN\n", HEAD);
+ else if (reqbufp->alert && *(reqbufp->alert))
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->alert);
+ break;
+
+ case RQ_OPTS:
+ if (reqbufp->options)
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->options);
+ break;
+
+ case RQ_PRIOR:
+ if (reqbufp->priority != -1)
+ (void)fdprintf(fd, "%s%d\n", HEAD, reqbufp->priority);
+ break;
+
+ case RQ_PAGES:
+ if (reqbufp->pages)
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->pages);
+ break;
+
+ case RQ_CHARS:
+ if (reqbufp->charset)
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->charset);
+ break;
+
+ case RQ_TITLE:
+ if (reqbufp->title)
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->title);
+ break;
+
+ case RQ_MODES:
+ if (reqbufp->modes)
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->modes);
+ break;
+
+ case RQ_TYPE:
+ if (reqbufp->input_type)
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->input_type);
+ break;
+
+ case RQ_USER:
+ if (reqbufp->user)
+ (void)fdprintf(fd, "%s%s\n", HEAD, reqbufp->user);
+ break;
+
+ case RQ_RAW:
+ if (reqbufp->actions & ACT_RAW)
+ (void)fdprintf(fd, "%s\n", HEAD);
+ break;
+
+ case RQ_FAST:
+ if (reqbufp->actions & ACT_FAST)
+ (void)fdprintf(fd, "%s\n", HEAD);
+ break;
+
+ case RQ_STAT:
+ (void)fdprintf(fd, "%s%#6.4x\n", HEAD, reqbufp->outcome);
+ break;
+
+ }
+
+ close(fd);
+ return (0);
+}
diff --git a/usr/src/cmd/lp/lib/requests/r_head.c b/usr/src/cmd/lp/lib/requests/r_head.c
new file mode 100644
index 0000000000..65b100be01
--- /dev/null
+++ b/usr/src/cmd/lp/lib/requests/r_head.c
@@ -0,0 +1,70 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "sys/types.h"
+
+#include "lp.h"
+#include "requests.h"
+
+struct {
+ char *v;
+ short len;
+} reqheadings[RQ_MAX] = {
+
+#define ENTRY(X) X, sizeof(X)-1
+
+ ENTRY("C "), /* RQ_COPIES */
+ ENTRY("D "), /* RQ_DEST */
+ ENTRY("F "), /* RQ_FILE */
+ ENTRY("f "), /* RQ_FORM */
+ ENTRY("H "), /* RQ_HANDL */
+ ENTRY("N "), /* RQ_NOTIFY */
+ ENTRY("O "), /* RQ_OPTS */
+ ENTRY("P "), /* RQ_PRIOR */
+ ENTRY("p "), /* RQ_PGES */
+ ENTRY("S "), /* RQ_CHARS */
+ ENTRY("T "), /* RQ_TITLE */
+ ENTRY("Y "), /* RQ_MODES */
+ ENTRY("t "), /* RQ_TYPE */
+ ENTRY("U "), /* RQ_USER */
+ ENTRY("r "), /* RQ_RAW */
+ ENTRY("a "), /* RQ_FAST */
+ ENTRY("s "), /* RQ_STAT */
+ ENTRY("v "), /* RQ_VERSION */
+/* ENTRY("x "), */ /* reserved (slow filter) */
+/* ENTRY("y "), */ /* reserved (fast filter) */
+/* ENTRY("z "), */ /* reserved (printer name) */
+
+#undef ENTRY
+
+};
diff --git a/usr/src/cmd/lp/lib/secure/Makefile b/usr/src/cmd/lp/lib/secure/Makefile
new file mode 100644
index 0000000000..5f1f8b3f9d
--- /dev/null
+++ b/usr/src/cmd/lp/lib/secure/Makefile
@@ -0,0 +1,64 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/secure/Makefile
+#
+
+LIBRARY = liblpsec.a
+
+OBJECTS = secure.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master) $(C_PICFLAGS)
+
+POFILE = lp_lib_secure.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpsec.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+LINT_CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+lint: lintlib
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT) $(LINTFLAGS) $(LINT_CPPFLAGS) -o lpsec llib-llpsec
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/secure/llib-llpsec b/usr/src/cmd/lp/lib/secure/llib-llpsec
new file mode 100644
index 0000000000..796719ea7a
--- /dev/null
+++ b/usr/src/cmd/lp/lib/secure/llib-llpsec
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "sys/types.h"
+
+typedef struct SECURE {
+ uid_t uid;
+ gid_t gid;
+ off_t size;
+ time_t date;
+ char *system;
+ char *user;
+ char *req_id;
+} SECURE;
+
+
+SECURE * getsecure ( char * );
+int putsecure ( char *, SECURE * );
+int rmsecure (char *);
+void freesecure ( SECURE * );
+
diff --git a/usr/src/cmd/lp/lib/secure/secure.c b/usr/src/cmd/lp/lib/secure/secure.c
new file mode 100644
index 0000000000..ff9d583cda
--- /dev/null
+++ b/usr/src/cmd/lp/lib/secure/secure.c
@@ -0,0 +1,269 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
+
+#include "string.h"
+#include "sys/param.h"
+#include "stdlib.h"
+
+#include "lp.h"
+#include "secure.h"
+#include <tsol/label.h>
+
+/**
+ ** getsecure() - EXTRACT SECURE REQUEST STRUCTURE FROM DISK FILE
+ **/
+
+SECURE *
+getsecure(char *file)
+{
+ SECURE *secp;
+
+ char buf[BUFSIZ],
+ *path;
+
+ int fd;
+
+ int fld;
+
+
+ if (*file == '/')
+ path = Strdup(file);
+ else
+ path = makepath(Lp_Requests, file, (char *)0);
+ if (!path)
+ return (0);
+
+ if ((fd = open_locked(path, "r", MODE_NOREAD)) < 0) {
+ Free (path);
+ return (0);
+ }
+ Free (path);
+
+ secp = calloc(sizeof (*secp), 1);
+
+ secp->user = 0;
+ errno = 0;
+ for (
+ fld = 0;
+ fld < SC_MAX && fdgets(buf, BUFSIZ, fd);
+ fld++
+ ) {
+ buf[strlen(buf) - 1] = 0;
+ switch (fld) {
+
+ case SC_REQID:
+ secp->req_id = Strdup(buf);
+ break;
+
+ case SC_UID:
+ secp->uid = (uid_t)atol(buf);
+ break;
+
+ case SC_USER:
+ secp->user = Strdup(buf);
+ break;
+
+ case SC_GID:
+ secp->gid = (gid_t)atol(buf);
+ break;
+
+ case SC_SIZE:
+ secp->size = (size_t)atol(buf);
+ break;
+
+ case SC_DATE:
+ secp->date = (time_t)atol(buf);
+ break;
+
+ case SC_SLABEL:
+ secp->slabel = Strdup(buf);
+ break;
+ }
+ }
+ if (errno != 0 || fld != SC_MAX) {
+ int save_errno = errno;
+
+ freesecure (secp);
+ close(fd);
+ errno = save_errno;
+ return (0);
+ }
+ close(fd);
+
+ /*
+ * Now go through the structure and see if we have
+ * anything strange.
+ */
+ if (
+ secp->uid > MAXUID
+ || !secp->user
+ || secp->gid > MAXUID
+ || secp->size == 0
+ || secp->date <= 0
+ ) {
+ freesecure (secp);
+ errno = EBADF;
+ return (0);
+ }
+
+ return (secp);
+}
+
+/**
+ ** putsecure() - WRITE SECURE REQUEST STRUCTURE TO DISK FILE
+ **/
+
+int
+putsecure(char *file, SECURE *secbufp)
+{
+ char *path;
+
+ int fd;
+
+ int fld;
+
+ if (*file == '/')
+ path = Strdup(file);
+ else
+ path = makepath(Lp_Requests, file, (char *)0);
+ if (!path)
+ return (-1);
+
+ if ((fd = open_locked(path, "w", MODE_NOREAD)) < 0) {
+ Free (path);
+ return (-1);
+ }
+ Free (path);
+
+ if (
+ !secbufp->req_id ||
+ !secbufp->user
+ )
+ return (-1);
+
+ for (fld = 0; fld < SC_MAX; fld++)
+
+ switch (fld) {
+
+ case SC_REQID:
+ (void)fdprintf(fd, "%s\n", secbufp->req_id);
+ break;
+
+ case SC_UID:
+ (void)fdprintf(fd, "%u\n", secbufp->uid);
+ break;
+
+ case SC_USER:
+ (void)fdprintf(fd, "%s\n", secbufp->user);
+ break;
+
+ case SC_GID:
+ (void)fdprintf(fd, "%u\n", secbufp->gid);
+ break;
+
+ case SC_SIZE:
+ (void)fdprintf(fd, "%lu\n", secbufp->size);
+ break;
+
+ case SC_DATE:
+ (void)fdprintf(fd, "%ld\n", secbufp->date);
+ break;
+
+ case SC_SLABEL:
+ if (secbufp->slabel == NULL) {
+ if (is_system_labeled()) {
+ m_label_t *sl;
+
+ sl = m_label_alloc(MAC_LABEL);
+ (void) getplabel(sl);
+ if (label_to_str(sl, &(secbufp->slabel),
+ M_INTERNAL, DEF_NAMES) != 0) {
+ perror("label_to_str");
+ secbufp->slabel =
+ strdup("bad_label");
+ }
+ m_label_free(sl);
+ (void) fdprintf(fd, "%s\n",
+ secbufp->slabel);
+ } else {
+ (void) fdprintf(fd, "none\n");
+ }
+ } else {
+ (void) fdprintf(fd, "%s\n", secbufp->slabel);
+ }
+ break;
+ }
+ close(fd);
+
+ return (0);
+}
+
+/*
+** rmsecure ()
+**
+** o 'reqfilep' is of the form 'node-name/request-file'
+** e.g. 'sfcalv/123-0'.
+*/
+int
+rmsecure (char *reqfilep)
+{
+ int n;
+ char * pathp;
+
+ pathp = makepath (Lp_Requests, reqfilep, (char *) 0);
+ if (! pathp)
+ return -1;
+
+ n = Unlink (pathp);
+ Free (pathp);
+
+ return n;
+}
+
+/**
+ ** freesecure() - FREE A SECURE STRUCTURE
+ **/
+
+void
+freesecure(SECURE *secbufp)
+{
+ if (!secbufp)
+ return;
+ if (secbufp->req_id)
+ Free (secbufp->req_id);
+ if (secbufp->user)
+ Free (secbufp->user);
+ Free (secbufp);
+
+ return;
+}
diff --git a/usr/src/cmd/lp/lib/users/Makefile b/usr/src/cmd/lp/lib/users/Makefile
new file mode 100644
index 0000000000..b225c95c7e
--- /dev/null
+++ b/usr/src/cmd/lp/lib/users/Makefile
@@ -0,0 +1,65 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 1990-2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/lp/lib/users/Makefile
+#
+
+LIBRARY = liblpusr.a
+
+OBJECTS = usermgmt.o \
+ loadpri.o \
+ storepri.o
+
+
+include ../../../../lib/Makefile.lib
+include ../../Makefile.lp
+
+# Specifically request the construction of a static library.
+# This library is not installed in the proto area.
+LIBS = $(LIBRARY)
+
+CPPFLAGS = -I../../include $(CPPFLAGS.master)
+
+POFILE = lp_lib_users.po
+
+.KEEP_STATE:
+
+all install : $(LIBS)
+
+include ../../../../lib/Makefile.targ
+
+CLEANFILES += llib-llpusr.ln
+LINTFLAGS = -nvx
+SRCS= $(OBJECTS:%.o=%.c)
+
+lint: lintlib
+ $(LINT.c) $(LINTFLAGS) $(SRCS)
+
+lintlib:
+ $(LINT.c) $(LINTFLAGS) -o lpusr llib-llpusr
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/lib/users/llib-llpusr b/usr/src/cmd/lp/lib/users/llib-llpusr
new file mode 100644
index 0000000000..86a18b8b1c
--- /dev/null
+++ b/usr/src/cmd/lp/lib/users/llib-llpusr
@@ -0,0 +1,59 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright (c) 1998 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdio.h"
+
+typedef struct
+{
+ short priority_limit;
+}
+USER;
+
+int putuser ( char * , USER * );
+int deluser ( char * );
+int getdfltpri ( void );
+void trashusers ( void );
+
+USER * getuser ( char *);
+
+#define PRI_MAX 39
+#define PRI_MIN 0
+
+struct user_priority
+{
+ short deflt; /* priority to use when not specified */
+ short deflt_limit; /* priority limit for users not
+ otherwise specified */
+ char **users[PRI_MAX - PRI_MIN + 1];
+};
diff --git a/usr/src/cmd/lp/lib/users/loadpri.c b/usr/src/cmd/lp/lib/users/loadpri.c
new file mode 100644
index 0000000000..0ade35eaa7
--- /dev/null
+++ b/usr/src/cmd/lp/lib/users/loadpri.c
@@ -0,0 +1,254 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+# include <errno.h>
+# include <stdio.h>
+# include <stdlib.h>
+
+# include "lp.h"
+# include "users.h"
+
+static long pri;
+
+/*
+ Input: Path name of the user priority file. It has the following
+ format:
+ 1 line with a number representing the default priority level.
+ This must be the first line of the file, and no extra
+ white space is allowed between the priority value and
+ the newline.
+ 1 line anywhere in the file with a number representing
+ the default priority limit. This number is followed
+ by a ':', and no extra white space is allowed.
+ any number of lines with a number followed by a ':', followed
+ by a white space (blank, tab or newline) separated
+ list of user names. No white space is allowed
+ between the priority value and the colon (:), but any
+ amount is ok in the UID list.
+
+ Note: If the default priority level is missing, a value of 20 will
+ be used. If the default limit is missing, zero will be used.
+ Also, the st_priority_file writes out the priority file in the
+ same order as the fields occur in the user_priority structure,
+ but the only order restriction is that the default level is
+ the first this. A priority level may occur more than once, and
+ this function will group them together (but the defaults may
+ only occur once, however the defaults may occur only once each.
+
+ Output: This function returns a pointer to a statically stored
+ structure containing the priority information.
+
+ Effect: The user priority file is read and parsed. Storage for
+ the priorities are allocated and loaded. In case of an error,
+ it prints out an error message, and returns 0 (NULL).
+*/
+
+struct user_priority * ld_priority_file ( char * path )
+{
+ char line[BUFSIZ],
+ *p,
+ *user,
+ *next_user();
+ static struct user_priority pri_tbl;
+ int line_no = 1,
+ opri;
+ int fd;
+
+ if ((fd = open_locked(path, "r", 0)) < 0) {
+ if (errno == ENOENT) {
+empty:
+ pri_tbl.deflt = LEVEL_DFLT;
+ pri_tbl.deflt_limit = LIMIT_DFLT;
+ memset ((char *)pri_tbl.users, 0, sizeof(pri_tbl.users));
+ return (&pri_tbl);
+ }
+ return(0);
+ }
+
+ /* initialize table to empty */
+ pri_tbl.deflt = -1;
+ pri_tbl.deflt_limit = -1;
+ memset ((char *)pri_tbl.users, 0, sizeof(pri_tbl.users));
+
+ /* this loop reads the line containing the default priority,
+ if any, and the first priority limit. p is left pointing
+ to the colon (:) in the line with the first limit. */
+
+ while (1)
+ {
+ if (!(p = fdgets(line, BUFSIZ, fd)))
+ goto empty;
+ p = line;
+ pri = strtol(line, &p, 10);
+ if (p == line)
+ goto Error;
+ if (pri < PRI_MIN || pri > PRI_MAX)
+ goto Error;
+ if (line_no == 1 && *p == '\n' && !p[1])
+ pri_tbl.deflt = pri;
+ else
+ if (*p == ':')
+ {
+ p++;
+ break;
+ }
+ else
+ goto Error;
+ line_no++;
+ }
+
+ do
+ {
+ /* search list for this priority */
+ opri = pri;
+ if (!(user = next_user(fd, line, &p)))
+ {
+ if (pri_tbl.deflt_limit == -1)
+ {
+ pri_tbl.deflt_limit = opri;
+ if (pri == -1) break;
+ if (!(user = next_user(fd, line, &p))) goto Error;
+ }
+ else
+ {
+Error:
+ errno = EBADF;
+ close(fd);
+ return(0);
+ }
+ }
+
+ do
+ {
+ add_user (&pri_tbl, user, pri);
+ }
+ while ((user = next_user(fd, line, &p)));
+ }
+ while (pri != -1);
+
+ if (pri_tbl.deflt == -1)
+ pri_tbl.deflt = LEVEL_DFLT;
+
+ if (pri_tbl.deflt_limit == -1)
+ pri_tbl.deflt_limit = LIMIT_DFLT;
+
+ close(fd);
+ return (&pri_tbl);
+}
+
+/*
+Inputs: A pointer to a limit structure, and a user.
+Ouputs: The limit structure is modified.
+Effects: Adds <user> to the list of users, if it is not already
+ there.
+*/
+
+int add_user ( struct user_priority * ppri_tbl, char * user, int limit )
+{
+ if (limit < PRI_MIN || PRI_MAX < limit)
+ return 1;
+ addlist (&(ppri_tbl->users[limit - PRI_MIN]), user);
+ return 0;
+}
+
+/*
+Inputs: The input file to read additional lines, a pointer to
+ a buffer containing the current line, and to read additional
+ lines into, and a pointer to the location pointer (a pointer
+ into buf).
+Outputs: The routine returns the next user-id read or 0 if all the
+ users for this priority are read. The buffer, the location
+ pointer, and the variable pri are modified as a side effect.
+Effects: The input buffer is scanned starting at *pp for the next
+ user-id, if the end of the line is reached, the next line is
+ read from the file. If it scans the next priority value, the
+ variable pri (static to this file), is set to that priority.
+ EOF is indicated by setting this variable to -1, and also
+ returning 0.
+*/
+char * next_user (int fd, char * buf, char ** pp )
+{
+ long temp;
+ char *p;
+ static int beg_line = 0; /* assumes a partial line is in buf to start */
+
+ do
+ {
+ while (**pp == ' ' || **pp == '\n' || **pp == '\t')
+ (*pp)++;
+ p = *pp;
+ if (*p)
+ {
+ if (*p >= '0' && *p <= '9')
+ {
+ temp = strtol(p, pp, 10);
+ if (beg_line && **pp == ':')
+ {
+ (*pp)++;
+ pri = temp;
+ beg_line = 0;
+ return (0);
+ }
+ }
+
+ for (; **pp && **pp != ' ' && **pp != '\n' && **pp != '\t'; (*pp)++)
+ ;
+ if (**pp)
+ *(*pp)++ = 0;
+ beg_line = 0;
+ return (p);
+ }
+ beg_line = 1;
+ }
+ while (*pp = fdgets(buf, BUFSIZ, fd));
+
+ pri = -1;
+ return (0);
+}
+
+/*
+Inputs: A pointer to a priority table and a user.
+Outputs: Zero if user found, else 1, and priority table is modified.
+Effects: All occurences of <user> in the priority table will be removed.
+ (There should only be one at most.)
+*/
+int del_user ( struct user_priority * ppri_tbl, char * user )
+{
+ int limit;
+
+ for (limit = PRI_MIN; limit <= PRI_MAX; limit++)
+ if (searchlist(user, ppri_tbl->users[limit - PRI_MIN]))
+ {
+ dellist (&(ppri_tbl->users[limit - PRI_MIN]), user);
+ return (0);
+ }
+ return (1);
+}
diff --git a/usr/src/cmd/lp/lib/users/storepri.c b/usr/src/cmd/lp/lib/users/storepri.c
new file mode 100644
index 0000000000..7356a88cd9
--- /dev/null
+++ b/usr/src/cmd/lp/lib/users/storepri.c
@@ -0,0 +1,81 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1997 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.6 */
+/* LINTLIBRARY */
+
+# include <stdio.h>
+
+# include "lp.h"
+# include "users.h"
+# include <locale.h>
+
+/*
+Inputs:
+Outputs:
+Effects:
+*/
+void
+print_tbl(struct user_priority * ppri_tbl)
+{
+ int limit;
+
+ printf(gettext("Default priority: %d\n"), ppri_tbl->deflt);
+ printf(gettext("Priority limit for users not listed below: %d\n"), ppri_tbl->deflt_limit);
+ printf(gettext("Priority Users\n"));
+ printlist_setup ("", "", ",", "\n");
+ for (limit = PRI_MIN; limit <= PRI_MAX; limit++) {
+ if (ppri_tbl->users[limit - PRI_MIN])
+ {
+ printf(" %2d ", limit);
+ fdprintlist(1, ppri_tbl->users[limit - PRI_MIN]);
+ }
+ }
+}
+
+/*
+Inputs:
+Outputs:
+Effects:
+*/
+void
+output_tbl(int fd, struct user_priority *ppri_tbl)
+{
+ int limit;
+
+ fdprintf(fd, "%d\n%d:\n", ppri_tbl->deflt, ppri_tbl->deflt_limit);
+ printlist_setup (" ", "\n", "", "");
+ for (limit = PRI_MIN; limit <= PRI_MAX; limit++)
+ if (ppri_tbl->users[limit - PRI_MIN])
+ {
+ fdprintf(fd, "%d:", limit);
+ fdprintlist(fd, ppri_tbl->users[limit - PRI_MIN]);
+ }
+}
diff --git a/usr/src/cmd/lp/lib/users/usermgmt.c b/usr/src/cmd/lp/lib/users/usermgmt.c
new file mode 100644
index 0000000000..dfb2a9258e
--- /dev/null
+++ b/usr/src/cmd/lp/lib/users/usermgmt.c
@@ -0,0 +1,148 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/* LINTLIBRARY */
+
+# include <stdio.h>
+
+# include "lp.h"
+# include "users.h"
+
+static int loaded = 0;
+static struct user_priority *ppri_tbl;
+struct user_priority *ld_priority_file();
+static USER usr;
+
+int putuser ( char * user, USER * pri_s )
+{
+ int fd;
+
+ if (!loaded)
+ {
+ if (!(ppri_tbl = ld_priority_file(Lp_Users)))
+ return(-1);
+ loaded = 1;
+ }
+
+ if (!add_user(ppri_tbl, user, pri_s->priority_limit))
+ {
+ return(-1);
+ }
+
+ if ((fd = open_locked(Lp_Users, "w", LPU_MODE)) < 0)
+ return(-1);
+ output_tbl(fd, ppri_tbl);
+ close(fd);
+ return(0);
+}
+
+USER * getuser ( char * user )
+{
+ int limit;
+
+ /* root and lp do not get a limit */
+ if (STREQU(user, "root") || STREQU(user, LPUSER))
+ {
+ usr.priority_limit = 0;
+ return(&usr);
+ }
+
+ if (!loaded)
+ {
+ if (!(ppri_tbl = ld_priority_file(Lp_Users)))
+ return((USER *)0);
+
+ loaded = 1;
+ }
+
+ for (limit = PRI_MIN; limit <= PRI_MAX; limit++)
+ if (bang_searchlist(user, ppri_tbl->users[limit - PRI_MIN]))
+ {
+ usr.priority_limit = limit;
+ return(&usr);
+ }
+
+ usr.priority_limit = ppri_tbl->deflt_limit;
+ return(&usr);
+}
+
+int deluser ( char * user )
+{
+ int fd;
+
+ if (!loaded)
+ {
+ if (!(ppri_tbl = ld_priority_file(Lp_Users)))
+ return(-1);
+
+ loaded = 1;
+ }
+
+ del_user(ppri_tbl, user);
+
+ if ((fd = open_locked(Lp_Users, "w", LPU_MODE)) < 0)
+ return(-1);
+
+ output_tbl(fd, ppri_tbl);
+ close(fd);
+ return(0);
+}
+
+int getdfltpri ( void )
+{
+ if (!loaded)
+ {
+ if (!(ppri_tbl = ld_priority_file(Lp_Users)))
+ return(-1);
+
+ loaded = 1;
+ }
+
+ return (ppri_tbl->deflt);
+}
+
+void
+trashusers(void)
+{
+ int limit;
+
+ if (loaded)
+ {
+ if (ppri_tbl)
+ {
+ for (limit = PRI_MIN; limit <= PRI_MAX; limit++)
+ freelist (ppri_tbl->users[limit - PRI_MIN]);
+ ppri_tbl = 0;
+ }
+ loaded = 0;
+ }
+}
+
diff --git a/usr/src/cmd/lp/model/Makefile b/usr/src/cmd/lp/model/Makefile
new file mode 100644
index 0000000000..5da2ee6539
--- /dev/null
+++ b/usr/src/cmd/lp/model/Makefile
@@ -0,0 +1,104 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/model/Makefile
+#
+
+include ../Makefile.lp
+
+SUBDIRS = netpr
+
+PROG = lp.set \
+ lp.cat \
+ lp.tell \
+ lp.tsol_separator \
+ drain.output
+
+SRCS = $(PROG:%=%.c)
+
+OBJS = $(PROG:%=%.o)
+
+MODELS = standard \
+ netstandard \
+ tsol_standard \
+ tsol_netstandard \
+ tsol_standard_foomatic \
+ tsol_netstandard_foomatic \
+ uri
+
+MISC = alert.proto
+
+
+ROOTLIBLPMODEL= $(ROOTLIBLP)/model
+ROOTLIBLPBIN = $(ROOTLIBLP)/bin
+
+ROOTMISC = $(MISC:%=$(ROOTLIBLPBIN)/%)
+ROOTLPPROG = $(PROG:%=$(ROOTLIBLPBIN)/%)
+ROOTMODELS = $(MODELS:%=$(ROOTLIBLPMODEL)/%)
+
+CPPFLAGS = -I$(LPINC) $(CPPFLAGS.master)
+
+# conditional assignments
+lp.tell := LDLIBS += $(LIBMSG) $(LIBLP)
+lp.set drain.output lp.cat := LDLIBS += $(LIBLP) -lcurses
+lp.tsol_separator := LDLIBS += -ltsol
+
+$(ROOTMISC) := FILEMODE = 0444
+
+POFILE= lp_model.po
+POFILES= $(SRCS:%.c=%.po)
+
+.KEEP_STATE:
+
+all: $(PROG) $(MODELS) $(MISC) $(SUBDIRS)
+
+install: all .WAIT $(ROOTLPPROG) $(ROOTMODELS) $(ROOTMISC) \
+ $(SUBDIRS)
+
+$(ROOTLIBLPMODEL)/% $(ROOTLIBLPBIN)/%: %
+ $(INS.file)
+
+catalog: $(SUBDIRS) $(POFILE)
+ $(CP) $(POFILE) ..
+
+clean: $(SUBDIRS)
+ $(RM) $(OBJS)
+
+clobber: $(SUBDIRS) clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint:
+ $(LINT.c) $(SRCS) $(LDLIBS)
+
+$(SUBDIRS) : FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+include ../Makefile.lp.msg
+
+FRC:
diff --git a/usr/src/cmd/lp/model/Makefile.msg b/usr/src/cmd/lp/model/Makefile.msg
new file mode 100644
index 0000000000..820d0cb1ff
--- /dev/null
+++ b/usr/src/cmd/lp/model/Makefile.msg
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/model/Makefile.msg
+
+POFILES = $(OBJS:%.o=%.po)
+
+include ../../Makefile.lp.msg
+
+catalog: $(POFILE)
+ $(CP) $(POFILE) ../..
diff --git a/usr/src/cmd/lp/model/alert.proto b/usr/src/cmd/lp/model/alert.proto
new file mode 100644
index 0000000000..6c46f63adb
--- /dev/null
+++ b/usr/src/cmd/lp/model/alert.proto
@@ -0,0 +1,81 @@
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.5 */
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Pardon the bizarre variable names, but we must not
+# conflict with any variables that the user gives us.
+#
+
+-ENVIRONMENT-
+
+cd -PWD-
+
+if [ "`ulimit`" -gt -ULIMIT- ]
+then
+ ulimit -ULIMIT-
+fi
+
+umask -UMASK-
+
+AlErT () {
+ 2>&1 (
+-CMD-
+ ) <$1 1>${TmPsTdErR} || return 1
+ return 0
+}
+
+TmPsTdErR=${TMPDIR:-/usr/tmp}/`/bin/uname -n`$$
+trap 'rm -f ${TmPsTdErR}; exit 0' 0 1 2 15
+
+while AlErT $1
+do
+ if [ -INTERVAL- -le 0 ]
+ then
+ exit 0
+ else
+ TiCk=0
+ while [ "${TiCk}" -lt -INTERVAL- ]
+ do
+ TiCk=`expr "${TiCk}" + 1`
+ sleep 60
+ done
+ fi
+done
+
+ec=$?
+if [ "${ec}" -ne 0 ]
+then
+ {
+
+ echo "
+One of your print service alerts failed with exit code ${ec}.
+The standard output and standard error were:
+ "
+ cat ${TmPsTdErR}
+ echo '
+
+The alert message is:
+'
+ cat $1
+
+ } | mailx -s 'Failed print service alert' -USER-
+fi
diff --git a/usr/src/cmd/lp/model/drain.output.c b/usr/src/cmd/lp/model/drain.output.c
new file mode 100644
index 0000000000..6a11c4713c
--- /dev/null
+++ b/usr/src/cmd/lp/model/drain.output.c
@@ -0,0 +1,100 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "termio.h"
+
+/*
+ * The following macro computes the number of seconds to sleep
+ * AFTER waiting for the system buffers to be drained.
+ *
+ * Various choices:
+ *
+ * - A percentage (perhaps even >100%) of the time it would
+ * take to print the printer's buffer. Use this if it appears
+ * the printers are affected if the port is closed before they
+ * finish printing.
+ *
+ * - 0. Use this to avoid any extra sleep after waiting for the
+ * system buffers to be flushed.
+ *
+ * - N > 0. Use this to have a fixed sleep after flushing the
+ * system buffers.
+ *
+ * The sleep period can be overridden by a single command line argument.
+ */
+ /* 25% of the print-full-buffer time, plus 1 */
+#define LONG_ENOUGH(BUFSZ,CPS) (1 + ((250 * BUFSZ) / CPS) / 1000)
+
+extern int tidbit();
+
+/**
+ ** main()
+ **/
+
+int
+main(int argc, char *argv[])
+{
+ extern char *getenv();
+
+ short bufsz = -1,
+ cps = -1;
+
+ char *TERM;
+
+ int sleep_time = 0;
+
+
+ /*
+ * Wait for the output to drain.
+ */
+ ioctl (1, TCSBRK, (struct termio *)1);
+
+ /*
+ * Decide how long to sleep.
+ */
+ if (argc != 2 || (sleep_time = atoi(argv[1])) < 0)
+ if ((TERM = getenv("TERM"))) {
+ tidbit (TERM, "bufsz", &bufsz);
+ tidbit (TERM, "cps", &cps);
+ if (cps > 0 && bufsz > 0)
+ sleep_time = LONG_ENOUGH(bufsz, cps);
+ } else
+ sleep_time = 2;
+
+ /*
+ * Wait ``long enough'' for the printer to finish
+ * printing what's in its buffer.
+ */
+ if (sleep_time)
+ sleep (sleep_time);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/model/lp.cat.c b/usr/src/cmd/lp/model/lp.cat.c
new file mode 100644
index 0000000000..29f14ad318
--- /dev/null
+++ b/usr/src/cmd/lp/model/lp.cat.c
@@ -0,0 +1,699 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <termio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/times.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/prnio.h>
+
+#include "lp.h"
+
+#include <locale.h>
+
+/*
+ * Begin Sun Additions for Parallel ports
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioccom.h>
+#include <sys/ioctl.h>
+
+#include <sys/bpp_io.h>
+#include <sys/ecppsys.h>
+#include <stropts.h>
+
+/*
+ * the parameter structure for the parallel port
+ */
+struct ppc_params_t {
+ int flags; /* same as above */
+ int state; /* status of the printer interface */
+ int strobe_w; /* strobe width, in uS */
+ int data_setup; /* data setup time, in uS */
+ int ack_timeout; /* ACK timeout, in secs */
+ int error_timeout; /* PAPER OUT, etc... timeout, in secs */
+ int busy_timeout; /* BUSY timeout, in seconds */
+};
+
+
+
+static void printer_info(char *fmt, ...);
+
+/* These are the routines avaliable to others for use */
+int is_a_parallel_bpp(int);
+int bpp_state(int);
+int parallel_comm(int, int());
+int get_ecpp_status(int fd);
+int is_a_prnio(int);
+int prnio_state(int);
+
+#define PRINTER_ERROR_PAPER_OUT 1
+#define PRINTER_ERROR_OFFLINE 2
+#define PRINTER_ERROR_BUSY 3
+#define PRINTER_ERROR_ERROR 4
+#define PRINTER_ERROR_CABLE_POWER 5
+#define PRINTER_ERROR_UNKNOWN 6
+#define PRINTER_ERROR_TIMEOUT 7
+#define PRINTER_IO_ERROR 129
+
+
+/*
+ * for BPP PARALLEL interfaces
+ */
+
+int
+is_a_parallel_bpp(int fd)
+{
+ if (ioctl(fd, BPPIOC_TESTIO) == 0 || errno == EIO)
+ return (1);
+ return (0);
+}
+
+
+#if defined(DEBUG) && defined(NOTDEF)
+char *
+BppState(int state)
+{
+ static char buf[BUFSIZ];
+
+ memset(buf, 0, sizeof (buf));
+ sprintf(buf, "State (0x%.4x) - (%s%s%s%s)\n", state,
+ ((state & BPP_SLCT_ERR) ? "offline " : ""),
+ ((state & BPP_BUSY_ERR) ? "busy " : ""),
+ ((state & BPP_PE_ERR) ? "paper " : ""),
+ ((state & BPP_ERR_ERR) ? "error " : ""));
+
+ return (buf);
+}
+#endif
+
+int
+bpp_state(int fd)
+{
+ if (ioctl(fd, BPPIOC_TESTIO)) {
+ struct bpp_error_status bpp_stat;
+ int state;
+
+ if (ioctl(fd, BPPIOC_GETERR, &bpp_stat) < 0)
+ exit(PRINTER_IO_ERROR);
+ state = bpp_stat.pin_status;
+
+#if defined(DEBUG) && defined(NOTDEF)
+ logit("%s", BppState(state));
+#endif
+
+ if (state == (BPP_PE_ERR | BPP_ERR_ERR | BPP_SLCT_ERR)) {
+ /* paper is out */
+ return (PRINTER_ERROR_PAPER_OUT);
+ } else if (state & BPP_BUSY_ERR) {
+ /* printer is busy */
+ return (PRINTER_ERROR_BUSY);
+ } else if (state & BPP_SLCT_ERR) {
+ /* printer is offline */
+ return (PRINTER_ERROR_OFFLINE);
+ } else if (state & BPP_ERR_ERR) {
+ /* printer is errored */
+ return (PRINTER_ERROR_ERROR);
+ } else if (state == BPP_PE_ERR) {
+ /* printer is off/unplugged */
+ return (PRINTER_ERROR_CABLE_POWER);
+ } else if (state) {
+ return (PRINTER_ERROR_UNKNOWN);
+ } else
+ return (0);
+ }
+ return (0);
+}
+
+/*
+ * For ecpp parallel port
+ */
+
+int
+get_ecpp_status(int fd)
+{
+ int state;
+ struct ecpp_transfer_parms transfer_parms;
+
+
+ if (ioctl(fd, ECPPIOC_GETPARMS, &transfer_parms) == -1) {
+ return (-1);
+ }
+
+ state = transfer_parms.mode;
+ /*
+ * We don't know what all printers will return in
+ * nibble mode, therefore if we support nibble mode we will
+ * force the printer to be in CENTRONICS mode.
+ */
+ if (state != ECPP_CENTRONICS) {
+ transfer_parms.mode = ECPP_CENTRONICS;
+ if (ioctl(fd, ECPPIOC_SETPARMS, &transfer_parms) == -1) {
+ return (-1);
+ } else {
+ state = ECPP_CENTRONICS;
+ }
+ }
+
+
+ return (state);
+}
+
+/*
+ * For prnio(7I) - generic printer interface
+ */
+int
+is_a_prnio(int fd)
+{
+ uint_t cap;
+
+ /* check if device supports prnio */
+ if (ioctl(fd, PRNIOC_GET_IFCAP, &cap) == -1) {
+ return (0);
+ }
+ /* we will use 1284 status if available */
+ if ((cap & PRN_1284_STATUS) == 0) {
+ /* some devices may only support 1284 status in unidir. mode */
+ if (cap & PRN_BIDI) {
+ cap &= ~PRN_BIDI;
+ (void) ioctl(fd, PRNIOC_SET_IFCAP, &cap);
+ }
+ }
+ return (1);
+}
+
+int
+prnio_state(int fd)
+{
+ uint_t status;
+ uchar_t pins;
+
+ if ((ioctl(fd, PRNIOC_GET_STATUS, &status) == 0) &&
+ (status & PRN_READY)) {
+ return (0);
+ }
+
+ if (ioctl(fd, PRNIOC_GET_1284_STATUS, &pins) != 0) {
+ return (PRINTER_ERROR_UNKNOWN);
+ }
+
+ if ((pins & ~PRN_1284_BUSY) == PRN_1284_PE) {
+ /* paper is out */
+ return (PRINTER_ERROR_PAPER_OUT);
+ } else if (pins == (PRN_1284_PE | PRN_1284_SELECT |
+ PRN_1284_NOFAULT | PRN_1284_BUSY)) {
+ /* printer is off/unplugged */
+ return (PRINTER_ERROR_CABLE_POWER);
+ } else if ((pins & PRN_1284_SELECT) == 0) {
+ /* printer is offline */
+ return (PRINTER_ERROR_OFFLINE);
+ } else if ((pins & PRN_1284_NOFAULT) == 0) {
+ /* printer is errored */
+ return (PRINTER_ERROR_ERROR);
+ } else if (pins & PRN_1284_PE) {
+ /* paper is out */
+ return (PRINTER_ERROR_PAPER_OUT);
+ } else if (pins ^ (PRN_1284_SELECT | PRN_1284_NOFAULT)) {
+ return (PRINTER_ERROR_UNKNOWN);
+ }
+
+ return (0);
+}
+
+/*
+ * Common routines
+ */
+
+/*ARGSUSED0*/
+static void
+ByeByeParallel(int sig)
+{
+ /* try to shove out the EOT */
+ (void) write(1, "\004", 1);
+ exit(0);
+}
+
+
+/*ARGSUSED0*/
+static void
+printer_info(char *fmt, ...)
+{
+ char mesg[BUFSIZ];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsprintf(mesg, fmt, ap);
+ va_end(ap);
+/*
+ * fprintf(stderr,
+ * "%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
+ * mesg);
+ */
+ fprintf(stderr, "%s\n", mesg);
+ fflush(stderr);
+ fsync(2);
+
+}
+
+static void
+printer_error(int error)
+{
+ switch (error) {
+ case -1:
+ printer_info("ioctl(): %s", strerror(errno));
+ break;
+ case PRINTER_ERROR_PAPER_OUT:
+ printer_info("out of paper");
+ break;
+ case PRINTER_ERROR_OFFLINE:
+ printer_info("offline");
+ break;
+ case PRINTER_ERROR_BUSY:
+ printer_info("busy");
+ break;
+ case PRINTER_ERROR_ERROR:
+ printer_info("printer error");
+ break;
+ case PRINTER_ERROR_CABLE_POWER:
+ printer_info("printer powered off or disconnected");
+ break;
+ case PRINTER_ERROR_UNKNOWN:
+ printer_info("unknown error");
+ break;
+ case PRINTER_ERROR_TIMEOUT:
+ printer_info("communications timeout");
+ break;
+ default:
+ printer_info("get_status() failed");
+ }
+}
+
+
+static void
+wait_state(int fd, int get_state())
+{
+ int state;
+ int was_faulted = 0;
+
+ while (state = get_state(fd)) {
+ was_faulted = 1;
+ printer_error(state);
+ sleep(15);
+ }
+
+ if (was_faulted) {
+ fprintf(stderr, "printer ok\n");
+ fflush(stderr);
+ fsync(2);
+ }
+}
+
+/*
+ * end of Sun Additions for parallel port
+ */
+#define IDENTICAL(A, B) (A.st_dev == B.st_dev && A.st_ino == B.st_ino)
+#define ISBLK(A) ((A.st_mode & S_IFMT) == S_IFBLK)
+#define ISCHR(A) ((A.st_mode & S_IFMT) == S_IFCHR)
+
+#define E_SUCCESS 0
+#define E_BAD_INPUT 1
+#define E_BAD_OUTPUT 2
+#define E_BAD_TERM 3
+#define E_IDENTICAL 4
+#define E_WRITE_FAILED 5
+#define E_TIMEOUT 6
+#define E_HANGUP 7
+#define E_INTERRUPT 8
+
+#define SAFETY_FACTOR 2.0
+#define R(F) (int)((F) + .5)
+#define DELAY(N, D) R(SAFETY_FACTOR * ((N) / (double)(D)))
+
+char buffer[BUFSIZ];
+
+void sighup(),
+ sigint(),
+ sigquit(),
+ sigpipe(),
+ sigalrm(),
+ sigterm();
+
+#if defined(baudrate)
+#undef baudrate
+#endif
+
+int baudrate();
+
+
+int
+nop(int fd)
+{
+ return (0);
+}
+
+int bpp_state(int);
+
+
+/*
+ * main()
+ */
+
+int
+main(int argc, char *argv[])
+{
+ int nin, nout, effective_rate, max_delay = 0, n;
+ int report_rate;
+ short print_rate;
+ struct stat in, out;
+ struct tms tms;
+ long epoch_start, epoch_end;
+ char *TERM;
+ int (*func)(int fd);
+
+ /*
+ * The Spooler can hit us with SIGTERM for three reasons:
+ *
+ * - the user's job has been canceled
+ * - the printer has been disabled while we were printing
+ * - the Spooler heard that the printer has a fault,
+ * and the fault recovery is wait or beginning
+ *
+ * We should exit cleanly for the first two cases,
+ * but we have to be careful with the last. If it was THIS
+ * PROGRAM that told the Spooler about the fault, we must
+ * exit consistently.
+ *
+ * The method of avoiding any problem is to turn off the
+ * trapping of SIGTERM before telling the Spooler about
+ * the fault.
+ *
+ * Faults that we can detect:
+ * - hangup (drop of carrier)
+ * - interrupt (printer sent a break or quit character)
+ * - SIGPIPE (output port is a FIFO, and was closed early)
+ * - failed or incomplete write()
+ * - excess delay in write() (handled with SIGALRM later)
+ *
+ * Pseudo-faults (errors in use):
+ * - No input/output, or strange input/output
+ * - Input/output identical
+ * - No TERM defined or trouble reading Terminfo database
+ */
+ signal(SIGTERM, sigterm);
+ signal(SIGHUP, sighup);
+ signal(SIGINT, sigint);
+ signal(SIGQUIT, sigint);
+ signal(SIGPIPE, sigpipe);
+
+
+ if (argc > 1 && STREQU(argv[1], "-r")) {
+ report_rate = 1;
+ argc--;
+ argv++;
+ } else
+ report_rate = 0;
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ /*
+ * Stat the standard output to be sure it is defined.
+ */
+ if (fstat(1, &out) < 0) {
+ signal(SIGTERM, SIG_IGN);
+ fprintf(stderr, gettext("Can't stat output "
+ "(%s);\nincorrect use of lp.cat!\n"), PERROR);
+ exit(E_BAD_OUTPUT);
+ }
+
+ /*
+ * Stat the standard input to be sure it is defined.
+ */
+ if (fstat(0, &in) < 0) {
+ signal(SIGTERM, SIG_IGN);
+ fprintf(stderr, gettext("Can't stat input "
+ "(%s);\nincorrect use of lp.cat!\n"), PERROR);
+ exit(E_BAD_INPUT);
+ }
+
+ /*
+ * If the standard output is not a character special file or a
+ * block special file, make sure it is not identical to the
+ * standard input.
+ *
+ * If we are an ecpp parallel port in centronics mode treat
+ * ourselves as a bpp compatible device.
+ */
+
+ if (is_a_prnio(1)) {
+ func = prnio_state;
+ } else if (is_a_parallel_bpp(1) ||
+ (get_ecpp_status(1) == ECPP_CENTRONICS)) {
+ func = bpp_state;
+ } else if (isatty(1)) {
+ /* serial connection (probably) - continue as usual */
+ func = nop;
+ } else {
+ func = nop;
+ }
+
+ if (!ISCHR(out) && !ISBLK(out) && IDENTICAL(out, in)) {
+ signal(SIGTERM, SIG_IGN);
+ fprintf(stderr, gettext("Input and output are identical; "
+ "incorrect use of lp.cat!\n"));
+ exit(E_IDENTICAL);
+ }
+
+ /*
+ * The effective data transfer rate is the lesser
+ * of the transmission rate and print rate. If an
+ * argument was passed to us, it should be a data
+ * rate and it may be lower still.
+ * Based on the effective data transfer rate,
+ * we can predict the maximum delay we should experience.
+ * But there are other factors that could introduce
+ * delay, so let's be generous; after all, we'd rather
+ * err in favor of waiting too long to detect a fault
+ * than err too often on false alarms.
+ */
+
+ if (!(TERM = getenv("TERM")) || !*TERM) {
+ signal(SIGTERM, SIG_IGN);
+ fprintf(stderr, gettext("No TERM variable defined! "
+ "Trouble with the Spooler!\n"));
+ exit(E_BAD_TERM);
+ }
+ if (!STREQU(TERM, NAME_UNKNOWN) &&
+ tidbit(TERM, "cps", &print_rate) == -1) {
+ signal(SIGTERM, SIG_IGN);
+ fprintf(stderr, gettext("Trouble identifying printer "
+ "type \"%s\"; check the Terminfo database.\n"), TERM);
+ exit(E_BAD_TERM);
+ }
+ if (STREQU(TERM, NAME_UNKNOWN))
+ print_rate = -1;
+
+ effective_rate = baudrate() / 10; /* okay for most bauds */
+ if (print_rate != -1 && print_rate < effective_rate)
+ effective_rate = print_rate;
+ if (argc > 1 && (n = atoi(argv[1])) >= 0 && n < effective_rate)
+ effective_rate = n; /* 0 means infinite delay */
+ if (effective_rate)
+ max_delay = DELAY(BUFSIZ, effective_rate);
+
+ /*
+ * We'll use the "alarm()" system call to keep us from
+ * waiting too long to write to a printer in trouble.
+ */
+ if (max_delay)
+ signal(SIGALRM, sigalrm);
+
+ /*
+ * While not end of standard input, copy blocks to
+ * standard output.
+ */
+ while ((nin = read(0, buffer, BUFSIZ)) > 0) {
+ char *ptr = buffer;
+
+ /*
+ * We should be safe from incomplete writes to a full
+ * pipe, as long as the size of the buffer we write is
+ * a even divisor of the pipe buffer limit. As long as
+ * we read from files or pipes (not communication devices)
+ * this should be true for all but the last buffer. The
+ * last will be smaller, and won't straddle the pipe max
+ * limit (think about it).
+ */
+#if PIPE_BUF < BUFSIZ || (PIPE_MAX % BUFSIZ)
+ this_wont_compile;
+#endif
+ if (report_rate)
+ epoch_start = times(&tms);
+ do {
+ wait_state(1, func);
+
+ if (max_delay)
+ alarm(max_delay);
+ nout = write(1, ptr, nin);
+ alarm(0);
+ if (nout < 0) {
+ fprintf(stderr, gettext("Write failed "
+ "(%s);\nperhaps the printer has gone "
+ "off-line.\n"), PERROR);
+ fflush(stderr);
+ if (errno != EINTR)
+ /* I/O error on device, get lpcshed to retry */
+ exit(PRINTER_IO_ERROR);
+ else /* wait for printer to come back online */
+ sleep(15);
+ } else {
+ nin -= nout;
+ ptr += nout;
+ }
+ } while (nin > 0);
+
+ if (max_delay)
+ alarm(0);
+ else if (report_rate) {
+ epoch_end = times(&tms);
+ if (epoch_end - epoch_start > 0)
+ fprintf(stderr, "%d CPS\n",
+ R((100 * BUFSIZ) /
+ (double)(epoch_end - epoch_start)));
+ }
+
+ }
+
+ return (E_SUCCESS);
+}
+
+/*
+ * sighup() - CATCH A HANGUP (LOSS OF CARRIER)
+ */
+void
+sighup()
+{
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ fprintf(stderr, gettext(HANGUP_FAULT_LPCAT));
+ exit(E_HANGUP);
+}
+
+/*
+ * sigint() - CATCH AN INTERRUPT
+ */
+void
+sigint()
+{
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ fprintf(stderr, gettext(INTERRUPT_FAULT));
+ exit(E_INTERRUPT);
+}
+
+/*
+ * sigpipe() - CATCH EARLY CLOSE OF PIPE
+ */
+void
+sigpipe()
+{
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ fprintf(stderr, gettext(PIPE_FAULT));
+ exit(E_INTERRUPT);
+}
+
+/*
+ * sigalrm() - CATCH AN ALARM
+ */
+void
+sigalrm()
+{
+ signal(SIGTERM, SIG_IGN);
+ fprintf(stderr, gettext("Excessive write delay; "
+ "perhaps the printer has gone off-line.\n"));
+ exit(E_TIMEOUT);
+}
+
+/*
+ * sigterm() - CATCH A TERMINATION SIGNAL
+ */
+void
+sigterm()
+{
+ signal(SIGTERM, SIG_IGN);
+ /*
+ * try to flush the output queue in the case of ecpp port.
+ * ignore the return code as this may not be the ecpp.
+ */
+ ioctl(1, I_FLUSH, FLUSHW);
+ exit(E_SUCCESS);
+}
+
+/*
+ * baudrate() - RETURN BAUD RATE OF OUTPUT LINE
+ */
+
+static int baud_convert[] =
+{
+ 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
+ 1800, 2400, 4800, 9600, 19200, 38400, 57600,
+ 76800, 115200, 153600, 230400, 307200, 460800, 921600
+};
+
+int
+baudrate()
+{
+ struct termio tm;
+ struct termios tms;
+ int speed;
+
+ if (ioctl(1, TCGETS, &tms) < 0) {
+ if (ioctl(1, TCGETA, &tm) < 0)
+ return (1200);
+ else
+ speed = tm.c_cflag&CBAUD;
+ } else
+ speed = cfgetospeed(&tms);
+
+ return (speed ? baud_convert[speed] : 1200);
+}
diff --git a/usr/src/cmd/lp/model/lp.set.c b/usr/src/cmd/lp/model/lp.set.c
new file mode 100644
index 0000000000..e2748a0890
--- /dev/null
+++ b/usr/src/cmd/lp/model/lp.set.c
@@ -0,0 +1,144 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "stdio.h"
+
+#include "lp.h"
+#include "lp.set.h"
+
+extern char *getenv();
+
+/**
+ ** main()
+ **/
+
+int
+main(int argc, char *argv[])
+{
+ static char not_set[10] = "H V W L S";
+
+ int exit_code;
+
+ char *TERM = getenv("TERM");
+
+
+ if (!TERM || !*TERM || tidbit(TERM, (char *)0) == -1)
+ exit (1);
+
+ /*
+ * Very simple calling sequence:
+ *
+ * lpset horz-pitch vert-pitch width length char-set
+ *
+ * The first four can be scaled with 'i' (inches) or
+ * 'c' (centimeters). A pitch scaled with 'i' is same
+ * as an unscaled pitch.
+ * Blank arguments will skip the corresponding setting.
+ */
+ if (argc != 6)
+ exit (1);
+
+ exit_code = 0;
+
+ if (argv[1][0]) {
+ switch (set_pitch(argv[1], 'H', 1)) {
+ case E_SUCCESS:
+ not_set[0] = ' ';
+ break;
+ case E_FAILURE:
+ break;
+ default:
+ exit_code = 1;
+ break;
+ }
+ } else
+ not_set[0] = ' ';
+
+ if (argv[2][0]) {
+ switch (set_pitch(argv[2], 'V', 1)) {
+ case E_SUCCESS:
+ not_set[2] = ' ';
+ break;
+ case E_FAILURE:
+ break;
+ default:
+ exit_code = 1;
+ break;
+ }
+ } else
+ not_set[2] = ' ';
+
+ if (argv[3][0]) {
+ switch (set_size(argv[3], 'W', 1)) {
+ case E_SUCCESS:
+ not_set[4] = ' ';
+ break;
+ case E_FAILURE:
+ break;
+ default:
+ exit_code = 1;
+ break;
+ }
+ } else
+ not_set[4] = ' ';
+
+ if (argv[4][0]) {
+ switch (set_size(argv[4], 'L', 1)) {
+ case E_SUCCESS:
+ not_set[6] = ' ';
+ break;
+ case E_FAILURE:
+ break;
+ default:
+ exit_code = 1;
+ break;
+ }
+ } else
+ not_set[6] = ' ';
+
+ if (argv[5][0]) {
+ switch (set_charset(argv[5], 1, TERM)) {
+ case E_SUCCESS:
+ not_set[8] = ' ';
+ break;
+ case E_FAILURE:
+ break;
+ default:
+ exit_code = 1;
+ break;
+ }
+ } else
+ not_set[8] = ' ';
+
+ fprintf (stderr, "%s\n", not_set);
+
+ return (exit_code);
+}
diff --git a/usr/src/cmd/lp/model/lp.tell.c b/usr/src/cmd/lp/model/lp.tell.c
new file mode 100644
index 0000000000..e58eb968b2
--- /dev/null
+++ b/usr/src/cmd/lp/model/lp.tell.c
@@ -0,0 +1,501 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "signal.h"
+#include "stdio.h"
+#include "errno.h"
+
+#include "lp.h"
+#include "msgs.h"
+#include "string.h"
+
+void startup(),
+ cleanup(),
+ done();
+
+extern char *getenv(),
+ *malloc(),
+ *realloc();
+
+extern long atol();
+
+extern int atoi();
+
+static void wakeup();
+extern char *optarg;
+extern int optind, opterr, optopt;
+int optsw;
+
+#define PREFIX_STRING "%%["
+#define SUFFIX_STRING "]%%"
+#define PRINTER_ERROR_STRING "PrinterError:"
+#define STATUS_STRING "status:"
+#define JOB_STRING "job:"
+#define STATUS_OK_STRING "ready and printing"
+#define PAPER_CHANGED_STRING "paper changed:"
+
+/*
+ * Some common postscript printer fault messages.
+ * These strings are here so that they get l10ned and then lpstat will
+ * be able to display them in the users language.
+ * This seemed like a good place for them, since lp.tell knows about
+ * postscript msgs.
+ */
+
+char *ps_m1 = "unable to print: out of media (paper)";
+char *ps_m2 = "out of media (paper)";
+char *ps_m3 = "unable to print: tray not (properly) installed";
+char *ps_m4 = "tray not (properly) installed";
+char *ps_m5 = "unable to print: paper out for the selected tray";
+char *ps_m6 = "paper out for the selected tray";
+char *ps_m7 = "unable to print: cartridge life expiring";
+char *ps_m8 = "cartridge life expiring";
+char *ps_m9 = "unable to print: printer cover not locked";
+char *ps_m10 = "printer cover not locked";
+char *ps_m11 = "unable to print: media (paper) jam in exit path";
+char *ps_m12 = "media (paper) jam in exit path";
+char *ps_m13 = "unable to print: media (paper) jam in feed path";
+char *ps_m14 = "media (paper) jam in feed path";
+char *ps_m15 = "unable to print: drum assembly almost expended";
+char *ps_m16 = "drum assembly almost expended";
+char *ps_m17 = "unable to print: toner cartridge almost expended";
+char *ps_m18 = "toner cartridge almost expended";
+char *ps_m19 = "unable to print: drum assembly not (properly) installed";
+char *ps_m20 = "drum assembly not (properly) installed";
+char *ps_m21 = "unable to print: toner cartridge not (properly) installed";
+char *ps_m22 = "toner cartridge not (properly) installed";
+char *ps_m23 = "unable to print: drum assembly requires replacement";
+char *ps_m24 = "drum assembly requires replacement";
+char *ps_m25 = "unable to print: toner cartridge requires replacement";
+char *ps_m26 = "toner cartridge requires replacement";
+char *ps_m27 = "unable to print: fuser warming up";
+char *ps_m28 = "fuser warming up";
+char *ps_m29 = "unable to print: printer not responding";
+char *ps_m30 = "printer not responding";
+char *ps_m31 = "unable to print: fuser pausing";
+char *ps_m32 = "fuser pausing";
+char *ps_m33 = "unable to print: printer turned off";
+char *ps_m34 = "printer turned off";
+char *ps_m35 = "unable to print: printer warming up";
+char *ps_m36 = "printer warming up";
+char *ps_m37 = "unable to print: interlock open";
+char *ps_m38 = "interlock open";
+char *ps_m39 = "unable to print: selected tray out";
+char *ps_m40 = "selected tray out";
+char *ps_m41 = "unable to print: paper out for the manual tray";
+char *ps_m42 = "paper out for the manual tray";
+char *ps_m43 = "unable to print: paper exit jam";
+char *ps_m44 = "paper exit jam";
+char *ps_m45 = "unable to print: paper misfeed jam";
+char *ps_m46 = "paper misfeed jam";
+char *ps_m47 = "unable to print: paper jam between registration & heat rollers";
+char *ps_m48 = "paper jam between registration & heat rollers";
+char *ps_m49 = "unable to print: paper jam at registration roller";
+char *ps_m50 = "paper jam at registration roller";
+char *ps_m51 = "unable to print: no cartridge";
+char *ps_m52 = "no cartridge";
+char *ps_m53 = "unable to print: cartridge out";
+char *ps_m54 = "cartridge out";
+
+/**
+ ** main()
+ **/
+
+int
+main(int argc, char *argv[])
+{
+ char *alert_text,
+ buf[BUFSIZ],
+ msgbuf[MSGMAX],
+ *bufPtr,
+ *printer,
+ *s_key;
+
+ char *printerErrorString = NULL;
+ char *statusString = NULL;
+ char *paperChangedString = NULL;
+ char *suffixString = NULL;
+ char *jobString = NULL;
+ char *prefixString = NULL;
+ char *statusOkString = NULL;
+ int mtype,
+ doStdOut,
+ doDebug,
+ first,
+ oldalarm;
+
+
+ short status;
+
+ long key,clearKey;
+ char *ptr1,*ptr2,*ptr3,*ptr4,*ptr5;
+ int trayNum = 0;
+ int mode = 0;
+ int pagesPrinted = 0;
+ char *paperType = NULL;
+ short mesgRetType;
+ int useLaserWriterMessages;
+ int pLen,sLen,peLen,jLen,pcLen ;
+
+ void (*oldsignal)();
+
+
+ /*
+ * Run immune from typical interruptions, so that
+ * we stand a chance to get the fault message.
+ * EOF (or startup error) is the only way out.
+ */
+ signal (SIGHUP, SIG_IGN);
+ signal (SIGINT, SIG_IGN);
+ signal (SIGQUIT, SIG_IGN);
+ signal (SIGTERM, SIG_IGN);
+
+ /*
+ * Do we have a key?
+ */
+ if (
+ argc < 2
+ || !(s_key = getenv("SPOOLER_KEY"))
+ || !*s_key
+ || (key = atol(s_key)) <= 0
+ ) {
+ printf( "Usage: lptell [-lodk] [-X String] printer\n");
+ printf("Options (where X is P,S,e,s, O or c )\n");
+ printf(" environment variable SPOOLER_KEY: must be defined and > 0\n");
+ printf(" printer: name of printer to give status for.\n");
+ printf(" -l: expect laser writer type messages (NeWSprint does)\n");
+ printf(" -o: send input to stdout\n");
+ printf(" -d: send additional debugging output to stdout\n");
+ printf(" -P String: string for prefix, default: '%%%%['\n");
+ printf(" -S String: string for suffix, default: ']%%%%'\n");
+ printf(" -e String: string to detect printer error,\n");
+ printf(" default: 'PrinterError:', send S_SEND_FAULT to lpsched\n");
+ printf(
+ " -c String: string to detect paper change in context of printer error,\n");
+ printf(" default: 'paper changed:', send S_PAPER_CHANGED to lpsched\n");
+ printf(" -s String: string to detect printer ok status, \n");
+ printf(" default: 'status:', send S_CLEAR_FAULT to lpsched\n");
+ printf(" -k: do not use the key for making status ok\n");
+ printf(" -O String: string sent as status message to lpsched,\n");
+ printf(" default: 'ready and printing:'\n");
+ exit (90);
+ }
+
+
+ doStdOut = 0;
+ doDebug = 0;
+ useLaserWriterMessages = 0;
+ clearKey = key;
+
+ prefixString = PREFIX_STRING; pLen = strlen(prefixString);
+ suffixString = SUFFIX_STRING;
+ printerErrorString = PRINTER_ERROR_STRING;
+ peLen = strlen(printerErrorString);
+ statusString = STATUS_STRING; sLen = strlen(statusString);
+ jobString = JOB_STRING; jLen = strlen(jobString);
+ paperChangedString = PAPER_CHANGED_STRING;
+ pcLen = strlen(paperChangedString);
+ statusOkString = STATUS_OK_STRING;
+
+ while ((optsw = getopt(argc, argv, "le:s:c:okdO:S:P:")) != EOF) {
+ switch ( optsw ) {
+ case 'l':
+ useLaserWriterMessages = 1;
+ break;
+ case 'P':
+ prefixString = (optarg ? strdup(optarg) : NULL);
+ pLen = strlen(prefixString );
+ break;
+ case 'S':
+ suffixString = (optarg ? strdup(optarg) : NULL);
+ break;
+ case 'e':
+ printerErrorString = (optarg ? strdup(optarg) : NULL);
+ peLen = strlen(printerErrorString);
+ break;
+ case 's':
+ statusString = (optarg ? strdup(optarg) : NULL);
+ sLen = strlen(statusString);
+ break;
+ case 'O':
+ statusOkString = (optarg ? strdup(optarg) : NULL);
+ break;
+ case 'c':
+ paperChangedString = (optarg ? strdup(optarg) : NULL);
+ pcLen = strlen(paperChangedString );
+ break;
+ case 'k':
+ clearKey = -1;
+ break;
+ case 'o':
+ doStdOut = 1;
+ break;
+ case 'd':
+ doDebug = 1;
+ break;
+ }
+ }
+ /*
+ * Which printer is this? Do we have a key?
+ */
+ if (
+ !(printer = argv[optind])
+ || !*printer
+ ) {
+ exit (90);
+ }
+ if (doDebug) {
+ printf( "start lp.tell for %s key %d mode %s %s\n",
+ printer,key,(useLaserWriterMessages ? "LW" : "standard"),
+ (doStdOut ? "doStdOut" : "no output"));
+ printf( "prefix (%s) suffix (%s) printerError (%s)\n",
+ prefixString,suffixString,printerErrorString);
+ printf( "paper_changed (%s) status (%s) key %d \n",
+ paperChangedString,statusString , clearKey);
+ fflush(stdout);
+ }
+ /*
+ * Wait for a message on the standard input. When a single line
+ * comes in, take a couple of more seconds to get any other lines
+ * that may be ready, then send them to the Spooler.
+ */
+ while (fgets(buf, BUFSIZ, stdin)) {
+ if (useLaserWriterMessages) {
+ /* NeWSprint style processing (which simulates the LaserWriter
+ *There are four types of messages:
+ * 1) fault messages: printer error message from handler
+ * 2) clear fault messages: printer ok messages from handler
+ * 3) paper changed messages: printer handler detected paper change
+ * 4) server messages: xnews problems
+ */
+ bufPtr = buf;
+ if (strncmp(prefixString, bufPtr, pLen) == 0) {
+ bufPtr += pLen;
+ while (*bufPtr == ' ')
+ bufPtr++;
+
+ if (strncmp(printerErrorString, bufPtr,
+ peLen) == 0) {
+ bufPtr += peLen;
+ while (*bufPtr == ' ')
+ bufPtr++;
+
+ if ((strncmp(bufPtr,paperChangedString,pcLen) == 0) &&
+ (ptr1 = bufPtr +pcLen) &&
+ (ptr2 = strchr(ptr1+1,':')) &&
+ (ptr3 = strchr(ptr2+1,':')) &&
+ (ptr4 = strchr(ptr3+1,':')) &&
+ (ptr5 = strchr(ptr4+1,'\n'))) {
+ if (doStdOut) printf("%s",buf);
+ *ptr2 =0;
+ *ptr3= 0;
+ *ptr4= 0;
+ *ptr5= 0;
+ trayNum = atoi(ptr1+1);
+ paperType = ptr2+1;
+ mode = atoi(ptr3+1);
+ pagesPrinted = atoi(ptr4+1);
+ if (doDebug) {
+ printf("Paper changed: %s tray %d paper %s md %d pages %d\n",
+ printer,trayNum,paperType,mode,pagesPrinted);
+ }
+ startup ();
+ mesgRetType = R_PAPER_CHANGED;
+ (void)putmessage ( msgbuf, S_PAPER_CHANGED, printer, trayNum,
+ paperType, mode, pagesPrinted);
+ } else {
+ if (doStdOut) printf("%s",buf);
+ if (ptr1 = strstr(bufPtr,suffixString)) *ptr1 = 0;
+ if ( doDebug ) {
+ printf("Send fault: %s key %d (%s)\n",printer,key,bufPtr);
+ }
+ mesgRetType = R_SEND_FAULT;
+ startup ();
+ (void)putmessage (msgbuf,S_SEND_FAULT,printer,key,bufPtr);
+ }
+ } else if ((first = (strncmp(statusString,bufPtr,sLen) == 0)) ||
+ (strncmp(jobString,bufPtr,jLen) == 0)) {
+ bufPtr += (first ? sLen : jLen);
+ if (doStdOut) printf("%s",buf);
+ if (ptr1 = strstr(bufPtr,suffixString)) *ptr1 = 0;
+ if ( doDebug ) {
+ printf("Clear fault: %s key %d (%s)\n",printer, clearKey,
+ bufPtr);
+ }
+ mesgRetType = R_CLEAR_FAULT;
+ startup ();
+ (void)putmessage( msgbuf,S_CLEAR_FAULT,printer,clearKey,
+ statusOkString);
+ } else {
+ if (doStdOut) printf("%s",buf);
+ if (ptr1 = strstr(bufPtr,suffixString)) *ptr1 = 0;
+ if ( doDebug ) {
+ printf("Server error: %s key %d (%s)\n",printer,key,
+ buf);
+ }
+ mesgRetType = 0;
+ }
+ } else {
+ if (doStdOut) printf("%s",buf);
+ if (ptr1 = strstr(bufPtr,suffixString))
+ *ptr1 = 0;
+ if (doDebug) {
+ printf("Server error: %s key %d (%s)\n",
+ printer, key, buf);
+ }
+ mesgRetType = 0;
+ }
+ } else { /* not generic PostScript style messages */
+ oldsignal = signal(SIGALRM, wakeup);
+ oldalarm = alarm(2);
+
+ alert_text = 0;
+ do {
+ if (alert_text)
+ alert_text = realloc(alert_text,
+ strlen(alert_text)+strlen(buf)+1
+ );
+ else {
+ alert_text = malloc(strlen(buf) + 1);
+ alert_text[0] = 0;
+ }
+ strcat (alert_text, buf);
+
+ } while (fgets(buf, BUFSIZ, stdin));
+
+ alarm (oldalarm);
+ signal (SIGALRM, oldsignal);
+
+ if (doStdOut) {
+ if ( doDebug ) {
+ printf("Send generic fault: %s key %d (%s)\n",printer,key,
+ alert_text);
+ }
+ else {
+ printf("%s\n",alert_text);
+ }
+ }
+ if (strcmp(alert_text, "printer ok\n") == 0) {
+ mesgRetType = R_CLEAR_FAULT;
+ startup ();
+ (void)putmessage(msgbuf, S_CLEAR_FAULT, printer,
+ clearKey, statusOkString);
+ } else {
+ mesgRetType = R_SEND_FAULT;
+ startup ();
+ (void)putmessage(msgbuf, S_SEND_FAULT, printer,
+ key, alert_text);
+ }
+ }
+
+ if (mesgRetType) {
+ if (msend(msgbuf) == -1)
+ done (91);
+ if (mrecv(msgbuf, sizeof(msgbuf)) == -1)
+ done (92);
+ mtype = getmessage(msgbuf, mesgRetType, &status);
+ /*
+ * check for R_CLEAR_FAULT here and 3 lines below
+ * because older lpsched doesn't pass S_CLEAR_FAULT
+ */
+ if ((mtype != mesgRetType) &&
+ (mesgRetType != R_CLEAR_FAULT))
+ done (93);
+
+ if ((status != MOK) && (mesgRetType != R_CLEAR_FAULT))
+ done (94);
+ }
+
+ }
+ done (0);
+
+ return (0);
+}
+
+/**
+ ** startup() - OPEN MESSAGE QUEUE TO SPOOLER
+ ** cleanup() - CLOSE THE MESSAGE QUEUE TO THE SPOOLER
+ **/
+
+static int have_contacted_spooler = 0;
+
+void startup ()
+{
+ void catch();
+
+ /*
+ * Open a message queue to the Spooler.
+ * An error is deadly.
+ */
+ if (!have_contacted_spooler) {
+ if (mopen() == -1) {
+
+ switch (errno) {
+ case ENOMEM:
+ case ENOSPC:
+ break;
+ default:
+ break;
+ }
+
+ exit (1);
+ }
+ have_contacted_spooler = 1;
+ }
+ return;
+}
+
+void cleanup ()
+{
+ if (have_contacted_spooler)
+ mclose ();
+ return;
+}
+
+/**
+ ** wakeup() - TRAP ALARM
+ **/
+
+static void wakeup ()
+{
+ return;
+}
+
+/**
+ ** done() - CLEANUP AND EXIT
+ **/
+
+void done (ec)
+ int ec;
+{
+ cleanup ();
+ exit (ec);
+}
diff --git a/usr/src/cmd/lp/model/lp.tsol_separator.c b/usr/src/cmd/lp/model/lp.tsol_separator.c
new file mode 100644
index 0000000000..a7ea55a154
--- /dev/null
+++ b/usr/src/cmd/lp/model/lp.tsol_separator.c
@@ -0,0 +1,528 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Add TSOL banner, trailer, page header/footers to a print job
+ */
+
+/* system header files */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <limits.h>
+#include <errno.h>
+#include <signal.h>
+#include <locale.h>
+#include <tsol/label.h>
+
+/* typedefs */
+
+typedef int BOOL;
+
+/* constants */
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define ME "lp.tsol_separator"
+#define POSTSCRIPTLIB "/usr/lib/lp/postscript"
+#define SEPARATORPS "tsol_separator.ps"
+#define BANNERPS "tsol_banner.ps"
+#define TRAILERPS "tsol_trailer.ps"
+#define MAXUSERLEN 32
+#define MAXHOSTLEN 32
+
+/* external variables */
+
+int optind; /* Used by getopt */
+char *optarg; /* Used by getopt */
+
+/* prototypes for static functions */
+
+static int ProcessArgs(int argc, char **argv);
+static void Usage(void);
+static void ParseUsername(char *input, char *user, char *host);
+static void EmitPSFile(const char *name);
+static BOOL EmitFile(FILE *file);
+static void EmitJobData(void);
+static void EmitPrologue(void);
+static void EmitCommandLineInfo(void);
+static void EmitClockBasedInfo(void);
+static void EmitLabelInfo(void);
+static void CopyStdin(void);
+
+/* static variables */
+
+static char *ArgSeparatorPS;
+static char *ArgBannerPS;
+static char *ArgTrailerPS;
+static char *ArgPSLib;
+static char *ArgPrinter;
+static char *ArgJobID;
+static char *ArgUser;
+static char *ArgTitle;
+static char *ArgFile;
+static BOOL ArgReverse;
+static BOOL ArgNoPageLabels;
+static int ArgDebugLevel;
+static FILE *ArgLogFile;
+static m_label_t *FileLabel;
+static char *remoteLabel;
+
+int
+main(int argc, char *argv[])
+{
+ int err;
+ /*
+ * Run immune from typical interruptions, so that
+ * we stand a chance to get the fault message.
+ * EOF (or startup error) is the only way out.
+ */
+ (void) signal(SIGHUP, SIG_IGN);
+ (void) signal(SIGINT, SIG_IGN);
+ (void) signal(SIGQUIT, SIG_IGN);
+ (void) signal(SIGTERM, SIG_IGN);
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ if (ProcessArgs(argc, argv) != 0)
+ exit(1);
+
+ if ((FileLabel = m_label_alloc(MAC_LABEL)) == NULL)
+ exit(1);
+ /*
+ * If the job was submitted via remotely, the label of the
+ * remote peer will be set in the SLABEL environment variable
+ * by copying it out of the SECURE structure.
+ *
+ * If there is no SLABEL value, the job was submitted locally
+ * via the named pipe, and the file label can be determined
+ * from its pathname.
+ */
+ if ((remoteLabel = getenv("SLABEL")) != NULL) {
+ m_label_free(FileLabel);
+ FileLabel = NULL;
+ if (str_to_label(remoteLabel, &FileLabel, MAC_LABEL,
+ L_NO_CORRECTION, &err) == -1) {
+ perror("str_to_label");
+ exit(1);
+ }
+ } else if (getlabel(ArgFile, FileLabel) != 0) {
+ (void) fprintf(ArgLogFile,
+ gettext("%1$s: cannot get label of %2$s: %3$s\n"),
+ ME, ArgFile, strerror(errno));
+ exit(1);
+ }
+
+ /* All of these functions exit if they encounter an error */
+ EmitJobData();
+ EmitPSFile(ArgSeparatorPS);
+ if (ArgReverse)
+ EmitPSFile(ArgTrailerPS);
+ else
+ EmitPSFile(ArgBannerPS);
+ CopyStdin();
+ if (ArgReverse)
+ EmitPSFile(ArgBannerPS);
+ else
+ EmitPSFile(ArgTrailerPS);
+ if (ArgDebugLevel >= 1)
+ (void) fprintf(ArgLogFile, gettext("Done.\n"));
+ m_label_free(FileLabel);
+ return (0);
+}
+
+static void
+EmitJobData(void)
+{
+ EmitPrologue();
+ EmitCommandLineInfo();
+ EmitClockBasedInfo();
+ EmitLabelInfo();
+
+ /* Emit ending PostScript code */
+ (void) printf("end\n\n");
+ (void) printf("%%%% End of code generated by lp.tsol_separator\n\n");
+
+}
+
+static void
+EmitPrologue(void)
+{
+ /* Emit preliminary PostScript code */
+ (void) printf("%%!\n\n");
+ (void) printf("%%%% Begin code generated by lp.tsol_separator\n\n");
+
+ (void) printf("%%%% Create JobDict if it doesn't exist\n");
+ (void) printf("userdict /JobDict known not {\n");
+ (void) printf(" userdict /JobDict 100 dict put\n");
+ (void) printf("} if\n\n");
+
+ (void) printf("%%%% Define job parameters, including TSOL security "
+ "info\n");
+ (void) printf("JobDict\n");
+ (void) printf("begin\n");
+}
+
+/* Emit parameters obtained from command line options */
+
+static void
+EmitCommandLineInfo(void)
+{
+ char user[MAXUSERLEN + 1];
+ char host[MAXHOSTLEN + 1];
+
+ (void) printf("\t/Job_Printer (%s) def\n", ArgPrinter);
+ ParseUsername(ArgUser, user, host);
+ (void) printf("\t/Job_Host (%s) def\n", host);
+ (void) printf("\t/Job_User (%s) def\n", user);
+ (void) printf("\t/Job_JobID (%s) def\n", ArgJobID);
+ (void) printf("\t/Job_Title (%s) def\n", ArgTitle);
+ (void) printf("\t/Job_DoPageLabels (%s) def\n",
+ ArgNoPageLabels ? "NO" : "YES");
+ (void) printf("\n");
+}
+
+/* Emit parameters generated from the system clock */
+
+static void
+EmitClockBasedInfo(void)
+{
+ char timebuf[80];
+ struct timeval clockval;
+
+ (void) gettimeofday(&clockval, NULL);
+ (void) strftime(timebuf, sizeof (timebuf), NULL,
+ localtime(&clockval.tv_sec));
+ (void) printf("\t/Job_Date (%s) def\n", timebuf);
+ (void) printf("\t/Job_Hash (%ld) def\n", clockval.tv_usec % 100000L);
+ (void) printf("\n");
+}
+
+/* Emit parameters derived from the SL and IL of the file being printed. */
+
+static void
+EmitLabelInfo(void)
+{
+ char *header = NULL; /* DIA banner page fields */
+ char *label = NULL;
+ char *caveats = NULL;
+ char *channels = NULL;
+ char *page_label = NULL; /* interior pages label */
+
+ if (label_to_str(FileLabel, &header, PRINTER_TOP_BOTTOM,
+ DEF_NAMES) != 0) {
+ (void) fprintf(ArgLogFile,
+ gettext("%s: label_to_str PRINTER_TOP_BOTTOM: %s.\n"),
+ ME, strerror(errno));
+ exit(1);
+ }
+ if (label_to_str(FileLabel, &label, PRINTER_LABEL,
+ DEF_NAMES) != 0) {
+ (void) fprintf(ArgLogFile,
+ gettext("%s: label_to_str PRINTER_LABEL: %s.\n"),
+ ME, strerror(errno));
+ exit(1);
+ }
+ if (label_to_str(FileLabel, &caveats, PRINTER_CAVEATS,
+ DEF_NAMES) != 0) {
+ (void) fprintf(ArgLogFile,
+ gettext("%s: label_to_str PRINTER_CAVEATS: %s.\n"),
+ ME, strerror(errno));
+ exit(1);
+ }
+ if (label_to_str(FileLabel, &channels, PRINTER_CHANNELS,
+ DEF_NAMES) != 0) {
+ (void) fprintf(ArgLogFile,
+ gettext("%s: label_to_str PRINTER_CHANNELS: %s.\n"),
+ ME, strerror(errno));
+ exit(1);
+ }
+ if (label_to_str(FileLabel, &page_label, M_LABEL,
+ LONG_NAMES) != 0) {
+ (void) fprintf(ArgLogFile,
+ gettext("%s: label_to_str M_LABEL: %s.\n"),
+ ME, strerror(errno));
+ exit(1);
+ }
+
+ (void) printf("\t/Job_Classification (%s) def\n", header);
+ (void) printf("\t/Job_Protect (%s) def\n", label);
+ (void) printf("\t/Job_Caveats (%s) def\n", caveats);
+ (void) printf("\t/Job_Channels (%s) def\n", channels);
+ (void) printf("\t/Job_SL_Internal (%s) def\n", page_label);
+
+ /* Free memory allocated label_to_str */
+ free(header);
+ free(label);
+ free(caveats);
+ free(channels);
+ free(page_label);
+}
+
+/*
+ * Parse input "host!user" to separate host and user names.
+ */
+
+static void
+ParseUsername(char *input, char *user, char *host)
+{
+ char *cp;
+
+ if ((cp = strchr(input, '@')) != NULL) {
+ /* user@host */
+ (void) strlcpy(host, cp + 1, MAXHOSTLEN + 1);
+ *cp = '\0';
+ (void) strlcpy(user, input, MAXUSERLEN + 1);
+ *cp = '@';
+ } else if ((cp = strchr(input, '!')) != NULL) {
+ /* host!user */
+ (void) strlcpy(user, cp + 1, MAXUSERLEN + 1);
+ *cp = '\0';
+ (void) strlcpy(host, input, MAXHOSTLEN + 1);
+ *cp = '!';
+ } else {
+ /* user */
+ (void) strlcpy(user, input, MAXUSERLEN + 1);
+ host[0] = '\0';
+ }
+}
+
+
+static void
+CopyStdin(void)
+{
+ if (!EmitFile(stdin)) {
+ (void) fprintf(ArgLogFile,
+ gettext("%s: Error copying stdin to stdout\n"), ME);
+ exit(1);
+ }
+}
+
+
+static BOOL
+EmitFile(FILE *file)
+{
+ int len;
+#define BUFLEN 1024
+ char buf[BUFLEN];
+
+ while ((len = fread(buf, 1, BUFLEN, file)) > 0) {
+ if (fwrite(buf, 1, len, stdout) != len)
+ return (FALSE);
+ }
+ if (!feof(file))
+ return (FALSE);
+ return (TRUE);
+}
+
+
+static void
+EmitPSFile(const char *name)
+{
+ char path[PATH_MAX];
+ FILE *file;
+ BOOL emitted;
+
+ if (name[0] != '/') {
+ (void) strlcpy(path, ArgPSLib, sizeof (path));
+ (void) strlcat(path, "/", sizeof (path));
+ (void) strlcat(path, name, sizeof (path));
+ } else {
+ (void) strlcpy(path, name, sizeof (path));
+ }
+
+ file = fopen(path, "r");
+ if (file == NULL) {
+ (void) fprintf(ArgLogFile,
+ gettext("%s: Error opening PostScript file %s. %s.\n"),
+ ME, path, strerror(errno));
+ exit(1);
+ }
+
+ emitted = EmitFile(file);
+ (void) fclose(file);
+ if (!emitted) {
+ (void) fprintf(ArgLogFile, gettext(
+ "%s: Error copying PostScript file %s to stdout.\n"),
+ ME, path);
+ exit(1);
+ }
+}
+
+
+static int
+ProcessArgs(int argc, char *argv[])
+{
+ int option_letter;
+ char *options_string = "lrd:e:s:b:t:L:";
+
+ /* set default values for arguments */
+ ArgSeparatorPS = SEPARATORPS;
+ ArgBannerPS = BANNERPS;
+ ArgTrailerPS = TRAILERPS;
+ ArgPSLib = POSTSCRIPTLIB;
+ ArgNoPageLabels = ArgReverse = FALSE;
+ ArgDebugLevel = 0;
+ ArgLogFile = stderr;
+
+ /* read switch arguments once to get error log file */
+ while ((option_letter = getopt(argc, argv, options_string)) != EOF) {
+ switch (option_letter) {
+ case 'd':
+ ArgDebugLevel = atoi(optarg);
+ break;
+ case 'e':
+ ArgLogFile = fopen(optarg, "a");
+ if (ArgLogFile == NULL) {
+ (void) fprintf(stderr,
+ gettext("Cannot open log file %s\n"),
+ optarg);
+ return (-1);
+ }
+ break;
+ case '?': /* ? or unrecognized option */
+ Usage();
+ return (-1);
+ }
+ }
+
+ if (ArgDebugLevel > 0)
+ (void) fprintf(ArgLogFile,
+ gettext("Processing switch arguments\n"));
+
+ /* re-read switch arguments */
+ optind = 1;
+ while ((option_letter = getopt(argc, argv, options_string)) != EOF) {
+ switch (option_letter) {
+ case 'd':
+ ArgDebugLevel = atoi(optarg);
+ break;
+ case 'e':
+ /* This was handled in earlier pass through args */
+ break;
+ case 'l':
+ ArgNoPageLabels = TRUE;
+ break;
+ case 'r':
+ ArgReverse = TRUE;
+ break;
+ case 's':
+ ArgSeparatorPS = optarg;
+ break;
+ case 'b':
+ ArgBannerPS = optarg;
+ break;
+ case 't':
+ ArgTrailerPS = optarg;
+ break;
+ case 'L':
+ ArgPSLib = optarg;
+ break;
+ case '?': /* ? or unrecognized option */
+ Usage();
+ return (-1);
+ }
+ }
+
+ /* Adjust arguments to skip over options */
+ argc -= optind; /* Number of remaining(non-switch) args */
+ argv += optind; /* argv[0] is first(non-switch) args */
+
+ if (argc != 5) {
+ (void) fprintf(ArgLogFile,
+ gettext("Wrong number of arguments.\n\n"));
+ Usage();
+ return (-1);
+ }
+
+ ArgPrinter = argv++[0];
+ ArgJobID = argv++[0];
+ ArgUser = argv++[0];
+ ArgTitle = argv++[0];
+ ArgFile = argv++[0];
+
+ if (ArgDebugLevel >= 1) {
+ (void) fprintf(ArgLogFile, gettext("Arguments processed\n"));
+ (void) fprintf(ArgLogFile, gettext("Printer: %s\n"),
+ ArgPrinter);
+ (void) fprintf(ArgLogFile, gettext("Job ID: %s\n"), ArgJobID);
+ (void) fprintf(ArgLogFile, gettext("User: %s\n"), ArgUser);
+ (void) fprintf(ArgLogFile, gettext("Title: %s\n"), ArgTitle);
+ (void) fprintf(ArgLogFile, gettext("File: %s\n"), ArgFile);
+ }
+
+ return (0);
+}
+
+
+static void
+Usage(void)
+{
+ static const char *OPTFMT = " %-8s %-9s %s\n";
+
+ (void) fprintf(ArgLogFile,
+ gettext("Usage: lp.tsol_separator [OPTIONS] %s\n"),
+ gettext("PRINTER JOBID HOST!USER TITLE FILE"));
+ (void) fprintf(ArgLogFile, gettext(" OPTIONS:\n"));
+ (void) fprintf(ArgLogFile, OPTFMT, "-r", gettext("Reverse"),
+ gettext("Reverse banner/trailer order"));
+ (void) fprintf(ArgLogFile, OPTFMT, "-l", gettext("Labels"),
+ gettext("Suppress page header/footer labels"));
+ (void) fprintf(ArgLogFile, OPTFMT, gettext("-b FILE"),
+ gettext("Banner"),
+ gettext("PostScript program for banner (default tsol_banner.ps)"));
+ (void) fprintf(ArgLogFile, OPTFMT, gettext("-s FILE"),
+ gettext("Separator"),
+ gettext("PostScript program for separator "
+ "(default tsol_separator.ps)"));
+ (void) fprintf(ArgLogFile, OPTFMT, gettext("-t FILE"),
+ gettext("Trailer"),
+ gettext("PostScript program for trailer "
+ "(default tsol_trailer.ps)"));
+ (void) fprintf(ArgLogFile, OPTFMT, gettext("-L DIR"),
+ gettext("Library"),
+ gettext("Directory to search for PostScript programs"));
+ (void) fprintf(ArgLogFile, OPTFMT, "", "",
+ gettext("(default /usr/lib/lp/postscript)"));
+ (void) fprintf(ArgLogFile, OPTFMT, gettext("-d N"), gettext("Debug"),
+ gettext("Set debug level to N"));
+ (void) fprintf(ArgLogFile, OPTFMT, gettext("-e FILE"),
+ gettext("Error File"),
+ gettext("Append error and debugging output to FILE"));
+}
diff --git a/usr/src/cmd/lp/model/netpr/Makefile b/usr/src/cmd/lp/model/netpr/Makefile
new file mode 100644
index 0000000000..f447336bc3
--- /dev/null
+++ b/usr/src/cmd/lp/model/netpr/Makefile
@@ -0,0 +1,113 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/model/netpr
+#
+
+PROG= netpr
+
+include ../../Makefile.lp
+
+PURIFYOPTS = -logfile=/tmp/errs.%p
+PURIFY = purify $(PURIFYOPTS)
+
+CPPFLAGS = -I. -I$(LPINC) \
+ $(CPPFLAGS.master)
+
+HDRS= \
+ netpr.h \
+ netdebug.h
+
+SRCS= \
+ netpr.c \
+ misc.c \
+ net.c \
+ tcp_misc.c \
+ bsd_misc.c
+
+OBJS= $(SRCS:.c=.o)
+
+
+LPLIBS = \
+ $(LIBMSG) \
+ $(LIBFRM) \
+ $(LIBREQ) \
+ $(LIBPRT) \
+ $(LIBCLS) \
+ $(LIBACC) \
+ $(LIBFLT) \
+ $(LIBUSR) \
+ $(LIBOAM) \
+ $(LIBLP) \
+ $(LIBSEC) \
+ $(LIBSYS)
+
+SYSLIBS= -lnsl -lsocket
+
+LDLIBS += $(LPLIBS) $(SYSLIBS)
+ROOTLIBLPBIN = $(ROOTLIBLP)/bin
+
+ROOTNETPRPROG = $(PROG:%=$(ROOTLIBLPBIN)/%)
+
+FILEMODE= 04511
+
+POFILE= lp_model_netpr.po
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTLIBLPBIN) $(ROOTNETPRPROG)
+
+$(ROOTLIBLPBIN):
+ $(INS.dir)
+
+$(ROOTLIBLPBIN)/%: %
+ $(INS.file)
+
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(PROG).pure: $(OBJS)
+ $(PURIFY) $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+clean:
+ $(RM) $(OBJS)
+
+clobber: clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
+
+strip:
+ $(STRIP) $(PROG)
+
+cstyle:
+ cstyle $(SRCS)
+
+LINTFLAGS += -lnsl -lsocket
+lint:
+ $(LINT.c) $(SRCS) $(LDLIBS)
+
+include ../Makefile.msg
diff --git a/usr/src/cmd/lp/model/netpr/bsd_misc.c b/usr/src/cmd/lp/model/netpr/bsd_misc.c
new file mode 100644
index 0000000000..a4402a5cde
--- /dev/null
+++ b/usr/src/cmd/lp/model/netpr/bsd_misc.c
@@ -0,0 +1,278 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include "netpr.h"
+#include "netdebug.h"
+
+static int job_primitive(np_bsdjob_t *, char, char *);
+static int create_cfA_file(np_bsdjob_t *);
+static char *create_cfname(np_bsdjob_t *);
+static char *create_dfname(np_bsdjob_t *);
+extern char data_file_type;
+
+np_bsdjob_t *
+create_bsd_job(np_job_t *injob, int pr_order, int filesize)
+{
+
+ np_bsdjob_t *job;
+ char *id;
+ int x;
+ np_data_t *jobdata;
+
+ if ((injob->request_id == NULL) || (injob->username == NULL) ||
+ (injob->dest == NULL) || (injob->printer == NULL)) {
+ return (NULL);
+ }
+
+ job = (np_bsdjob_t *)malloc(sizeof (np_bsdjob_t));
+ ASSERT(job, MALLOC_ERR);
+ (void) memset(job, 0, sizeof (np_bsdjob_t));
+ job->np_printer = "auto"; /* default "queue" */
+ /*
+ * request-id comes in as printer-number
+ * pull apart to create number
+ */
+ if ((id = strrchr(injob->request_id, (int)'-')) == NULL) {
+ (void) fprintf(stderr,
+ gettext("Netpr: request_id in unknown format:<%s>\n"),
+ injob->request_id);
+ syslog(LOG_DEBUG, "request id in unknown format: %s",
+ injob->request_id);
+ return (NULL);
+ }
+
+ id++;
+
+ /*
+ * 4261563 - A ID collides with an existing one, it plus
+ * 1,000 with the ID causes breaking
+ * Max job id for bsd is 999.
+ */
+ job->np_request_id = malloc(4);
+ ASSERT(job->np_request_id, MALLOC_ERR);
+ errno = 0;
+ x = atoi(id);
+ if ((errno != 0) || (x < 0)) {
+ x = 0;
+ }
+ (void) snprintf(job->np_request_id, (size_t)4,
+ "%.3d", x % 1000);
+
+ /* seperate the user/host from host!user or user@host */
+ if ((id = strchr(injob->username, '@')) != NULL) {
+ *id++ = '\0';
+ job->np_username = strdup(injob->username);
+ job->np_host = strdup(id);
+ *--id = '@';
+ } else if ((id = strrchr(injob->username, '!')) != NULL) {
+ *id++ = '\0';
+ job->np_username = strdup(id);
+ job->np_host = strdup(injob->username);
+ *--id = '!';
+ } else {
+ syslog(LOG_DEBUG, "using localhost for user %s",
+ injob->username);
+ job->np_username = strdup(injob->username);
+ job->np_host = strdup("localhost");
+ }
+
+ job->np_printer = injob->printer;
+ job->np_filename = injob->filename;
+
+ job->np_df_letter = 'A';
+
+ /* build cfAfilename: (cfA)(np_request_id)(np_host) */
+ if ((job->np_cfAfilename = create_cfname(job)) == NULL) {
+ (void) fprintf(stderr,
+ gettext("Netpr: System error creating cfAfilename\n"));
+ syslog(LOG_DEBUG, "System error creating cfAfilename");
+ return (NULL);
+ }
+
+ job->np_timeout = injob->timeout;
+ job->np_banner = injob->banner;
+ job->np_print_order = pr_order;
+
+ if (injob->title == NULL)
+ job->np_title = injob->filename;
+ else
+ job->np_title = injob->title;
+
+ if ((create_cfA_file(job)) == -1) {
+ (void) fprintf(stderr,
+ gettext("Netpr: Cannot create bsd control file\n"));
+ syslog(LOG_DEBUG, "Cannot create bsd control file");
+ return (NULL);
+ }
+
+ /* Now we have a title, add to the control file */
+ if (injob->banner == BANNER) {
+ (void) job_primitive(job, 'C', job->np_host);
+ (void) job_primitive(job, 'J', job->np_title);
+ (void) job_primitive(job, 'L', job->np_username);
+ }
+
+
+ /* create dfname for this file */
+
+ /* allocate the jobdata and initialize what we have so far */
+ jobdata = malloc(sizeof (np_data_t));
+ ASSERT(jobdata, MALLOC_ERR);
+ (void) memset(jobdata, 0, sizeof (np_data_t));
+
+ jobdata->np_path_file = malloc(strlen(job->np_filename) + 1);
+ ASSERT(jobdata->np_path_file, MALLOC_ERR);
+ (void) strcpy(jobdata->np_path_file, job->np_filename);
+
+ jobdata->np_data_size = filesize;
+
+ if ((jobdata->np_dfAfilename = create_dfname(job)) == NULL) {
+ return (NULL);
+ }
+
+ /*
+ * data_file_type should contain the RFC-1179 control file message
+ * type for the control file. The is is set via the "-f" option
+ * to netpr, which get it from the "destination-full-control-file-type"
+ * option passed in. Normally this will be either 'l' or 'f'.
+ */
+ if (data_file_type != 0) {
+ (void) job_primitive(job, data_file_type,
+ jobdata->np_dfAfilename);
+ (void) job_primitive(job, 'U', jobdata->np_dfAfilename);
+ (void) job_primitive(job, 'N', "print-data");
+ }
+
+ syslog(LOG_DEBUG, "data file info: %s", job->np_cfAfile);
+
+ /*
+ * attach np_data to bsdjob
+ */
+ job->np_data = jobdata;
+
+ return (job);
+}
+
+
+/*
+ * Create df<x>name for this file
+ * df<X><nnn><hostname>
+ */
+static char *
+create_dfname(np_bsdjob_t *job)
+{
+ char *dfname;
+
+ if (job == NULL)
+ return (NULL);
+
+ /* Trying to print too many files */
+ if (job->np_df_letter > 'z') {
+ errno = ENFILE;
+ return (NULL);
+ }
+
+ dfname = (char *)malloc(strlen(job->np_host) + 3 + 3 + 1);
+ ASSERT(dfname, MALLOC_ERR);
+ (void) memset(dfname, 0, strlen(job->np_host) + 3 + 3 + 1);
+ (void) sprintf(dfname, "%s%c%s%s", "df", job->np_df_letter,
+ job->np_request_id, job->np_host);
+
+ /* udate np_df_letter for the next caller */
+ job->np_df_letter += 1;
+ if ((job->np_df_letter > 'Z') && (job->np_df_letter < 'a'))
+ job->np_df_letter = 'a';
+
+ return (dfname);
+}
+
+static char *
+create_cfname(np_bsdjob_t *job)
+{
+ char *cfname;
+
+ if (job == NULL)
+ return (NULL);
+
+ cfname = (char *)malloc(strlen(job->np_host) + 3 + 3 + 1);
+ ASSERT(cfname, MALLOC_ERR);
+ (void) memset(cfname, 0, strlen(job->np_host) + 3 + 3 + 1);
+ (void) sprintf(cfname, "%s%s%s", "cfA",
+ job->np_request_id, job->np_host);
+ return (cfname);
+}
+
+static int
+create_cfA_file(np_bsdjob_t *job)
+{
+ /*
+ * Read through job structure, creating entries
+ * in control file as appropriate
+ */
+ if ((job->np_host == NULL) || (job->np_username == NULL)) {
+ (void) fprintf(stderr, gettext(
+ "Netpr: Missing required data, cannot build control file\n"));
+ return (-1);
+ }
+ (void) job_primitive(job, 'H', job->np_host);
+ (void) job_primitive(job, 'P', job->np_username);
+
+ return (0);
+}
+
+static int
+job_primitive(np_bsdjob_t *job, char option, char *value)
+{
+ char buf[BUFSIZ];
+
+ if ((job == NULL) || (value == NULL))
+ return (-1);
+
+ job->np_cfAfilesize += strlen(value) + 2; /* (opt)(value)\n */
+ if (job->np_cfAfile == NULL) {
+ /* Always allocate one greater than cfAfilesize for the \0 */
+ job->np_cfAfile = calloc(1, job->np_cfAfilesize + 1);
+ ASSERT(job->np_cfAfile, MALLOC_ERR);
+ } else {
+ job->np_cfAfile = realloc(job->np_cfAfile,
+ job->np_cfAfilesize + 1);
+ ASSERT(job->np_cfAfile, REALLOC_ERR);
+ }
+ (void) snprintf(buf, sizeof (buf), "%c%s\n", option, value);
+ (void) strcat(job->np_cfAfile, buf);
+ syslog(LOG_DEBUG, "adding: %d %s", job->np_cfAfilesize, buf);
+
+ return (0);
+}
diff --git a/usr/src/cmd/lp/model/netpr/misc.c b/usr/src/cmd/lp/model/netpr/misc.c
new file mode 100644
index 0000000000..cec2b533bc
--- /dev/null
+++ b/usr/src/cmd/lp/model/netpr/misc.c
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1996-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "netpr.h"
+#include "netdebug.h"
+
+extern char *strtok_r(char *, const char *, char **);
+
+int
+check_file(char * filename)
+{
+ struct stat status;
+
+ if (filename == NULL)
+ return (-1);
+
+ /* Checking read permission */
+ if (access(filename, R_OK) < 0)
+ return (-1);
+
+ if (stat(filename, &status) < 0)
+ return (-1);
+
+ /* Checking for regular file */
+ if (S_ISREG(status.st_mode) == 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+
+ /* Checking for empty file */
+ if (status.st_size == 0) {
+ errno = ESRCH;
+ return (-1);
+ }
+ return (status.st_size);
+}
+
+
+/*
+ * allocate the space; fill with input
+ */
+char *
+alloc_str(char * instr)
+{
+ char * outstr;
+
+ outstr = (char *)malloc(strlen(instr) + 1);
+ ASSERT(outstr, MALLOC_ERR);
+ (void) memset(outstr, 0, strlen(instr) + 1);
+ (void) strcpy(outstr, instr);
+
+ return (outstr);
+}
+
+np_job_t *
+init_job()
+{
+ np_job_t * job;
+
+ if ((job = calloc(1, sizeof (*job))) != NULL) {
+ job->protocol = BSD;
+ job->banner = BANNER;
+ }
+
+ return (job);
+}
+
+void
+tell_lptell(int type, char *fmt, ...)
+{
+ char msg[BUFSIZ];
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void) vsnprintf(msg, sizeof (msg), fmt, ap);
+ va_end(ap);
+
+ if (msg == NULL)
+ return;
+
+ switch (type) {
+ case ERRORMSG:
+ (void) fprintf(stderr, "%%%%[PrinterError: %s ]%%%%\n", msg);
+ break;
+ case OKMSG:
+ /* In this case, the message is the job request-id */
+ (void) fprintf(stderr,
+ "%%%%[job: %s status: ok source: Netpr]%%%%\n", msg);
+ break;
+ default:
+ /* unknown type, ignore */
+ break;
+ }
+
+
+}
+
+
+/*
+ * Parse destination
+ * bsd: <printer_host>[:<printer_vendor_defined_name]
+ * tcp: <printer_host>[:port_number]
+ */
+
+void
+parse_dest(char * dest, char **str1, char **str2, char * sep)
+{
+ char * tmp;
+ char * nexttok;
+
+ *str1 = NULL;
+ *str2 = NULL;
+
+ if (dest != NULL) {
+ tmp = (char *)strtok_r(dest, sep, &nexttok);
+ if (tmp != NULL)
+ *str1 = strdup(tmp);
+ tmp = (char *)strtok_r(NULL, sep, &nexttok);
+ if (tmp != NULL)
+ *str2 = strdup(tmp);
+ }
+
+}
+
+/*
+ * void panic call
+ * used with ASSERT macro; gives us a place to stop the debugger
+ */
+void
+panic()
+{
+}
diff --git a/usr/src/cmd/lp/model/netpr/net.c b/usr/src/cmd/lp/model/netpr/net.c
new file mode 100644
index 0000000000..9e056f2eef
--- /dev/null
+++ b/usr/src/cmd/lp/model/netpr/net.c
@@ -0,0 +1,377 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <libintl.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include "netpr.h"
+
+#define TIMEOUT 1
+
+static int netpr_send_message(int, char *, ...);
+static int xfer_cfAfile(int, char *, char *, uint);
+
+int
+bsd_print(int sockfd, caddr_t pa, np_bsdjob_t * bsdjob)
+{
+ int filesize;
+ int xfer;
+ int net;
+
+ syslog(LOG_DEBUG, "bsd_print");
+
+ filesize = bsdjob->np_data->np_data_size;
+ syslog(LOG_DEBUG, "filesize is %d", filesize);
+
+
+ if (netpr_send_message(sockfd, "%c%s\n", XFER_REQUEST,
+ bsdjob->np_printer) != 0) {
+ return (NETWORK_ERROR_SEND_RESPONSE);
+ }
+
+ /*
+ * control file
+ */
+
+ if (bsdjob->np_print_order == CONTROL_FIRST) {
+ if ((xfer_cfAfile(sockfd, bsdjob->np_cfAfile,
+ bsdjob->np_cfAfilename,
+ bsdjob->np_cfAfilesize)) != 0) {
+ (void) fprintf(stderr,
+ gettext("Netpr: Error sending control file\n"));
+ syslog(LOG_DEBUG, "Error sending control file");
+ return (NETWORK_ERROR_UNKNOWN);
+
+ }
+ }
+
+ /* send msg - get ready for transfer */
+
+ if ((netpr_send_message(sockfd, "%c%d %s\n", XFER_DATA, filesize,
+ bsdjob->np_data->np_dfAfilename)) != 0) {
+ return (NETWORK_ERROR_SEND_RESPONSE);
+ }
+
+ /*
+ * send the file
+ */
+
+ if ((xfer = xfer_file(sockfd, pa, filesize, bsdjob->np_timeout)) != 0) {
+ return (xfer);
+ }
+
+ /* send msg - done */
+ if ((net = netpr_send_message(sockfd, "", NULL)) != 0) {
+ (void) fprintf(stderr,
+ gettext("Netpr: network error transfering %s returns: %d\n"),
+ bsdjob->np_filename, net);
+ syslog(LOG_DEBUG,
+ "network error transfering %s returns: %d",
+ bsdjob->np_filename, net);
+ return (NETWORK_ERROR_WRITE_FAILED);
+ }
+
+ /*
+ * control file
+ */
+
+ if (bsdjob->np_print_order == DATA_FIRST) {
+ if ((xfer_cfAfile(sockfd, bsdjob->np_cfAfile,
+ bsdjob->np_cfAfilename,
+ bsdjob->np_cfAfilesize)) != 0) {
+
+ (void) fprintf(stderr,
+ gettext("Netpr: Error sending control file\n"));
+ syslog(LOG_DEBUG, "Error sending control file");
+ return (NETWORK_ERROR_UNKNOWN);
+ }
+ }
+
+ return (0);
+}
+
+int
+xfer_file(int sockfd, caddr_t pa, int filesize, int seed)
+{
+ int ctr;
+ int timeout;
+ int nw;
+ int error_msg = 0;
+ int pause = 0;
+
+ syslog(LOG_DEBUG, "xfer_file");
+
+ /* send file */
+ ctr = filesize;
+ timeout = seed = seed ? seed : 10;
+
+ while (ctr > 0) {
+
+ syslog(LOG_DEBUG, "xfer_file: write while loop => ctr = %d", ctr);
+ syslog(LOG_DEBUG, "xfer_file: timeout = %d", timeout);
+
+ (void) signal(SIGALRM, null_sighandler);
+ (void) alarm(10);
+ nw = write(sockfd, pa, ctr);
+ syslog(LOG_DEBUG, "xfer_file: write while loop => nw = %d", nw);
+ (void) alarm(0);
+ if ((nw == 0) || (nw < 0)) {
+ if (timeout < (seed * 4)) {
+ (void) sleep(timeout);
+ timeout *= 2;
+ } else if (timeout == (seed * 4)) {
+ (void) sleep(timeout);
+ timeout *= 2;
+
+ /*
+ * Send message to user once
+ */
+ if (error_msg == 0) {
+ error_msg++;
+ tell_lptell(ERRORMSG,
+ gettext("Printer not accepting input;"
+ "possibly offline or out of paper."));
+ }
+
+ } else if (timeout > (seed * 4)) {
+ (void) sleep(timeout);
+ if (pause++ > 3)
+ timeout = (seed * 10);
+ }
+
+ } else {
+ ctr -= nw;
+ pa += nw;
+ if (error_msg) {
+ tell_lptell(OKMSG, "Current");
+ error_msg = 0;
+ pause = 0;
+ }
+ timeout = seed;
+ }
+ }
+
+ return (E_SUCCESS);
+}
+
+static int
+xfer_cfAfile(int sockfd, char * cfAfile, char * cfAname, uint size)
+{
+ int ctr;
+ caddr_t pa;
+ int nw = 0;
+ int timeout;
+ int printererr;
+
+ syslog(LOG_DEBUG, "xfer_cfAfile");
+
+ if ((netpr_send_message(sockfd, "%c%d %s\n", XFER_CONTROL,
+ size, cfAname)) != 0) {
+ return (NETWORK_ERROR_MSG_FAILED);
+ }
+
+ /* send the control file */
+ pa = cfAfile;
+ ctr = size;
+ syslog(LOG_DEBUG, "xfer_cfAfile : cfAfile %s", pa);
+ syslog(LOG_DEBUG, "xfer_cfAfile : size %d", size);
+
+ /* send control file */
+ timeout = TIMEOUT;
+ printererr = 0;
+ while (ctr > 0) {
+ (void) signal(SIGALRM, null_sighandler);
+ (void) alarm(2);
+ nw = write(sockfd, pa, size);
+ (void) alarm(0);
+ if (nw <= 0) {
+ if (timeout < 16) {
+ (void) sleep(timeout);
+ timeout *= 2;
+ } else if (timeout == 16) {
+ /* talk with the printer and see what's happening */
+ /* send message back to caller */
+ (void) sleep(timeout);
+ timeout *= 2;
+ printererr = 1;
+
+ tell_lptell(ERRORMSG,
+ gettext("Printer not accepting input;"
+ "possibly offline or out of paper."));
+
+ } else if (timeout > 16) {
+ (void) sleep(timeout);
+ }
+ }
+ ctr -= nw;
+ pa += nw;
+ }
+
+ if (printererr == 1) {
+ (void) fprintf(stderr, gettext("Printer status ok\n"));
+ tell_lptell(OKMSG, "Current");
+ }
+
+
+ /* send msg - done */
+ if (netpr_send_message(sockfd, "", NULL) != 0) {
+ return (NETWORK_ERROR_MSG_FAILED);
+ }
+
+ return (0);
+}
+
+/*
+ * netpr_response() reads in a byte from the network printer
+ */
+static int
+netpr_response(int nd)
+{
+ char c;
+ int msg_given = 0;
+ int firstloop = 0;
+
+ syslog(LOG_DEBUG, "netpr_response");
+
+ (void) signal(SIGALRM, null_sighandler);
+ (void) alarm(2);
+ while (1) {
+ errno = 0;
+ if ((read(nd, &c, 1) != 1)) {
+
+ if (firstloop == 0) {
+ (void) alarm(0);
+ firstloop++;
+ }
+
+ if (errno == EINTR) {
+ if (msg_given == 0) {
+ tell_lptell(ERRORMSG,
+ gettext("Printer not responding;"
+ "Either warming up or needs attention"));
+ msg_given++;
+ syslog(LOG_DEBUG,
+ "read hanging in netpr_response: %m");
+ }
+
+ } else {
+ syslog(LOG_DEBUG,
+ "read in netpr_response failed: %m");
+ return (NETWORK_READ_RESPONSE_FAILED);
+ }
+
+ } else {
+ if (c) {
+ syslog(LOG_DEBUG,
+ "Printer returned error: %m");
+ return (NETWORK_PRINTER_REFUSED_CONN);
+ } else {
+ if (msg_given)
+ tell_lptell(OKMSG, "Current");
+ return (0);
+ }
+ }
+ }
+
+}
+
+static int
+netpr_send_message(int nd, char *fmt, ...)
+{
+ char buf[BUFSIZ];
+ int ctr;
+ char * pa;
+ va_list ap;
+ int timeout = 1;
+ int nw;
+ int err_msg = 0;
+
+ syslog(LOG_DEBUG, "netpr_send_message");
+ va_start(ap, fmt);
+ (void) vsnprintf(buf, sizeof (buf), fmt, ap);
+ va_end(ap);
+
+ pa = buf;
+ ctr = (strlen(buf) != 0) ? strlen(buf) : 1;
+
+ syslog(LOG_DEBUG, "netpr_send_message : ctr = %d", ctr);
+ while (ctr > 0) {
+ (void) signal(SIGALRM, null_sighandler);
+ (void) alarm(2);
+ nw = write(nd, pa, ctr);
+ syslog(LOG_DEBUG, "netpr_send_message : nw = %d", nw);
+ (void) alarm(0);
+
+ if (nw <= 0) {
+ if (timeout < 16) {
+ (void) sleep(timeout);
+ timeout *= 2;
+ } else if (timeout == 16) {
+ (void) sleep(timeout);
+ timeout *= 2;
+ if (err_msg == 0) {
+ err_msg++;
+ tell_lptell(ERRORMSG,
+ gettext("Printer not accepting input;"
+ "possibly offline or out of paper."));
+ }
+ } else
+ (void) sleep(timeout);
+ } else {
+ ctr -= nw;
+ pa += nw;
+ if (err_msg)
+ tell_lptell(OKMSG, "Current");
+ }
+ }
+
+ return (netpr_response(nd));
+}
+
+/*
+ * null() is to be used as a signal handler that does nothing. It is used in
+ * place of SIG_IGN, because we want the signal to be delivered and
+ * interupt the current system call.
+ */
+/*ARGSUSED*/
+void
+null_sighandler(int i)
+{
+}
diff --git a/usr/src/cmd/lp/model/netpr/netdebug.h b/usr/src/cmd/lp/model/netpr/netdebug.h
new file mode 100644
index 0000000000..ed1d91e216
--- /dev/null
+++ b/usr/src/cmd/lp/model/netpr/netdebug.h
@@ -0,0 +1,51 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1996, by Sun Microsystems, Inc. */
+/* All rights reserved. */
+
+#ifndef _NETDEBUG_H
+#define _NETDEBUG_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MALLOC_ERR "aborting netpr: malloc returns NULL"
+#define REALLOC_ERR "aborting netpr: realloc returns NULL"
+
+#define ASSERT(expr, str) \
+{ \
+ if (!expr) { \
+ (void) fprintf(stderr, \
+ "%s: line %d %s\n", __FILE__, __LINE__, str); \
+ panic(); \
+ exit(E_RETRY); \
+ } \
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETDEBUG_H */
diff --git a/usr/src/cmd/lp/model/netpr/netpr.c b/usr/src/cmd/lp/model/netpr/netpr.c
new file mode 100644
index 0000000000..bdce543aa5
--- /dev/null
+++ b/usr/src/cmd/lp/model/netpr/netpr.c
@@ -0,0 +1,482 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <locale.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <sys/utsname.h>
+#include "netpr.h"
+
+
+static void usage_exit();
+
+static void pipehandler(int);
+char data_file_type = 0;
+
+/*
+ * null() is to be used as a signal handler that does nothing. It is used in
+ * place of SIG_IGN, because we want the signal to be delivered and
+ * interupt the current system call.
+ */
+static void
+null(int i)
+{
+ syslog(LOG_DEBUG, "null(%d)", i);
+}
+
+/*
+ * net_open() opens a tcp connection to the printer port on the host specified
+ * in the arguments passed in. If the connection is not made in the
+ * timeout (in seconds) passed in, an error it returned. If the host is
+ * unknown, an error is returned. If all is well, a file descriptor is
+ * returned to be used for future communications.
+ */
+int
+net_open(char *host, int timeout)
+{
+ struct hostent *hp;
+ struct servent *sp;
+ struct sockaddr_in6 sin;
+ void (*old_handler)();
+ static struct utsname uts;
+
+ int s,
+ lport,
+ err,
+ error_num;
+ unsigned timo = 1;
+
+ syslog(LOG_DEBUG, "net_open(%s, %d)", (host != NULL ? host : "NULL"),
+ timeout);
+ /*
+ * Get the host address and port number to connect to.
+ */
+ if (host == NULL) {
+ return (-1);
+ }
+
+ (void) memset((char *)&sin, NULL, sizeof (sin));
+ if ((hp = getipnodebyname(host, AF_INET6, AI_DEFAULT,
+ &error_num)) == NULL) {
+ syslog(LOG_DEBUG|LOG_ERR, "unknown host %s "
+ "getipnodebyname() returned %d", host, error_num);
+ return (NETWORK_ERROR_HOST);
+ }
+ (void) memcpy((caddr_t)&sin.sin6_addr, hp->h_addr, hp->h_length);
+ sin.sin6_family = hp->h_addrtype;
+ freehostent(hp);
+
+ if ((sp = getservbyname("printer", "tcp")) == NULL) {
+ syslog(LOG_DEBUG|LOG_ERR, "printer/tcp: unknown service");
+ return (NETWORK_ERROR_SERVICE);
+ }
+ sin.sin6_port = sp->s_port;
+
+retry:
+ /*
+ * Try connecting to the server.
+ *
+ * Use 0 as lport means that rresvport_af() will bind to a port in
+ * the anonymous privileged port range.
+ */
+ lport = 0;
+ s = rresvport_af(&lport, AF_INET6);
+ if (s < 0)
+ return (NETWORK_ERROR_PORT);
+
+ old_handler = signal(SIGALRM, null);
+ (void) alarm(timeout);
+ if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+ (void) alarm(0);
+ (void) signal(SIGALRM, old_handler);
+ err = errno;
+ (void) close(s);
+ errno = err;
+ if (errno == EADDRINUSE) {
+ goto retry;
+ }
+ /*
+ * If connecting to the local system fails, try
+ * again with "localhost" address instead.
+ */
+ if (uts.nodename[0] == '\0')
+ (void) uname(&uts);
+ if (strcmp(host, uts.nodename) == 0) {
+ IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_LOOPBACK),
+ &sin.sin6_addr);
+ sin.sin6_family = AF_INET6;
+ goto retry;
+ }
+ if (errno == ECONNREFUSED && timo <= 16) {
+ (void) sleep(timo);
+ timo *= 2;
+ goto retry;
+ }
+ return (NETWORK_ERROR_UNKNOWN);
+ }
+ (void) alarm(0);
+ (void) signal(SIGALRM, old_handler);
+ return (s);
+}
+
+int
+main(int argc, char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+ np_job_t *job_data;
+ char *destination = NULL;
+ np_bsdjob_t *bsdjob;
+ np_tcpjob_t *tcpjob;
+ int sockfd;
+ int pr_order = CONTROL_FIRST;
+ char *vendor_pr_name = NULL;
+ char *tcp_port = NULL;
+ size_t filesize;
+ int fd;
+ caddr_t pa;
+ int jobstatus;
+ int exit_status = 0;
+ int on = 1;
+
+
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ openlog("netpr", LOG_PID, LOG_LPR);
+ (void) signal(SIGPIPE, pipehandler);
+
+ /* reduce privileges until needed to open reserved port */
+ if (seteuid(getuid())) {
+ syslog(LOG_DEBUG, "seteuid failed, exiting netpr");
+ exit(E_FAILURE);
+ }
+
+ if ((job_data = init_job()) == NULL) {
+ fprintf(stderr, gettext("init_job(): out of memory\n"));
+ exit(E_RETRY);
+ }
+
+ while ((opt = getopt(argc, argv, "f:I:p:d:T:P:t:U:c:b")) != EOF)
+ switch (opt) {
+ case 'f':
+ data_file_type = optarg[0];
+ break;
+ case 'I': /* foo-49 */
+ job_data->request_id = alloc_str((char *)optarg);
+ syslog(LOG_DEBUG, "request_id: %s",
+ job_data->request_id);
+ break;
+ case 'U': /* awe172-126!wendyp */
+ job_data->username = alloc_str((char *)optarg);
+ syslog(LOG_DEBUG, "username: %s",
+ job_data->username);
+ break;
+ case 'p': /* foo */
+ job_data->printer = alloc_str((char *)optarg);
+ syslog(LOG_DEBUG, "printer: %s",
+ job_data->printer);
+ break;
+ case 'd': /* server for printer */
+ job_data->dest = alloc_str((char *)optarg);
+ syslog(LOG_DEBUG, "dest: %s",
+ job_data->dest);
+ break;
+ case 'T': /* /tmp/file2 */
+ job_data->title = alloc_str((char *)optarg);
+ syslog(LOG_DEBUG, "title: %s",
+ job_data->title);
+ break;
+ case 'P':
+ if ((strcmp(optarg, "bsd")) == 0)
+ job_data->protocol = BSD;
+ else if ((strcmp(optarg, "tcp")) == 0)
+ job_data->protocol = TCP;
+ else
+ usage_exit();
+
+ syslog(LOG_DEBUG, "protocol: %d",
+ job_data->protocol);
+ break;
+ case 't':
+ job_data->timeout = atoi(optarg);
+ if (job_data->timeout < 0)
+ usage_exit();
+ break;
+ case 'c':
+ if ((strcmp(optarg, "first")) == 0)
+ pr_order = CONTROL_FIRST;
+ else if ((strcmp(optarg, "last")) == 0)
+ pr_order = DATA_FIRST;
+ else
+ usage_exit();
+
+ syslog(LOG_DEBUG, "bsd print order: %d", pr_order);
+ break;
+ case 'b':
+ job_data->banner = NOBANNER;
+ syslog(LOG_DEBUG, "banner : %d",
+ job_data->banner);
+ break;
+ case '?':
+ usage_exit();
+ }
+
+
+ if ((job_data->dest == NULL) || (job_data->request_id == NULL) ||
+ (job_data->printer == NULL) || (job_data->username == NULL))
+ usage_exit();
+
+ /*
+ * Check that there is a file
+ */
+ if (optind == argc) {
+ usage_exit();
+ }
+
+ job_data->filename = alloc_str(argv[optind]);
+ syslog(LOG_DEBUG, "filename : %s", job_data->filename);
+
+
+ /*
+ * Sanity check the file
+ * returns filesize
+ */
+
+ if ((filesize = check_file(job_data->filename)) == -1) {
+ syslog(LOG_DEBUG, "Skipping file %s",
+ job_data->filename ? job_data->filename : "Error NULL file");
+
+ switch (errno) {
+ case EISDIR:
+ (void) fprintf(stderr,
+ gettext("Netpr: %s: Not a regular file\n"),
+ (job_data->filename ? job_data->filename : "Noname"));
+ syslog(LOG_DEBUG, "Not a regular file");
+ break;
+ case ESRCH:
+ (void) fprintf(stderr,
+ gettext("Netpr: %s: Empty file\n"),
+ (job_data->filename ? job_data->filename : "Noname"));
+ syslog(LOG_DEBUG, "Empty file");
+ break;
+ default:
+ perror(job_data->filename);
+ (void) fprintf(stderr,
+ gettext("Netpr: Cannot access file %s\n"),
+ (job_data->filename ? job_data->filename : "Noname"));
+ syslog(LOG_DEBUG, "Cannot access file.");
+ break;
+
+ }
+
+ /*
+ * This file not valid, so bail
+ * Exit with zero so system will keep printing
+ */
+ exit(0);
+ }
+
+ /*
+ * file looks ok, open and mmap it
+ */
+ if ((fd = open(job_data->filename, O_RDONLY)) < 0) {
+ (void) fprintf(stderr, gettext("Netpr: Cannot open file %s\n"),
+ (job_data->filename ? job_data->filename : "Error: NULL file"));
+ syslog(LOG_DEBUG, "Cannot open file: %s",
+ job_data->filename ? job_data->filename : "Error NULL file");
+ exit(E_BAD_FILE);
+ }
+
+ if ((pa = mmap((caddr_t)0, filesize, PROT_READ,
+ (MAP_SHARED | MAP_NORESERVE), fd, (off_t)0)) == MAP_FAILED) {
+
+ (void) close(fd);
+ (void) fprintf(stderr, gettext("Netpr: Cannot mmap file %s"),
+ (job_data->filename ? job_data->filename : "Error: NULL file"));
+
+ syslog(LOG_DEBUG, "Cannot mmap file: %s",
+ job_data->filename ? job_data->filename : "Error NULL file");
+
+ exit(E_RETRY);
+ }
+
+
+ if (job_data->protocol == BSD) {
+ bsdjob = (np_bsdjob_t *)
+ create_bsd_job(job_data, pr_order, filesize);
+ if (bsdjob == NULL)
+ exit(E_FAILURE);
+ } else {
+ tcpjob = (np_tcpjob_t *)create_tcp_job(job_data, filesize);
+ if (tcpjob == NULL)
+ exit(E_FAILURE);
+ }
+
+ /*
+ * Parse destination
+ */
+
+ if ((strpbrk(job_data->dest, DEST_SEP)) != NULL) {
+ if (job_data->protocol == BSD) {
+ parse_dest(job_data->dest, &destination,
+ &vendor_pr_name, DEST_SEP);
+ if (vendor_pr_name != NULL) {
+ bsdjob->np_printer = vendor_pr_name;
+ syslog(LOG_DEBUG, "bsd vendor name: %s",
+ bsdjob->np_printer);
+ }
+ } else {
+ parse_dest(job_data->dest, &destination, &tcp_port,
+ DEST_SEP);
+ if (tcp_port != NULL)
+ tcpjob->np_port = tcp_port;
+ syslog(LOG_DEBUG, "tcp_port %s",
+ tcpjob->np_port);
+ }
+ if (destination == NULL ||
+ (job_data->protocol == TCP && tcp_port == NULL)) {
+ (void) fprintf(stderr,
+ gettext("Netpr: system error parsing destination %s\n"),
+ job_data->dest);
+ syslog(LOG_DEBUG, "system error parsing destination %s",
+ job_data->dest);
+
+ exit(E_FAILURE);
+ }
+
+ } else {
+ destination = job_data->dest;
+ }
+ syslog(LOG_DEBUG, "destination : %s", destination);
+
+ /*
+ * We are now ready to open a connection to the printer
+ * and print each of the files
+ */
+
+ if (job_data->protocol == BSD) {
+
+ /* set privileges to get reserved port */
+ if (seteuid(0)) {
+ syslog(LOG_DEBUG, "seteuid(0) failed, exiting netpr");
+ exit(E_FAILURE);
+ }
+ if ((sockfd = net_open(destination, 20)) < 0) {
+ (void) fprintf(stderr,
+ gettext("Netpr: Cannot open connection to <%s>\n"),
+ destination);
+ syslog(LOG_DEBUG,
+ "Cannot open connection to %s: retrying",
+ destination);
+ exit(E_RETRY);
+ }
+ } else {
+ if ((sockfd = tcp_open(destination, tcpjob, 20)) == -1) {
+ exit(E_RETRY);
+ }
+ }
+
+ /* lower privileges as we now have the reserved port */
+ if (setuid(getuid())) {
+ syslog(LOG_DEBUG, "setuid() failed, exiting netpr");
+ exit(E_FAILURE);
+ }
+
+
+ /* Set SO_KEEPALIVE on socket to keep open */
+ if ((setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof (on))) < 0) {
+ syslog(LOG_DEBUG, "setsocket (SO_KEEPALIVE): %m");
+ }
+
+ if (job_data->protocol == BSD) {
+ if ((jobstatus = bsd_print(sockfd, pa, bsdjob)) != 0) {
+ (void) fprintf(stderr,
+ gettext("Netpr: Error return from bsd_print <%d>\n"),
+ jobstatus);
+ syslog(LOG_DEBUG,
+ "Error return from bsd_print <%d>", jobstatus);
+ exit_status = E_RETRY;
+ }
+ } else {
+ if ((jobstatus =
+ tcp_print(sockfd, pa, tcpjob)) != 0) {
+ (void) fprintf(stderr,
+ gettext("Netpr: Error return from tcp_print <%d>\n"),
+ jobstatus);
+ syslog(LOG_DEBUG,
+ "Error return from tcp_print <%d>", jobstatus);
+ exit_status = E_RETRY;
+ }
+ }
+
+ (void) close(fd);
+ (void) close(sockfd);
+ (void) munmap(pa, filesize);
+
+ syslog(LOG_DEBUG, "exit status: %d", exit_status);
+ return (exit_status);
+}
+
+static void
+usage_exit()
+{
+ (void) fprintf(stderr,
+ gettext("Usage: netpr -I request_id -p printer -d destination\n"));
+ (void) fprintf(stderr,
+ gettext("\t\t-U username [ -f type ] [ -T title ] [ -P protocol ]\n"));
+ (void) fprintf(stderr,
+ gettext("\t\t[-t timeout] [ -c ] [ -b ]\n"));
+ (void) fprintf(stderr, gettext("\t\tfiles\n"));
+ exit(E_BAD_INPUT);
+}
+
+/*ARGSUSED*/
+void
+pipehandler(int i)
+{
+ (void) signal(SIGPIPE, pipehandler);
+ syslog(LOG_DEBUG, "Received SIGPIPE, connection to printer broken");
+ exit(E_SIGPIPE);
+}
diff --git a/usr/src/cmd/lp/model/netpr/netpr.h b/usr/src/cmd/lp/model/netpr/netpr.h
new file mode 100644
index 0000000000..f155690a3c
--- /dev/null
+++ b/usr/src/cmd/lp/model/netpr/netpr.h
@@ -0,0 +1,174 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NETPR_H
+#define _NETPR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BSD 0
+#define TCP 1
+#define NOBANNER 0
+#define BANNER 1
+
+#define CONTROL_FIRST 0
+#define DATA_FIRST 1
+
+#define ERRORMSG 0
+#define OKMSG 1
+
+#define DEST_SEP ":"
+
+#define MAX_REQ_ID 3
+
+#define ASCII_UULONG_MAX 22
+
+#define XFER_REQUEST 2 /* \2printer\n */
+#define XFER_CLEANUP 1 /* \1 */
+#define XFER_CONTROL 2 /* \2size name\n */
+#define XFER_DATA 3 /* \3size name\n */
+#define PRINT_REQUEST 1 /* \1printer\n */
+#define REMOVE_REQUEST 5 /* \5printer person [users|jobs ...]\n */
+#define SHOW_QUEUE_SHORT_REQUEST 3 /* \3printer [users|jobs ...]\n */
+#define SHOW_QUEUE_LONG_REQUEST 4 /* \4printer [users|jobs ...]\n */
+
+
+#define E_SUCCESS 0
+#define E_FAILURE 1
+#define E_SYSTEM_ERROR 2
+#define E_BAD_FILE 3
+#define E_BAD_INPUT 4
+#define E_SYSTEM_ERR 5
+#define E_SEND_OK 6
+#define E_RETRY 129
+#define E_SIGPIPE 130
+
+
+#define NETWORK_ERROR_UNKNOWN 20
+#define NETWORK_ERROR_HOST 21
+#define NETWORK_ERROR_SERVICE 22
+#define NETWORK_ERROR_PORT 23
+#define NETWORK_ERROR_SEND_RESPONSE 24
+#define NETWORK_ERROR_SEND_FAILED 25
+#define NETWORK_ERROR_MSG_FAILED 26
+#define NETWORK_ERROR_WRITE_FAILED 27
+#define NETWORK_PRINTER_REFUSED_CONN 28
+#define NETWORK_READ_RESPONSE_FAILED 29
+
+
+#define MALLOC (int size, char * msg) \
+ { \
+ printf("File %s line %d\n", __FILE__, __LINE__); \
+ printf("malloc: size: <%d>, for <%s>\n"); \
+ malloc(size); \
+ }
+
+
+typedef struct np_data np_data_t;
+typedef struct np_bsdjob np_bsdjob_t;
+typedef struct job np_job_t;
+typedef struct np_tcp_job np_tcpjob_t;
+
+/*
+ * Contains the input data for this job.
+ * Data is independent of protocol
+ */
+
+struct job {
+ char *filename;
+ char *request_id;
+ char *printer;
+ char *dest;
+ char *title;
+ int protocol;
+ char *username;
+ int timeout;
+ int banner;
+ int filesize;
+};
+
+struct np_tcp_job {
+ np_job_t * gen_data;
+ char * np_port;
+ char * np_host;
+};
+
+struct np_data {
+ char *np_dfAfilename;
+ char *np_path_file; /* /<path>/<filename> we are printing */
+ long np_data_size; /* using stat, XXX mmap better?? */
+ char *jobfile_data;
+};
+
+
+struct np_bsdjob {
+ char *np_filename;
+ char *np_request_id;
+ char *np_printer;
+ char *np_destination;
+ char *np_title;
+ char *np_username;
+ int np_timeout;
+ int np_banner;
+ char *np_host;
+ int np_print_order;
+ char *np_cfAfilename;
+ char *np_cfAfile;
+ uint np_cfAfilesize;
+ char np_df_letter; /* [A-Z][a-z] use this one */
+ np_data_t *np_data;
+};
+
+extern char * long2str(long, char *);
+extern void null_sighandler(int);
+extern int open_network(char *, int);
+extern int xfer_file(int, caddr_t, int, int);
+extern int add_bsd_file(char *, np_bsdjob_t *);
+extern int start_bsd_job(int, char *);
+extern void done_and_close(int);
+extern void panic();
+extern char * alloc_str(char *);
+extern np_bsdjob_t * create_bsd_job(np_job_t *, int, int);
+extern np_tcpjob_t * create_tcp_job(np_job_t *, int);
+extern int net_send_cmd(int, char *, ...);
+extern np_job_t * init_job(void);
+extern int bsd_print(int, caddr_t, np_bsdjob_t *);
+extern int tcp_print(int, caddr_t, np_tcpjob_t *);
+extern int tcp_open(char *, np_tcpjob_t *, int);
+extern void tell_lptell(int, char *, ...);
+extern int net_open(char *, int);
+extern void parse_dest(char *, char **, char **, char *);
+extern int check_file(char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETPR_H */
diff --git a/usr/src/cmd/lp/model/netpr/tcp_misc.c b/usr/src/cmd/lp/model/netpr/tcp_misc.c
new file mode 100644
index 0000000000..8412550d4d
--- /dev/null
+++ b/usr/src/cmd/lp/model/netpr/tcp_misc.c
@@ -0,0 +1,208 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include "netpr.h"
+#include "netdebug.h"
+
+#define MAX_NLPS 60 /* Max no. loops in while */
+
+np_tcpjob_t *
+create_tcp_job(np_job_t *genjob, int filesize)
+{
+ np_tcpjob_t *tcpjob;
+
+ if (genjob == NULL)
+ return (NULL);
+
+ tcpjob = (np_tcpjob_t *)malloc(sizeof (np_tcpjob_t));
+ ASSERT(tcpjob, MALLOC_ERR);
+ (void) memset(tcpjob, 0, sizeof (np_tcpjob_t));
+
+ tcpjob->np_port = "9100";
+ tcpjob->gen_data = genjob;
+ tcpjob->gen_data->filesize = filesize;
+
+ return (tcpjob);
+}
+
+int
+tcp_open(char *dest, np_tcpjob_t *tcpjob, int timeout)
+{
+ struct hostent *hp;
+ struct sockaddr_in6 serv_addr;
+ int s,
+ err,
+ error_num;
+ unsigned timo = 1;
+ int retry;
+ int rtnerr;
+
+ /*
+ * Get the host address and port number to connect to.
+ */
+ if (dest == NULL) {
+ return (-1);
+ }
+
+ if ((hp = (getipnodebyname(dest, AF_INET6, AI_DEFAULT,
+ &error_num))) == NULL) {
+ (void) fprintf(stderr,
+ gettext("Netpr: System call getipnodebyname fails\n"));
+ syslog(LOG_DEBUG, "System call getipnodebyname fails "
+ "getipnodebyname() returned %d", error_num);
+ return (-1);
+ }
+
+ (void) memset(&serv_addr, 0, sizeof (struct sockaddr_in6));
+ bcopy(hp->h_addr, (caddr_t)&serv_addr.sin6_addr, hp->h_length);
+ serv_addr.sin6_family = hp->h_addrtype;
+ serv_addr.sin6_port = (int)htons(atoi(tcpjob->np_port));
+
+ do {
+
+ retry = 0;
+ rtnerr = 0;
+ /*
+ * Try connecting to the printer.
+ */
+ s = socket(PF_INET6, SOCK_STREAM, 0);
+ if (s < 0) {
+ (void) fprintf(stderr,
+ gettext("Netpr: System call socket fails\n"));
+ syslog(LOG_DEBUG, "System call socket fails");
+ rtnerr = -1;
+ } else {
+ (void) signal(SIGALRM, null_sighandler);
+ (void) alarm(timeout);
+ if (connect(s, (struct sockaddr *)&serv_addr,
+ sizeof (serv_addr)) < 0) {
+ err = errno;
+ (void) alarm(0);
+ errno = err;
+
+ if (errno == ECONNREFUSED && timo <= 16) {
+ (void) sleep(timo);
+ timo *= 2;
+ retry++;
+ } else {
+ (void) fprintf(stderr,
+ gettext("Netpr: Cannot connect to printer\n"));
+ syslog(LOG_DEBUG, "Cannot connect to printer");
+ rtnerr = -1;
+ }
+ /* The connect on this socket failed; close it */
+ (void) close(s);
+ } else
+ (void) alarm(0);
+ }
+
+ } while (retry);
+
+ return ((rtnerr) ? rtnerr : s);
+}
+
+
+int
+tcp_print(int sockfd, caddr_t pa, np_tcpjob_t *tcpjob)
+{
+ char c;
+ int xfer;
+ char buf[BUFSIZ + 1];
+ int nr = 0;
+ int ctr = 0;
+ int msg_given = 0;
+ int nlps = 0;
+
+ if ((xfer = xfer_file(sockfd, pa,
+ tcpjob->gen_data->filesize, tcpjob->gen_data->timeout)) < 0) {
+ return (xfer);
+ }
+
+ if ((shutdown(sockfd, 1)) != 0) {
+ (void) fprintf(stderr,
+ gettext("Netpr: System error: possible loss of data\n"));
+ syslog(LOG_DEBUG,
+ "shutdown error; possible loss of data");
+ return (E_SYSTEM_ERROR);
+ }
+
+
+ /* read in single character ack or msg from printer */
+
+ (void) memset(buf, 0, BUFSIZ + 1);
+ while (ctr < BUFSIZ) {
+ (void) signal(SIGALRM, null_sighandler);
+ (void) alarm(2);
+ errno = 0;
+ nr = read(sockfd, &c, 1);
+ (void) alarm(0);
+ if (errno == EINTR) {
+ if (msg_given == 0) {
+ tell_lptell(ERRORMSG,
+ gettext("Printer not responding;" \
+ "Either warming up or needs attention\n"));
+ msg_given++;
+ }
+
+ /* if no ACK received, do not loop forever */
+
+ if (nlps++ >= MAX_NLPS) {
+ syslog(LOG_DEBUG, "No final ack received");
+ break;
+ }
+ } else {
+ if ((buf[ctr++] = c) == '\n' || (nr == 0))
+ break;
+ }
+ }
+ if (ctr > 1)
+ syslog(LOG_DEBUG, "Message from tcp printer on read: %s",
+ buf);
+
+ if (msg_given && (nlps < MAX_NLPS)) {
+ (void) fprintf(stderr, gettext("Printer ok\n"));
+ tell_lptell(OKMSG, "Current");
+ }
+
+ return (E_SUCCESS);
+}
diff --git a/usr/src/cmd/lp/model/netstandard b/usr/src/cmd/lp/model/netstandard
new file mode 100644
index 0000000000..0b428fdcd4
--- /dev/null
+++ b/usr/src/cmd/lp/model/netstandard
@@ -0,0 +1,644 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+###########
+##
+## Network Standard printer interface program.
+##
+###########
+
+#####
+# We can't do much except exit if spooler/scheduler
+# cancels us.
+#####
+trap 'eval exit_clean 15' 15
+
+####
+#
+# Send standard error messages to /dev/null rather than to
+# the spooler. Avoids "Terminated" messages that shell puts out
+# when gets SIGTERM. Save standard error so it can be used
+# when we need it
+####
+exec 5>&2 2>/dev/null 3>&1
+
+####
+# set some global variables
+####
+
+: ${LPTMPDIR:=/tmp}
+: ${SPOOLDIR:=/usr/spool/lp}
+: ${LOCALPATH:=${SPOOLDIR}/bin}
+PATH="/bin:/usr/bin:${LOCALPATH}"
+exit_code=0
+
+
+# ${LPTELL} is the name of a program that will send its
+# standard input to the Spooler. It is used to forward
+# the description of a printer fault to the Spooler,
+# which uses it in an alert to the administrator.
+#####
+if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ]
+then
+ fake_lptell () {
+ header="no"
+ while read line
+ do
+ if [ "no" = "${header}" ]
+ then
+ errmsg ERROR ${E_IP_UNKNOWN} \
+ "unknown printer/interface failure" \
+ "consult your system administrator;
+ reasons for failure (if any) follow:"
+ header=yes
+ fi
+ echo "${line}" >&2
+ done
+ return 1
+ }
+ LPTELL=fake_lptell
+fi
+
+#####
+# Error message formatter:
+#
+# Invoke as
+#
+# errmsg severity message-number problem help
+#
+# where severity is "ERROR" or "WARNING", message-number is
+# a unique identifier, problem is a short description of the
+# problem, and help is a short suggestion for fixing the problem.
+#####
+
+LP_ERR_LABEL="UX:lp"
+E_IP_ARGS=1
+E_IP_OPTS=2
+#E_IP_FILTER=3
+E_IP_UNKNOWN=5
+E_IP_BADFILE=6
+E_IP_ERRORS=12 # (in slow.filter)
+
+errmsg () {
+
+ case $1 in
+ ERROR )
+ sev=" ERROR";
+ ;;
+ WARNING )
+ sev="WARNING";
+ ;;
+ esac
+
+ echo "${LP_ERR_LABEL}:$2 ${sev}: $3
+ TO FIX: $4" >&5
+}
+
+###########
+##
+## Check arguments
+###########
+
+parse () {
+ echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
+}
+
+#####
+##
+## Error Cleanup and Exit
+##
+#####
+
+exit_clean()
+{
+
+ if [ -f "${LPTMPDIR}/pr_eexit_code.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/pr_eexit_code.$$
+ fi
+
+ if [ -f "${LPTMPDIR}/small_banner.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/small_banner.$$
+ fi
+
+ if [ -f "${tmpfile}" ]
+ then
+ /bin/rm "${tmpfile}"
+ fi
+
+ exit $1
+}
+
+#####
+#
+# This program is invoked as
+#
+# ${SPOOLDIR}/.../printer request-id user title copies options files...
+#
+# The first three arguments are simply reprinted on the banner page,
+# the fourth (copies) is used to control the number of copies to print,
+# the fifth (options) is a blank separated list (in a single argument)
+# of user or Spooler supplied options (without the -o prefix),
+# and the last arguments are the files to print.
+#####
+
+if [ $# -lt 5 ]
+then
+
+ errmsg ERROR ${E_IP_ARGS} \
+ "wrong number of arguments to interface program" \
+ "consult your system administrator"
+ exit 1
+fi
+
+printer=`basename $0`
+request_id=$1
+user_name=$2
+title=$3
+copies=$4
+option_list=$5
+
+shift 5
+files="$*"
+
+
+#
+# debug sent to file if defined in /etc/syslog.conf
+# syslog.conf entry:
+# lpr.debug /path/filename
+#
+logger -p lpr.debug -t "netstandard: ${request_id}" " "
+logger -p lpr.debug -t "netstandard: ${request_id}" "INPUT"
+logger -p lpr.debug -t "netstandard: ${request_id}" " printer : ${printer}"
+logger -p lpr.debug -t "netstandard: ${request_id}" " request_id : ${request_id}"
+logger -p lpr.debug -t "netstandard: ${request_id}" " user_name : ${user_name}"
+logger -p lpr.debug -t "netstandard: ${request_id}" " title : ${title}"
+logger -p lpr.debug -t "netstandard: ${request_id}" " copies : ${copies}"
+logger -p lpr.debug -t "netstandard: ${request_id}" " option_list : ${option_list}"
+logger -p lpr.debug -t "netstandard: ${request_id}" " files : ${files}"
+logger -p lpr.debug -t "netstandard: ${request_id}" " spooler_key ${SPOOLER_KEY}"
+
+####
+# default: do print a banner
+####
+nobanner=no
+nofilebreak="no"
+inlist=
+data_file_flag=
+
+for i in ${option_list}
+do
+ case "${inlist}${i}" in
+
+ nobanner )
+ nobanner="yes"
+ ;;
+
+ nofilebreak )
+ nofilebreak="yes"
+ ;;
+
+ #####
+ #
+ # If you want to add simple options (e.g. -o simple)
+ # identify them here.
+ #####
+# simple )
+# simple="yes"
+# ;;
+
+ cpi=pica )
+ cpi=10
+ ;;
+ cpi=elite )
+ cpi=12
+ ;;
+ cpi=* )
+ cpi=`parse ${i}`
+ ;;
+
+ lpi=* )
+ lpi=`parse ${i}`
+ ;;
+
+ length=* )
+ length=`parse ${i}`
+ ;;
+
+ width=* )
+ width=`parse ${i}`
+ ;;
+ dest=* )
+ dest="-d `parse ${i}`"
+ ;;
+
+ protocol=* )
+ protocol="-P `parse ${i}`"
+ ;;
+ bsdctrl=* )
+ controlfile="-c `parse ${i}`"
+ ;;
+ timeout=* )
+ timeout="-t `parse ${i}`"
+ ;;
+
+ data-file-type=* )
+ data_file_flag="-f `parse ${i}`"
+ ;;
+
+ #####
+ #
+ # If you want to add simple-value options (e.g. -o value=a)
+ # identify them here.
+ #####
+# value=* )
+# value=`parse ${i}`
+# ;;
+
+ #####
+ #
+ # If you want to add options that,
+ # take a list (e.g. -o lopt='a b c'), identif
+ # them here and below (look for LOPT).
+ #####
+
+# flist=* | lpd=* | options=* )
+ flist=* | lpd=* )
+#LOPT stty=* | flist=* | lpd=* | lopt=* )
+
+ inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"`
+ case "${i}" in
+ ${inlist}\'*\' )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"`
+ ;;
+ ${inlist}\' )
+ continue
+ ;;
+ ${inlist}\'* )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)\$"`
+ ;;
+ ${inlist}* )
+ item=`expr "${i}" : "^[^=]*=\(.*\)\$"`
+ ;;
+ *\' )
+ item=`expr "${i}" : "^\(.*\)'\$"`
+ ;;
+ * )
+ item="${i}"
+ ;;
+ esac
+
+ #####
+ #
+ # We don't dare use "eval" because a clever user could
+ # put something in an option value that we'd end up
+ # exec'ing.
+ #####
+ case "${inlist}" in
+ flist= )
+ flist="${flist} ${item}"
+ ;;
+ lpd= )
+ lpd="${lpd} ${item}"
+ ;;
+#LOPT lopt= )
+#LOPT lopt="${lopt} ${item}"
+#LOPT ;;
+# options= )
+# options="${options} ${item}"
+# ;;
+ esac
+
+ case "${i}" in
+ ${inlist}\'*\' )
+ inlist=
+ ;;
+ ${inlist}\'* )
+ ;;
+ *\' | ${inlist}* )
+ inlist=
+ ;;
+ esac
+ ;;
+
+ * )
+ errmsg WARNING ${E_IP_OPTS} \
+ "unrecognized \"-o ${i}\" option" \
+ "check the option, resubmit if necessary
+ printing continues"
+ ;;
+ esac
+done
+
+logger -p lpr.debug -t "netstandard: ${request_id}" "term : ${TERM}"
+
+if [ -z "${FILTER}" ]
+then
+ #####
+ #
+ # If no filter is being used, we use netpr to push the
+ # file to the printer.
+ # (QUOTES ARE IMPORTANT!)
+ #####
+
+ case "$TERM" in
+ PS )
+ # make the "postscript" printers use netpr
+ FILTER=
+ ;;
+ PSR )
+ # make the "reverse postscript" printers reverse the
+ # output and the use postio to talk to the printer
+ #FILTER="/usr/lib/lp/postscript/postreverse "
+ #FILTER=
+ FILTER="/usr/lib/lp/postscript/postreverse "
+ ;;
+ * )
+ # We don't know the type, so just assume that the
+ # input and output are the same. Use netpr.
+ #FILTER=/bin/cat
+ FILTER=
+ ;;
+ esac
+fi
+
+####
+# sets default value for ordering of data and control files with
+# bsd protocol. Default: data files first. Administrator
+# may set to control file first with lpadmin -o bsdctrl=first
+####
+
+banner_flag=""
+case "${nobanner}" in
+ yes )
+ banner_flag="-b"
+ ;;
+esac
+
+NETPR="/usr/lib/lp/bin/netpr ${banner_flag} ${data_file_flag} \
+ -I ${request_id} -U ${user_name} \
+ -p ${printer} ${dest} -T \"${title}\" \
+ ${timeout} ${protocol} ${controlfile} "
+LPTELL_OPTS="-l" # netpr sends LaserWriter style messages back
+
+logger -p lpr.debug -t "netstandard: ${request_id}" "NETPR= ${NETPR}"
+logger -p lpr.debug -t "netstandard: ${request_id}" "filter : ${FILTER}"
+
+node=`uname -n`
+pid=$$
+tmpfile=${LPTMPDIR}/${node}.${pid}
+
+logger -p lpr.debug -t "netstandard: ${request_id}" "tmpfile : ${tmpfile}"
+
+#####
+#
+# Set up filter for banner page
+#
+#####
+banner_filter=
+case "${TERM}" in
+PS | PSR )
+ banner_filter=" | /usr/lib/lp/postscript/postprint "
+ LPTELL_OPTS="-l"
+ ;;
+esac
+
+#####
+#
+# Build temporary file that is the banner page
+#
+#####
+PAD="#####${NL}"
+CR="\r"
+NL="${CR}\n"
+FF=
+
+small_banner() {
+ echo "${CR}\c"
+ echo "${PAD}\c"
+ echo "##### User: ${user_name}${NL}\c"
+ if [ -n "${title}" ]
+ then
+ echo "##### Title: ${title}${NL}\c"
+ fi
+ echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c"
+ echo "##### Job: ${request_id}${NL}\c"
+ echo "${PAD}\c"
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+#####
+#
+# Doing small banner as we don't know what printer is out there
+#
+#####
+banner=small_banner
+
+if [ "no" = "${nobanner}" ]
+then
+ eval "${banner} ${banner_filter}" 2>&1 1>${LPTMPDIR}/small_banner.$$
+fi
+
+#####
+#
+# Print banner page before job unless PSR
+#
+#####
+
+
+if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" ]
+then
+ (
+ eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug -t "netstandard: ${request_id}" \
+ "banner page exit code : ${exit_code}"
+
+fi
+
+i=1
+while [ $i -le $copies ]
+do
+ for file in ${files}
+ do
+ if [ -r "${file}" ]
+ then
+
+ if [ ! -z "${FILTER}" ]
+ then
+ (
+ #####
+ # There is a filter, use it
+ #
+ # Put 0<${file} before the "eval" to keep
+ # clever users from giving a file name that
+ # evaluates as something to execute.
+ # Redirect stderr to stdout so LPTELL will
+ # get error messages from pipe.
+ #####
+
+ 0<${file} eval ${FILTER} 2>&1 1>${tmpfile}
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug -t "netstandard: ${request_id}" \
+ "filter exit_code : ${exit_code}"
+
+ if [ -n "${exit_code}" ]
+ then
+ if [ "${exit_code}" -eq 0 ]
+ then
+ printfile=${tmpfile}
+ else
+ ####
+ # The filter did not succeed, so don't try to print
+ ####
+ printfile=
+ fi
+ fi
+
+ else
+ printfile=${file}
+ fi
+
+ logger -p lpr.debug -t "netstandard: ${request_id}" \
+ "printfile : ${printfile}"
+
+ #####
+ # Print the file
+ #####
+
+ if [ -r "${printfile}" ]
+ then
+ (
+ eval ${NETPR} ${printfile} 2>&1
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug -t "netstandard: ${request_id}" \
+ "netpr exit_code : ${exit_code}"
+
+ if [ -f "${tmpfile}" ]
+ then
+ /bin/rm "${tmpfile}"
+ fi
+
+ if [ -n "${exit_code}" ]
+ then
+ if [ "${exit_code}" -eq 0 ]
+ then
+ printone=yes
+ else
+ if [ "${exit_code}" -lt 128 ]
+ then
+ noprint=yes
+ else
+ retry=yes
+ fi
+ fi
+ fi
+
+
+ else
+
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read temporary file \"${printfile}\""\
+ "see if file still exists,
+ or consult your system administrator;
+ printing continues"
+
+ fi
+ else
+
+ #####
+ #
+ # Don't complain about not being able to read
+ # a file on second and subsequent copies, unless
+ # we've not complained yet. This removes repeated
+ # messages about the same file yet reduces the
+ # chance that the user can remove a file and not
+ # know that we had trouble finding it.
+ #####
+
+ if [ "${i}" -le 1 -o -z "${badfileyet}" ]
+ then
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read file \"${file}\"" \
+ "see if the file still exists and is readable,
+ or consult your system administrator;
+ printing continues"
+ badfileyet=yes
+ fi
+
+ fi
+
+# for file in ${files}
+ done
+ i=`expr $i + 1`
+done
+
+#####
+#
+# If printing in reverse order, print the banner page now
+#
+#####
+
+if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ]
+then
+(
+ eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+fi
+
+exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+logger -p lpr.debug -t "netstandard: ${request_id}" \
+ "banner page exit code : ${exit_code}"
+
+if [ -n "${printone}" -a -z "${retry}" -a -z "${noprint}" ]
+then
+ exit_code=`expr 0`
+else
+ if [ -n "${retry}" -a -z "${printone}" -a -z "${noprint}" ]
+ then
+ exit_code=`expr 129`
+ else
+ exit_code=`expr 1`
+ fi
+fi
+
+logger -p lpr.debug -t "netstandard: ${request_id}" \
+ "FINAL exit_code : ${exit_code}"
+
+exit_clean ${exit_code}
diff --git a/usr/src/cmd/lp/model/standard b/usr/src/cmd/lp/model/standard
new file mode 100644
index 0000000000..5823de6d6e
--- /dev/null
+++ b/usr/src/cmd/lp/model/standard
@@ -0,0 +1,1078 @@
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.26 */
+
+###########
+##
+## Standard printer interface program.
+###########
+
+#####
+#
+# Until we get to the point below where the printer port
+# and physical printer are initialized, we can't do much
+# except exit if the Spooler/Scheduler cancels us.
+#####
+trap 'exit' 15
+
+#####
+#
+# We can be clever about getting a hangup or interrupt, though, at least
+# until the filter runs. Do this early, even though $LPTELL
+# isn't defined, so that we're covered.
+#####
+catch_hangup () {
+ if [ -n "${LPTELL}" ]
+ then
+ echo \
+"The connection to the printer dropped; perhaps the printer went off-line?" \
+ | ${LPTELL} ${printer}
+ fi
+ return 0
+}
+catch_interrupt () {
+ if [ -n "${LPTELL}" ]
+ then
+ echo \
+"Received an interrupt from the printer. The reason is unknown,
+although a common cause is that the baud rate is too high." \
+ | ${LPTELL} ${printer}
+ fi
+ return 0
+}
+trap 'catch_hangup; exit_code=129 exit 129' 1
+trap 'catch_interrupt; exit_code=129 exit 129' 2 3
+
+#####
+#
+# Most of the time we don't want the standard error to be captured
+# by the Spooler, mainly to avoid "Terminated" messages that the
+# shell puts out when we get a SIGTERM. We'll save the standard
+# error channel under another number, so we can use it when it
+# should be captured.
+#
+# Open another channel to the printer port, for use when the
+# regular standard output won't be directed there, such as in
+# command substitution (`cmd`).
+#####
+exec 5>&2 2>/dev/null 3>&1
+
+#####
+#
+# Set some globally used variables and functions.
+#####
+
+: ${TMPDIR:=/tmp}
+: ${SPOOLDIR:=/usr/spool/lp}
+: ${TERMINFO:=/usr/lib/terminfo}
+: ${CHARSETDIR:=/usr/lib/charsets}
+
+: ${LOCALPATH:=${SPOOLDIR}/bin}
+PATH="/bin:/usr/bin:${LOCALPATH}"
+
+MAX_COLS_SMALL_BANNER=40
+
+#####
+#
+# On the 3.2 release of the 386unix product, the parallel port does
+# not support any ioctl calls. As a result, we cannot set the opost
+# and onlcr attributes to have <NL>'s expanded to <CR><NL>. This
+# "filter" gets the job done for us.
+#####
+: ${FIX386BD:=${LOCALPATH}/386parallel}
+if [ -n "${FIX386BD}" -a -x "${FIX386BD}" ]
+then
+ FIX386BD="| ${FIX386BD}"
+else
+ FIX386BD=""
+fi
+
+#####
+# Use ${TMPPREFIX} as the prefix for all temporary files, so
+# that cleanup is easy. The prefix may be up to 13 characters
+# long, so you only have space for one more character to make
+# a file name. If necessary, make a directory using this prefix
+# for better management of unique temporary file names.
+#####
+TMPPREFIX=${TMPDIR}/`uname -n`$$
+
+#####
+# Before exiting, set ${exit_code} to the value with which to exit.
+# Otherwise, the exit from this script will be 0.
+#####
+trap 'rm -fr ${TMPPREFIX}*; exit ${exit_code}' 0
+
+#####
+# ${LPTELL} is the name of a program that will send its
+# standard input to the Spooler. It is used to forward
+# the description of a printer fault to the Spooler,
+# which uses it in an alert to the administrator.
+#####
+if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ]
+then
+ fake_lptell () {
+ header="no"
+ while read line
+ do
+ if [ "no" = "${header}" ]
+ then
+ errmsg ERROR ${E_IP_UNKNOWN} \
+ "unknown printer/interface failure" \
+ "consult your system administrator;
+ reasons for failure (if any) follow:"
+ header=yes
+ fi
+ echo "${line}" >&2
+ done
+ return 1
+ }
+ LPTELL=fake_lptell
+fi
+
+#####
+# ${DRAIN} is the name of a program that will wait
+# long enough for data sent to the printer to print.
+#####
+if [ -x "${LOCALPATH}/drain.output" ]
+then
+ DRAIN="${LOCALPATH}/drain.output 5" # wait only five seconds
+else
+ DRAIN=
+fi
+
+#####
+# ${LPCAT} is the name of a program to use as a default
+# filter. Minimally it should copy its standard input to
+# the standard output, but it should also trap printer
+# faults. The current LPCAT traps hangups (DCD dropping, SIGHUP),
+# interrupts (SIGINT, SIGQUIT), broken pipe (SIGPIPE), and
+# excess delays in sending data to the printer, interpreting all
+# as printer faults.
+#####
+if [ ! -x "${LPCAT:=${LOCALPATH}/lp.cat}" ]
+then
+ LPCAT="cat"
+fi
+
+#####
+# ${LPSET} is the name of a program that will set the
+# character pitch, line pitch, page width, page length,
+# and character set. It helps to have this in a single
+# binary program so that (1) it's faster than calls
+# to "tput"; and (2) it can access the new Terminfo
+# capabilities for printers (on pre SVR3.2 machines, tput can't).
+#####
+if [ ! -x "${LPSET:=${LOCALPATH}/lp.set}" ]
+then
+ fake_lpset () {
+ echo H V W L S >&2
+ false
+ }
+ LPSET=fake_lpset
+fi
+
+internal_lpset () {
+ #####
+ #
+ # The funny business with the "2>&1 1>&3" is to let us capture
+ # the standard ERROR, not the standard OUTPUT as is the usual case
+ # with foo=`cmd`. The standard output will go to the printer.
+ #####
+ [ -n "${stty1}" ] && stty ${stty1} 0<&1
+ chk=`${LPSET} "$1" "$2" "$3" "$4" "$5" 2>&1 1>&3`
+ [ -n "${stty2}" ] && stty ${stty2} 0<&1
+
+ #####
+ #
+ # The standard error of the delivered ${LPSET} program
+ # is a string of letters, H, V, W, L, S, which correspond
+ # to cpi, lpi, width, length, and character set. A letter
+ # is present only if the corresponding attribute could not
+ # be set.
+ #####
+ for err in ${chk}
+ do
+ case ${err} in
+ H )
+ errmsg WARNING ${E_IP_BADCPI} \
+ "can't select the character pitch \"${cpi}\"" \
+ "check the valid pitches for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ V )
+ errmsg WARNING ${E_IP_BADLPI} \
+ "can't select the line pitch \"${lpi}\"" \
+ "check the valid pitches for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ W )
+ width=${cols}
+ errmsg WARNING ${E_IP_BADWIDTH} \
+ "can't select the page width \"${width}\"" \
+ "check the valid widths for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ L )
+ length=${lines}
+ errmsg WARNING ${E_IP_BADLENGTH} \
+ "can't select the page length \"${length}\"" \
+ "check the valid lengths for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ S )
+ errmsg WARNING ${E_IP_BADCHARSET} \
+ "can't select the character set \"${CHARSET}\"" \
+ "check the name given in the -S option,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ esac
+ done
+}
+
+
+#####
+# ${TPUT} is "tput" IF it works. We'll disable it if we get an
+# ugly error message the first time we use it. See the TERM variable
+# later in the script.
+#
+# NOTE: The check we use to see if "tput" works is to use an OLD
+# Terminfo capability, like "lines". If it works with that it may
+# still fail with some of the newer capabilities like "init" (SVR3.0)
+# or "swidm" (SVR3.2), because the version of "tput" we have on your
+# machine is older. Thus, on some of the code where ${TPUT} is used
+# you'll see "2>/dev/null" being used to avoid ugly error messages.
+#####
+TPUT=tput
+
+#####
+# Error message formatter:
+#
+# Invoke as
+#
+# errmsg severity message-number problem help
+#
+# where severity is "ERROR" or "WARNING", message-number is
+# a unique identifier, problem is a short description of the
+# problem, and help is a short suggestion for fixing the problem.
+#####
+
+LP_ERR_LABEL="UX:lp"
+
+E_IP_ARGS=1
+E_IP_OPTS=2
+#E_IP_FILTER=3
+E_IP_STTY=4
+E_IP_UNKNOWN=5
+E_IP_BADFILE=6
+E_IP_BADCHARSET=7
+E_IP_BADCPI=8
+E_IP_BADLPI=9
+E_IP_BADWIDTH=10
+E_IP_BADLENGTH=11
+E_IP_ERRORS=12 # (in slow.filter)
+
+errmsg () {
+ case $1 in
+ ERROR )
+ sev=" ERROR";
+ ;;
+ WARNING )
+ sev="WARNING";
+ ;;
+ esac
+# tag=`expr "${LP_ERR_LABEL}" : "\(.*\):"``expr "${LP_ERR_LABEL}" : ".*:\(.*\)"`
+ echo "${LP_ERR_LABEL}: ${sev}: $3
+ TO FIX: $4" >&5
+}
+
+
+###########
+##
+## Check arguments
+###########
+
+parse () {
+ echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
+}
+
+#####
+#
+# This program is invoked as
+#
+# ${SPOOLDIR}/.../printer request-id user title copies options files...
+#
+# The first three arguments are simply reprinted on the banner page,
+# the fourth (copies) is used to control the number of copies to print,
+# the fifth (options) is a blank separated list (in a single argument)
+# of user or Spooler supplied options (without the -o prefix),
+# and the last arguments are the files to print.
+#####
+
+if [ $# -lt 5 ]
+then
+ errmsg ERROR ${E_IP_ARGS} \
+ "wrong number of arguments to interface program" \
+ "consult your system administrator"
+ exit 1
+fi
+
+printer=`basename $0`
+request_id=$1
+user_name=$2
+title=$3
+copies=$4
+option_list=$5
+
+shift 5
+files="$*"
+
+nobanner="no"
+nofilebreak="no"
+stty=
+
+inlist=
+for i in ${option_list}
+do
+ case "${inlist}${i}" in
+
+
+ nobanner )
+ nobanner="yes"
+ ;;
+
+ nofilebreak )
+ nofilebreak="yes"
+ ;;
+
+ #####
+ #
+ # If you want to add simple options (e.g. -o simple)
+ # identify them here.
+ #####
+# simple )
+# simple="yes"
+# ;;
+
+
+ cpi=pica )
+ cpi=10
+ ;;
+ cpi=elite )
+ cpi=12
+ ;;
+ cpi=* )
+ cpi=`parse ${i}`
+ ;;
+
+ lpi=* )
+ lpi=`parse ${i}`
+ ;;
+
+ length=* )
+ length=`parse ${i}`
+ ;;
+
+ width=* )
+ width=`parse ${i}`
+ ;;
+
+ #####
+ #
+ # If you want to add simple-value options (e.g. -o value=a)
+ # identify them here.
+ #####
+# value=* )
+# value=`parse ${i}`
+# ;;
+
+
+ #####
+ #
+ # If you want to add options that, like "stty",
+ # take a list (e.g. -o lopt='a b c'), identify
+ # them here and below (look for LOPT).
+ #####
+ stty=* | flist=* | lpd=* )
+#LOPT stty=* | flist=* | lpd=* | lopt=* )
+
+ inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"`
+ case "${i}" in
+ ${inlist}\'*\' )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"`
+ ;;
+ ${inlist}\' )
+ continue
+ ;;
+ ${inlist}\'* )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)\$"`
+ ;;
+ ${inlist}* )
+ item=`expr "${i}" : "^[^=]*=\(.*\)\$"`
+ ;;
+ *\' )
+ item=`expr "${i}" : "^\(.*\)'\$"`
+ ;;
+ * )
+ item="${i}"
+ ;;
+ esac
+
+ #####
+ #
+ # We don't dare use "eval" because a clever user could
+ # put something in an option value that we'd end up
+ # exec'ing.
+ #####
+ case "${inlist}" in
+ stty= )
+ stty="${stty} ${item}"
+ ;;
+ flist= )
+ flist="${flist} ${item}"
+ ;;
+ lpd= )
+ lpd="${lpd} ${item}"
+ ;;
+#LOPT lopt= )
+#LOPT lopt="${lopt} ${item}"
+#LOPT ;;
+ esac
+
+ case "${i}" in
+ ${inlist}\'*\' )
+ inlist=
+ ;;
+ ${inlist}\'* )
+ ;;
+ *\' | ${inlist}* )
+ inlist=
+ ;;
+ esac
+ ;;
+
+ * )
+ errmsg WARNING ${E_IP_OPTS} \
+ "unrecognized \"-o ${i}\" option" \
+ "check the option, resubmit if necessary
+ printing continues"
+ ;;
+ esac
+done
+
+#####
+#
+# Additional ``parameters'' are passed via Shell environment
+# variables:
+#
+# TERM The printer type (used for Terminfo access)
+# CHARSET The character set to choose
+# FILTER The filter to run
+#####
+
+#####
+# Set defaults for unset variables.
+#####
+
+: ${TERM:=unknown}
+tput lines 1>/dev/null 2>&1 || TPUT=:
+
+: ${CHARSET:=cs0}
+
+if [ -z "${FILTER}" ]
+then
+ #####
+ #
+ # If no filter is being used, we have a little routine that
+ # will push the data to the printer. It traps hangups (loss
+ # of carrier) and checks for excessive delays in sending the
+ # data to the printer. The lesser of the print rate of the printer
+ # (obtained from Terminfo) or the baud rate is used to compute
+ # the expected delay. If neither of these is correct, you
+ # may be experiencing false alarms. If so, give the correct
+ # rate, in characters per second, as a single argument.
+ # An argument of 0 means don't check for delays.
+ # Give an -r option to get a printout of actual delays.
+ # (QUOTES ARE IMPORTANT!)
+ #####
+ case "$TERM" in
+ PS )
+ # make the "postscript" printers use postio to
+ # talk to the printer and periodically get a
+ # status from them
+ FILTER="/usr/lib/lp/postscript/postio"
+ ;;
+ PSR )
+ # make the "reverse postscript" printers reverse the
+ # output and the use postio to talk to the printer
+ FILTER="/usr/lib/lp/postscript/postreverse | \
+ /usr/lib/lp/postscript/postio"
+ ;;
+ * )
+ # we don't know the type, so just assume that the
+ # input and output are the same
+ if [ `basename "${LPCAT}"` = "lp.cat" ] ; then
+ FILTER="${LPCAT} 0" # infinite delays
+ # FILTER="${LPCAT} 120" # e.g. 120 CPS
+ # FILTER="${LPCAT} -r 0 2>/tmp/delays"
+ # FILTER=${LPCAT}
+ fi
+ ;;
+ esac
+fi
+
+###########
+##
+## Initialize the printer port
+###########
+
+#####
+#
+# SERIAL PORTS:
+# Initialize everything.
+#
+# PARALLEL PORTS:
+# Don't initialize baud rate.
+#
+# It's not obvious how to tell if a port is parallel or serial.
+# However, by splitting the initialization into two steps and letting
+# the serial-only part fail nicely, it'll work.
+#
+# Another point: The output must be a ``tty'' device. If not, don't
+# bother with any of this.
+#####
+stty1= stty2=
+tty 0<&1 1>/dev/null 2>&1 && {
+
+ #####
+ #
+ # First set the default parameters,
+ # then the requested parameters.
+ #####
+
+ stty \
+ 9600 \
+ 0<&1 2>/dev/null 1>&2
+ stty \
+ cs8 -cstopb -parenb -parodd \
+ ixon -ixany \
+ opost -olcuc onlcr -ocrnl -onocr -onlret -ofill \
+ nl0 cr0 tab0 bs0 vt0 ff0 \
+ 0<&1 2>/dev/null 1>&2
+
+ if [ -n "${stty}" ]
+ then
+ if stty ${stty} 0<&1 1>/dev/null 2>&5
+ then
+ :
+ else
+ errmsg ERROR ${E_IP_STTY} \
+ "stty option list failed" \
+ "check the \"-o stty\" option you used,
+ or consult your system administrator"
+ exit 1
+ fi
+ fi
+
+ #####
+ #
+ # Here you may want to add other port initialization code.
+ # Some examples:
+ #
+ # estty # for printer needing hardware flow control (3B2/EPORTS)
+ # fctty # for printer needing hardware flow control (3B15,3B20)
+ #####
+ #estty 0<&1
+ #fctty 0<&1
+
+
+ ##########
+ #
+ # Find out if we have to turn off opost before initializing the
+ # printer and on after. Likewise, check clocal.
+ #
+ # Turning OFF opost (output postprocessing) keeps the UNIX system
+ # from changing what we try to send to the printer. Turning ON
+ # clocal keeps the UNIX system from dropping what we are trying to
+ # send if the printer drops DTR. An example of the former is the
+ # AT&T 479, which wants to send a linefeed (ASCII 10) when a page
+ # width of 10 is set; with opost on, this COULD BE turned into a
+ # carriage-return/linefeed pair. An example of the latter is the
+ # AT&T 455, which momentarily drops DTR when it gets the
+ # initialization string, is2; with clocal off, the UNIX system
+ # stops sending the rest of the initialization sequence at that
+ # point.
+ #
+ # THIS CODE MUST FOLLOW THE REST OF THE PORT INITIALIZATION CODE.
+ ##########
+ cur_stty=`stty -a 0<&3`
+ expr "${cur_stty}" : '.*-opost' 1>/dev/null 2>&1 \
+ || stty1="${stty1} -opost" stty2="${stty2} opost"
+ expr "${cur_stty}" : '.*-clocal' 1>/dev/null 2>&1 \
+ && stty1="${stty1} clocal" stty2="${stty2} -clocal"
+ expr "${cur_stty}" : '.* opost.*' 1>/dev/null 2>&1 \
+ || banner_filter=${FIX386BD}
+
+}
+
+
+###########
+##
+## Initialize the physical printer (Part I).
+## Here we bring the printer to a sane state and set the page size.
+###########
+
+##########
+#
+# WARNING! The "echo" command will catch backslashes (\) and
+# try to interpret the characters following it. Thus, using
+# "echo" to print string values obtained from "tput" is dangerous.
+##########
+
+#####
+# We're confident that most printers don't have backslashes
+# in the control sequences for carriage return and form-feed.
+# We're also confident that these don't contain newlines.
+# We're also confident that most printers have a linefeed
+# in the control sequence for doing a newline (move to beginning
+# of next line), but we can't capture it like we do the
+# carriage return or form-feed. Thus we set it unconditionally.
+# We don't set form-feed if it isn't defined, however, because
+# maybe the printer doesn't have a formfeed. If not set, we're
+# out of luck.
+#####
+
+CR=`${TPUT} cr`
+[ -z "${CR}" ] && CR="\r"
+
+FF=`${TPUT} ff`
+
+NL="${CR}\n"
+
+lines=`${TPUT} lines`
+[ -z "${lines}" -o 0 -ge "${lines}" ] && lines=66
+
+cols=`${TPUT} cols`
+[ -z "${cols}" -o 0 -ge "${cols}" ] && cols=132
+
+#####
+#
+# Basic initialization. The ``else'' clause is equivalent,
+# but covers cases where old Terminal Information Utilities are present.
+#####
+[ -n "${stty1}" ] && stty ${stty1} 0<&1
+
+#
+# "tput init" will return an "^M" in many cases to "stdout", i.e., printer!
+# This creates problems for some PS printers
+#
+if [ "${TERM}" = "PS" -o "${TERM}" = "PSR" ]
+then
+ :
+elif ${TPUT} init 2>/dev/null
+then
+ :
+else
+ pgm=`${TPUT} iprog`
+ if [ -x "${pgm}" ]
+ then
+ eval ${pgm}
+ fi
+
+ ${TPUT} is1
+ ${TPUT} is2
+
+ tabset=
+ if [ "8" != "`${TPUT} it`" ]
+ then
+ stty tab3 0<&1 1>/dev/null 2>&1
+
+ elif `${TPUT} ht >/dev/null`
+ then
+ tabset="/usr/lib/tabset/${TERM}"
+ if [ -r ${tabset} ]
+ then
+ cat -s ${tabset}
+ fi
+ stty tab3 0<&1 1>/dev/null 2>&1
+ fi
+
+ file=`${TPUT} if`
+ if [ "${tabset}" != "${file}" -a -r "${file}" ]
+ then
+ cat -s "${file}"
+ fi
+
+ ${TPUT} is3
+ echo "${CR}\c"
+fi
+[ -n "${stty2}" ] && stty ${stty2} 0<&1
+
+#####
+#
+# Set the page size and print spacing, but not the character set.
+# We will be doing the character set later (after the header).
+#####
+internal_lpset "${cpi}" "${lpi}" "${width}" "${length}" ""
+
+#####
+#
+# The banner page (and cancellation page) will
+# use double width characters if they're available.
+#####
+WIDE_CS=`${TPUT} swidm 2>/dev/null` && NORM_CS=`${TPUT} rwidm 2>/dev/null`
+PAD="#####${NL}"
+
+#####
+#
+# Some printers need to have the banner page filtered.
+#####
+case "${TERM}" in
+
+PS | PSR )
+ banner_filter="/usr/lib/lp/postscript/postprint | /usr/lib/lp/postscript/postio"
+ LPTELL_OPTS="-l"
+ ;;
+
+esac
+if [ -n "${banner_filter}" ]
+then
+ banner_filter="| ${banner_filter}"
+fi
+
+#####
+#
+# Now that the printer is ready for printing, we're able
+# to record on paper a cancellation.
+#####
+
+cancel_banner () {
+ echo "${PAD}${PAD}\c"
+ echo "#####${WIDE_CS} Job ${request_id}${NORM_CS}${NL}\c"
+ echo "#####${WIDE_CS} suspended or canceled${NORM_CS}${NL}\c"
+ echo "${PAD}${PAD}\c"
+}
+
+canceled () {
+ ${TPUT} scs 0 2>/dev/null
+ echo "${CR}\c"
+ if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
+ then
+ WIDE_CS= NORM_CS=
+ fi
+ cancel_banner
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+trap 'eval canceled ${banner_filter}; exit_code=0 exit' 15
+
+
+###########
+##
+## Print the banner page
+###########
+
+#####
+#
+# You may want to change the following code to get a custom banner.
+#####
+
+regular_banner () {
+ echo "${CR}\c"
+ echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c"
+ echo "#####${WIDE_CS} User: ${user_name}${NORM_CS}${NL}\c"
+ if [ -n "$ALIAS_USERNAME" ]
+ then
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Alias: ${ALIAS_USERNAME}${NORM_CS}${NL}\c"
+ fi
+ if [ -n "${title}" ]
+ then
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Title: ${title}${NORM_CS}${NL}\c"
+ fi
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Printed: `LANG=C date '+%a %H:%M %h %d, %Y'`${NORM_CS}${NL}\c"
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Job number: ${request_id}${NORM_CS}${NL}\c"
+ echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c"
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+small_banner () {
+ echo "${CR}\c"
+ echo "${PAD}\c"
+ echo "##### User: ${user_name}${NL}\c"
+ if [ -n "${title}" ]
+ then
+ echo "##### Title: ${title}${NL}\c"
+ fi
+ echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c"
+ echo "##### Job: ${request_id}${NL}\c"
+ echo "${PAD}\c"
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
+then
+ banner=small_banner
+else
+ banner=regular_banner
+fi
+
+if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" ]
+then
+ ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
+ | ${LPTELL} ${LPTELL_OPTS} ${printer}
+fi
+
+
+###########
+##
+## Initialize the physical printer (Part II)
+## Here we select the character set.
+## One could argue that this should be done before the banner is printed,
+## but we don't, to keep the banner page looking consistent for the
+## operator. You can move this code before the banner code if you
+## disagree. If you do, combine it with the other call to "internal_lpset"
+## to do everything in one shot.
+###########
+internal_lpset "" "" "" "" "${CHARSET}"
+
+###########
+##
+## Print some copies of the file(s)
+###########
+
+#####
+#
+# The protocol between the interface program and the Spooler
+# is fairly simple:
+#
+# All standard error output is assumed to indicate a
+# fault WITH THE REQUEST. The output is mailed to the
+# user who submitted the print request and the print
+# request is finished.
+#
+# If the interface program sets a zero exit code,
+# it is assumed that the file printed correctly.
+# If the interface program sets a non-zero exit code
+# less than 128, it is assumed that the file did not
+# print correctly, and the user will be notified.
+# In either case the print request is finished.
+#
+# If the interface program sets an exit code greater
+# than 128, it is assumed that the file did not print
+# because of a printer fault. If an alert isn't already
+# active (see below) one will be activated. (Exit code
+# 128 should not be used at all. The shell, which executes
+# this program, turns SIGTERM, used to kill this program
+# for a cancellation or disabling, into exit 128. The
+# Spooler thus interpretes 128 as SIGTERM.)
+#
+# A message sent to the standard input of the ${LPTELL}
+# program is assumed to describe a fault WITH THE PRINTER.
+# The output is used in an alert (if alerts are defined).
+# If the fault recovery is "wait" or "begin", the printer
+# is disabled (killing the interface program if need be),
+# and the print request is left on the queue.
+# If the fault recovery is "continue", the interface program
+# is allowed to wait for the printer fault to be cleared so
+# it can resume printing.
+#
+# This interface program relies on filters to detect printer faults.
+# In absence of a filter provided by the customer, it uses a simple
+# filter (${LPCAT}) to detect the class of faults that cause DCD
+# (``carrier'') drop. The protocol between the interface program and
+# the filter:
+#
+# The filter should exit with zero if printing was
+# successful and non-zero if printing failed because
+# of a printer fault. This interface program turns a
+# non-zero exit of the filter into an "exit 129" from
+# itself, thus telling the Spooler that a printer fault
+# (still) exists.
+#
+# The filter should report printer faults via a message
+# to its standard error. This interface program takes all
+# standard error output from the filter and feeds it as
+# standard input to the ${LPTELL} program.
+#
+# The filter should wait for a printer fault to clear,
+# and should resume printing when the fault clears.
+# Preferably it should resume at the top of the page
+# that was being printed when the fault occurred.
+# If it waits and finishes printing, it should exit
+# with a 0 exit code. If it can't wait, it should exit
+# with a non-zero exit code.
+#
+# The interface program expects that ANY message on the
+# standard error from the filter indicates a printer fault.
+# Therefore, a filter should not put user (input) error
+# messages on the standard error, but on the standard output
+# (where the user can read them when he or she examines
+# the print-out).
+#
+#####
+
+badfileyet=
+i=1
+while [ $i -le $copies ]
+do
+ for file in ${files}
+ do
+ if [ -r "${file}" ]
+ then
+ #####
+ #
+ # Here's where we set up the $LPTELL program to
+ # capture fault messages, and...
+ #
+ # Here's where we print the file.
+ #
+ # We set up a pipeline to $LPTELL, but play a trick
+ # to get the filter's standard ERROR piped instead of
+ # its standard OUTPUT: Divert the standard error (#2) to
+ # the standard output (#1) IN THE PIPELINE. The shell
+ # will have changed #1 to be the pipe, not the
+ # printer, so diverting #2 connects it to the pipe.
+ # We then change the filter's #1 to a copy of the real
+ # standard output (the printer port) made earlier,
+ # so that is connected back to the printer again.
+ #
+ # We do all this inside a parenthesized expression
+ # so that we can get the exit code; this is necessary
+ # because the exit code of a pipeline is the exit
+ # code of the right-most command, which isn't the
+ # filter.
+ #
+ # These two tricks could be avoided by using a named
+ # pipe to connect the standard error to $LPTELL. In
+ # fact an early prototype of this script did just
+ # that; however, the named pipe introduced a timing
+ # problem. The processes that open a named pipe hang
+ # until both ends of the pipe are opened. Cancelling
+ # a request or disabling the printer often killed one
+ # of the processes, causing the other process to hang
+ # forever waiting for the other end of the pipe to
+ # be opened.
+ #####
+ EXIT_CODE=${TMPPREFIX}e
+ trap '' 1 # Let the filter handle a hangup
+ trap '' 2 3 # and interrupts
+ (
+ #####
+ # Put the 0<${file} before the "eval" to keep
+ # clever users from giving a file name that
+ # evaluates as something to execute.
+ #####
+ 0<${file} eval ${FILTER} 2>&1 1>&3
+ echo $? >${EXIT_CODE}
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+ trap 'catch_hangup; exit_code=129 exit 129' 1
+ trap 'catch_interrupt; exit_code=129 exit 129' 2 3
+ exit_code=`cat ${EXIT_CODE}`
+
+ if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
+ then
+ trap '' 15 # Avoid dying from disable
+ sleep 4 # Give $LPTELL a chance to tell
+ exit ${exit_code}
+ fi
+
+ if [ -n "${FF}" -a "no" = "${nofilebreak}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+
+ else
+
+ #####
+ #
+ # Don't complain about not being able to read
+ # a file on second and subsequent copies, unless
+ # we've not complained yet. This removes repeated
+ # messages about the same file yet reduces the
+ # chance that the user can remove a file and not
+ # know that we had trouble finding it.
+ #####
+ if [ "${i}" -le 1 -o -z "${badfileyet}" ]
+ then
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read file \"${file}\"" \
+ "see if the file still exists and is readable,
+ or consult your system administrator;
+ printing continues"
+ badfileyet=yes
+ fi
+
+ fi
+
+ done
+ i=`expr $i + 1`
+
+done
+
+if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ]
+then
+ ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
+ | ${LPTELL} ${LPTELL_OPTS} ${printer}
+fi
+
+if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
+then
+ exit ${exit_code}
+fi
+
+#####
+#
+# Always ensure the complete job ends with a ``formfeed'', to
+# let the next job start on a new page. (If someone wants to
+# concatenate files, they can give them in one job.)
+# So, if we haven't been putting out a ``formfeed'' between files,
+# it means we haven't followed the last file with a formfeed,
+# so we do it here.
+#####
+if [ -n "${FF}" -a "yes" = "${nofilebreak}" ]
+then
+ echo "${CR}${FF}\c"
+fi
+
+${DRAIN}
+
+exit_code=0 exit 0
diff --git a/usr/src/cmd/lp/model/tsol_netstandard b/usr/src/cmd/lp/model/tsol_netstandard
new file mode 100644
index 0000000000..6a04d5061d
--- /dev/null
+++ b/usr/src/cmd/lp/model/tsol_netstandard
@@ -0,0 +1,751 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+###########
+##
+## Network Standard printer interface program.
+##
+###########
+
+#####
+# We can't do much except exit if spooler/scheduler
+# cancels us.
+#####
+trap 'eval exit_clean 15' 15
+
+####
+#
+# Send standard error messages to /dev/null rather than to
+# the spooler. Avoids "Terminated" messages that shell puts out
+# when gets SIGTERM. Save standard error so it can be used
+# when we need it
+####
+exec 5>&2 2>/dev/null 3>&1
+
+####
+# set some global variables
+####
+
+: ${LPTMPDIR:=/tmp}
+: ${SPOOLDIR:=/usr/spool/lp}
+: ${LOCALPATH:=${SPOOLDIR}/bin}
+PATH="/bin:/usr/bin:${LOCALPATH}"
+exit_code=0
+
+
+# ${LPTELL} is the name of a program that will send its
+# standard input to the Spooler. It is used to forward
+# the description of a printer fault to the Spooler,
+# which uses it in an alert to the administrator.
+#####
+if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ]
+then
+ fake_lptell () {
+ header="no"
+ while read line
+ do
+ if [ "no" = "${header}" ]
+ then
+ errmsg ERROR ${E_IP_UNKNOWN} \
+ "unknown printer/interface failure" \
+ "consult your system administrator;
+ reasons for failure (if any) follow:"
+ header=yes
+ fi
+ echo "${line}" >&2
+ done
+ return 1
+ }
+ LPTELL=fake_lptell
+fi
+
+#####
+# ${LPTSOLSEPARATOR} is the name of a program to put banner and trailer
+# pages around the job.
+#####
+if [ -x ${LOCALPATH}/lp.tsol_separator ]
+then
+ LPTSOLSEPARATOR=${LOCALPATH}/lp.tsol_separator
+else
+ echo "${LOCALPATH}/lp.tsol_separator not found." >&2
+ exit 1
+fi
+
+#####
+# Error message formatter:
+#
+# Invoke as
+#
+# errmsg severity message-number problem help
+#
+# where severity is "ERROR" or "WARNING", message-number is
+# a unique identifier, problem is a short description of the
+# problem, and help is a short suggestion for fixing the problem.
+#####
+
+LP_ERR_LABEL="UX:lp"
+E_IP_ARGS=1
+E_IP_OPTS=2
+#E_IP_FILTER=3
+E_IP_UNKNOWN=5
+E_IP_BADFILE=6
+E_IP_ERRORS=12 # (in slow.filter)
+
+errmsg () {
+
+ case $1 in
+ ERROR )
+ sev=" ERROR";
+ ;;
+ WARNING )
+ sev="WARNING";
+ ;;
+ esac
+
+ echo "${LP_ERR_LABEL}:$2 ${sev}: $3
+ TO FIX: $4" >&5
+}
+
+###########
+##
+## Check arguments
+###########
+
+parse () {
+ echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
+}
+
+#####
+##
+## Error Cleanup and Exit
+##
+#####
+
+exit_clean()
+{
+
+ if [ -f "${LPTMPDIR}/pr_eexit_code.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/pr_eexit_code.$$
+ fi
+
+ if [ -f "${LPTMPDIR}/small_banner.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/small_banner.$$
+ fi
+
+ if [ -f "${LPTMPDIR}/banner.exit_code.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/banner.exit_code.$$
+ fi
+
+ if [ -f "${LPTMPDIR}/banner.errmsg.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/banner.errmsg.$$
+ fi
+
+ if [ -f "${tmpfile}" ]
+ then
+ /bin/rm "${tmpfile}"
+ fi
+
+ exit $1
+}
+
+#####
+#
+# This program is invoked as
+#
+# ${SPOOLDIR}/.../printer request-id user title copies options files...
+#
+# The first three arguments are simply reprinted on the banner page,
+# the fourth (copies) is used to control the number of copies to print,
+# the fifth (options) is a blank separated list (in a single argument)
+# of user or Spooler supplied options (without the -o prefix),
+# and the last arguments are the files to print.
+#####
+
+if [ $# -lt 5 ]
+then
+
+ errmsg ERROR ${E_IP_ARGS} \
+ "wrong number of arguments to interface program" \
+ "consult your system administrator"
+ exit 1
+fi
+
+printer=`basename $0`
+request_id=$1
+user_name=$2
+title=$3
+copies=$4
+option_list=$5
+
+shift 5
+files="$*"
+
+
+#
+# debug sent to file if defined in /etc/syslog.conf
+# syslog.conf entry:
+# lpr.debug /path/filename
+#
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " "
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "INPUT"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \
+ printer : ${printer}"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \
+ request_id : ${request_id}"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \
+ user_name : ${user_name}"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " title : ${title}"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \
+ copies : ${copies}"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \
+ option_list : ${option_list}"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " files : ${files}"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" " \
+ spooler_key ${SPOOLER_KEY}"
+
+####
+# default: do print a banner
+####
+nobanner=no
+nolabels="no"
+nofilebreak="no"
+inlist=
+data_file_flag=
+
+for i in ${option_list}
+do
+ case "${inlist}${i}" in
+
+ nobanner )
+ nobanner="yes"
+ ;;
+
+ nofilebreak )
+ nofilebreak="yes"
+ ;;
+
+ nolabels )
+ nolabels="yes"
+ ;;
+
+ #####
+ #
+ # If you want to add simple options (e.g. -o simple)
+ # identify them here.
+ #####
+# simple )
+# simple="yes"
+# ;;
+
+ cpi=pica )
+ cpi=10
+ ;;
+ cpi=elite )
+ cpi=12
+ ;;
+ cpi=* )
+ cpi=`parse ${i}`
+ ;;
+
+ lpi=* )
+ lpi=`parse ${i}`
+ ;;
+
+ length=* )
+ length=`parse ${i}`
+ ;;
+
+ width=* )
+ width=`parse ${i}`
+ ;;
+ dest=* )
+ dest="-d `parse ${i}`"
+ ;;
+
+ protocol=* )
+ protocol="-P `parse ${i}`"
+ ;;
+ bsdctrl=* )
+ controlfile="-c `parse ${i}`"
+ ;;
+ timeout=* )
+ timeout="-t `parse ${i}`"
+ ;;
+
+ data-file-type=* )
+ data_file_flag="-f `parse ${i}`"
+ ;;
+
+ #####
+ #
+ # If you want to add simple-value options (e.g. -o value=a)
+ # identify them here.
+ #####
+# value=* )
+# value=`parse ${i}`
+# ;;
+
+ #####
+ #
+ # If you want to add options that,
+ # take a list (e.g. -o lopt='a b c'), identif
+ # them here and below (look for LOPT).
+ #####
+
+# flist=* | lpd=* | options=* )
+ flist=* | lpd=* )
+#LOPT stty=* | flist=* | lpd=* | lopt=* )
+
+ inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"`
+ case "${i}" in
+ ${inlist}\'*\' )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"`
+ ;;
+ ${inlist}\' )
+ continue
+ ;;
+ ${inlist}\'* )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)\$"`
+ ;;
+ ${inlist}* )
+ item=`expr "${i}" : "^[^=]*=\(.*\)\$"`
+ ;;
+ *\' )
+ item=`expr "${i}" : "^\(.*\)'\$"`
+ ;;
+ * )
+ item="${i}"
+ ;;
+ esac
+
+ #####
+ #
+ # We don't dare use "eval" because a clever user could
+ # put something in an option value that we'd end up
+ # exec'ing.
+ #####
+ case "${inlist}" in
+ flist= )
+ flist="${flist} ${item}"
+ ;;
+ lpd= )
+ lpd="${lpd} ${item}"
+ ;;
+#LOPT lopt= )
+#LOPT lopt="${lopt} ${item}"
+#LOPT ;;
+# options= )
+# options="${options} ${item}"
+# ;;
+ esac
+
+ case "${i}" in
+ ${inlist}\'*\' )
+ inlist=
+ ;;
+ ${inlist}\'* )
+ ;;
+ *\' | ${inlist}* )
+ inlist=
+ ;;
+ esac
+ ;;
+
+ * )
+ errmsg WARNING ${E_IP_OPTS} \
+ "unrecognized \"-o ${i}\" option" \
+ "check the option, resubmit if necessary
+ printing continues"
+ ;;
+ esac
+done
+
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "term : ${TERM}"
+
+if [ -z "${FILTER}" ]
+then
+ #####
+ #
+ # If no filter is being used, we use netpr to push the
+ # file to the printer.
+ # (QUOTES ARE IMPORTANT!)
+ #####
+
+ case "$TERM" in
+ PS )
+ # make the "postscript" printers use cat
+ # (TSOL banners are added during filtering, so we have
+ # to use some filter.)
+ FILTER=/bin/cat
+ ;;
+ PSR )
+ # make the "reverse postscript" printers reverse the
+ # output and the use postio to talk to the printer
+ #FILTER="/usr/lib/lp/postscript/postreverse "
+ #FILTER=
+ FILTER="/usr/lib/lp/postscript/postreverse "
+ ;;
+ * )
+ # We don't know the type, so just assume that the
+ # input and output are the same. Use netpr.
+ #FILTER=/bin/cat
+ FILTER=
+ ;;
+ esac
+fi
+
+####
+# sets default value for ordering of data and control files with
+# bsd protocol. Default: data files first. Administrator
+# may set to control file first with lpadmin -o bsdctrl=first
+####
+
+banner_flag=""
+case "${nobanner}" in
+ yes )
+ banner_flag="-b"
+ ;;
+esac
+
+NETPR="/usr/lib/lp/bin/netpr ${banner_flag} ${data_file_flag} \
+ -I ${request_id} -U ${user_name} \
+ -p ${printer} ${dest} -T \"${title}\" \
+ ${timeout} ${protocol} ${controlfile} "
+LPTELL_OPTS="-l" # netpr sends LaserWriter style messages back
+
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "NETPR= ${NETPR}"
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "filter : ${FILTER}"
+
+node=`uname -n`
+pid=$$
+tmpfile=${LPTMPDIR}/${node}.${pid}
+
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" "tmpfile : ${tmpfile}"
+
+#####
+#
+# Set up filter for banner page
+#
+#####
+banner_filter=
+case "${TERM}" in
+PS | PSR )
+ banner_filter=" | /usr/lib/lp/postscript/postprint "
+ LPTELL_OPTS="-l"
+ ;;
+esac
+
+#####
+#
+# Build temporary file that is the banner page
+#
+#####
+PAD="#####${NL}"
+CR="\r"
+NL="${CR}\n"
+FF=
+
+small_banner() {
+ echo "${CR}\c"
+ echo "${PAD}\c"
+ echo "##### User: ${user_name}${NL}\c"
+ if [ -n "${title}" ]
+ then
+ echo "##### Title: ${title}${NL}\c"
+ fi
+ echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c"
+ echo "##### Job: ${request_id}${NL}\c"
+ echo "${PAD}\c"
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+#####
+#
+# Doing small banner as we don't know what printer is out there
+#
+#####
+banner=small_banner
+
+## Skip this for PS/PSR printers, since lp.tsol_separator handles the banners
+if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ eval "${banner} ${banner_filter}" 2>&1 1>${LPTMPDIR}/small_banner.$$
+fi
+
+###########
+##
+## Surround the job by PostScript code to produce banner
+## and trailerpages and page headers and footers.
+##
+###########
+
+BANNER_EXIT_CODE=${LPTMPDIR}/banner.exit_code.$$
+echo 0 > ${BANNER_EXIT_CODE}
+TSOLSEPARATOR_LOG=${LPTMPDIR}/banner.errmsg.$$
+
+tsol_bannerize () {
+ TSOLSEPARATOR_OPTS="-e ${TSOLSEPARATOR_LOG}"
+
+ if [ "yes" = "${nolabels}" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -l"
+ fi
+
+ if [ "yes" = "${nobanner}" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -t /dev/null -b /dev/null"
+ fi
+
+ if [ "${TERM}" = "PSR" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -r"
+ fi
+
+ # Get rid of the #, TAB and NL characters in the title
+ tsol_title=`echo $title`
+ tsol_title=`echo $tsol_title | sed 's/#//g'`
+
+ logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \
+ "banner command: ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} \
+ ${printer} ${request_id} ${user_name} \"${tsol_title}\" ${file}"
+ ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} ${printer} \
+ ${request_id} ${user_name} "${tsol_title}" ${file}
+
+ echo $? > ${BANNER_EXIT_CODE}
+ true
+}
+
+bannerize=tsol_bannerize
+
+if [ "yes" = "${nobanner}" -a "yes" = "${nolabels}" ]
+then
+ bannerize=cat
+fi
+
+if [ "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ bannerize=cat
+fi
+
+#####
+#
+# Print banner page before job unless PS or PSR.
+#
+#####
+
+if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ (
+ eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \
+ "banner page exit code : ${exit_code}"
+
+fi
+
+i=1
+while [ $i -le $copies ]
+do
+ for file in ${files}
+ do
+ if [ -r "${file}" ]
+ then
+
+ if [ ! -z "${FILTER}" ]
+ then
+ (
+ #####
+ # There is a filter, use it
+ #
+ # Put 0<${file} before the "eval" to keep
+ # clever users from giving a file name that
+ # evaluates as something to execute.
+ # Redirect stderr to stdout so LPTELL will
+ # get error messages from pipe.
+ #####
+ 0<${file} $bannerize | eval ${FILTER} 2>&1 1>${tmpfile}
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ # if lp.tsol_separator had an error, send its logged
+ # error message to LPTELL.
+ banner_exit_code=`cat ${BANNER_EXIT_CODE}`
+ if [ -n "${banner_exit_code}" -a \
+ 0 -ne "${banner_exit_code}" -a \
+ -n "${LPTELL}" -a \
+ -r "${TSOLSEPARATOR_LOG}" ]
+ then
+ cat ${TSOLSEPARATOR_LOG} | ${LPTELL} ${printer}
+ echo 77 > ${LPTMPDIR}/pr_eexit_code
+ fi
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug \
+ -t "tsol_netstandard: ${request_id}" \
+ "filter exit_code : ${exit_code}"
+
+ if [ -n "${exit_code}" ]
+ then
+ if [ "${exit_code}" -eq 0 ]
+ then
+ printfile=${tmpfile}
+ else
+ ####
+ # The filter did not succeed, so don't try to print
+ ####
+ printfile=
+ fi
+ fi
+
+ else
+ printfile=${file}
+ fi
+
+ logger -p lpr.debug \
+ -t "tsol_netstandard: ${request_id}" \
+ "printfile : ${printfile}"
+
+ #####
+ # Print the file
+ #####
+
+ if [ -r "${printfile}" ]
+ then
+ (
+ eval ${NETPR} ${printfile} 2>&1
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug \
+ -t "tsol_netstandard: ${request_id}" \
+ "netpr exit_code : ${exit_code}"
+
+# if [ -f "${tmpfile}" ]
+# then
+# /bin/rm "${tmpfile}"
+# fi
+
+ if [ -n "${exit_code}" ]
+ then
+ if [ "${exit_code}" -eq 0 ]
+ then
+ printone=yes
+ else
+ if [ "${exit_code}" -lt 128 ]
+ then
+ noprint=yes
+ else
+ retry=yes
+ fi
+ fi
+ fi
+
+
+ else
+
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read temporary file \"${printfile}\""\
+ "see if file still exists,
+ or consult your system administrator;
+ printing continues"
+
+ fi
+ else
+
+ #####
+ #
+ # Don't complain about not being able to read
+ # a file on second and subsequent copies, unless
+ # we've not complained yet. This removes repeated
+ # messages about the same file yet reduces the
+ # chance that the user can remove a file and not
+ # know that we had trouble finding it.
+ #####
+
+ if [ "${i}" -le 1 -o -z "${badfileyet}" ]
+ then
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read file \"${file}\"" \
+ "see if the file still exists and is readable,
+ or consult your system administrator;
+ printing continues"
+ badfileyet=yes
+ fi
+
+ fi
+
+# for file in ${files}
+ done
+ i=`expr $i + 1`
+done
+
+#####
+#
+# If printing in reverse order, print the banner page now
+# Skip this for TSOL, since lp.tsol_separator handles the banners
+#
+#####
+
+#
+# if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ]
+# then
+# (
+# eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1
+# echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+# ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+# fi
+
+exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \
+ "banner page exit code : ${exit_code}"
+
+if [ -n "${printone}" -a -z "${retry}" -a -z "${noprint}" ]
+then
+ exit_code=`expr 0`
+else
+ if [ -n "${retry}" -a -z "${printone}" -a -z "${noprint}" ]
+ then
+ exit_code=`expr 129`
+ else
+ exit_code=`expr 1`
+ fi
+fi
+
+logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \
+ "FINAL exit_code : ${exit_code}"
+
+exit_clean ${exit_code}
diff --git a/usr/src/cmd/lp/model/tsol_netstandard_foomatic b/usr/src/cmd/lp/model/tsol_netstandard_foomatic
new file mode 100644
index 0000000000..b23d06a1ba
--- /dev/null
+++ b/usr/src/cmd/lp/model/tsol_netstandard_foomatic
@@ -0,0 +1,788 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+###########
+##
+## Network Standard printer interface program for foomatic.
+##
+###########
+
+#####
+# We can't do much except exit if spooler/scheduler
+# cancels us.
+#####
+trap 'eval exit_clean 15' 15
+
+####
+#
+# Send standard error messages to /dev/null rather than to
+# the spooler. Avoids "Terminated" messages that shell puts out
+# when gets SIGTERM. Save standard error so it can be used
+# when we need it
+####
+exec 5>&2 2>/dev/null 3>&1
+
+####
+# set some global variables
+####
+
+: ${LPTMPDIR:=/tmp}
+: ${SPOOLDIR:=/usr/spool/lp}
+: ${LOCALPATH:=${SPOOLDIR}/bin}
+PATH="/bin:/usr/bin:${LOCALPATH}"
+exit_code=0
+
+
+# ${LPTELL} is the name of a program that will send its
+# standard input to the Spooler. It is used to forward
+# the description of a printer fault to the Spooler,
+# which uses it in an alert to the administrator.
+#####
+if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ]
+then
+ fake_lptell () {
+ header="no"
+ while read line
+ do
+ if [ "no" = "${header}" ]
+ then
+ errmsg ERROR ${E_IP_UNKNOWN} \
+ "unknown printer/interface failure" \
+ "consult your system administrator;
+ reasons for failure (if any) follow:"
+ header=yes
+ fi
+ echo "${line}" >&2
+ done
+ return 1
+ }
+ LPTELL=fake_lptell
+fi
+
+#####
+# ${LPTSOLSEPARATOR} is the name of a program to put banner and trailer
+# pages around the job.
+#####
+if [ -x ${LOCALPATH}/lp.tsol_separator ]
+then
+ LPTSOLSEPARATOR=${LOCALPATH}/lp.tsol_separator
+else
+ echo "${LOCALPATH}/lp.tsol_separator not found." >&2
+ exit 1
+fi
+
+#####
+# Error message formatter:
+#
+# Invoke as
+#
+# errmsg severity message-number problem help
+#
+# where severity is "ERROR" or "WARNING", message-number is
+# a unique identifier, problem is a short description of the
+# problem, and help is a short suggestion for fixing the problem.
+#####
+
+LP_ERR_LABEL="UX:lp"
+E_IP_ARGS=1
+E_IP_OPTS=2
+#E_IP_FILTER=3
+E_IP_UNKNOWN=5
+E_IP_BADFILE=6
+E_IP_ERRORS=12 # (in slow.filter)
+
+errmsg () {
+
+ case $1 in
+ ERROR )
+ sev=" ERROR";
+ ;;
+ WARNING )
+ sev="WARNING";
+ ;;
+ esac
+
+ echo "${LP_ERR_LABEL}:$2 ${sev}: $3
+ TO FIX: $4" >&5
+}
+
+###########
+##
+## Check arguments
+###########
+
+parse () {
+ echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
+}
+
+#####
+##
+## Error Cleanup and Exit
+##
+#####
+
+exit_clean()
+{
+
+ if [ -f "${LPTMPDIR}/pr_eexit_code.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/pr_eexit_code.$$
+ fi
+
+ if [ -f "${LPTMPDIR}/small_banner.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/small_banner.$$
+ fi
+
+ if [ -f "${LPTMPDIR}/banner.exit_code.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/banner.exit_code.$$
+ fi
+
+ if [ -f "${LPTMPDIR}/banner.errmsg.$$" ]
+ then
+ /bin/rm ${LPTMPDIR}/banner.errmsg.$$
+ fi
+
+ if [ -f "${tmpfile}" ]
+ then
+ /bin/rm "${tmpfile}"
+ fi
+
+ exit $1
+}
+
+#####
+#
+# This program is invoked as
+#
+# ${SPOOLDIR}/.../printer request-id user title copies options files...
+#
+# The first three arguments are simply reprinted on the banner page,
+# the fourth (copies) is used to control the number of copies to print,
+# the fifth (options) is a blank separated list (in a single argument)
+# of user or Spooler supplied options (without the -o prefix),
+# and the last arguments are the files to print.
+#####
+
+if [ $# -lt 5 ]
+then
+
+ errmsg ERROR ${E_IP_ARGS} \
+ "wrong number of arguments to interface program" \
+ "consult your system administrator"
+ exit 1
+fi
+
+printer=`basename $0`
+request_id=$1
+user_name=$2
+title=$3
+copies=$4
+option_list=$5
+
+shift 5
+files="$*"
+
+
+#
+# debug sent to file if defined in /etc/syslog.conf
+# syslog.conf entry:
+# lpr.debug /path/filename
+#
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" " "
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" "INPUT"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ " printer : ${printer}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ " request_id : ${request_id}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ " user_name : ${user_name}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ " title : ${title}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ " copies : ${copies}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ " option_list : ${option_list}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ " files : ${files}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ " spooler_key ${SPOOLER_KEY}"
+
+####
+# default: do print a banner
+####
+nobanner=no
+nolabels="no"
+nofilebreak="no"
+inlist=
+data_file_flag=
+
+for i in ${option_list}
+do
+ case "${inlist}${i}" in
+
+ nobanner )
+ nobanner="yes"
+ ;;
+
+ nofilebreak )
+ nofilebreak="yes"
+ ;;
+
+ nolabels )
+ nolabels="yes"
+ ;;
+
+ #####
+ #
+ # If you want to add simple options (e.g. -o simple)
+ # identify them here.
+ #####
+# simple )
+# simple="yes"
+# ;;
+
+ cpi=pica )
+ cpi=10
+ ;;
+ cpi=elite )
+ cpi=12
+ ;;
+ cpi=* )
+ cpi=`parse ${i}`
+ ;;
+
+ lpi=* )
+ lpi=`parse ${i}`
+ ;;
+
+ length=* )
+ length=`parse ${i}`
+ ;;
+
+ width=* )
+ width=`parse ${i}`
+ ;;
+ dest=* )
+ dest="-d `parse ${i}`"
+ ;;
+
+ protocol=* )
+ protocol="-P `parse ${i}`"
+ ;;
+ bsdctrl=* )
+ controlfile="-c `parse ${i}`"
+ ;;
+ timeout=* )
+ timeout="-t `parse ${i}`"
+ ;;
+
+ data-file-type=* )
+ data_file_flag="-f `parse ${i}`"
+ ;;
+
+ #
+ # The IPP/PAPI attributes are handled by the foomatic-rip filter so
+ # all we need to do here is ignore them so that they don't invoke the
+ # "unrecognized option" message.
+ #
+
+ finishing=* | page-ranges=* | sides=* )
+ ;;
+ number-up=* | orientation-requested=* | media=* )
+ ;;
+ printer-resolution=* | print-quality=* )
+ ;;
+
+ #####
+ #
+ # If you want to add simple-value options (e.g. -o value=a)
+ # identify them here.
+ #####
+# value=* )
+# value=`parse ${i}`
+# ;;
+
+ #####
+ #
+ # If you want to add options that,
+ # take a list (e.g. -o lopt='a b c'), identif
+ # them here and below (look for LOPT).
+ #####
+
+# flist=* | lpd=* | options=* )
+ flist=* | lpd=* )
+#LOPT stty=* | flist=* | lpd=* | lopt=* )
+
+ inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"`
+ case "${i}" in
+ ${inlist}\'*\' )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"`
+ ;;
+ ${inlist}\' )
+ continue
+ ;;
+ ${inlist}\'* )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)\$"`
+ ;;
+ ${inlist}* )
+ item=`expr "${i}" : "^[^=]*=\(.*\)\$"`
+ ;;
+ *\' )
+ item=`expr "${i}" : "^\(.*\)'\$"`
+ ;;
+ * )
+ item="${i}"
+ ;;
+ esac
+
+ #####
+ #
+ # We don't dare use "eval" because a clever user could
+ # put something in an option value that we'd end up
+ # exec'ing.
+ #####
+ case "${inlist}" in
+ flist= )
+ flist="${flist} ${item}"
+ ;;
+ lpd= )
+ lpd="${lpd} ${item}"
+ ;;
+#LOPT lopt= )
+#LOPT lopt="${lopt} ${item}"
+#LOPT ;;
+# options= )
+# options="${options} ${item}"
+# ;;
+ esac
+
+ case "${i}" in
+ ${inlist}\'*\' )
+ inlist=
+ ;;
+ ${inlist}\'* )
+ ;;
+ *\' | ${inlist}* )
+ inlist=
+ ;;
+ esac
+ ;;
+
+ * )
+ errmsg WARNING ${E_IP_OPTS} \
+ "unrecognized \"-o ${i}\" option" \
+ "check the option, resubmit if necessary
+ printing continues"
+ ;;
+ esac
+done
+
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ "term : ${TERM}"
+
+if [ -z "${FILTER}" ]
+then
+ #####
+ #
+ # If no filter is being used, we use netpr to push the
+ # file to the printer.
+ # (QUOTES ARE IMPORTANT!)
+ #####
+
+ case "$TERM" in
+ PS )
+ # make the "postscript" printers use cat
+ # (TSOL banners are added during filtering, so we have
+ # to use some filter.)
+ FILTER=/bin/cat
+ ;;
+ PSR )
+ # make the "reverse postscript" printers reverse the
+ # output and the use postio to talk to the printer
+ #FILTER="/usr/lib/lp/postscript/postreverse "
+ #FILTER=
+ FILTER="/usr/lib/lp/postscript/postreverse "
+ ;;
+ * )
+ # We don't know the type, so just assume that the
+ # input and output are the same. Use netpr.
+ #FILTER=/bin/cat
+ FILTER=
+ ;;
+ esac
+fi
+
+####
+# sets default value for ordering of data and control files with
+# bsd protocol. Default: data files first. Administrator
+# may set to control file first with lpadmin -o bsdctrl=first
+####
+
+banner_flag=""
+case "${nobanner}" in
+ yes )
+ banner_flag="-b"
+ ;;
+esac
+
+NETPR="/usr/lib/lp/bin/netpr ${banner_flag} ${data_file_flag} \
+ -I ${request_id} -U ${user_name} \
+ -p ${printer} ${dest} -T \"${title}\" \
+ ${timeout} ${protocol} ${controlfile} "
+LPTELL_OPTS="-l" # netpr sends LaserWriter style messages back
+PPDFILTER=/usr/lib/lp/bin/foomatic-rip
+PPDFILTERA="${PPDFILTER} ${request_id} ${user_name} \"${title}\" ${copies} \"${option_list}\""
+
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ "NETPR= ${NETPR}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ "filter : ${FILTER}"
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ "ppdfilter : ${PPDFILTERA}"
+
+node=`uname -n`
+pid=$$
+tmpfile=${LPTMPDIR}/${node}.${pid}
+tmpfilefoo=${LPTMPDIR}/${node}.${pid}.1
+
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ "tmpfile : ${tmpfile}"
+
+#####
+#
+# Set up filter for banner page
+#
+#####
+banner_filter=
+case "${TERM}" in
+PS | PSR )
+ banner_filter=" | /usr/lib/lp/postscript/postprint "
+ LPTELL_OPTS="-l"
+ ;;
+esac
+
+#####
+#
+# Build temporary file that is the banner page
+#
+#####
+PAD="#####${NL}"
+CR="\r"
+NL="${CR}\n"
+FF=
+
+small_banner() {
+ echo "${CR}\c"
+ echo "${PAD}\c"
+ echo "##### User: ${user_name}${NL}\c"
+ if [ -n "${title}" ]
+ then
+ echo "##### Title: ${title}${NL}\c"
+ fi
+ echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c"
+ echo "##### Job: ${request_id}${NL}\c"
+ echo "${PAD}\c"
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+#####
+#
+# Doing small banner as we don't know what printer is out there
+#
+#####
+banner=small_banner
+
+## Skip this for PS/PSR printers, since lp.tsol_separator handles the banners
+if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ eval "${banner} ${banner_filter}" 2>&1 1>${LPTMPDIR}/small_banner.$$
+fi
+
+###########
+##
+## Surround the job by PostScript code to produce banner
+## and trailerpages and page headers and footers.
+##
+###########
+
+BANNER_EXIT_CODE=${LPTMPDIR}/banner.exit_code.$$
+echo 0 > ${BANNER_EXIT_CODE}
+TSOLSEPARATOR_LOG=${LPTMPDIR}/banner.errmsg.$$
+
+tsol_bannerize () {
+ TSOLSEPARATOR_OPTS="-e ${TSOLSEPARATOR_LOG}"
+
+ if [ "yes" = "${nolabels}" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -l"
+ fi
+
+ if [ "yes" = "${nobanner}" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -t /dev/null -b /dev/null"
+ fi
+
+ if [ "${TERM}" = "PSR" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -r"
+ fi
+
+ # Get rid of the #, TAB and NL characters in the title
+ tsol_title=`echo $title`
+ tsol_title=`echo $tsol_title | sed 's/#//g'`
+
+ logger -p lpr.debug -t "tsol_netstandard: ${request_id}" \
+ "banner command: ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} \
+ ${printer} ${request_id} ${user_name} \"${tsol_title}\" ${file}"
+ ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} ${printer} \
+ ${request_id} ${user_name} "${tsol_title}" ${file}
+
+ echo $? > ${BANNER_EXIT_CODE}
+ true
+}
+
+bannerize=tsol_bannerize
+
+if [ "yes" = "${nobanner}" -a "yes" = "${nolabels}" ]
+then
+ bannerize=cat
+fi
+
+if [ "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ bannerize=cat
+fi
+
+#####
+#
+# Print banner page before job unless PSR or PS
+#
+#####
+
+
+## Skip this for PS/PSR printers, since lp.tsol_separator handles the banners
+if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ (
+ eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug -t \
+ "tsol_netstandard_foomatic: ${request_id}" \
+ "banner page exit code : ${exit_code}"
+
+fi
+
+i=1
+while [ $i -le $copies ]
+do
+ for file in ${files}
+ do
+ if [ -r "${file}" ]
+ then
+
+ if [ ! -z "${FILTER}" ]
+ then
+ (
+ #####
+ # There is a filter, use it
+ #
+ # Put 0<${file} before the "eval" to keep
+ # clever users from giving a file name that
+ # evaluates as something to execute.
+ # Redirect stderr to stdout so LPTELL will
+ # get error messages from pipe.
+ #####
+
+ 0<${file} $bannerize | eval ${FILTER} 2>&1 1>${tmpfile}
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ # if lp.tsol_separator had an error,
+ # send its logged error message to LPTELL.
+ banner_exit_code=`cat ${BANNER_EXIT_CODE}`
+ if [ -n "${banner_exit_code}" -a \
+ 0 -ne "${banner_exit_code}" -a \
+ -n "${LPTELL}" -a \
+ -r "${TSOLSEPARATOR_LOG}" ]
+ then
+ cat ${TSOLSEPARATOR_LOG} | ${LPTELL} ${printer}
+ echo 77 > ${LPTMPDIR}/pr_eexit_code
+ fi
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug -t \
+ "tsol_netstandard_foomatic: ${request_id}" \
+ "filter exit_code : ${exit_code}"
+
+ if [ -n "${exit_code}" ]
+ then
+ if [ "${exit_code}" -eq 0 ]
+ then
+ printfile=${tmpfile}
+ else
+ ####
+ # The filter did not succeed, so don't try to print
+ ####
+ printfile=
+ fi
+ fi
+
+ else
+ printfile=${file}
+ fi
+
+ logger -p lpr.debug -t \
+ "tsol_netstandard_foomatic: ${request_id}" \
+ "printfile : ${printfile}"
+
+ #####
+ # Print the file
+ #####
+
+ if [ -r "${printfile}" ]
+ then
+ (
+logger -p lpr.debug -t \
+ "@1 tsol_netstandard_foomatic: printfile = ${printfile}" ""
+logger -p lpr.debug -t \
+ "tsol_netstandard_foomatic: ${NETPR} ${printfile}" ""
+ #eval ${NETPR} ${printfile} 2>&1
+ cat ${printfile} | ${PPDFILTER} \
+ ${request_id} ${user_name} "${title}" ${copies} "${option_list}" \
+ > ${tmpfilefoo} 2> /dev/null
+ eval ${NETPR} ${tmpfilefoo} 2>&1
+ echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+ /bin/rm -f ${tmpfilefoo}
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+ logger -p lpr.debug -t \
+ "@2 netstandard_foomatic: ${request_id}" \
+ "netpr exit_code : ${exit_code}"
+
+# if [ -f "${tmpfile}" ]
+# then
+# /bin/rm "${tmpfile}"
+# fi
+
+ if [ -n "${exit_code}" ]
+ then
+ if [ "${exit_code}" -eq 0 ]
+ then
+ printone=yes
+ else
+ if [ "${exit_code}" -lt 128 ]
+ then
+ noprint=yes
+ else
+ retry=yes
+ fi
+ fi
+ fi
+
+
+ else
+
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read temporary file \"${printfile}\""\
+ "see if file still exists,
+ or consult your system administrator;
+ printing continues"
+
+ fi
+ else
+
+ #####
+ #
+ # Don't complain about not being able to read
+ # a file on second and subsequent copies, unless
+ # we've not complained yet. This removes repeated
+ # messages about the same file yet reduces the
+ # chance that the user can remove a file and not
+ # know that we had trouble finding it.
+ #####
+
+ if [ "${i}" -le 1 -o -z "${badfileyet}" ]
+ then
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read file \"${file}\"" \
+ "see if the file still exists and is readable,
+ or consult your system administrator;
+ printing continues"
+ badfileyet=yes
+ fi
+
+ fi
+
+# for file in ${files}
+ done
+ i=`expr $i + 1`
+done
+
+#####
+#
+# If printing in reverse order, print the banner page now
+# Skip this for TSOL, since lp.tsol_separator handles the banners
+#
+#####
+
+#if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ]
+#then
+#(
+# eval ${NETPR} ${LPTMPDIR}/small_banner.$$ 2>&1
+# echo $? > ${LPTMPDIR}/pr_eexit_code.$$
+#) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+#fi
+
+exit_code=`cat ${LPTMPDIR}/pr_eexit_code.$$`
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ "banner page exit code : ${exit_code}"
+
+if [ -n "${printone}" -a -z "${retry}" -a -z "${noprint}" ]
+then
+ exit_code=`expr 0`
+else
+ if [ -n "${retry}" -a -z "${printone}" -a -z "${noprint}" ]
+ then
+ exit_code=`expr 129`
+ else
+ exit_code=`expr 1`
+ fi
+fi
+
+logger -p lpr.debug -t "tsol_netstandard_foomatic: ${request_id}" \
+ "FINAL exit_code : ${exit_code}"
+
+exit_clean ${exit_code}
diff --git a/usr/src/cmd/lp/model/tsol_standard b/usr/src/cmd/lp/model/tsol_standard
new file mode 100644
index 0000000000..fe972a4148
--- /dev/null
+++ b/usr/src/cmd/lp/model/tsol_standard
@@ -0,0 +1,1162 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+###########
+##
+## Standard printer interface program.
+###########
+
+#####
+#
+# Until we get to the point below where the printer port
+# and physical printer are initialized, we can't do much
+# except exit if the Spooler/Scheduler cancels us.
+#####
+trap 'exit' 15
+
+#####
+#
+# We can be clever about getting a hangup or interrupt, though, at least
+# until the filter runs. Do this early, even though $LPTELL
+# isn't defined, so that we're covered.
+#####
+catch_hangup () {
+ if [ -n "${LPTELL}" ]
+ then
+ echo \
+"The connection to the printer dropped; perhaps the printer went off-line?" \
+ | ${LPTELL} ${printer}
+ fi
+ return 0
+}
+catch_interrupt () {
+ if [ -n "${LPTELL}" ]
+ then
+ echo \
+"Received an interrupt from the printer. The reason is unknown,
+although a common cause is that the baud rate is too high." \
+ | ${LPTELL} ${printer}
+ fi
+ return 0
+}
+trap 'catch_hangup; exit_code=129 exit 129' 1
+trap 'catch_interrupt; exit_code=129 exit 129' 2 3
+
+#####
+#
+# Most of the time we don't want the standard error to be captured
+# by the Spooler, mainly to avoid "Terminated" messages that the
+# shell puts out when we get a SIGTERM. We'll save the standard
+# error channel under another number, so we can use it when it
+# should be captured.
+#
+# Open another channel to the printer port, for use when the
+# regular standard output won't be directed there, such as in
+# command substitution (`cmd`).
+#####
+exec 5>&2 2>/dev/null 3>&1
+
+#####
+#
+# Set some globally used variables and functions.
+#####
+
+: ${TMPDIR:=/tmp}
+: ${SPOOLDIR:=/usr/spool/lp}
+: ${TERMINFO:=/usr/lib/terminfo}
+: ${CHARSETDIR:=/usr/lib/charsets}
+
+: ${LOCALPATH:=${SPOOLDIR}/bin}
+PATH="/bin:/usr/bin:${LOCALPATH}"
+
+MAX_COLS_SMALL_BANNER=40
+
+#####
+#
+# On the 3.2 release of the 386unix product, the parallel port does
+# not support any ioctl calls. As a result, we cannot set the opost
+# and onlcr attributes to have <NL>'s expanded to <CR><NL>. This
+# "filter" gets the job done for us.
+#####
+: ${FIX386BD:=${LOCALPATH}/386parallel}
+if [ -n "${FIX386BD}" -a -x "${FIX386BD}" ]
+then
+ FIX386BD="| ${FIX386BD}"
+else
+ FIX386BD=""
+fi
+
+#####
+# Use ${TMPPREFIX} as the prefix for all temporary files, so
+# that cleanup is easy. The prefix may be up to 13 characters
+# long, so you only have space for one more character to make
+# a file name. If necessary, make a directory using this prefix
+# for better management of unique temporary file names.
+#####
+TMPPREFIX=${TMPDIR}/`uname -n`$$
+
+#####
+# Before exiting, set ${exit_code} to the value with which to exit.
+# Otherwise, the exit from this script will be 0.
+#####
+trap 'rm -fr ${TMPPREFIX}*; exit ${exit_code}' 0
+
+#####
+# ${LPTELL} is the name of a program that will send its
+# standard input to the Spooler. It is used to forward
+# the description of a printer fault to the Spooler,
+# which uses it in an alert to the administrator.
+#####
+if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ]
+then
+ fake_lptell () {
+ header="no"
+ while read line
+ do
+ if [ "no" = "${header}" ]
+ then
+ errmsg ERROR ${E_IP_UNKNOWN} \
+ "unknown printer/interface failure" \
+ "consult your system administrator;
+ reasons for failure (if any) follow:"
+ header=yes
+ fi
+ echo "${line}" >&2
+ done
+ return 1
+ }
+ LPTELL=fake_lptell
+fi
+
+#####
+# ${DRAIN} is the name of a program that will wait
+# long enough for data sent to the printer to print.
+#####
+if [ -x "${LOCALPATH}/drain.output" ]
+then
+ DRAIN="${LOCALPATH}/drain.output 5" # wait only five seconds
+else
+ DRAIN=
+fi
+
+#####
+# ${LPTSOLSEPARATOR} is the name of a program to put banner and trailer
+# pages around the job.
+#####
+if [ -x ${LOCALPATH}/lp.tsol_separator ]
+then
+ LPTSOLSEPARATOR=${LOCALPATH}/lp.tsol_separator
+else
+ echo "${LOCALPATH}/lp.tsol_separator not found." >&2
+ exit 1
+fi
+
+#####
+# ${LPCAT} is the name of a program to use as a default
+# filter. Minimally it should copy its standard input to
+# the standard output, but it should also trap printer
+# faults. The current LPCAT traps hangups (DCD dropping, SIGHUP),
+# interrupts (SIGINT, SIGQUIT), broken pipe (SIGPIPE), and
+# excess delays in sending data to the printer, interpreting all
+# as printer faults.
+#####
+if [ ! -x "${LPCAT:=${LOCALPATH}/lp.cat}" ]
+then
+ LPCAT="cat"
+fi
+
+#####
+# ${LPSET} is the name of a program that will set the
+# character pitch, line pitch, page width, page length,
+# and character set. It helps to have this in a single
+# binary program so that (1) it's faster than calls
+# to "tput"; and (2) it can access the new Terminfo
+# capabilities for printers (on pre SVR3.2 machines, tput can't).
+#####
+if [ ! -x "${LPSET:=${LOCALPATH}/lp.set}" ]
+then
+ fake_lpset () {
+ echo H V W L S >&2
+ false
+ }
+ LPSET=fake_lpset
+fi
+
+internal_lpset () {
+ #####
+ #
+ # The funny business with the "2>&1 1>&3" is to let us capture
+ # the standard ERROR, not the standard OUTPUT as is the usual case
+ # with foo=`cmd`. The standard output will go to the printer.
+ #####
+ [ -n "${stty1}" ] && stty ${stty1} 0<&1
+ chk=`${LPSET} "$1" "$2" "$3" "$4" "$5" 2>&1 1>&3`
+ [ -n "${stty2}" ] && stty ${stty2} 0<&1
+
+ #####
+ #
+ # The standard error of the delivered ${LPSET} program
+ # is a string of letters, H, V, W, L, S, which correspond
+ # to cpi, lpi, width, length, and character set. A letter
+ # is present only if the corresponding attribute could not
+ # be set.
+ #####
+ for err in ${chk}
+ do
+ case ${err} in
+ H )
+ errmsg WARNING ${E_IP_BADCPI} \
+ "can't select the character pitch \"${cpi}\"" \
+ "check the valid pitches for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ V )
+ errmsg WARNING ${E_IP_BADLPI} \
+ "can't select the line pitch \"${lpi}\"" \
+ "check the valid pitches for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ W )
+ width=${cols}
+ errmsg WARNING ${E_IP_BADWIDTH} \
+ "can't select the page width \"${width}\"" \
+ "check the valid widths for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ L )
+ length=${lines}
+ errmsg WARNING ${E_IP_BADLENGTH} \
+ "can't select the page length \"${length}\"" \
+ "check the valid lengths for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ S )
+ errmsg WARNING ${E_IP_BADCHARSET} \
+ "can't select the character set \"${CHARSET}\"" \
+ "check the name given in the -S option,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ esac
+ done
+}
+
+
+#####
+# ${TPUT} is "tput" IF it works. We'll disable it if we get an
+# ugly error message the first time we use it. See the TERM variable
+# later in the script.
+#
+# NOTE: The check we use to see if "tput" works is to use an OLD
+# Terminfo capability, like "lines". If it works with that it may
+# still fail with some of the newer capabilities like "init" (SVR3.0)
+# or "swidm" (SVR3.2), because the version of "tput" we have on your
+# machine is older. Thus, on some of the code where ${TPUT} is used
+# you'll see "2>/dev/null" being used to avoid ugly error messages.
+#####
+TPUT=tput
+
+#####
+# Error message formatter:
+#
+# Invoke as
+#
+# errmsg severity message-number problem help
+#
+# where severity is "ERROR" or "WARNING", message-number is
+# a unique identifier, problem is a short description of the
+# problem, and help is a short suggestion for fixing the problem.
+#####
+
+LP_ERR_LABEL="UX:lp"
+
+E_IP_ARGS=1
+E_IP_OPTS=2
+#E_IP_FILTER=3
+E_IP_STTY=4
+E_IP_UNKNOWN=5
+E_IP_BADFILE=6
+E_IP_BADCHARSET=7
+E_IP_BADCPI=8
+E_IP_BADLPI=9
+E_IP_BADWIDTH=10
+E_IP_BADLENGTH=11
+E_IP_ERRORS=12 # (in slow.filter)
+
+errmsg () {
+ case $1 in
+ ERROR )
+ sev=" ERROR";
+ ;;
+ WARNING )
+ sev="WARNING";
+ ;;
+ esac
+# tag=`expr "${LP_ERR_LABEL}" : "\(.*\):"``expr "${LP_ERR_LABEL}" : ".*:\(.*\)"`
+ echo "${LP_ERR_LABEL}: ${sev}: $3
+ TO FIX: $4" >&5
+}
+
+
+###########
+##
+## Check arguments
+###########
+
+parse () {
+ echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
+}
+
+#####
+#
+# This program is invoked as
+#
+# ${SPOOLDIR}/.../printer request-id user title copies options files...
+#
+# The first three arguments are simply reprinted on the banner page,
+# the fourth (copies) is used to control the number of copies to print,
+# the fifth (options) is a blank separated list (in a single argument)
+# of user or Spooler supplied options (without the -o prefix),
+# and the last arguments are the files to print.
+#####
+
+if [ $# -lt 5 ]
+then
+ errmsg ERROR ${E_IP_ARGS} \
+ "wrong number of arguments to interface program" \
+ "consult your system administrator"
+ exit 1
+fi
+
+printer=`basename $0`
+request_id=$1
+user_name=$2
+title=$3
+copies=$4
+option_list=$5
+
+shift 5
+files="$*"
+
+nobanner="no"
+nofilebreak="no"
+nolabels="no"
+stty=
+
+inlist=
+for i in ${option_list}
+do
+ case "${inlist}${i}" in
+
+
+ nobanner )
+ nobanner="yes"
+ ;;
+
+ nofilebreak )
+ nofilebreak="yes"
+ ;;
+
+ nolabels )
+ nolabels="yes"
+ ;;
+
+ #####
+ #
+ # If you want to add simple options (e.g. -o simple)
+ # identify them here.
+ #####
+# simple )
+# simple="yes"
+# ;;
+
+
+ cpi=pica )
+ cpi=10
+ ;;
+ cpi=elite )
+ cpi=12
+ ;;
+ cpi=* )
+ cpi=`parse ${i}`
+ ;;
+
+ lpi=* )
+ lpi=`parse ${i}`
+ ;;
+
+ length=* )
+ length=`parse ${i}`
+ ;;
+
+ width=* )
+ width=`parse ${i}`
+ ;;
+
+ #####
+ #
+ # If you want to add simple-value options (e.g. -o value=a)
+ # identify them here.
+ #####
+# value=* )
+# value=`parse ${i}`
+# ;;
+
+
+ #####
+ #
+ # If you want to add options that, like "stty",
+ # take a list (e.g. -o lopt='a b c'), identify
+ # them here and below (look for LOPT).
+ #####
+ stty=* | flist=* | lpd=* )
+#LOPT stty=* | flist=* | lpd=* | lopt=* )
+
+ inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"`
+ case "${i}" in
+ ${inlist}\'*\' )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"`
+ ;;
+ ${inlist}\' )
+ continue
+ ;;
+ ${inlist}\'* )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)\$"`
+ ;;
+ ${inlist}* )
+ item=`expr "${i}" : "^[^=]*=\(.*\)\$"`
+ ;;
+ *\' )
+ item=`expr "${i}" : "^\(.*\)'\$"`
+ ;;
+ * )
+ item="${i}"
+ ;;
+ esac
+
+ #####
+ #
+ # We don't dare use "eval" because a clever user could
+ # put something in an option value that we'd end up
+ # exec'ing.
+ #####
+ case "${inlist}" in
+ stty= )
+ stty="${stty} ${item}"
+ ;;
+ flist= )
+ flist="${flist} ${item}"
+ ;;
+ lpd= )
+ lpd="${lpd} ${item}"
+ ;;
+#LOPT lopt= )
+#LOPT lopt="${lopt} ${item}"
+#LOPT ;;
+ esac
+
+ case "${i}" in
+ ${inlist}\'*\' )
+ inlist=
+ ;;
+ ${inlist}\'* )
+ ;;
+ *\' | ${inlist}* )
+ inlist=
+ ;;
+ esac
+ ;;
+
+ * )
+ errmsg WARNING ${E_IP_OPTS} \
+ "unrecognized \"-o ${i}\" option" \
+ "check the option, resubmit if necessary
+ printing continues"
+ ;;
+ esac
+done
+
+#####
+#
+# Additional ``parameters'' are passed via Shell environment
+# variables:
+#
+# TERM The printer type (used for Terminfo access)
+# CHARSET The character set to choose
+# FILTER The filter to run
+#####
+
+#####
+# Set defaults for unset variables.
+#####
+
+: ${TERM:=unknown}
+tput lines 1>/dev/null 2>&1 || TPUT=:
+
+: ${CHARSET:=cs0}
+
+if [ -z "${FILTER}" ]
+then
+ #####
+ #
+ # If no filter is being used, we have a little routine that
+ # will push the data to the printer. It traps hangups (loss
+ # of carrier) and checks for excessive delays in sending the
+ # data to the printer. The lesser of the print rate of the printer
+ # (obtained from Terminfo) or the baud rate is used to compute
+ # the expected delay. If neither of these is correct, you
+ # may be experiencing false alarms. If so, give the correct
+ # rate, in characters per second, as a single argument.
+ # An argument of 0 means don't check for delays.
+ # Give an -r option to get a printout of actual delays.
+ # (QUOTES ARE IMPORTANT!)
+ #####
+ case "$TERM" in
+ PS )
+ # make the "postscript" printers use postio to
+ # talk to the printer and periodically get a
+ # status from them
+ FILTER="/usr/lib/lp/postscript/postio"
+ ;;
+ PSR )
+ # make the "reverse postscript" printers reverse the
+ # output and the use postio to talk to the printer
+ FILTER="/usr/lib/lp/postscript/postreverse | \
+ /usr/lib/lp/postscript/postio"
+ ;;
+ * )
+ # we don't know the type, so just assume that the
+ # input and output are the same
+ if [ `basename "${LPCAT}"` = "lp.cat" ] ; then
+ FILTER="${LPCAT} 0" # infinite delays
+ # FILTER="${LPCAT} 120" # e.g. 120 CPS
+ # FILTER="${LPCAT} -r 0 2>/tmp/delays"
+ # FILTER=${LPCAT}
+ fi
+ ;;
+ esac
+fi
+
+###########
+##
+## Initialize the printer port
+###########
+
+#####
+#
+# SERIAL PORTS:
+# Initialize everything.
+#
+# PARALLEL PORTS:
+# Don't initialize baud rate.
+#
+# It's not obvious how to tell if a port is parallel or serial.
+# However, by splitting the initialization into two steps and letting
+# the serial-only part fail nicely, it'll work.
+#
+# Another point: The output must be a ``tty'' device. If not, don't
+# bother with any of this.
+#####
+stty1= stty2=
+tty 0<&1 1>/dev/null 2>&1 && {
+
+ #####
+ #
+ # First set the default parameters,
+ # then the requested parameters.
+ #####
+
+ stty \
+ 9600 \
+ 0<&1 2>/dev/null 1>&2
+ stty \
+ cs8 -cstopb -parenb -parodd \
+ ixon -ixany \
+ opost -olcuc onlcr -ocrnl -onocr -onlret -ofill \
+ nl0 cr0 tab0 bs0 vt0 ff0 \
+ 0<&1 2>/dev/null 1>&2
+
+ if [ -n "${stty}" ]
+ then
+ if stty ${stty} 0<&1 1>/dev/null 2>&5
+ then
+ :
+ else
+ errmsg ERROR ${E_IP_STTY} \
+ "stty option list failed" \
+ "check the \"-o stty\" option you used,
+ or consult your system administrator"
+ exit 1
+ fi
+ fi
+
+ #####
+ #
+ # Here you may want to add other port initialization code.
+ # Some examples:
+ #
+ # estty # for printer needing hardware flow control (3B2/EPORTS)
+ # fctty # for printer needing hardware flow control (3B15,3B20)
+ #####
+ #estty 0<&1
+ #fctty 0<&1
+
+
+ ##########
+ #
+ # Find out if we have to turn off opost before initializing the
+ # printer and on after. Likewise, check clocal.
+ #
+ # Turning OFF opost (output postprocessing) keeps the UNIX system
+ # from changing what we try to send to the printer. Turning ON
+ # clocal keeps the UNIX system from dropping what we are trying to
+ # send if the printer drops DTR. An example of the former is the
+ # AT&T 479, which wants to send a linefeed (ASCII 10) when a page
+ # width of 10 is set; with opost on, this COULD BE turned into a
+ # carriage-return/linefeed pair. An example of the latter is the
+ # AT&T 455, which momentarily drops DTR when it gets the
+ # initialization string, is2; with clocal off, the UNIX system
+ # stops sending the rest of the initialization sequence at that
+ # point.
+ #
+ # THIS CODE MUST FOLLOW THE REST OF THE PORT INITIALIZATION CODE.
+ ##########
+ cur_stty=`stty -a 0<&3`
+ expr "${cur_stty}" : '.*-opost' 1>/dev/null 2>&1 \
+ || stty1="${stty1} -opost" stty2="${stty2} opost"
+ expr "${cur_stty}" : '.*-clocal' 1>/dev/null 2>&1 \
+ && stty1="${stty1} clocal" stty2="${stty2} -clocal"
+ expr "${cur_stty}" : '.* opost.*' 1>/dev/null 2>&1 \
+ || banner_filter=${FIX386BD}
+
+}
+
+
+###########
+##
+## Initialize the physical printer (Part I).
+## Here we bring the printer to a sane state and set the page size.
+###########
+
+##########
+#
+# WARNING! The "echo" command will catch backslashes (\) and
+# try to interpret the characters following it. Thus, using
+# "echo" to print string values obtained from "tput" is dangerous.
+##########
+
+#####
+# We're confident that most printers don't have backslashes
+# in the control sequences for carriage return and form-feed.
+# We're also confident that these don't contain newlines.
+# We're also confident that most printers have a linefeed
+# in the control sequence for doing a newline (move to beginning
+# of next line), but we can't capture it like we do the
+# carriage return or form-feed. Thus we set it unconditionally.
+# We don't set form-feed if it isn't defined, however, because
+# maybe the printer doesn't have a formfeed. If not set, we're
+# out of luck.
+#####
+
+CR=`${TPUT} cr`
+[ -z "${CR}" ] && CR="\r"
+
+FF=`${TPUT} ff`
+
+NL="${CR}\n"
+
+lines=`${TPUT} lines`
+[ -z "${lines}" -o 0 -ge "${lines}" ] && lines=66
+
+cols=`${TPUT} cols`
+[ -z "${cols}" -o 0 -ge "${cols}" ] && cols=132
+
+#####
+#
+# Basic initialization. The ``else'' clause is equivalent,
+# but covers cases where old Terminal Information Utilities are present.
+#####
+[ -n "${stty1}" ] && stty ${stty1} 0<&1
+
+#
+# "tput init" will return an "^M" in many cases to "stdout", i.e., printer!
+# This creates problems for some PS printers
+#
+if [ "${TERM}" = "PS" -o "${TERM}" = "PSR" ]
+then
+ :
+elif ${TPUT} init 2>/dev/null
+then
+ :
+else
+ pgm=`${TPUT} iprog`
+ if [ -x "${pgm}" ]
+ then
+ eval ${pgm}
+ fi
+
+ ${TPUT} is1
+ ${TPUT} is2
+
+ tabset=
+ if [ "8" != "`${TPUT} it`" ]
+ then
+ stty tab3 0<&1 1>/dev/null 2>&1
+
+ elif `${TPUT} ht >/dev/null`
+ then
+ tabset="/usr/lib/tabset/${TERM}"
+ if [ -r ${tabset} ]
+ then
+ cat -s ${tabset}
+ fi
+ stty tab3 0<&1 1>/dev/null 2>&1
+ fi
+
+ file=`${TPUT} if`
+ if [ "${tabset}" != "${file}" -a -r "${file}" ]
+ then
+ cat -s "${file}"
+ fi
+
+ ${TPUT} is3
+ echo "${CR}\c"
+fi
+[ -n "${stty2}" ] && stty ${stty2} 0<&1
+
+#####
+#
+# Set the page size and print spacing, but not the character set.
+# We will be doing the character set later (after the header).
+#####
+internal_lpset "${cpi}" "${lpi}" "${width}" "${length}" ""
+
+#####
+#
+# The banner page (and cancellation page) will
+# use double width characters if they're available.
+#####
+WIDE_CS=`${TPUT} swidm 2>/dev/null` && NORM_CS=`${TPUT} rwidm 2>/dev/null`
+PAD="#####${NL}"
+
+#####
+#
+# Some printers need to have the banner page filtered.
+#####
+case "${TERM}" in
+
+PS | PSR )
+ banner_filter="/usr/lib/lp/postscript/postprint | /usr/lib/lp/postscript/postio"
+ LPTELL_OPTS="-l"
+ ;;
+
+esac
+if [ -n "${banner_filter}" ]
+then
+ banner_filter="| ${banner_filter}"
+fi
+
+#####
+#
+# Now that the printer is ready for printing, we're able
+# to record on paper a cancellation.
+#####
+
+cancel_banner () {
+ echo "${PAD}${PAD}\c"
+ echo "#####${WIDE_CS} Job ${request_id}${NORM_CS}${NL}\c"
+ echo "#####${WIDE_CS} suspended or canceled${NORM_CS}${NL}\c"
+ echo "${PAD}${PAD}\c"
+}
+
+canceled () {
+ ${TPUT} scs 0 2>/dev/null
+ echo "${CR}\c"
+ if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
+ then
+ WIDE_CS= NORM_CS=
+ fi
+ cancel_banner
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+trap 'eval canceled ${banner_filter}; exit_code=0 exit' 15
+
+
+###########
+##
+## Print the banner page
+###########
+
+#####
+#
+# You may want to change the following code to get a custom banner.
+#####
+
+regular_banner () {
+ echo "${CR}\c"
+ echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c"
+ echo "#####${WIDE_CS} User: ${user_name}${NORM_CS}${NL}\c"
+ if [ -n "$ALIAS_USERNAME" ]
+ then
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Alias: ${ALIAS_USERNAME}${NORM_CS}${NL}\c"
+ fi
+ if [ -n "${title}" ]
+ then
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Title: ${title}${NORM_CS}${NL}\c"
+ fi
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Printed: `LANG=C date '+%a %H:%M %h %d, %Y'`${NORM_CS}${NL}\c"
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Job number: ${request_id}${NORM_CS}${NL}\c"
+ echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c"
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+small_banner () {
+ echo "${CR}\c"
+ echo "${PAD}\c"
+ echo "##### User: ${user_name}${NL}\c"
+ if [ -n "${title}" ]
+ then
+ echo "##### Title: ${title}${NL}\c"
+ fi
+ echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c"
+ echo "##### Job: ${request_id}${NL}\c"
+ echo "${PAD}\c"
+ if [ -n "${FF}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+}
+
+if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
+then
+ banner=small_banner
+else
+ banner=regular_banner
+fi
+
+## Skip this for PS/PSR in TSOL, since lp.tsol_separator handles the banners
+if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
+ | ${LPTELL} ${LPTELL_OPTS} ${printer}
+fi
+
+###########
+##
+## Surround the job by PostScript code to produce banner
+## and trailerpages and page headers and footers.
+##
+###########
+
+BANNER_EXIT_CODE=${TMPPREFIX}.banner.exit_code
+echo 0 > ${BANNER_EXIT_CODE}
+TSOLSEPARATOR_LOG=${TMPPREFIX}.banner.errmsg
+
+tsol_bannerize () {
+ TSOLSEPARATOR_OPTS="-e ${TSOLSEPARATOR_LOG}"
+
+ if [ "yes" = "${nolabels}" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -l"
+ fi
+
+ if [ "yes" = "${nobanner}" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -t /dev/null -b /dev/null"
+ fi
+
+ if [ "${TERM}" = "PSR" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -r"
+ fi
+
+ # Get rid of the #, TAB and NL characters in the title
+ tsol_title=`echo $title`
+ tsol_title=`echo $tsol_title | sed 's/#//g'`
+
+ LC_TIME=C ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} "${printer}" \
+ "${request_id}" "${user_name}" "${tsol_title}" "${file}"
+ echo $? > ${BANNER_EXIT_CODE}
+ true
+}
+
+bannerize=tsol_bannerize
+
+if [ "yes" = "${nobanner}" -a "yes" = "${nolabels}" ]
+then
+ bannerize=cat
+fi
+
+if [ "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ bannerize=cat
+fi
+
+
+###########
+##
+## Initialize the physical printer (Part II)
+## Here we select the character set.
+## One could argue that this should be done before the banner is printed,
+## but we don't, to keep the banner page looking consistent for the
+## operator. You can move this code before the banner code if you
+## disagree. If you do, combine it with the other call to "internal_lpset"
+## to do everything in one shot.
+###########
+internal_lpset "" "" "" "" "${CHARSET}"
+
+###########
+##
+## Print some copies of the file(s)
+###########
+
+#####
+#
+# The protocol between the interface program and the Spooler
+# is fairly simple:
+#
+# All standard error output is assumed to indicate a
+# fault WITH THE REQUEST. The output is mailed to the
+# user who submitted the print request and the print
+# request is finished.
+#
+# If the interface program sets a zero exit code,
+# it is assumed that the file printed correctly.
+# If the interface program sets a non-zero exit code
+# less than 128, it is assumed that the file did not
+# print correctly, and the user will be notified.
+# In either case the print request is finished.
+#
+# If the interface program sets an exit code greater
+# than 128, it is assumed that the file did not print
+# because of a printer fault. If an alert isn't already
+# active (see below) one will be activated. (Exit code
+# 128 should not be used at all. The shell, which executes
+# this program, turns SIGTERM, used to kill this program
+# for a cancellation or disabling, into exit 128. The
+# Spooler thus interpretes 128 as SIGTERM.)
+#
+# A message sent to the standard input of the ${LPTELL}
+# program is assumed to describe a fault WITH THE PRINTER.
+# The output is used in an alert (if alerts are defined).
+# If the fault recovery is "wait" or "begin", the printer
+# is disabled (killing the interface program if need be),
+# and the print request is left on the queue.
+# If the fault recovery is "continue", the interface program
+# is allowed to wait for the printer fault to be cleared so
+# it can resume printing.
+#
+# This interface program relies on filters to detect printer faults.
+# In absence of a filter provided by the customer, it uses a simple
+# filter (${LPCAT}) to detect the class of faults that cause DCD
+# (``carrier'') drop. The protocol between the interface program and
+# the filter:
+#
+# The filter should exit with zero if printing was
+# successful and non-zero if printing failed because
+# of a printer fault. This interface program turns a
+# non-zero exit of the filter into an "exit 129" from
+# itself, thus telling the Spooler that a printer fault
+# (still) exists.
+#
+# The filter should report printer faults via a message
+# to its standard error. This interface program takes all
+# standard error output from the filter and feeds it as
+# standard input to the ${LPTELL} program.
+#
+# The filter should wait for a printer fault to clear,
+# and should resume printing when the fault clears.
+# Preferably it should resume at the top of the page
+# that was being printed when the fault occurred.
+# If it waits and finishes printing, it should exit
+# with a 0 exit code. If it can't wait, it should exit
+# with a non-zero exit code.
+#
+# The interface program expects that ANY message on the
+# standard error from the filter indicates a printer fault.
+# Therefore, a filter should not put user (input) error
+# messages on the standard error, but on the standard output
+# (where the user can read them when he or she examines
+# the print-out).
+#
+#####
+
+badfileyet=
+i=1
+while [ $i -le $copies ]
+do
+ for file in ${files}
+ do
+ if [ -r "${file}" ]
+ then
+ #####
+ #
+ # Here's where we set up the $LPTELL program to
+ # capture fault messages, and...
+ #
+ # Here's where we print the file.
+ #
+ # We set up a pipeline to $LPTELL, but play a trick
+ # to get the filter's standard ERROR piped instead of
+ # its standard OUTPUT: Divert the standard error (#2) to
+ # the standard output (#1) IN THE PIPELINE. The shell
+ # will have changed #1 to be the pipe, not the
+ # printer, so diverting #2 connects it to the pipe.
+ # We then change the filter's #1 to a copy of the real
+ # standard output (the printer port) made earlier,
+ # so that is connected back to the printer again.
+ #
+ # We do all this inside a parenthesized expression
+ # so that we can get the exit code; this is necessary
+ # because the exit code of a pipeline is the exit
+ # code of the right-most command, which isn't the
+ # filter.
+ #
+ # These two tricks could be avoided by using a named
+ # pipe to connect the standard error to $LPTELL. In
+ # fact an early prototype of this script did just
+ # that; however, the named pipe introduced a timing
+ # problem. The processes that open a named pipe hang
+ # until both ends of the pipe are opened. Cancelling
+ # a request or disabling the printer often killed one
+ # of the processes, causing the other process to hang
+ # forever waiting for the other end of the pipe to
+ # be opened.
+ #####
+ EXIT_CODE=${TMPPREFIX}e
+ trap '' 1 # Let the filter handle a hangup
+ trap '' 2 3 # and interrupts
+ (
+ #####
+ # Put the 0<${file} before the "eval" to keep
+ # clever users from giving a file name that
+ # evaluates as something to execute.
+ #####
+ 0<${file} $bannerize | eval ${FILTER} 2>&1 1>&3
+ echo $? >${EXIT_CODE}
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ # if lp.tsol_separator had an error, send its logged
+ # error message to LPTELL.
+ banner_exit_code=`cat ${BANNER_EXIT_CODE}`
+ if [ -n "${banner_exit_code}" -a \
+ 0 -ne "${banner_exit_code}" -a \
+ -n "${LPTELL}" -a \
+ -r "${TSOLSEPARATOR_LOG}" ]
+ then
+ cat ${TSOLSEPARATOR_LOG} | ${LPTELL} ${printer}
+ echo 77 > ${EXIT_CODE}
+ fi
+
+ trap 'catch_hangup; exit_code=129 exit 129' 1
+ trap 'catch_interrupt; exit_code=129 exit 129' 2 3
+ exit_code=`cat ${EXIT_CODE}`
+
+ if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
+ then
+ trap '' 15 # Avoid dying from disable
+ sleep 4 # Give $LPTELL a chance to tell
+ exit ${exit_code}
+ fi
+
+ if [ -n "${FF}" -a "no" = "${nofilebreak}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+
+ else
+
+ #####
+ #
+ # Don't complain about not being able to read
+ # a file on second and subsequent copies, unless
+ # we've not complained yet. This removes repeated
+ # messages about the same file yet reduces the
+ # chance that the user can remove a file and not
+ # know that we had trouble finding it.
+ #####
+ if [ "${i}" -le 1 -o -z "${badfileyet}" ]
+ then
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read file \"${file}\"" \
+ "see if the file still exists and is readable,
+ or consult your system administrator;
+ printing continues"
+ badfileyet=yes
+ fi
+
+ fi
+
+ done
+ i=`expr $i + 1`
+
+done
+
+# Skip this for TSOL, since lp.tsol_separator handles the banners
+#
+# if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ]
+# then
+# ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
+# | ${LPTELL} ${LPTELL_OPTS} ${printer}
+# fi
+
+if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
+then
+ exit ${exit_code}
+fi
+
+#####
+#
+# Always ensure the complete job ends with a ``formfeed'', to
+# let the next job start on a new page. (If someone wants to
+# concatenate files, they can give them in one job.)
+# So, if we haven't been putting out a ``formfeed'' between files,
+# it means we haven't followed the last file with a formfeed,
+# so we do it here.
+#####
+if [ -n "${FF}" -a "yes" = "${nofilebreak}" ]
+then
+ echo "${CR}${FF}\c"
+fi
+
+${DRAIN}
+
+exit_code=0 exit 0
diff --git a/usr/src/cmd/lp/model/tsol_standard_foomatic b/usr/src/cmd/lp/model/tsol_standard_foomatic
new file mode 100644
index 0000000000..c446b0ad8c
--- /dev/null
+++ b/usr/src/cmd/lp/model/tsol_standard_foomatic
@@ -0,0 +1,1190 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+###########
+##
+## Standard printer interface program.
+##
+###########
+
+#####
+#
+# Until we get to the point below where the printer port
+# and physical printer are initialized, we can't do much
+# except exit if the Spooler/Scheduler cancels us.
+#####
+trap 'exit' 15
+
+#####
+#
+# We can be clever about getting a hangup or interrupt, though, at least
+# until the filter runs. Do this early, even though $LPTELL
+# isn't defined, so that we're covered.
+#####
+catch_hangup () {
+ if [ -n "${LPTELL}" ]
+ then
+ echo \
+"The connection to the printer dropped; perhaps the printer went off-line?" \
+ | ${LPTELL} ${printer}
+ fi
+ return 0
+}
+catch_interrupt () {
+ if [ -n "${LPTELL}" ]
+ then
+ echo \
+"Received an interrupt from the printer. The reason is unknown,
+although a common cause is that the baud rate is too high." \
+ | ${LPTELL} ${printer}
+ fi
+ return 0
+}
+trap 'catch_hangup; exit_code=129 exit 129' 1
+trap 'catch_interrupt; exit_code=129 exit 129' 2 3
+
+#####
+#
+# Most of the time we don't want the standard error to be captured
+# by the Spooler, mainly to avoid "Terminated" messages that the
+# shell puts out when we get a SIGTERM. We'll save the standard
+# error channel under another number, so we can use it when it
+# should be captured.
+#
+# Open another channel to the printer port, for use when the
+# regular standard output won't be directed there, such as in
+# command substitution (`cmd`).
+#####
+exec 5>&2 2>/dev/null 3>&1
+
+#####
+#
+# Set some globally used variables and functions.
+#####
+
+: ${TMPDIR:=/tmp}
+: ${SPOOLDIR:=/usr/spool/lp}
+: ${TERMINFO:=/usr/lib/terminfo}
+: ${CHARSETDIR:=/usr/lib/charsets}
+
+: ${LOCALPATH:=${SPOOLDIR}/bin}
+PATH="/bin:/usr/bin:${LOCALPATH}"
+
+MAX_COLS_SMALL_BANNER=40
+
+#####
+#
+# On the 3.2 release of the 386unix product, the parallel port does
+# not support any ioctl calls. As a result, we cannot set the opost
+# and onlcr attributes to have <NL>'s expanded to <CR><NL>. This
+# "filter" gets the job done for us.
+#####
+: ${FIX386BD:=${LOCALPATH}/386parallel}
+if [ -n "${FIX386BD}" -a -x "${FIX386BD}" ]
+then
+ FIX386BD="| ${FIX386BD}"
+else
+ FIX386BD=""
+fi
+
+#####
+# Use ${TMPPREFIX} as the prefix for all temporary files, so
+# that cleanup is easy. The prefix may be up to 13 characters
+# long, so you only have space for one more character to make
+# a file name. If necessary, make a directory using this prefix
+# for better management of unique temporary file names.
+#####
+TMPPREFIX=${TMPDIR}/`uname -n`$$
+
+#####
+# Before exiting, set ${exit_code} to the value with which to exit.
+# Otherwise, the exit from this script will be 0.
+#####
+trap 'rm -fr ${TMPPREFIX}*; exit ${exit_code}' 0
+
+#####
+# ${LPTELL} is the name of a program that will send its
+# standard input to the Spooler. It is used to forward
+# the description of a printer fault to the Spooler,
+# which uses it in an alert to the administrator.
+#####
+if [ ! -x "${LPTELL:=${LOCALPATH}/lp.tell}" ]
+then
+ fake_lptell () {
+ header="no"
+ while read line
+ do
+ if [ "no" = "${header}" ]
+ then
+ errmsg ERROR ${E_IP_UNKNOWN} \
+ "unknown printer/interface failure" \
+ "consult your system administrator;
+ reasons for failure (if any) follow:"
+ header=yes
+ fi
+ echo "${line}" >&2
+ done
+ return 1
+ }
+ LPTELL=fake_lptell
+fi
+
+#####
+# ${DRAIN} is the name of a program that will wait
+# long enough for data sent to the printer to print.
+#####
+if [ -x "${LOCALPATH}/drain.output" ]
+then
+ DRAIN="${LOCALPATH}/drain.output 5" # wait only five seconds
+else
+ DRAIN=
+fi
+
+#####
+# ${LPTSOLSEPARATOR} is the name of a program to put banner and trailer
+# pages around the job.
+#####
+if [ -x ${LOCALPATH}/lp.tsol_separator ]
+then
+ LPTSOLSEPARATOR=${LOCALPATH}/lp.tsol_separator
+else
+ echo "${LOCALPATH}/lp.tsol_separator not found." >&2
+ exit 1
+fi
+
+#####
+# ${LPCAT} is the name of a program to use as a default
+# filter. Minimally it should copy its standard input to
+# the standard output, but it should also trap printer
+# faults. The current LPCAT traps hangups (DCD dropping, SIGHUP),
+# interrupts (SIGINT, SIGQUIT), broken pipe (SIGPIPE), and
+# excess delays in sending data to the printer, interpreting all
+# as printer faults.
+#####
+if [ ! -x "${LPCAT:=${LOCALPATH}/lp.cat}" ]
+then
+ LPCAT="cat"
+fi
+
+#####
+# ${LPSET} is the name of a program that will set the
+# character pitch, line pitch, page width, page length,
+# and character set. It helps to have this in a single
+# binary program so that (1) it's faster than calls
+# to "tput"; and (2) it can access the new Terminfo
+# capabilities for printers (on pre SVR3.2 machines, tput can't).
+#####
+if [ ! -x "${LPSET:=${LOCALPATH}/lp.set}" ]
+then
+ fake_lpset () {
+ echo H V W L S >&2
+ false
+ }
+ LPSET=fake_lpset
+fi
+
+internal_lpset () {
+ #####
+ #
+ # The funny business with the "2>&1 1>&3" is to let us capture
+ # the standard ERROR, not the standard OUTPUT as is the usual case
+ # with foo=`cmd`. The standard output will go to the printer.
+ #####
+ [ -n "${stty1}" ] && stty ${stty1} 0<&1
+ chk=`${LPSET} "$1" "$2" "$3" "$4" "$5" 2>&1 1>&3`
+ [ -n "${stty2}" ] && stty ${stty2} 0<&1
+
+ #####
+ #
+ # The standard error of the delivered ${LPSET} program
+ # is a string of letters, H, V, W, L, S, which correspond
+ # to cpi, lpi, width, length, and character set. A letter
+ # is present only if the corresponding attribute could not
+ # be set.
+ #####
+ for err in ${chk}
+ do
+ case ${err} in
+ H )
+ errmsg WARNING ${E_IP_BADCPI} \
+ "can't select the character pitch \"${cpi}\"" \
+ "check the valid pitches for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ V )
+ errmsg WARNING ${E_IP_BADLPI} \
+ "can't select the line pitch \"${lpi}\"" \
+ "check the valid pitches for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ W )
+ width=${cols}
+ errmsg WARNING ${E_IP_BADWIDTH} \
+ "can't select the page width \"${width}\"" \
+ "check the valid widths for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ L )
+ length=${lines}
+ errmsg WARNING ${E_IP_BADLENGTH} \
+ "can't select the page length \"${length}\"" \
+ "check the valid lengths for the printer,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ S )
+ errmsg WARNING ${E_IP_BADCHARSET} \
+ "can't select the character set \"${CHARSET}\"" \
+ "check the name given in the -S option,
+ or consult your system administrator;
+ printing continues"
+ ;;
+ esac
+ done
+}
+
+
+#####
+# ${TPUT} is "tput" IF it works. We'll disable it if we get an
+# ugly error message the first time we use it. See the TERM variable
+# later in the script.
+#
+# NOTE: The check we use to see if "tput" works is to use an OLD
+# Terminfo capability, like "lines". If it works with that it may
+# still fail with some of the newer capabilities like "init" (SVR3.0)
+# or "swidm" (SVR3.2), because the version of "tput" we have on your
+# machine is older. Thus, on some of the code where ${TPUT} is used
+# you'll see "2>/dev/null" being used to avoid ugly error messages.
+#####
+TPUT=tput
+
+#####
+# Error message formatter:
+#
+# Invoke as
+#
+# errmsg severity message-number problem help
+#
+# where severity is "ERROR" or "WARNING", message-number is
+# a unique identifier, problem is a short description of the
+# problem, and help is a short suggestion for fixing the problem.
+#####
+
+LP_ERR_LABEL="UX:lp"
+
+E_IP_ARGS=1
+E_IP_OPTS=2
+#E_IP_FILTER=3
+E_IP_STTY=4
+E_IP_UNKNOWN=5
+E_IP_BADFILE=6
+E_IP_BADCHARSET=7
+E_IP_BADCPI=8
+E_IP_BADLPI=9
+E_IP_BADWIDTH=10
+E_IP_BADLENGTH=11
+E_IP_ERRORS=12 # (in slow.filter)
+
+errmsg () {
+ case $1 in
+ ERROR )
+ sev=" ERROR";
+ ;;
+ WARNING )
+ sev="WARNING";
+ ;;
+ esac
+# tag=`expr "${LP_ERR_LABEL}" : "\(.*\):"``expr "${LP_ERR_LABEL}" : ".*:\(.*\)"`
+ echo "${LP_ERR_LABEL}: ${sev}: $3
+ TO FIX: $4" >&5
+}
+
+
+###########
+##
+## Check arguments
+###########
+
+parse () {
+ echo "`expr \"$1\" : \"^[^=]*=\(.*\)\"`"
+}
+
+#####
+#
+# This program is invoked as
+#
+# ${SPOOLDIR}/.../printer request-id user title copies options files...
+#
+# The first three arguments are simply reprinted on the banner page,
+# the fourth (copies) is used to control the number of copies to print,
+# the fifth (options) is a blank separated list (in a single argument)
+# of user or Spooler supplied options (without the -o prefix),
+# and the last arguments are the files to print.
+#####
+
+if [ $# -lt 5 ]
+then
+ errmsg ERROR ${E_IP_ARGS} \
+ "wrong number of arguments to interface program" \
+ "consult your system administrator"
+ exit 1
+fi
+
+printer=`basename $0`
+request_id=$1
+user_name=$2
+title=$3
+copies=$4
+option_list=$5
+
+shift 5
+files="$*"
+
+nobanner="no"
+nofilebreak="no"
+nolabels="no"
+stty=
+
+inlist=
+for i in ${option_list}
+do
+ case "${inlist}${i}" in
+
+
+ nobanner )
+ nobanner="yes"
+ ;;
+
+ nofilebreak )
+ nofilebreak="yes"
+ ;;
+
+ nolabels )
+ nolabels="yes"
+ ;;
+
+ #
+ # The IPP/PAPI attributes are handled by the foomatic-rip filter so
+ # all we need to do here is ignore them so that they don't invoke the
+ # "unrecognized option" message.
+ #
+
+ finishing=* | page-ranges=* | sides=* )
+ ;;
+ number-up=* | orientation-requested=* | media=* )
+ ;;
+ printer-resolution=* | print-quality=* )
+ ;;
+
+ #####
+ #
+ # If you want to add simple options (e.g. -o simple)
+ # identify them here.
+ #####
+# simple )
+# simple="yes"
+# ;;
+
+
+ cpi=pica )
+ cpi=10
+ ;;
+ cpi=elite )
+ cpi=12
+ ;;
+ cpi=* )
+ cpi=`parse ${i}`
+ ;;
+
+ lpi=* )
+ lpi=`parse ${i}`
+ ;;
+
+ length=* )
+ length=`parse ${i}`
+ ;;
+
+ width=* )
+ width=`parse ${i}`
+ ;;
+
+ #####
+ #
+ # If you want to add simple-value options (e.g. -o value=a)
+ # identify them here.
+ #####
+# value=* )
+# value=`parse ${i}`
+# ;;
+
+
+ #####
+ #
+ # If you want to add options that, like "stty",
+ # take a list (e.g. -o lopt='a b c'), identify
+ # them here and below (look for LOPT).
+ #####
+ stty=* | flist=* | lpd=* )
+#LOPT stty=* | flist=* | lpd=* | lopt=* )
+
+ inlist=`expr "${inlist}${i}" : "^\([^=]*=\)"`
+ case "${i}" in
+ ${inlist}\'*\' )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)'\$"`
+ ;;
+ ${inlist}\' )
+ continue
+ ;;
+ ${inlist}\'* )
+ item=`expr "${i}" : "^[^=]*='*\(.*\)\$"`
+ ;;
+ ${inlist}* )
+ item=`expr "${i}" : "^[^=]*=\(.*\)\$"`
+ ;;
+ *\' )
+ item=`expr "${i}" : "^\(.*\)'\$"`
+ ;;
+ * )
+ item="${i}"
+ ;;
+ esac
+
+ #####
+ #
+ # We don't dare use "eval" because a clever user could
+ # put something in an option value that we'd end up
+ # exec'ing.
+ #####
+ case "${inlist}" in
+ stty= )
+ stty="${stty} ${item}"
+ ;;
+ flist= )
+ flist="${flist} ${item}"
+ ;;
+ lpd= )
+ lpd="${lpd} ${item}"
+ ;;
+#LOPT lopt= )
+#LOPT lopt="${lopt} ${item}"
+#LOPT ;;
+ esac
+
+ case "${i}" in
+ ${inlist}\'*\' )
+ inlist=
+ ;;
+ ${inlist}\'* )
+ ;;
+ *\' | ${inlist}* )
+ inlist=
+ ;;
+ esac
+ ;;
+
+ * )
+ errmsg WARNING ${E_IP_OPTS} \
+ "unrecognized \"-o ${i}\" option" \
+ "check the option, resubmit if necessary
+ printing continues"
+ ;;
+ esac
+done
+
+#####
+#
+# Additional ``parameters'' are passed via Shell environment
+# variables:
+#
+# TERM The printer type (used for Terminfo access)
+# CHARSET The character set to choose
+# FILTER The filter to run
+#####
+
+#####
+# Set defaults for unset variables.
+#####
+
+: ${TERM:=unknown}
+tput lines 1>/dev/null 2>&1 || TPUT=:
+
+: ${CHARSET:=cs0}
+
+PPDFILTER=/usr/lib/lp/bin/foomatic-rip
+PPDFILTERA="${PPDFILTER} ${request_id} ${user_name} \"${title}\" ${copies} \"${option_list}\""
+
+if [ -z "${FILTER}" ]
+then
+ #####
+ #
+ # If no filter is being used, we have a little routine that
+ # will push the data to the printer. It traps hangups (loss
+ # of carrier) and checks for excessive delays in sending the
+ # data to the printer. The lesser of the print rate of the printer
+ # (obtained from Terminfo) or the baud rate is used to compute
+ # the expected delay. If neither of these is correct, you
+ # may be experiencing false alarms. If so, give the correct
+ # rate, in characters per second, as a single argument.
+ # An argument of 0 means don't check for delays.
+ # Give an -r option to get a printout of actual delays.
+ # (QUOTES ARE IMPORTANT!)
+ #####
+ case "$TERM" in
+ PS )
+ # make the "postscript" printers use postio to
+ # talk to the printer and periodically get a
+ # status from them
+ FILTER="/usr/lib/lp/postscript/postio"
+ ;;
+ PSR )
+ # make the "reverse postscript" printers reverse the
+ # output and the use postio to talk to the printer
+ FILTER="/usr/lib/lp/postscript/postreverse | \
+ /usr/lib/lp/postscript/postio"
+ ;;
+ * )
+ # we don't know the type, so just assume that the
+ # input and output are the same
+ if [ `basename "${LPCAT}"` = "lp.cat" ] ; then
+ FILTER="${LPCAT} 0" # infinite delays
+ # FILTER="${LPCAT} 120" # e.g. 120 CPS
+ # FILTER="${LPCAT} -r 0 2>/tmp/delays"
+ # FILTER=${LPCAT}
+ fi
+ ;;
+ esac
+fi
+
+logger -p lpr.debug -t "tsol_standard_foomatic: ${request_id}" "filter : ${FILTER}"
+logger -p lpr.debug -t "tsol_standard_foomatic: ${request_id}" "ppdfilter : ${PPDFILTERA}"
+
+#
+# Append the PPD foomatic-rip filter
+#
+FILTER="${FILTER} | ${PPDFILTERA}"
+
+###########
+##
+## Initialize the printer port
+###########
+
+#####
+#
+# SERIAL PORTS:
+# Initialize everything.
+#
+# PARALLEL PORTS:
+# Don't initialize baud rate.
+#
+# It's not obvious how to tell if a port is parallel or serial.
+# However, by splitting the initialization into two steps and letting
+# the serial-only part fail nicely, it'll work.
+#
+# Another point: The output must be a ``tty'' device. If not, don't
+# bother with any of this.
+#####
+stty1= stty2=
+tty 0<&1 1>/dev/null 2>&1 && {
+
+ #####
+ #
+ # First set the default parameters,
+ # then the requested parameters.
+ #####
+
+ stty \
+ 9600 \
+ 0<&1 2>/dev/null 1>&2
+ stty \
+ cs8 -cstopb -parenb -parodd \
+ ixon -ixany \
+ opost -olcuc onlcr -ocrnl -onocr -onlret -ofill \
+ nl0 cr0 tab0 bs0 vt0 ff0 \
+ 0<&1 2>/dev/null 1>&2
+
+ if [ -n "${stty}" ]
+ then
+ if stty ${stty} 0<&1 1>/dev/null 2>&5
+ then
+ :
+ else
+ errmsg ERROR ${E_IP_STTY} \
+ "stty option list failed" \
+ "check the \"-o stty\" option you used,
+ or consult your system administrator"
+ exit 1
+ fi
+ fi
+
+ #####
+ #
+ # Here you may want to add other port initialization code.
+ # Some examples:
+ #
+ # estty # for printer needing hardware flow control (3B2/EPORTS)
+ # fctty # for printer needing hardware flow control (3B15,3B20)
+ #####
+ #estty 0<&1
+ #fctty 0<&1
+
+
+ ##########
+ #
+ # Find out if we have to turn off opost before initializing the
+ # printer and on after. Likewise, check clocal.
+ #
+ # Turning OFF opost (output postprocessing) keeps the UNIX system
+ # from changing what we try to send to the printer. Turning ON
+ # clocal keeps the UNIX system from dropping what we are trying to
+ # send if the printer drops DTR. An example of the former is the
+ # AT&T 479, which wants to send a linefeed (ASCII 10) when a page
+ # width of 10 is set; with opost on, this COULD BE turned into a
+ # carriage-return/linefeed pair. An example of the latter is the
+ # AT&T 455, which momentarily drops DTR when it gets the
+ # initialization string, is2; with clocal off, the UNIX system
+ # stops sending the rest of the initialization sequence at that
+ # point.
+ #
+ # THIS CODE MUST FOLLOW THE REST OF THE PORT INITIALIZATION CODE.
+ ##########
+ cur_stty=`stty -a 0<&3`
+ expr "${cur_stty}" : '.*-opost' 1>/dev/null 2>&1 \
+ || stty1="${stty1} -opost" stty2="${stty2} opost"
+ expr "${cur_stty}" : '.*-clocal' 1>/dev/null 2>&1 \
+ && stty1="${stty1} clocal" stty2="${stty2} -clocal"
+ expr "${cur_stty}" : '.* opost.*' 1>/dev/null 2>&1 \
+ || banner_filter=${FIX386BD}
+
+}
+
+
+###########
+##
+## Initialize the physical printer (Part I).
+## Here we bring the printer to a sane state and set the page size.
+###########
+
+##########
+#
+# WARNING! The "echo" command will catch backslashes (\) and
+# try to interpret the characters following it. Thus, using
+# "echo" to print string values obtained from "tput" is dangerous.
+##########
+
+#####
+# We're confident that most printers don't have backslashes
+# in the control sequences for carriage return and form-feed.
+# We're also confident that these don't contain newlines.
+# We're also confident that most printers have a linefeed
+# in the control sequence for doing a newline (move to beginning
+# of next line), but we can't capture it like we do the
+# carriage return or form-feed. Thus we set it unconditionally.
+# We don't set form-feed if it isn't defined, however, because
+# maybe the printer doesn't have a formfeed. If not set, we're
+# out of luck.
+#####
+
+CR=`${TPUT} cr`
+[ -z "${CR}" ] && CR="\r"
+
+FF=`${TPUT} ff`
+BFF=$FF
+[ -z "${BFF}" ] && BFF="\f"
+
+NL="${CR}\n"
+
+lines=`${TPUT} lines`
+[ -z "${lines}" -o 0 -ge "${lines}" ] && lines=66
+
+cols=`${TPUT} cols`
+[ -z "${cols}" -o 0 -ge "${cols}" ] && cols=132
+
+#####
+#
+# Basic initialization. The ``else'' clause is equivalent,
+# but covers cases where old Terminal Information Utilities are present.
+#####
+[ -n "${stty1}" ] && stty ${stty1} 0<&1
+
+#
+# "tput init" will return an "^M" in many cases to "stdout", i.e., printer!
+# This creates problems for some PS printers
+#
+if [ "${TERM}" = "PS" -o "${TERM}" = "PSR" ]
+then
+ :
+elif ${TPUT} init 2>/dev/null
+then
+ :
+else
+ pgm=`${TPUT} iprog`
+ if [ -x "${pgm}" ]
+ then
+ eval ${pgm}
+ fi
+
+ ${TPUT} is1
+ ${TPUT} is2
+
+ tabset=
+ if [ "8" != "`${TPUT} it`" ]
+ then
+ stty tab3 0<&1 1>/dev/null 2>&1
+
+ elif `${TPUT} ht >/dev/null`
+ then
+ tabset="/usr/lib/tabset/${TERM}"
+ if [ -r ${tabset} ]
+ then
+ cat -s ${tabset}
+ fi
+ stty tab3 0<&1 1>/dev/null 2>&1
+ fi
+
+ file=`${TPUT} if`
+ if [ "${tabset}" != "${file}" -a -r "${file}" ]
+ then
+ cat -s "${file}"
+ fi
+
+ ${TPUT} is3
+ echo "${CR}\c"
+fi
+[ -n "${stty2}" ] && stty ${stty2} 0<&1
+
+#####
+#
+# Set the page size and print spacing, but not the character set.
+# We will be doing the character set later (after the header).
+#####
+internal_lpset "${cpi}" "${lpi}" "${width}" "${length}" ""
+
+#####
+#
+# The banner page (and cancellation page) will
+# use double width characters if they're available.
+#####
+WIDE_CS=`${TPUT} swidm 2>/dev/null` && NORM_CS=`${TPUT} rwidm 2>/dev/null`
+PAD="#####${NL}"
+
+#####
+#
+# Some printers need to have the banner page filtered.
+#####
+case "${TERM}" in
+
+PS | PSR )
+ banner_filter="/usr/lib/lp/postscript/postprint | /usr/lib/lp/postscript/postio"
+ LPTELL_OPTS="-l"
+ ;;
+
+esac
+if [ -n "${banner_filter}" ]
+then
+ banner_filter="| ${banner_filter}"
+fi
+
+#####
+#
+# Now that the printer is ready for printing, we're able
+# to record on paper a cancellation.
+#####
+
+cancel_banner () {
+ echo "${PAD}${PAD}\c"
+ echo "#####${WIDE_CS} Job ${request_id}${NORM_CS}${NL}\c"
+ echo "#####${WIDE_CS} suspended or canceled${NORM_CS}${NL}\c"
+ echo "${PAD}${PAD}\c"
+}
+
+canceled () {
+ ${TPUT} scs 0 2>/dev/null
+ echo "${CR}\c"
+ if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
+ then
+ WIDE_CS= NORM_CS=
+ fi
+ cancel_banner
+ if [ -n "${BFF}" ]
+ then
+ echo "${CR}${BFF}\c"
+ fi
+}
+
+trap 'eval canceled ${banner_filter}; exit_code=0 exit' 15
+
+
+###########
+##
+## Print the banner page
+###########
+
+#####
+#
+# You may want to change the following code to get a custom banner.
+#####
+
+regular_banner () {
+ echo "${CR}\c"
+ echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c"
+ echo "#####${WIDE_CS} User: ${user_name}${NORM_CS}${NL}\c"
+ if [ -n "$ALIAS_USERNAME" ]
+ then
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Alias: ${ALIAS_USERNAME}${NORM_CS}${NL}\c"
+ fi
+ if [ -n "${title}" ]
+ then
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Title: ${title}${NORM_CS}${NL}\c"
+ fi
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Printed: `LANG=C date '+%a %H:%M %h %d, %Y'`${NORM_CS}${NL}\c"
+ echo "${PAD}\c"
+ echo "#####${WIDE_CS} Job number: ${request_id}${NORM_CS}${NL}\c"
+ echo "${PAD}${PAD}${PAD}${PAD}${PAD}\c"
+ if [ -n "${BFF}" ]
+ then
+ echo "${CR}${BFF}\c"
+ fi
+}
+
+small_banner () {
+ echo "${CR}\c"
+ echo "${PAD}\c"
+ echo "##### User: ${user_name}${NL}\c"
+ if [ -n "${title}" ]
+ then
+ echo "##### Title: ${title}${NL}\c"
+ fi
+ echo "##### Date: `LANG=C date '+%a %H:%M %h %d, %Y'`${NL}\c"
+ echo "##### Job: ${request_id}${NL}\c"
+ echo "${PAD}\c"
+ if [ -n "${BFF}" ]
+ then
+ echo "${CR}${BFF}\c"
+ fi
+}
+
+if [ "${width:-${cols}}" -lt "${MAX_COLS_SMALL_BANNER}" ]
+then
+ banner=small_banner
+else
+ banner=regular_banner
+fi
+
+## Skip this for PS/PSR in TSOL, since lp.tsol_separator handles the banners
+if [ "no" = "${nobanner}" -a "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
+ | ${LPTELL} ${LPTELL_OPTS} ${printer}
+fi
+
+###########
+##
+## Surround the job by PostScript code to produce banner
+## and trailerpages and page headers and footers.
+##
+###########
+
+BANNER_EXIT_CODE=${TMPPREFIX}.banner.exit_code
+echo 0 > ${BANNER_EXIT_CODE}
+TSOLSEPARATOR_LOG=${TMPPREFIX}.banner.errmsg
+
+tsol_bannerize () {
+ TSOLSEPARATOR_OPTS="-e ${TSOLSEPARATOR_LOG}"
+
+ if [ "yes" = "${nolabels}" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -l"
+ fi
+
+ if [ "yes" = "${nobanner}" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -t /dev/null -b /dev/null"
+ fi
+
+ if [ "${TERM}" = "PSR" ]
+ then
+ TSOLSEPARATOR_OPTS="${TSOLSEPARATOR_OPTS} -r"
+ fi
+
+ # Get rid of the #, TAB and NL characters in the title
+ tsol_title=`echo $title`
+ tsol_title=`echo $tsol_title | sed 's/#//g'`
+
+ LC_TIME=C ${LPTSOLSEPARATOR} ${TSOLSEPARATOR_OPTS} "${printer}" \
+ "${request_id}" "${user_name}" "${tsol_title}" "${file}"
+ echo $? > ${BANNER_EXIT_CODE}
+ true
+}
+
+bannerize=tsol_bannerize
+
+if [ "yes" = "${nobanner}" -a "yes" = "${nolabels}" ]
+then
+ bannerize=cat
+fi
+
+if [ "${TERM}" != "PSR" -a "${TERM}" != "PS" ]
+then
+ bannerize=cat
+fi
+
+
+###########
+##
+## Initialize the physical printer (Part II)
+## Here we select the character set.
+## One could argue that this should be done before the banner is printed,
+## but we don't, to keep the banner page looking consistent for the
+## operator. You can move this code before the banner code if you
+## disagree. If you do, combine it with the other call to "internal_lpset"
+## to do everything in one shot.
+###########
+internal_lpset "" "" "" "" "${CHARSET}"
+
+###########
+##
+## Print some copies of the file(s)
+###########
+
+#####
+#
+# The protocol between the interface program and the Spooler
+# is fairly simple:
+#
+# All standard error output is assumed to indicate a
+# fault WITH THE REQUEST. The output is mailed to the
+# user who submitted the print request and the print
+# request is finished.
+#
+# If the interface program sets a zero exit code,
+# it is assumed that the file printed correctly.
+# If the interface program sets a non-zero exit code
+# less than 128, it is assumed that the file did not
+# print correctly, and the user will be notified.
+# In either case the print request is finished.
+#
+# If the interface program sets an exit code greater
+# than 128, it is assumed that the file did not print
+# because of a printer fault. If an alert isn't already
+# active (see below) one will be activated. (Exit code
+# 128 should not be used at all. The shell, which executes
+# this program, turns SIGTERM, used to kill this program
+# for a cancellation or disabling, into exit 128. The
+# Spooler thus interpretes 128 as SIGTERM.)
+#
+# A message sent to the standard input of the ${LPTELL}
+# program is assumed to describe a fault WITH THE PRINTER.
+# The output is used in an alert (if alerts are defined).
+# If the fault recovery is "wait" or "begin", the printer
+# is disabled (killing the interface program if need be),
+# and the print request is left on the queue.
+# If the fault recovery is "continue", the interface program
+# is allowed to wait for the printer fault to be cleared so
+# it can resume printing.
+#
+# This interface program relies on filters to detect printer faults.
+# In absence of a filter provided by the customer, it uses a simple
+# filter (${LPCAT}) to detect the class of faults that cause DCD
+# (``carrier'') drop. The protocol between the interface program and
+# the filter:
+#
+# The filter should exit with zero if printing was
+# successful and non-zero if printing failed because
+# of a printer fault. This interface program turns a
+# non-zero exit of the filter into an "exit 129" from
+# itself, thus telling the Spooler that a printer fault
+# (still) exists.
+#
+# The filter should report printer faults via a message
+# to its standard error. This interface program takes all
+# standard error output from the filter and feeds it as
+# standard input to the ${LPTELL} program.
+#
+# The filter should wait for a printer fault to clear,
+# and should resume printing when the fault clears.
+# Preferably it should resume at the top of the page
+# that was being printed when the fault occurred.
+# If it waits and finishes printing, it should exit
+# with a 0 exit code. If it can't wait, it should exit
+# with a non-zero exit code.
+#
+# The interface program expects that ANY message on the
+# standard error from the filter indicates a printer fault.
+# Therefore, a filter should not put user (input) error
+# messages on the standard error, but on the standard output
+# (where the user can read them when he or she examines
+# the print-out).
+#
+#####
+
+badfileyet=
+i=1
+while [ $i -le $copies ]
+do
+ for file in ${files}
+ do
+ if [ -r "${file}" ]
+ then
+ #####
+ #
+ # Here's where we set up the $LPTELL program to
+ # capture fault messages, and...
+ #
+ # Here's where we print the file.
+ #
+ # We set up a pipeline to $LPTELL, but play a trick
+ # to get the filter's standard ERROR piped instead of
+ # its standard OUTPUT: Divert the standard error (#2) to
+ # the standard output (#1) IN THE PIPELINE. The shell
+ # will have changed #1 to be the pipe, not the
+ # printer, so diverting #2 connects it to the pipe.
+ # We then change the filter's #1 to a copy of the real
+ # standard output (the printer port) made earlier,
+ # so that is connected back to the printer again.
+ #
+ # We do all this inside a parenthesized expression
+ # so that we can get the exit code; this is necessary
+ # because the exit code of a pipeline is the exit
+ # code of the right-most command, which isn't the
+ # filter.
+ #
+ # These two tricks could be avoided by using a named
+ # pipe to connect the standard error to $LPTELL. In
+ # fact an early prototype of this script did just
+ # that; however, the named pipe introduced a timing
+ # problem. The processes that open a named pipe hang
+ # until both ends of the pipe are opened. Cancelling
+ # a request or disabling the printer often killed one
+ # of the processes, causing the other process to hang
+ # forever waiting for the other end of the pipe to
+ # be opened.
+ #####
+ EXIT_CODE=${TMPPREFIX}e
+ trap '' 1 # Let the filter handle a hangup
+ trap '' 2 3 # and interrupts
+ (
+ #####
+ # Put the 0<${file} before the "eval" to keep
+ # clever users from giving a file name that
+ # evaluates as something to execute.
+ #####
+ 0<${file} $bannerize | eval ${FILTER} 2>&1 1>&3
+ echo $? >${EXIT_CODE}
+ ) | ${LPTELL} ${LPTELL_OPTS} ${printer}
+
+ # if lp.tsol_separator had an error, send its logged
+ # error message to LPTELL.
+ banner_exit_code=`cat ${BANNER_EXIT_CODE}`
+ if [ -n "${banner_exit_code}" -a \
+ 0 -ne "${banner_exit_code}" -a \
+ -n "${LPTELL}" -a \
+ -r "${TSOLSEPARATOR_LOG}" ]
+ then
+ cat ${TSOLSEPARATOR_LOG} | ${LPTELL} ${printer}
+ echo 77 > ${EXIT_CODE}
+ fi
+
+ trap 'catch_hangup; exit_code=129 exit 129' 1
+ trap 'catch_interrupt; exit_code=129 exit 129' 2 3
+ exit_code=`cat ${EXIT_CODE}`
+
+ if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
+ then
+ trap '' 15 # Avoid dying from disable
+ sleep 4 # Give $LPTELL a chance to tell
+ exit ${exit_code}
+ fi
+
+ if [ -n "${FF}" -a "no" = "${nofilebreak}" ]
+ then
+ echo "${CR}${FF}\c"
+ fi
+
+ else
+
+ #####
+ #
+ # Don't complain about not being able to read
+ # a file on second and subsequent copies, unless
+ # we've not complained yet. This removes repeated
+ # messages about the same file yet reduces the
+ # chance that the user can remove a file and not
+ # know that we had trouble finding it.
+ #####
+ if [ "${i}" -le 1 -o -z "${badfileyet}" ]
+ then
+ errmsg WARNING ${E_IP_BADFILE} \
+ "cannot read file \"${file}\"" \
+ "see if the file still exists and is readable,
+ or consult your system administrator;
+ printing continues"
+ badfileyet=yes
+ fi
+
+ fi
+
+ done
+ i=`expr $i + 1`
+
+done
+
+# Skip this for TSOL, since lp.tsol_separator handles the banners
+#
+# if [ "no" = "${nobanner}" -a "${TERM}" = "PSR" ]
+# then
+# ( eval "${banner} ${banner_filter}" 2>&1 1>&3 ) \
+# | ${LPTELL} ${LPTELL_OPTS} ${printer}
+# fi
+
+if [ -n "${exit_code}" -a 0 -ne "${exit_code}" ]
+then
+ exit ${exit_code}
+fi
+
+#####
+#
+# Always ensure the complete job ends with a ``formfeed'', to
+# let the next job start on a new page. (If someone wants to
+# concatenate files, they can give them in one job.)
+# So, if we haven't been putting out a ``formfeed'' between files,
+# it means we haven't followed the last file with a formfeed,
+# so we do it here.
+#####
+if [ -n "${FF}" -a "yes" = "${nofilebreak}" ]
+then
+ echo "${CR}${FF}\c"
+fi
+
+${DRAIN}
+
+exit_code=0 exit 0
diff --git a/usr/src/cmd/lp/model/uri b/usr/src/cmd/lp/model/uri
new file mode 100755
index 0000000000..7d8a26dfea
--- /dev/null
+++ b/usr/src/cmd/lp/model/uri
@@ -0,0 +1,253 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# printer interface script for printers with a URI instead of
+# device name.
+#
+# The existence of a "PPD" environment variable in the calling environment
+# indicates that Foomatic is to be used for filtering all job data as it is
+# streamed to the output device (printer).
+#
+# The contents of a "DEVICE_URI" environment variable in the calling
+# environment indicates the method and endpoint used in communicating with
+# the output device (printer). If no DEVICE_URI is present or the value
+# contains a missing or unknown scheme, the URI scheme is assumed to be
+# "file" and output streaming will be handled accordingly.
+
+export PATH=/bin:/usr/bin:/usr/lib/lp/bin:/usr/sfw/bin
+
+TAG="uri-interface"
+
+
+# Re-arrange fds for later use
+exec 5>&2 2>/dev/null 3>&1
+
+#
+# Exit Codes:
+#
+EXIT_OK=0
+EXIT_FATAL=1
+EXIT_TERM=128
+EXIT_RETRY=129
+
+fail() { # exit-code "message"
+ logger -p lpr.error -t ${TAG} "${2}"
+ echo ${2} >&5
+ exit ${1}
+}
+
+# signal handling
+# EXIT 0 - normal exit
+# HUP 1 - the output stream disconnected
+# INT 2 - the output stream interupted us
+# QUIT 3 - the output stream interupted us
+# TERM 15 - we have been cancelled or shutdown
+
+catch_exit() {
+ exit $exit_code
+}
+
+catch_disconnect() {
+ fail ${EXIT_RETRY} "connection to the printer dropped; off-line?"
+}
+
+catch_interrupt() {
+ fail ${EXIT_RETRY} "interrupt from the printer; baud-rate issues?"
+}
+
+catch_cancellation() {
+ fail ${EXIT_RETRY} "job cancelled"
+}
+
+trap 'catch_disconnect()' HUP
+trap 'catch_interrupt()' INT QUIT
+trap 'catch_cancellation()' TERM
+
+parse_uri() { # scheme://[[user[:password]@]host[:port]]/path
+ URI_SCHEME=$(expr "$1" : "\(.*\)://.*")
+}
+
+parse() {
+ echo "$(expr \"$1\" : \"^[^=]*=\(.*\)\")"
+}
+
+#
+# Generate an ASCII burst page and pass it to the printer
+# This may be much faster than the PostScript(TM) burst page
+#
+ascii_burst_page() {
+ cat <<EOF
+ ${title}
+ Request: ${request_id}
+ User: ${user}
+ Printer: ${printer}
+ Time: $(date)
+ Copies: ${copies}
+EOF
+ tput ff
+}
+
+#
+# Generate a PostScript(TM) burst page (this assumes an 8.5x11 page size)
+#
+postscript_burst_page() {
+ cat <<-EOF
+ %!ps
+ /PrintLine { exch findfont exch scalefont setfont moveto show } def
+ newpath 4 setlinewidth 1 setlinejoin
+ 15 760 moveto 595 760 lineto 595 585 lineto 15 585 lineto closepath
+ gsave .75 setgray fill grestore
+ 0 setgray stroke
+ (${user}) 30 730 /Times-Bold 24 PrintLine
+ (${request_id}) 415 730 /Times-Bold 24 PrintLine
+ (${printer}) 30 600 /Times-Bold 16 PrintLine
+ ($(date)) 350 600 /Times-Roman 16 PrintLine
+ (${title}) 100 660 /Times-Bold 36 PrintLine
+ (Copies: ${copies}) 30 25 /Times-Roman 16 PrintLine
+ showpage
+ EOF
+}
+
+logger -p lpr.debug -t ${TAG} "$0 $*"
+
+#
+# Detemine if we were called correctly
+#
+if [[ $# -lt 5 ]] ; then
+ fail ${EXIT_FATAL} "wrong number of arguments to interface script"
+fi
+
+
+printer=$(basename $0)
+request_id=$1
+user=$2
+title=$3
+copies=$4
+options=$5
+
+shift 5
+files="$*"
+
+burst_page="postscript_burst_page"
+
+for i in ${options}
+do
+ case "${i}" in
+
+ nobanner )
+ burst_page=""
+ ;;
+
+ nofilebreak )
+ nofilebreak="yes"
+ ;;
+
+ burst-page-type=* )
+ burst_page="$(parse ${i})_burst_page"
+ ;;
+
+ * )
+ logger -p lpr.error -t ${TAG} \
+ "unrecognized \"-o ${i}\" option, ignored" 1>&2
+ ;;
+ esac
+done
+
+
+#
+# Procss the DEVICE_URI if we have one
+#
+if [[ -n "${DEVICE_URI}" ]] ; then
+ parse_uri ${DEVICE_URI} # split up the URI
+
+ URI_SCHEME=${URI_SCHEME:-file} # if there is no scheme, assume "file"
+
+ case "${URI_SCHEME}" in
+ file|usb|ecpp|serial|parallel)
+ IO_HANDLER="lp.cat"
+ IO_HANDLER_ARGS=""
+ ;;
+ smb)
+ IO_HANDLER="smbspool"
+ IO_HANDLER_ARGS="${request_id} ${user} \"${title}\" 1
+ \"${options}\""
+ ;;
+ tcp|socket)
+ URI_HOST=$(expr "${DEVICE_URI}" : ".*://\([^:/]*\)")
+ URI_PORT=$(expr "${DEVICE_URI}" : ".*://.*:\([^/]*\)")
+ if [[ -z "${URI_HOST}" ]] ; then
+ fail ${EXIT_FATAL} "invalid device-uri: ${DEVICE_URI}, reset with lpadmin -v"
+ fi
+ URI_PORT=${URI_PORT:-"9100"}
+ IO_HANDLER="telnet"
+ IO_HANDLER_ARGS="-c -E ${URI_HOST} ${URI_PORT}"
+ ;;
+ lpd|ipp)
+ IO_HANDLER="lp"
+ IO_HANDLER_ARGS="-s -d ${DEVICE_URI}"
+ ;;
+ *)
+ IO_HANDLER=${URI_SCHEME}
+ IO_HANDLER_ARGS=""
+ ;;
+ esac
+fi
+IO_HANDLER=${IO_HANDLER:-"lp.cat"} # if IO_HANDLER is still unset, use lp.cat
+
+# determine if the IO handler is available for us to use when communicating with
+# the output device (printer.)
+whence ${IO_HANDLER} >/dev/null
+if [[ $? -ne 0 ]] ; then
+ fail ${ERR_FATAL} \
+ "Interface script unable to locate IO handler: ${IO_HANDLER}"
+fi
+
+# There is a PPD file specified, so use foomatic
+if [[ -n "${PPD}" ]] ; then
+ FILTER_CHAIN="| foomatic-rip"
+fi
+
+#
+# Start processing the job here
+#
+set | logger -p lpr.debug -t "${TAG}"
+
+(
+ if [[ -n "${burst_page}" ]] ; then
+ eval "${burst_page} ${FILTER_CHAIN}"
+ fi
+ while [[ $copies -gt 0 ]] ; do
+ for file in ${files} ; do
+ if [[ -r "${file}" ]] ; then
+ eval "cat ${file} ${FILTER_CHAIN}"
+ fi
+ done
+ copies=$(( copies - 1 ))
+ done
+) | ${IO_HANDLER} ${IO_HANDLER_ARGS}
+
+exit ${EXIT_OK}
diff --git a/usr/src/cmd/lp/terminfo/40.ti b/usr/src/cmd/lp/terminfo/40.ti
new file mode 100644
index 0000000000..2e08ece1ca
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/40.ti
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.4 */
+
+######################################################################
+#
+# Entries for the AT&T Model 40 line printers
+#
+
+
+
+40-80-6|att40-80-6|AT&T Model 40 line printer 80 cloumn 6 line per inch,
+
+ daisy,
+ bufsz#160,
+ cols#80,
+ lines#66,
+ orc#1,
+ orhi#10,
+ orl#1,
+ orvi#6,
+ cps#400,
+
+ cr=^M,
+ cuf1=\s,
+ ff=^L,
+
+40-80-8|att40-80-8|AT&T Model 40 line printer 80 cloumn 8 line per inch,
+
+ lines#88,
+ orvi#8,
+ use=40-80-6,
+
+40-132-6|att40-132-6|AT&T Model 40 line printer 132 cloumn 6 line per inch,
+
+ bufsz#264,
+ cols#132,
+ use=40-80-6,
+
+40-132-8|att40-132-8|AT&T Model 40 line printer 132 cloumn 8 line per inch,
+
+ lines#88,
+ orvi#8,
+ use=40-132-6,
+
diff --git a/usr/src/cmd/lp/terminfo/44x.ti b/usr/src/cmd/lp/terminfo/44x.ti
new file mode 100644
index 0000000000..d932bf441e
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/44x.ti
@@ -0,0 +1,57 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+######################################################################
+#
+# Entries for the AT&T 440 seris line printers
+#
+
+
+442|att442|AT&T 442 line printer,
+
+ bufsz#2048,
+ cols#132,
+ lines#66,
+ orc#1,
+ orhi#10,
+ orl#1,
+ orvi#6,
+ cps#440,
+
+ cr=^M,
+ cuf1=\s,
+ ff=^L,
+
+444|att444|AT&T 444 line printer,
+
+ use=442,
+
+446|att446|AT&T 446 line printer,
+
+ cps#1100,
+ use=442,
+
diff --git a/usr/src/cmd/lp/terminfo/45x.ti b/usr/src/cmd/lp/terminfo/45x.ti
new file mode 100644
index 0000000000..e4a6c5ab92
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/45x.ti
@@ -0,0 +1,42 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+######################################################################
+#
+# Entries for the AT&T 455, 457, 459 printers
+#
+
+455|att455|AT&T 455 Daisywheel printer,
+
+ use=Gdaisy+basic,
+
+457|att457|458|att458|AT&T 457 Daisy printer,
+
+ bufsz#1024,
+ use=455,
+
+
diff --git a/usr/src/cmd/lp/terminfo/477.ti b/usr/src/cmd/lp/terminfo/477.ti
new file mode 100644
index 0000000000..51b808b2ce
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/477.ti
@@ -0,0 +1,181 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.7 */
+
+######################################################################
+#
+# Entries for the AT&T 477 printer
+#
+
+#
+# Basic capabilities (all emulations):
+#
+att477+basic1,
+
+ bufsz#8192,
+ cps#80,
+
+######################################################################
+#
+# Particular printers:
+#
+
+477-470|att477-470|AT&T 477; 470 emulation,
+
+ cols#136,
+ cpix,
+
+ orc#10,
+ orhi#100,
+ orl#30,
+ orvi#180,
+
+ csnm=%?%p1%{0}%=%tamerican%e%p1%{1}%=%tbritish%e%p1%{2}%=%tswedish%e%p1%{3}%=%tgerman%e%p1%{4}%=%tfrench%e%p1%{5}%=%titalian%e%p1%{6}%=%tspanish%;,
+ scs=%?%p1%{0}%=%t\EZ^O@\ED^B@%e%p1%{1}%=%t\EZ^O@\ED^C@%e%p1%{2}%=%t\EZ^O@\ED^E@%e%p1%{3}%=%t\EZ^O@\ED^D@%e%p1%{4}%=%t\EZ^O@\ED^A@%e%p1%{5}%=%t\EZ^O@\ED^F@%e%p1%{6}%=%t\EZ^O@\ED^G@%;,
+
+ use=470,
+
+477ibmc|att477ibmc|AT&T 477 IBM Color printer emulation,
+
+ cols#135,
+
+ orc#15,
+ orhi#150,
+
+ orl#10,
+ orvi#60,
+
+ cvr=%?%p1%{0}%>%p1%{256}%<%&%t\EA%p1%c\E2%;
+
+ cpi=%?%p1%{10}%=%t^R%e%p1%{12}%=%t\E:%e%p1%{17}%=%t^O%;,
+
+
+ smglp=\EX%p1%{1}%+%c%p2%{2}%+%c,
+ smgt=\E4,
+
+
+ use=att477+basic1, use=Gibmc+basic, use=Gibmc+low+5x6,
+ use=Gibmc+color,
+
+477ibmg|att477ibmg|AT&T 477 IBM Graphics printer emulation,
+
+ cols#136,
+
+ orc#10,
+ orhi#100,
+ orl#10,
+ orvi#60,
+
+ is2=\E@,
+
+ smglp=%?%p1%{256}%<%t\El%p1%{1}%+%c,
+ smgrp=%?%p1%{256}%<%t\EQ%p1%{2}%+%c,
+
+
+ use=att477+basic1, use=Gibmg+basic, use=Gibmg+low,
+
+477qume|att477qume|477-455|att477-455|AT&T 477 qume emulation,
+
+
+ cols#136,
+
+
+ is2=\E\rP\EW\E.\EL08\EY,
+
+ use=att477+basic1, use=Gdaisy+basic, use=Gdaisy+lowres,
+
+######################################################################
+#
+# In Fujitsu DPL24C mode. This seems to be more like the Epson LQ-2500
+# than the IBM Proprinter XL.
+#
+
+#
+# Basic capabilities (Fujitsu emulation only):
+#
+att477+basic2,
+
+ orc#18,
+ orhi#180,
+ orl#30,
+ orvi#180,
+
+
+#
+# The following is not redundant with the cpi capability, because
+# the cpi changes the character size as well, so that printing
+# looks balanced, while this leaves the character size alone.
+ chr=%?%p1%{256}%<%t\Eh%p1%c%;,
+
+
+ is2=\E@,
+
+ csnm=%?%p1%{0}%=%tcharacter_set_1%e%p1%{1}%=%tcharacter_set_2%e%p1%{2}%=%tusa%e%p1%{3}%=%tfrench%e%p1%{4}%=%tgerman%e%p1%{5}%=%tuk%e%p1%{6}%=%tdanish%e%p1%{7}%=%tswedish%e%p1%{8}%=%titalian%e%p1%{9}%=%tspanish%;,
+ scs=%?%p1%{0}%=%t\E7%e%p1%{1}%=%t\E6%e%p1%{3}%=%t\ER0%e%p1%{3}%=%t\ER1%e%p1%{4}%=%t\ER2%e%p1%{5}%=%t\ER3%e%p1%{6}%=%t\ER4%e%p1%{7}%=%t\ER5%e%p1%{8}%=%t\ER6%e%p1%{9}%=%t\ER7%;,
+
+
+477-5x6|att477-5x6|AT&T 477 as Fujitsu DPL24C; 5:6 aspect ratio,
+
+ spinh#50,
+
+# defbi=
+# Like the defbi for the epson2500, except:
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 50 dots per inch horizontally this means 5
+# dots per character.
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\E3\030^R\EP\EB%p2%{8}%/%c$<>\ED%p1%{6}%/%c$<>\013\r\t%;,
+
+#
+# Note that the epson2500 drives a real Epson LQ-2500 at
+# 60 dots per inch horizontally; the same control sequences
+# drive the Fujitsu DPL24C at 50 dots per inch horixontally.
+ use=att477+basic1, use=att477+basic2, use=Gep2500+basic,
+ use=Gep2500+low, use=Gep2500+color,
+
+477|att477|AT&T 477 as Fujitsu DPL24C; 1:1; low res,
+
+ is1@,
+
+#
+# This mode differs from the 5x6 mode only in sbim and defbi
+# (and spinh, of course). However, it is even closer to the
+# epson2500, so we use that.
+
+ sdrfq=\EH,
+ snlq=\EG,
+ snrmq@,
+
+ sbim=\E*\005%p1%{256}%m%c%p1%{256}%/%c,
+
+ use=att477+basic1, use=att477+basic2, use=Gep2500+basic,
+ use=Gep2500+low, use=Gep2500+color,
+
+477-hi|att477-hi|AT&T 477 as Fujitsu DPL24C; 1:1; high res,
+
+ use=att477+basic1, use=att477+basic2, use=Gep2500+basic,
+ use=Gep2500+high, use=Gep2500+color,
diff --git a/usr/src/cmd/lp/terminfo/47x.ti b/usr/src/cmd/lp/terminfo/47x.ti
new file mode 100644
index 0000000000..a5db8850de
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/47x.ti
@@ -0,0 +1,134 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+######################################################################
+#
+# Entries for the AT&T 470, 471, 473, 474, 475, 476, 478, 479 printers
+#
+
+#
+# C.Itoh derived printers:
+#
+
+470|att470|AT&T 470; C.Itoh 8510; 8"; parallel matrix printer,
+
+ bufsz#4096,
+
+ cols#80,
+ cpix,
+
+ sdrfq@,
+ snlq@,
+ snrmq@,
+ ssubm@,
+ ssupm@,
+ rsubm@,
+ rsupm@,
+
+ sgr0=\E"\EY,
+
+# Reset command does not reset form length
+
+ is2=\Ec1\Ev66,
+
+ csnm=%?%p1%{0}%=%tusa%e%p1%{1}%=%tbritish%e%p1%{2}%=%tdanish%e%p1%{3}%=%tjapanese%e%p1%{4}%=%tnorwegian%e%p1%{5}%=%tswedish%e%p1%{6}%=%tgerman%e%p1%{7}%=%tfrench%e%p1%{8}%=%tfrench2%e%p1%{9}%=%titalian%e%p1%{10}%=%tspanish%e%p1%{11}%=%tnetherland%e%p1%{12}%=%tafrikaans%e%p1%{13}%=%tbritish2%;,
+ scs=%?%p1%{0}%=%t\EZ^O@\ED^B@%e%p1%{1}%=%t\EZ^O@\ED^C@%e%p1%{2}%=%t\EZ^O@\ED\b@%e%p1%{3}%=%t\EZ^O@%e%p1%{4}%=%t\EZ^O@\ED\t@%e%p1%{5}%=%t\EZ^O@\ED^E@%e%p1%{6}%=%t\EZ^O@\ED^D@%e%p1%{7}%=%t\EZ^O@\ED^A@%e%p1%{8}%=%t\EZ^O@\ED^N@%e%p1%{9}%=%t\EZ^O@\ED^F@%e%p1%{10}%=%t\EZ^O@\ED^G@%e%p1%{11}%=%t\EZ^O@\ED\n@%e%p1%{12}%=%t\EZ^O@\ED^K@%e%p1%{13}%=%t\ED^O@%;,
+
+
+ use=Gcitoh+basic, use=Gcitoh+low,
+
+471|att471|AT&T 471; C.Itoh 1550; 14"; parallel matrix printer,
+
+ cols#136,
+
+ use=470,
+
+475|att475|AT&T 475; C.Itoh 8510; 8"; serial matrix printer,
+
+ use=470,
+
+476|att476|AT&T 475; C.Itoh 1550; 14"; serial matrix printer,
+
+ use=471,
+
+#
+# IBM derived printers:
+#
+
+473|att473|AT&T 473; 8"; C.Itoh 8510EP; IBM Graphics,
+
+ bufsz#4096,
+ cps#120,
+
+#
+# FIX: The AT&T 473 doesn't seem to have fine-scale horizontal
+# motion--the only motion is by columns.
+ orc#10,
+ orhi#100,
+
+
+
+
+ use=Gibmg+basic, use=Gibmg+low,
+
+474|att474|AT&T 474; 14"; C.Itoh 1550EP; IBM Graphics,
+
+ cols#132,
+
+ use=473,
+
+478|att478|AT&T 478; 8"; parallel matrix printer,
+
+ bufsz#16384,
+ cps#120,
+
+#
+# FIX: The AT&T 478 doesn't seem to have fine-scale horizontal
+# motion--the only motion is by columns.
+ orc#10,
+ orhi#100,
+
+ cpi=%?%p1%{10}%=%t^R%e%p1%{12}%=%t\E:%e%p1%{13}%=%p1%{14}%=%O%t\Eh%e%p1%{16}%=%p1%{17}%=%O%t\Em%e%p1%{18}%=%t^O%;,
+
+ is2=^R\EW0\E-0\E_0\EF\EH\EI\ET\EA\014\E2\ER\El\001\Er\120\Et\001\EC\102\E7\EU0\EO,
+
+ sdrfq=\EI^D,
+ snlq=\EI^B,
+
+ smglp=\El%{1}%p1%+%c,
+ smgrp=\Er%{1}%p1%+%c,
+ smgtp=\Et%{1}%p1%+%c,
+
+ use=Gibmg+basic, use=Gibmg+low,
+
+479|att479|AT&T 479; 14"; IBM parallel; matrix printer,
+
+ cols#132,
+ is2=^R\EW0\E-0\E_0\EF\EH\EI\004\ET\EA\014\E2\ER\El\001\Er\204\Et\001\EC\102\E7\EU0\EO,
+
+
+ use=478,
diff --git a/usr/src/cmd/lp/terminfo/495.ti b/usr/src/cmd/lp/terminfo/495.ti
new file mode 100644
index 0000000000..562c62b6be
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/495.ti
@@ -0,0 +1,78 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+######################################################################
+#
+# Entries for the AT&T 495 printer
+#
+
+495ibm|att495ibm|AT&T 495 IBM Graphics emulation,
+
+ bufsz#1024,
+ cps#800,
+
+
+ orc#12,
+ orhi#120,
+
+ lines#63,
+
+ cpi=%?%p1%{10}%=%t^R%e%p1%{17}%=%t^O%;,
+
+# Reset defaults, enter IBM Graphics emulation mode
+ is2=\E[0~\E[12~,
+
+ use=Gibmg+basic, use=Gibmg+low,
+
+495qume|att495qume|AT&T 495 Qume emulation,
+
+ daisy@,
+
+ bufsz#1024,
+ cps#800,
+
+ cols#80,
+ lines#63,
+
+
+ chr=%?%p1%{0}%>%p1%{127}%<%&%t\E^_%p1%{1}%+%c%;,
+ cvr=%?%p1%{0}%>%p1%{127}%<%&%t\E^^%p1%{1}%+%c%;,
+
+ is2=\E[0~\E[11~\E^_\r,
+
+ u9=%?%p1%{128}%<%t\EF%p1%02d%;,
+
+ use=Gdaisy+basic, use=Gdaisy+lowres,
+
+495hp|att495hp|AT&T 495 HP Laserjet I emulation,
+
+ bufsz#1024,
+ cps#800,
+
+ is2=\E[0~\E[10~\E&k0S,
+
+ use=Ghplaser+basic, use=Ghplaser+high,
diff --git a/usr/src/cmd/lp/terminfo/53x0.ti b/usr/src/cmd/lp/terminfo/53x0.ti
new file mode 100644
index 0000000000..fc6fb2cef9
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/53x0.ti
@@ -0,0 +1,81 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+######################################################################
+#
+# Entries for the AT&T 5310, 5320 printers
+#
+
+53x0+high,
+
+ spinv#72,
+ spinh#150,
+
+ bitwin#2,
+ u1=2,
+
+# defbi=
+# X is in 1/150 increments; set char spacing to 1/16.7
+# increments to allow us to get close; column is X*16.7/150.
+# Y is in 1/144 increments; set line spacing to 1/12
+# increments to allow us to get close; line is Y/12.
+# Note: The 5310/5320 won't move upward with the absolute
+# addressing control sequence, so we use the relative motion.
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\E[4w\E[%p1%{167}%*%{1500}%/%d`\E[w\E[3z\E[%p2%{12}%/%de\E[z\EP\035q%;,
+ defbi=%?%p5%{1}%=%t\E[4w\E[%p1%{167}%*%{1500}%/%d`\E[w\E[3z\E[%p2%{12}%/%de\E[z\EP\035q%;,
+
+ use=Gdec+low,
+
+5320|att5320|AT&T Model 5320 printer (EMUL set to ANSI),
+
+ bufsz#8192,
+ cps#120,
+
+
+#
+# FIX: The AT&T 5320 doesn't seem to have fine-scale horizontal
+# motion--the only motion is by columns.
+ orc#10,
+ orhi#100,
+
+#
+# FIX: The AT&T 5320 seems to only have half-line vertical motion
+# at best.
+ orl#12,
+ orvi#72,
+
+
+
+ use=53x0+high, use=Gdec+basic, use=Gdec+low,
+
+5310|att5310|AT&T 5310 matrix printer (EMUL set to ANSI),
+
+ cols#80,
+
+ use=5320,
diff --git a/usr/src/cmd/lp/terminfo/57x.ti b/usr/src/cmd/lp/terminfo/57x.ti
new file mode 100644
index 0000000000..677090111e
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/57x.ti
@@ -0,0 +1,105 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+######################################################################
+#
+# Entries for the AT&T 570 series printers
+#
+
+570eps|att570eps|AT&T 570 Epson emulation,
+
+ bufsz#10000,
+ cps#250,
+ cols#80,
+ orl#36,
+ orvi#216,
+
+ use=Gepson+basic,
+ use=Gepson+low,
+
+570ibm|att570ibm|AT&T 570 IBM ProPrinter emulation,
+
+ bufsz#10000,
+ cps#250,
+
+ use=Gibmg+basic,
+ use=Gibmg+low,
+
+571eps|att571eps|AT&T 571 Epson emulation,
+
+ cols#136,
+
+ use=570eps,
+
+571ibm|att571ibm|AT&T 571 IBM ProPrinter emulation,
+
+ cols#136,
+ use=570ibm,
+
+572|att572|AT&T 572 9-wire Matrix Printer,
+
+ bufsz#10000,
+ cps#250,
+ cols#80,
+ xhpa@,
+ xvpa@,
+
+ csnm=%?%p1%{0}%=%tusascii%e%p1%{1}%=%tbritish%e%p1%{2}%=%tfinnish%e%p1%{3}%=%tjapanese%e%p1%{4}%=%tnorwegian%e%p1%{5}%=%tswedish%e%p1%{6}%=%tgerman%e%p1%{7}%=%tfrench%e%p1%{8}%=%tfrench_canadian%e%p1%{9}%=%titalian%e%p1%{10}%=%tspanish%e%p1%{11}%=%tline_drawing%e%p1%{12}%=%tdanish%e%p1%{13}%=%tebcdic%e%p1%{14}%=%tmulti_national%;,
+ scs=%?%p1%{0}%=%t\E(B%e%p1%{1}%=%t\E(A%e%p1%{2}%=%t\E(C%e%p1%{3}%=%t\E(J%e%p1%{4}%=%t\E(E%e%p1%{5}%=%t\E(H%e%p1%{6}%=%t\E(K%e%p1%{7}%=%t\E(R%e%p1%{8}%=%t\E(Q%e%p1%{9}%=%t\E(Y%e%p1%{10}%=%t\E(Z%e%p1%{11}%=%t\E(O%e%p1%{12}%=%t\E(E%e%p1%{13}%=%t\E(3%e%p1%{14}%=%t\E(<%;,
+
+ is3=\E[0"z,
+
+ snlq=\E[2"z,
+ snrmq=\E[3"z,
+ sdrfq=\E[0"z,
+ sshm=\E[1m,
+ rshm=\E[22m,
+ smul=\E[4m,
+ rmul=\E[24m,
+
+# The following are not supported by 572/573
+
+ smgbp@,
+ smgtp@,
+ smglp@,
+ smgrp@,
+ cud@,
+ cuf@,
+ cuu1@,
+ hpa@,
+ vpa@,
+ nel@,
+
+ use=Gdec+basic,
+ use=Gdec+low,
+
+573|att573|AT&T 573 9-wire Matrix Printer,
+
+ cols#132,
+
+ use=572,
diff --git a/usr/src/cmd/lp/terminfo/58x.ti b/usr/src/cmd/lp/terminfo/58x.ti
new file mode 100644
index 0000000000..bd5b65c663
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/58x.ti
@@ -0,0 +1,103 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+######################################################################
+#
+# Generic entry:
+#
+
+att583+basic,
+
+ bufsz#16384,
+ cps#200,
+
+######################################################################
+#
+# Specific printers:
+#
+
+583ibm|att583ibm|AT&T 583 as IBM Proprinter XL,
+
+ cols#136,
+ is3=\EX\210,
+
+ use=att583+basic, use=Gibmxl+basic, use=Gibmxl+low+5x6, use=Gibmc+color,
+
+
+583ibm-80|att583ibm-80|AT&T 583 as IBM Proprinter XL;80-col,
+
+ use=att583+basic, use=Gibmxl+basic, use=Gibmxl+low+5x6, use=Gibmc+color,
+
+
+583eps|att583eps|AT&T 583 as Epson LQ-2500; low resolution,
+
+ use=att583+basic, use=Gep2500+basic, use=Gep2500+low, use=Gep2500+color,
+
+583eps-hi|att583eps-hi|AT&T 583 as Epson LQ-2500; high resolution,
+
+ use=att583+basic, use=Gep2500+basic, use=Gep2500+high, use=Gep2500+color,
+
+583eps-80|att583eps-80|AT&T 583 as Epson LQ-2500; low resolution; 80-col,
+
+ cols#80,
+ use=att583+basic, use=Gep2500+basic, use=Gep2500+low, use=Gep2500+color,
+
+583eps-hi-80|att583eps-hi-80|AT&T 583 as Epson LQ-2500; high resolution; 80-col,
+
+ cols#80,
+ use=att583+basic, use=Gep2500+basic, use=Gep2500+high, use=Gep2500+color,
+
+
+580ibm|att580ibm|AT&T 580 as IBM Proprinter XL,
+
+ use=att583+basic, use=Gibmxl+basic, use=Gibmxl+low+5x6,
+
+581ibm|att581ibm|AT&T 581 as IBM Proprinter XL,
+
+ cols#136,
+ is3=\EX\210,
+
+ use=580ibm,
+
+
+581eps|att581eps|AT&T 581 as Epson LQ-2500; low resolution,
+
+ use=att583+basic, use=Gep2500+basic, use=Gep2500+low,
+
+581eps-hi|att581eps-hi|AT&T 581 as Epson LQ-2500; high resolution,
+
+ use=att583+basic, use=Gep2500+basic, use=Gep2500+high,
+
+580eps|att580eps|AT&T 580 as Epson LQ-2500; low resolution,
+
+ cols#80,
+ use=att583+basic, use=Gep2500+basic, use=Gep2500+low,
+
+580eps-hi|att580eps-hi|AT&T 580 as Epson LQ-2500; high resolution,
+
+ cols#80,
+ use=att583+basic, use=Gep2500+basic, use=Gep2500+high,
diff --git a/usr/src/cmd/lp/terminfo/593.ti b/usr/src/cmd/lp/terminfo/593.ti
new file mode 100644
index 0000000000..3d2a592c47
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/593.ti
@@ -0,0 +1,73 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+######################################################################
+#
+# Entries for the AT&T 593 printer
+#
+
+593eps|att593eps|AT&T 593 Epson FX86e emulation,
+
+ bufsz#2000,
+ cps#480,
+ cols#80,
+ lines#62,
+ orl#36,
+ orvi#216,
+
+# Only letter quality for laser printer
+ snlq@,
+ snrmq@,
+ sdrfq@,
+
+ use=Gep2500+basic,
+ use=Gepson+low,
+
+593ibm|att593ibm|AT&T 593 IBM ProPrinter XL emulation,
+
+ bufsz#2000,
+ cps#480,
+
+ lines#62,
+
+# Only letter quality for laser printer
+ snlq@,
+ sdrfq@,
+
+ smglp=\EX%p1%{1}%+%c%p2%{1}%+%c,
+
+ use=Gibmxl+basic,
+ use=Gibmxl+low+1x1,
+
+
+593hp|att593hp|AT&T 593 HP Laserjet II emulation,
+
+ bufsz#2000,
+ cps#480,
+
+
+ use=Ghplaser+II,
diff --git a/usr/src/cmd/lp/terminfo/Makefile b/usr/src/cmd/lp/terminfo/Makefile
new file mode 100644
index 0000000000..b94f821b6b
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/Makefile
@@ -0,0 +1,77 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/terminfo/Makefile
+#
+
+include ../Makefile.lp
+
+ROOTTERMINFO = $(ROOT)/usr/share/lib/terminfo
+
+TIC = tic
+
+SRCS = PS.ti 40.ti 477.ti 53x0.ti 593.ti daisy.ti hplaser.ti \
+ 44x.ti 47x.ti 57x.ti dec.ti ibm.ti 45x.ti 495.ti \
+ 58x.ti citoh.ti epson.ti unknown.ti
+
+
+TMPSRC = terminfo.src
+
+DIRMODE= 755
+FILEMODE= 644
+
+.KEEP_STATE:
+
+all : $(TMPSRC)
+
+$(TMPSRC) : $(SRCS)
+ $(RM) $@; cat $(SRCS) > $@
+
+#
+# Since all entries are created at once, we simply choose one of the
+# target files and assume everything will be made at one time. This
+# has holes (like if somebody removes P/PSR but not P/PS), but those
+# are the breaks.
+#
+install : all $(ROOTTERMINFO) $(ROOTTERMINFO)/P/PS
+
+$(ROOTTERMINFO)/P/PS: $(TMPSRC)
+ TERMINFO=$(ROOTTERMINFO) 2>&1 $(TIC) -v $(TMPSRC) > errs
+ @$(ECHO) "\n`2>/dev/null cat errs|wc -l` entries have been compiled\n"
+ @-( 2>/dev/null cat errs|grep -iv "^mkdir"|grep -iv "^create"|grep -iv "^link"|grep -vi $(TMPSRC)|grep -vi touch|grep -vi "working"; \
+ if [ $$? -ne 0 ] ; \
+ then \
+ $(ECHO) "\tNo errors\n"; \
+ else \
+ $(ECHO) "\n\tErrors can be found in `pwd`/errs\n"; \
+ fi \
+ )
+
+$(ROOTTERMINFO) :
+ $(INS.dir)
+
+clean clobber:
+ $(RM) $(TMPSRC)
+
+strip lint :
+
diff --git a/usr/src/cmd/lp/terminfo/PS.ti b/usr/src/cmd/lp/terminfo/PS.ti
new file mode 100644
index 0000000000..28a83e988b
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/PS.ti
@@ -0,0 +1,36 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+# ident "%Z%%M% %I% %E% SMI" /* SVr4 1.1 */
+
+PS|PSR|PS-b|PS-r|PS-br|Fake PostScript entry,
+ slines=\004,
+ u9=\004,
+ csnm=\004,
+ scs=\004,
+ cpi=null,
+ lpi=null,
+ cols#80,
+ lines#66,
diff --git a/usr/src/cmd/lp/terminfo/citoh.ti b/usr/src/cmd/lp/terminfo/citoh.ti
new file mode 100644
index 0000000000..c2b584b7c6
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/citoh.ti
@@ -0,0 +1,127 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+######################################################################
+#
+# Generic entry for the C.Itoh 8510 printer and emulations:
+#
+
+Gcitoh+basic,
+
+# The 8510 I use only allows 79 columns!
+ cols#79,
+
+ lines#66,
+ it#8,
+
+ orc#1,
+ orhi#10,
+ orl#24,
+ orvi#144,
+
+ cr=\r,
+ cud1=\n,
+ cuf1=\s,
+ ff=\f,
+ ht=\t,
+
+ cpi=%?%p1%{10}%=%t\EN%e%p1%{12}%=%t\EE%e%p1%{16}%=%p1%{17}%=%O%t\EQ%;,
+ cvr=%?%p1%{0}%>%p1%{100}%<%&%t\ET%p1%02d%;,
+
+ is1=^Q^X,
+ is2=\Ec1\Ev66.,
+
+ smso=\E!,
+ rmso=\E",
+ smul=\EX,
+ rmul=\EY,
+ bold=\E!,
+ ssubm=\Es2,
+ rsubm=\Es0,
+ ssupm=\Es1,
+ rsupm=\Es0,
+ swidm=^N,
+ rwidm=^O,
+ sgr0=\E"\EY\Es0^O,
+ sgr=%?%p1%p6%|%t\E!%e\E"%;%?%p2%t\EX%e\EY%;,
+
+ rep=\ER%p2%03d%p1%c,
+
+ snlq=\Em2,
+ snrmq=\Em1,
+ sdrfq=\Em0,
+
+ smglp=\EL%p1%03d,
+ smgrp=\E/%{1}%p1%+%03d,
+
+# slines=
+ u9=\Ev%p1%02d.,
+ slines=\Ev%p1%02d.,
+
+Gcitoh+low,
+
+ npins#8,
+ spinv#68,
+ spinh#136,
+
+ porder=8\,7\,6\,5\,4\,3\,2\,1;0,
+
+ sbim=\ES%p1%04d,
+
+# birep=
+ u4=\EV%p2%04d%p3%c,
+ birep=\EV%p2%04d%p3%c,
+
+ bitwin#1,
+ u1=1,
+ bitype#1,
+ u2=1,
+
+# defbi=
+# Set the line spacing to 17/144 inch to get (almost) 68 dots
+# per inch vertically (8 * 144/17).
+# Set the character spacing to compressed (1/17 inch or 17
+# characters per inch); at 136 dots per inch horizontally this
+# means 8 dots per character.
+# Set the left margin at the left edge of the image.
+# The C.Itoh doesn't have parameterized vertical motion,
+# so we simulate it with linefeeds. Assume we never need
+# to move more than 63 lines (at 17/144 LPI).
+# Set uni-directional motion; bi-directional causes a wavy
+# image.
+# defbi=
+ u6=%?%p5%{1}%=%t\ET17\EQ\EL%p1%{8}%/%03d%p2%{8}%/%Py%?%gy%{31}%>%t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n%gy%{32}%-%Py%;%?%gy%{15}%>%t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n%gy%{16}%-%Py%;%?%gy%{7}%>%t\n\n\n\n\n\n\n\n%gy%{8}%-%Py%;%?%gy%{3}%>%t\n\n\n\n%gy%{4}%-%Py%;%?%gy%{1}%>%t\n\n%gy%{2}%-%Py%;%?%gy%{0}%>%t\n%;\E>%;,
+ defbi=%?%p5%{1}%=%t\ET17\EQ\EL%p1%{8}%/%03d%p2%{8}%/%Py%?%gy%{31}%>%t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n%gy%{32}%-%Py%;%?%gy%{15}%>%t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n%gy%{16}%-%Py%;%?%gy%{7}%>%t\n\n\n\n\n\n\n\n%gy%{8}%-%Py%;%?%gy%{3}%>%t\n\n\n\n%gy%{4}%-%Py%;%?%gy%{1}%>%t\n\n%gy%{2}%-%Py%;%?%gy%{0}%>%t\n%;\E>%;,
+
+# endbi=
+ u7=\EA\EP\EL001\E<,
+ endbi=\EA\EP\EL001\E<,
+
+# binel=
+ u5=\n\r\EL%p1%{8}%/%03d,
+ binel=\n\r\EL%p1%{8}%/%03d,
+
diff --git a/usr/src/cmd/lp/terminfo/daisy.ti b/usr/src/cmd/lp/terminfo/daisy.ti
new file mode 100644
index 0000000000..26c7b31d9f
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/daisy.ti
@@ -0,0 +1,126 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+######################################################################
+#
+# Generic entry for the daisy wheel printers and emulations:
+#
+
+#
+# Basic capabilities:
+#
+Gdaisy+basic,
+
+ daisy,
+
+ cols#132,
+ lines#66,
+
+ bufsz#500,
+ cps#55,
+ orc#12,
+ orhi#120,
+ orl#8,
+ orvi#48,
+
+ cr=^M,
+ cud1=^J,
+ cuf1=\s,
+ ff=^L,
+ ht=^I,
+ hpa=%?%p1%{100}%<%t\EC%p1%02d%e%p1%{110}%<%t\ECA%p1%{100}%-%d%e%p1%{120}%<%t\ECB%p1%{110}%-%d%e%p1%{130}%<%t\ECC%p1%{120}%-%d%e%p1%{140}%<%t\ECD%p1%{130}%-%d%e%p1%{150}%<%t\ECE%p1%{140}%-%d%e%p1%{160}%<%t\ECF%p1%{150}%-%d%;,
+ vpa=%?%p1%{100}%<%t\EP%p1%02d%e%p1%{110}%<%t\EPA%p1%{100}%-%d%e%p1%{120}%<%t\EPB%p1%{110}%-%d%e%p1%{130}%<%t\EPC%p1%{120}%-%d%e%p1%{140}%<%t\EPD%p1%{130}%-%d%e%p1%{150}%<%t\EPE%p1%{140}%-%d%e%p1%{160}%<%t\EPF%p1%{150}%-%d%;,
+
+ chr=%?%p1%{100}%<%t\EE%p1%02d%e%p1%{110}%<%t\EEA%p1%{100}%-%d%e%p1%{120}%<%t\EEB%p1%{110}%-%d%e%p1%{130}%<%t\EEC%p1%{120}%-%d%e%p1%{140}%<%t\EED%p1%{130}%-%d%e%p1%{150}%<%t\EEE%p1%{140}%-%d%e%p1%{160}%<%t\EEF%p1%{150}%-%d%;,
+ cvr=%?%p1%{100}%<%t\EL%p1%02d%e%p1%{110}%<%t\ELA%p1%{100}%-%d%e%p1%{120}%<%t\ELB%p1%{110}%-%d%e%p1%{130}%<%t\ELC%p1%{120}%-%d%e%p1%{140}%<%t\ELD%p1%{130}%-%d%e%p1%{150}%<%t\ELE%p1%{140}%-%d%e%p1%{160}%<%t\ELF%p1%{150}%-%d%;,
+
+
+ is2=\E\015P\EW\E.\EL08\EE12\E%\E<,
+
+ smso=\EQ,
+ rmso=\ER,
+ smul=\EI,
+ rmul=\EJ,
+ bold=\EK3,
+ sshm=\EQ,
+ rshm=\ER,
+ sgr0=\ER\EM\EJ,
+ sgr=%?%p1%t\EQ%e\ER%;%?%p2%t\EI%e\EJ%;%?%p6%t\EK3%e\EM%;,
+
+ smgb=\E-,
+ smgl=\E9,
+ smgr=\E0,
+ smgt=\E+,
+
+# slines=,
+ u9=\EF%p1%02d,
+
+#
+# Graphics capabilities:
+#
+Gdaisy+lowres,
+
+#
+# We could use the graphics on/graphics off control sequences
+# (ESC G/ESC 4) but for these problems:
+#
+# - graphics mode gets turned off when a \r is received;
+# - printing a character doesn't cause motion, which
+# means that each ``cell'' must be followed by a space;
+# - to get the best aspect ratio, three horizontal dots
+# must be sent per ``cell'' (using the ESC 3 graphics mode
+# (1/60 instead of 1/120) alleviates this problem but
+# gives a worse aspect ratio).
+#
+# So instead we set the HMI and VMI to 1/40 and 1/48 inch,
+# respectively.
+#
+ npins#1,
+ spinv#48,
+ spinh#40,
+
+ porder=o\,o\,o\,o\,1\,1\,1\,o;32,
+
+# bitwin#
+ u1=1,
+# bitype#
+ u2=1,
+
+# birep=
+ u4=%?%p3%{32}%=%t\EH%p2%{3}%*%Px%gx%{256}%/%{64}%+%c%gx%{256}%m%{16}%/%{64}%+%c%gx%{16}%m%{64}%+%c%;,
+
+# defbi=
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\EL01\EE03%p1%{3}%*%Px\r\EH%gx%{256}%/%{64}%+%c%gx%{256}%m%{16}%/%{64}%+%c%gx%{16}%m%{64}%+%c\EV%p2%{256}%/%{64}%+%c%p2%{256}%m%{16}%/%{64}%+%c%p2%{16}%m%{64}%+%c\E>%;,
+
+# endbi=
+ u7=\EL08\EE12\E<,
+
+# binel=
+ u5=\n\r%p1%{3}%*%Px\EH%gx%{256}%/%{64}%+%c%gx%{256}%m%{16}%/%{64}%+%c%gx%{16}%m%{64}%+%c,
+
diff --git a/usr/src/cmd/lp/terminfo/dec.ti b/usr/src/cmd/lp/terminfo/dec.ti
new file mode 100644
index 0000000000..5cc0ae6d55
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/dec.ti
@@ -0,0 +1,130 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+######################################################################
+#
+# Generic entries for the various DEC printers and emulations.
+#
+# The Gdec+... entries are really for any ANSI X3.64 printer,
+# but "ansi" is already used for terminals. It would be more
+# work to do "use=ansi" because there are too many screen
+# oriented caps that would have to be removed.
+#
+
+#
+# Basic capabilities:
+#
+Gdec+basic,
+
+ cols#132,
+ lines#66,
+ it#8,
+
+ cpix,
+ orc#1,
+ orhi#10,
+ orl#2,
+ orvi#12,
+
+#
+# FIX? Are xhpa and xvpa really needed?
+ xhpa,
+ xvpa,
+
+ cr=^M,
+ ff=^L,
+ ht=^I,
+ cud1=^J,
+ cuf1=\s,
+ cuu1=\EM,
+ cud=\E[%p1%de,
+ cuf=\E[%p1%da,
+ hpa=\E[%p1%d`,
+ vpa=\E[%p1%dd,
+ nel=\EE,
+
+ is1=\Ec,
+ is2=\E[20l,
+
+ cpi=%?%p1%{10}%=%t\E[w%e%p1%{12}%=%t\E[2w%e%p1%{5}%=%t\E[5w%e%p1%{13}%=%p1%{14}%=%O%t\E[3w%e%p1%{16}%=%p1%{17}%=%O%t\E[4w%e%p1%{6}%=%t\E[6w%e%p1%{7}%=%t\E[7w%e%p1%{8}%=%t\E[8w%;,
+ lpi=%?%p1%{2}%=%t\E[4z%e%p1%{3}%=%t\E[5z%e%p1%{4}%=%t\E[6z%e%p1%{6}%=%t\E[z%e%p1%{8}%=%t\E[2z%e%p1%{12}%=%t\E[3z%;,
+
+ csnm=%?%p1%{0}%=%tusascii%e%p1%{1}%=%tenglish%e%p1%{2}%=%tfinnish%e%p1%{3}%=%tjapanese%e%p1%{4}%=%tnorwegian%e%p1%{5}%=%tswedish%e%p1%{6}%=%tgermanic%e%p1%{7}%=%tfrench%e%p1%{8}%=%tcanadian_french%e%p1%{9}%=%titalian%e%p1%{10}%=%tspanish%e%p1%{11}%=%tline%e%p1%{12}%=%tsecurity%e%p1%{13}%=%tebcdic%e%p1%{14}%=%tapl%e%p1%{15}%=%tmosaic%;,
+ scs=%?%p1%{0}%=%t\E(B%e%p1%{1}%=%t\E(A%e%p1%{2}%=%t\E(C%e%p1%{3}%=%t\E(D%e%p1%{4}%=%t\E(E%e%p1%{5}%=%t\E(H%e%p1%{6}%=%t\E(K%e%p1%{7}%=%t\E(R%e%p1%{8}%=%t\E(Q%e%p1%{9}%=%t\E(Y%e%p1%{10}%=%t\E(Z%e%p1%{11}%=%t\E(0%e%p1%{12}%=%t\E(1%e%p1%{13}%=%t\E(3%e%p1%{14}%=%t\E(8%e%p1%{15}%=%t\E(}%;,
+
+ sshm=\E[5m,
+ rshm=\E[m,
+
+ smgtp=\E[%p1%dr,
+ smgbp=\E[;%p1%dr,
+ smglp=\E[%{1}%p1%+%ds,
+ smgrp=\E[;%{1}%p1%+%ds,
+
+# slines=
+ u9=\E[%p1%dt,
+ slines=\E[%p1%dt,
+
+#
+# Graphics capabilities (low resolution, 6-pin):
+#
+Gdec+low,
+
+ npins#6,
+ spinv#72,
+ spinh#75,
+
+ porder=o\,o\,6\,5\,4\,3\,2\,1;63,
+
+ bitwin#1,
+ u1=1,
+ bitype#1,
+ u2=1,
+
+# birep=
+ u4=!%p2%d%p3%c,
+ birep=!%p2%d%p3%c,
+
+# defbi=
+# X is in 1/75 increments; set char spacing to 1/16.7
+# increments to allow us to get close; column is X*16.7/75.
+# Y is in 1/72 increments; set line spacing to 1/12
+# increments to allow us to get close; line is Y/6.
+ u6=%?%p5%{1}%=%t\E[4w\E[%p1%{167}%*%{750}%/%d`\E[w\E[3z\E[%p2%{6}%/%dd\E[z\EP0q%;,
+ defbi=%?%p5%{1}%=%t\E[4w\E[%p1%{167}%*%{750}%/%d`\E[w\E[3z\E[%p2%{6}%/%dd\E[z\EP0q%;,
+
+# endbi=
+ u7=^X,
+ endbi=^X,
+
+# binel=
+ u5=-,
+ binel=-,
+
+# bicr=
+ u3=$,
+ bicr=$,
+
diff --git a/usr/src/cmd/lp/terminfo/epson.ti b/usr/src/cmd/lp/terminfo/epson.ti
new file mode 100644
index 0000000000..8beceb1e74
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/epson.ti
@@ -0,0 +1,301 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+######################################################################
+#
+# Epson
+#
+
+#
+# Basic capabilities:
+#
+Gepson+basic,
+
+ cols#80,
+ lines#66,
+ it#8,
+
+ cpix,
+ orc#6,
+ orhi#60,
+ orl#30,
+ orvi#180,
+
+ cr=^M,
+ cud1=^J,
+ cuf1=\s,
+ cub1=\b,
+ ff=^L,
+ ht=^I,
+
+ cpi=%?%p1%{10}%=%t^R\EP%e%p1%{12}%=%t^R\EM%e%p1%{20}%=%t^O\EM%e%p1%{17}%=%t^O\EP%;,
+ cvr=%?%p1%{0}%>%p1%{256}%<%&%t\E3%p1%c%;,
+
+ is1=^Q^X,
+ is2=\E@\E%0\EO,
+
+ csnm=%?%p1%{0}%=%tusa%e%p1%{1}%=%tfrench%e%p1%{2}%=%tgerman%e%p1%{3}%=%tbritish%e%p1%{4}%=%tdanish%e%p1%{5}%=%tswedish%e%p1%{6}%=%titalian%e%p1%{7}%=%tspanish%e%p1%{8}%=%tjapanese%e%p1%{9}%=%tnorwegian%e%p1%{10}%=%tdanish2%e%p1%{11}%=%tspanish2%e%p1%{12}%=%tlatin_american%e%p1%{13}%=%tafrikaans%e%p1%{14}%=%tdutch%e%p1%{15}%=%tfrench_canadian%e%p1%{16}%=%tfrench2%e%p1%{17}%=%tbritish2%e%p1%{18}%=%tmulti_national%e%p1%{19}%=%tibmgraphics%;,
+ scs=%?%p1%{0}%=%t\ER\200%e%p1%{1}%=%t\ER\001%e%p1%{2}%=%t\ER\002%e%p1%{3}%=%t\ER\003%e%p1%{4}%=%t\ER\004%e%p1%{5}%=%t\ER\005%e%p1%{6}%=%t\ER\006%e%p1%{7}%=%t\ER\007%e%p1%{8}%=%t\ER\010%e%p1%{9}%=%t\ER\011%e%p1%{10}%=%t\ER\012%e%p1%{11}%=%t\ER\013%e%p1%{12}%=%t\ER\014%e%p1%{13}%=%t\ER\100%e%p1%{14}%=%t\ERA%e%p1%{15}%=%t\ERB%e%p1%{16}%=%t\ERC%e%p1%{17}%=%t\ERD%e%p1%{18}%=%t\E6%e%p1%{19}%=%t\Et1%;,
+
+ smso=\EE,
+ rmso=\EF,
+ smul=\E-1,
+ rmul=\E-0,
+ bold=\EG,
+ sshm=\EE,
+ rshm=\EF,
+ ssubm=\ES1,
+ rsubm=\ET,
+ ssupm=\ES0,
+ rsupm=\ET,
+ swidm=\EW1,
+ rwidm=\EW0,
+ sitm=\E4,
+ ritm=\E5,
+ sgr0=\EF\E-0\EH\ET\EW0\E5,
+ sgr=%?%p1%t\EE%e\EF%;%?%p2%t\E-1%e\E-0%;%?%p6%t\EG%e\EH%;,
+
+#
+# For now we can't set the margin in the first (0th) column
+# due to limitations in the Curses code. This should be changed
+# in the future. For now, shift right 1. Note that the right
+# margin is the last USEABLE column in Terminfo, but is 1
+# PAST that for the Epson.
+ smglp=%?%p1%{256}%<%t\El%p1%{1}%+%c%;,
+ smgrp=%?%p1%{256}%<%t\EQ%p1%{2}%+%c%;,
+
+# slines= u9 used for svr3.2
+ u9=%?%p1%{0}%>%p1%{128}%<%&%t\EC%p1%c%;,
+ slines=%?%p1%{0}%>%p1%{128}%<%&%t\EC%p1%d%;,
+
+ sdrfq=\Ex0,
+ snlq=\Ex1,
+ snrmq=\Ek1,
+
+#
+# Graphics capabilities:
+#
+Gepson+low,
+
+ npins#8,
+ spinv#60,
+ spinh#60,
+
+ porder=1\,2\,3\,4\,5\,6\,7\,8;0,
+
+ sbim=\EK%p1%{256}%m%c%p1%{256}%/%c,
+
+# u1 - u8 used for svr3.2
+ bitwin#1,
+ u1=1,
+ bitype#1,
+ u2=1,
+
+# defbi=
+# Set the line spacing to 8/60 inch (7.5 lines per inch)
+# to get 60 dots per inch vertically (7.5 lines/" * 8 pins/line).
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 60 dots per inch horizontally this means 6
+# dots per character.
+# Set vertical and horizontal tab stops at the upper left corner
+# of the image, then tab to the upper left corner.
+# Note: $<> is a true null (only works with special Curses routine).
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ defbi=%?%p5%{1}%=%t\E3\030^R\EP\EB%p2%{8}%/%c$<>\ED%p1%{6}%/%c$<>\013\r\t%;,
+
+# endbi=
+ u7=\E3\036,
+ endbi=\E3\036,
+
+# binel=
+ u5=\n\r\t,
+ binel=\n\r\t,
+
+# bicr=
+ u3=\r\t,
+ bicr=\r\t,
+
+######################################################################
+#
+# Epson LQ-2500
+#
+
+#
+# Basic capabilities:
+#
+Gep2500+basic,
+
+ cols#136,
+ lines#66,
+ it#8,
+
+ cpix,
+ orc#6,
+ orhi#60,
+ orl#30,
+ orvi#180,
+
+ cr=^M,
+ cud1=^J,
+ cuf1=\s,
+ cub1=\b,
+ ff=^L,
+ ht=^I,
+
+ cpi=%?%p1%{10}%=%t^R\EP%e%p1%{12}%=%t^R\EM%e%p1%{20}%=%t^O\EM%e%p1%{17}%=%t^O\EP%;,
+ cvr=%?%p1%{0}%>%p1%{256}%<%&%t\E3%p1%c%;,
+
+ is1=^Q^X,
+ is2=\E@\E%0\EO,
+
+
+ csnm=%?%p1%{0}%=%tusa%e%p1%{1}%=%tfrench%e%p1%{2}%=%tgerman%e%p1%{3}%=%tbritish%e%p1%{4}%=%tdanish%e%p1%{5}%=%tswedish%e%p1%{6}%=%titalian%e%p1%{7}%=%tspanish%e%p1%{8}%=%tjapanese%e%p1%{9}%=%tnorwegian%e%p1%{10}%=%tdanish2%e%p1%{11}%=%tspanish2%e%p1%{12}%=%tlatin_american%e%p1%{13}%=%tibmgraphics%;,
+ scs=%?%p1%{0}%=%t\ER\200%e%p1%{1}%=%t\ER\001%e%p1%{2}%=%t\ER\002%e%p1%{3}%=%t\ER\003%e%p1%{4}%=%t\ER\004%e%p1%{5}%=%t\ER\005%e%p1%{6}%=%t\ER\006%e%p1%{7}%=%t\ER\007%e%p1%{8}%=%t\ER\010%e%p1%{9}%=%t\ER\011%e%p1%{10}%=%t\ER\012%e%p1%{11}%=%t\ER\013%e%p1%{12}%=%t\ER\014%e%p1%{13}%=%t\Et1%;,
+
+ smso=\EE,
+ rmso=\EF,
+ smul=\E-1,
+ rmul=\E-0,
+ bold=\EG,
+ sshm=\EE,
+ rshm=\EF,
+ ssubm=\ES1,
+ rsubm=\ET,
+ ssupm=\ES0,
+ rsupm=\ET,
+ swidm=\EW1,
+ rwidm=\EW0,
+ sitm=\E4,
+ ritm=\E5,
+ sgr0=\EF\E-0\EH\ET\EW0\E5,
+ sgr=%?%p1%t\EE%e\EF%;%?%p2%t\E-1%e\E-0%;%?%p6%t\EG%e\EH%;,
+
+#
+# For now we can't set the margin in the first (0th) column
+# due to limitations in the Curses code. This should be changed
+# in the future. For now, shift right 1. Note that the right
+# margin is the last USEABLE column in Terminfo, but is 1
+# PAST that for the Epson.
+ smglp=%?%p1%{256}%<%t\El%p1%{1}%+%c%;,
+ smgrp=%?%p1%{256}%<%t\EQ%p1%{2}%+%c%;,
+
+# slines=
+ u9=%?%p1%{0}%>%p1%{128}%<%&%t\EC%p1%c%;,
+ slines=%?%p1%{0}%>%p1%{128}%<%&%t\EC%p1%c%;,
+
+ sdrfq=\Ex0,
+ snlq=\Ex1,
+ snrmq=\Ek1,
+
+#
+# Graphics capabilities:
+#
+Gep2500+low,
+
+ npins#8,
+ spinv#60,
+ spinh#60,
+
+ porder=1\,2\,3\,4\,5\,6\,7\,8;0,
+
+ sbim=\EK%p1%{256}%m%c%p1%{256}%/%c,
+
+ bitwin#1,
+ u1=1,
+ bitype#1,
+ u2=1,
+
+# defbi=
+# Set the line spacing to 8/60 inch (7.5 lines per inch)
+# to get 60 dots per inch vertically (7.5 lines/" * 8 pins/line).
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 60 dots per inch horizontally this means 6
+# dots per character.
+# Set vertical and horizontal tab stops at the upper left corner
+# of the image, then tab to the upper left corner.
+# Note: $<> is a true null (only works with special Curses routine).
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\E3\030^R\EP\EB%p2%{8}%/%c$<>\ED%p1%{6}%/%c$<>\013\r\t%;,
+ defbi=%?%p5%{1}%=%t\E3\030^R\EP\EB%p2%{8}%/%c$<>\ED%p1%{6}%/%c$<>\013\r\t%;,
+
+# endbi=
+ u7=\E3\036,
+ endbi=\E3\036,
+
+# binel=
+ u5=\n\r\t,
+ binel=\n\r\t,
+
+# bicr=
+ u3=\r\t,
+ bicr=\r\t,
+
+#
+# Graphics capabilities:
+#
+Gep2500+high,
+
+ npins#24,
+ spinv#180,
+ spinh#180,
+
+ porder=1\,2\,3\,4\,5\,6\,7\,8\,9\,10\,11\,12\,13\,14\,15\,16\,17\,18\,19\,20\,21\,22\,23\,24;0,
+
+ sbim=\E*\047%p1%{256}%m%c%p1%{256}%/%c,
+
+# defbi=
+# Set the line spacing to 8/60 inch (7.5 lines per inch)
+# to get 180 dots per inch vertically (7.5 lines/" * 24 pins/line).
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 180 dots per inch horizontally this means 18
+# dots per character.
+# Set vertical and horizontal tab stops at the upper left corner
+# of the image, then tab to the upper left corner.
+# Note: $<> is a true null (only works with special Curses routine).
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\E3\030^R\EP\EB%p2%{24}%/%c$<>\ED%p1%{18}%/%c$<>\013\r\t%;,
+ defbi=%?%p5%{1}%=%t\E3\030^R\EP\EB%p2%{24}%/%c$<>\ED%p1%{18}%/%c$<>\013\r\t%;,
+
+ use=Gep2500+low,
+
+#
+# Color capability:
+#
+Gep2500+color,
+
+ colors#3,
+
+# setcolor=
+ initc=%?%p1%{0}%=%t\Er0%;%?%p1%{1}%=%t\Er2%;%?%p1%{2}%=%t\Er1%;%?%p1%{3}%=%t\Er4%;,
+
+# colornm=
+ u8=%?%p1%{0}%=%tblack%;%?%p1%{1}%=%tcyan%;%?%p1%{2}%=%tmagenta%;%?%p1%{3}%=%tyellow%;%?%p1%{4}%=%torange=yellow+magenta%;%?%p1%{5}%=%tgreen=yellow+cyan%;%?%p1%{6}%=%tviolet=magenta+cyan%;%?%p1%{7}%=%tbrown=magenta+black%;,
+ colornm=%?%p1%{0}%=%tblack%;%?%p1%{1}%=%tcyan%;%?%p1%{2}%=%tmagenta%;%?%p1%{3}%=%tyellow%;%?%p1%{4}%=%torange=yellow+magenta%;%?%p1%{5}%=%tgreen=yellow+cyan%;%?%p1%{6}%=%tviolet=magenta+cyan%;%?%p1%{7}%=%tbrown=magenta+black%;,
+
diff --git a/usr/src/cmd/lp/terminfo/hplaser.ti b/usr/src/cmd/lp/terminfo/hplaser.ti
new file mode 100644
index 0000000000..4d887f99ab
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/hplaser.ti
@@ -0,0 +1,122 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+
+######################################################################
+#
+# Generic entry for the HP Laserjet printers and emulations:
+#
+
+#
+# Basic capabilities:
+#
+Ghplaser+basic,
+
+ cols#80,
+ lines#60,
+
+ orc#12,
+ orhi#120,
+ orl#8,
+ orvi#48,
+
+ cr=^M,
+ cud1=^J,
+ cuf1=\s,
+ cud=\E&a+%p1%dR,
+ cuf=\E&a+%p1%dC,
+ ff=^L,
+ hpa=\E&a%p1%dC,
+ vpa=\E&a%p1%dR,
+
+ cpi=%?%p1%{10}%=%t\E&k0S%e%p1%{17}%=%t\E&k2S%;,
+ chr=%?%p1%{0}%>%p1%{127}%<%t\E&k%p1%dH%;,
+ cvr=%?%p1%{0}%>%p1%{127}%<%t\E&l%p1%dC%;,
+ lpi=%?%p1%{1}%=%t\E&l1D%e%p1%{2}%=%t\E&l2D%e%p1%{3}%=%t\E&l3D%e%p1%{4}%=%t\E&l4D%e%p1%{6}%=%t\E&l6D%e%p1%{8}%=%t\E&l8D%e%p1%{12}%=%t\E&l12D%e%p1%{16}%=%t\E&l16D%e%p1%{24}%=%t\E&l24D%e%p1%{48}%=%t\E&l48D%;,
+
+ is2=\EE\E&k0G,
+ mgc=\E9,
+
+ rmul=\E&d\100,
+ ritm=\E(s0S,
+ smul=\E&dD,
+ sitm=\E(s1S,
+ smgtp=\E&l%p1%{1}%+%dE,
+ smgbp=\E&l%p1%{1}%+%dF,
+ smglp=\E&a%p1%dL,
+ smgrp=\E&a%p1%dM,
+
+#Set top margin at +2 offset
+ smgtp=\E&l%p1%dE,
+
+#Set page length u9 used for 3.2 slines for 4.0
+ u9=\E&l%p1P,
+ slines=\E&l%p1%dF,
+
+#
+# Graphics capabilities:
+#
+Ghplaser+high,
+
+ npins#8,
+ spinv#300,
+ spinh#300,
+
+ porder=1\,2\,3\,4\,5\,6\,7\,8;0,
+
+ sbim=\E*b%p1%dW,
+
+# u1 - u7 used for svr3.2
+# bitwin#,
+ u1=1,
+ bitwin#1,
+# bitype#
+ u2=2,
+ bitype#2,
+
+# defbi=
+# X (or Y) * scale * 12/5 == pos in decipoints (12/5 == 720/300)
+ u6=%?%p5%{0}%>%p5%{5}%<%&%t\E&a%p1%p5%*%{12}%*%{5}%/%dH\E&a%p2%p5%*%{12}%*%{5}%/%dV\E*t%{300}%p5%/%dR\E*r1A%;,
+ defbi=%?%p5%{0}%>%p5%{5}%<%&%t\E&a%p1%p5%*%{12}%*%{5}%/%dH\E&a%p2%p5%*%{12}%*%{5}%/%dV\E*t%{300}%p5%/%dR\E*r1A%;,
+
+# endbi=
+ u7=\E*rB,
+ endbi=\E*rB,
+
+Ghplaser+II,
+
+ cpi=%?%p1%{10}%=%t\E(s10H%e%p1%{16}%=%p1%{17}%=%O%t\E(s16.66H%e%;,
+
+ csnm=%?%p1%{0}%=%troman-8%e%p1%{1}%=%tibm-us%e%p1%{2}%=%tibm-dn%e%p1%{3}%=%tgerman%e%p1%{4}%=%tspanish%e%p1%{5}%=%tecma-94%e%p1%{6}%=%tiso2%e%p1%{7}%=%tiso4%e%p1%{8}%=%tiso6%e%p1%{9}%=%tiso10%e%p1%{10}%=%tiso11%e%p1%{11}%=%tiso14%e%p1%{12}%=%tiso15%e%p1%{13}%=%tiso16%e%p1%{14}%=%tiso17%e%p1%{15}%=%tiso21%e%p1%{16}%=%tiso25%e%p1%{17}%=%tiso57%e%p1%{18}%=%tiso60%e%p1%{19}%=%tiso61%e%p1%{20}%=%tiso69%e%p1%{21}%=%tiso84%e%p1%{22}%=%tiso85%;,
+
+ scs=%?%p1%{0}%=%t\E(8U%e%p1%{1}%=%t\E(10U%e%p1%{2}%=%t\E(11U%e%p1%{3}%=%t\E(0G%e%p1%{4}%=%t\E(1S%e%p1%{5}%=%t\E(0N%e%p1%{6}%=%t\E(2U%e%p1%{7}%=%t\E(1E%e%p1%{8}%=%t\E(0U%e%p1%{9}%=%t\E(3S%e%p1%{10}%=%t\E(0S%e%p1%{11}%=%t\E(0K%e%p1%{12}%=%t\E(0I%e%p1%{13}%=%t\E(4S%e%p1%{14}%=%t\E(2S%e%p1%{15}%=%t\E(1G%e%p1%{16}%=%t\E(0F%e%p1%{17}%=%t\E(2K%e%p1%{18}%=%t\E(0D%e%p1%{19}%=%t\E(1D%e%p1%{20}%=%t\E(1F%e%p1%{21}%=%t\E(5S%e%p1%{22}%=%t\E(6S%;,
+
+ use=Ghplaser+basic, use=Ghplaser+high,
+
diff --git a/usr/src/cmd/lp/terminfo/ibm.ti b/usr/src/cmd/lp/terminfo/ibm.ti
new file mode 100644
index 0000000000..e58aca21eb
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/ibm.ti
@@ -0,0 +1,353 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */
+
+######################################################################
+#
+# Generic entries for the various IBM printers and emulations.
+#
+
+###################################
+#
+# IBM Graphics
+#
+
+#
+# Basic capabilities:
+#
+Gibmg+basic,
+
+ cols#80,
+ lines#66,
+ it#8,
+
+ cpix,
+ orc#1,
+ orhi#10,
+ orl#12,
+ orvi#72,
+
+ cr=^M,
+ ff=^L,
+ ht=^I,
+ cud1=^J,
+ cuf1=\s,
+
+ cpi=%?%p1%{10}%=%t^R%e%p1%{16}%=%p1%{17}%=%O%t^O%;,
+ cvr=%?%p1%{0}%>%p1%{256}%<%&%t\EA%p1%c\E2%;,
+
+ is1=^X,
+ is2=^R\EA\014\E2\EF\EH\EW0\ET\E-0\E7\EO\ECB,
+
+ csnm=%?%p1%{0}%=%tcharacter_set_1%e%p1%{1}%=%tcharacter_set_2%;,
+ scs=%?%p1%{0}%=%t\E7%e%p1%{2}%=%t\E6%;,
+
+ smso=\EE,
+ rmso=\EF,
+ smul=\E-1,
+ rmul=\E-0,
+ bold=\EG,
+ smacs=\E6,
+ rmacs=\E7,
+ sshm=\EE,
+ rshm=\EF,
+ ssubm=\ES1,
+ rsubm=\ET,
+ ssupm=\ES0,
+ rsupm=\ET,
+ swidm=\EW1,
+ rwidm=\EW0,
+ sgr0=\EF\E-0\EH\E7\ET\EW0,
+ sgr=%?%p1%t\EE%e\EF%;%?%p2%t\E-1%e\E-0%;%?%p6%t\EG%e\EH%;%?%p9%t\E6%e\E7%;,
+ sdrfq=\EH,
+ snlq=\EG,
+
+# slines= u9 used for svr3.2
+ u9=%?%p1%{0}%>%p1%{128}%<%&%t\EC%p1%c%;,
+ slines=%?%p1%{0}%>%p1%{128}%<%&%t\EC%p1%c%;,
+
+#
+# Graphics capabilities (low resolution, 9-pin):
+#
+Gibmg+low,
+
+ npins#8,
+ spinv#72,
+ spinh#60,
+
+ porder=1\,2\,3\,4\,5\,6\,7\,8;0,
+
+ sbim=\EK%p1%{256}%m%c%p1%{256}%/%c,
+
+ bitwin#1,
+ u1=1,
+ bitype#1,
+ u2=1,
+
+# defbi=
+# Set the line spacing to 8/72 inch (9 lines per inch)
+# to get 72 dots per inch vertically (9 lines/inch * 8 pins/line).
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 60 dots per inch horizontally this means 6
+# dots per character.
+# The IBM Graphics doesn't have parameterized motion,
+# so we simulate it with linefeeds and spaces.
+# Assume we never need to move across more than 63 colums
+# or down more than 31 lines.
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\EA\010\E2^R%p2%{8}%/%Py%?%gy%{15}%>%t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n%gy%{16}%-%Py%;%?%gy%{7}%>%t\n\n\n\n\n\n\n\n%gy%{8}%-%Py%;%?%gy%{3}%>%t\n\n\n\n%gy%{4}%-%Py%;%?%gy%{1}%>%t\n\n%gy%{2}%-%Py%;%?%gy%{0}%>%t\n%;\r%p1%{6}%/%Px%?%gx%{31}%>%t %gx%{32}%-%Px%;%?%gx%{15}%>%t %gx%{16}%-%Px%;%?%gx%{7}%>%t %gx%{8}%-%Px%;%?%gx%{3}%>%t %gx%{4}%-%Px%;%?%gx%{1}%>%t %gx%{2}%-%Px%;%?%gx%{0}%>%t %;%;,
+ defbi=%?%p5%{1}%=%t\EA\010\E2^R%p2%{8}%/%Py%?%gy%{15}%>%t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n%gy%{16}%-%Py%;%?%gy%{7}%>%t\n\n\n\n\n\n\n\n%gy%{8}%-%Py%;%?%gy%{3}%>%t\n\n\n\n%gy%{4}%-%Py%;%?%gy%{1}%>%t\n\n%gy%{2}%-%Py%;%?%gy%{0}%>%t\n%;\r%p1%{6}%/%Px%?%gx%{31}%>%t %gx%{32}%-%Px%;%?%gx%{15}%>%t %gx%{16}%-%Px%;%?%gx%{7}%>%t %gx%{8}%-%Px%;%?%gx%{3}%>%t %gx%{4}%-%Px%;%?%gx%{1}%>%t %gx%{2}%-%Px%;%?%gx%{0}%>%t %;%;,
+
+# endbi=
+ u7=\EA\014\E2,
+ endbi=\EA\014\E2,
+
+# binel=
+ u5=\n\r%p1%{6}%/%Px%?%gx%{31}%>%t %gx%{32}%-%Px%;%?%gx%{15}%>%t %gx%{16}%-%Px%;%?%gx%{7}%>%t %gx%{8}%-%Px%;%?%gx%{3}%>%t %gx%{4}%-%Px%;%?%gx%{1}%>%t %gx%{2}%-%Px%;%?%gx%{0}%>%t %;,
+ binel=\n\r%p1%{6}%/%Px%?%gx%{31}%>%t %gx%{32}%-%Px%;%?%gx%{15}%>%t %gx%{16}%-%Px%;%?%gx%{7}%>%t %gx%{8}%-%Px%;%?%gx%{3}%>%t %gx%{4}%-%Px%;%?%gx%{1}%>%t %gx%{2}%-%Px%;%?%gx%{0}%>%t %;,
+
+# bicr=
+ u3=\r%p1%{6}%/%Px%?%gx%{31}%>%t %gx%{32}%-%Px%;%?%gx%{15}%>%t %gx%{16}%-%Px%;%?%gx%{7}%>%t %gx%{8}%-%Px%;%?%gx%{3}%>%t %gx%{4}%-%Px%;%?%gx%{1}%>%t %gx%{2}%-%Px%;%?%gx%{0}%>%t %;,
+ bicr=\r%p1%{6}%/%Px%?%gx%{31}%>%t %gx%{32}%-%Px%;%?%gx%{15}%>%t %gx%{16}%-%Px%;%?%gx%{7}%>%t %gx%{8}%-%Px%;%?%gx%{3}%>%t %gx%{4}%-%Px%;%?%gx%{1}%>%t %gx%{2}%-%Px%;%?%gx%{0}%>%t %;,
+
+###################################
+#
+# IBM Color
+#
+
+#
+# Basic capabilities:
+#
+Gibmc+basic,
+
+ cub1=\b,
+
+ is1=^Q^X,
+ is2=^R\EA\014\E2\EF\EH\EW0\ET\E-0\E7\EO\ER\E50\EM0\EX^A\210\Eb\ECB,
+
+ cvr=%?%p1%{0}%>%p1%{256}%<%&%t\E3%p1%c%;,
+
+ smglp=\EX%p1%{1}%+%c%p2%{1}%+%c,
+
+ use=Gibmg+basic,
+
+#
+# Graphics capabilities (low resolution, 9-pin, 5:6 aspect ratio):
+#
+Gibmc+low+5x6,
+
+ spinv#84,
+ spinh#70,
+
+# defbi=
+# Set 5:6 aspect ratio.
+# Set the line spacing to 7/72 inch (10.29 lines per inch)
+# to get approximately 84 dots per inch vertically
+# (10.29 lines/inch * 8 pins/line equals 82.28 dots per inch).
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 70 dots per inch horizontally this means 7
+# dots per character.
+# Set vertical and horizontal tab stops at the upper left corner
+# of the image, then tab to the upper left corner.
+# Note: $<> is a true null (only works with special Curses routine).
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\En^B\E1^R\EB%p2%{8}%/%c$<>\ED%p1%{7}%/%c$<>\013\r\t%;,
+ defbi=%?%p5%{1}%=%t\En^B\E1^R\EB%p2%{8}%/%c$<>\ED%p1%{7}%/%c$<>\013\r\t%;,
+
+# binel=
+ u5=\n\r\t,
+ binel=\n\r\t,
+
+# bicr=
+ u3=\r\t,
+ bicr=\r\t,
+
+ use=Gibmg+low,
+
+#
+# Graphics capabilities (low resolution, 9-pin, 1:1 aspect ratio):
+#
+Gibmc+low+1x1,
+
+ spinh#84,
+
+# defbi=
+# Set 1:1 aspect ratio.
+# Set the line spacing to 7/72 inch (10.29 lines per inch)
+# to get approximately 84 dots per inch vertically
+# (10.29 lines/inch * 8 pins/line equals 82.28 dots per inch).
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 84 dots per inch horizontally this means 8.4
+# dots per character.
+# Set vertical and horizontal tab stops at the upper left corner
+# of the image, then tab to the upper left corner.
+# Note: $<> is a true null (only works with special Curses routine).
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\En^A\E1^R\EB%p2%{8}%/%c$<>\ED%p1%{10}%*%{84}%/%c$<>\013\r\t%;,
+ defbi=%?%p5%{1}%=%t\En^A\E1^R\EB%p2%{8}%/%c$<>\ED%p1%{10}%*%{84}%/%c$<>\013\r\t%;,
+
+ use=Gibmc+low+5x6,
+
+#
+# Color capability:
+#
+Gibmc+color,
+
+ colors#3,
+
+# setcolor=
+ initc=%?%p1%{0}%=%t\Eb%;%?%p1%{1}%=%t\Ec%;%?%p1%{2}%=%t\Em%;%?%p1%{3}%=%t\Ey%;,
+
+# colornm=
+ u8=%?%p1%{0}%=%tblack%;%?%p1%{1}%=%tcyan%;%?%p1%{2}%=%tmagenta%;%?%p1%{3}%=%tyellow%;%?%p1%{4}%=%torange=yellow+magenta%;%?%p1%{5}%=%tgreen=yellow+cyan%;%?%p1%{6}%=%tviolet=magenta+cyan%;%?%p1%{7}%=%tbrown=magenta+black%;,
+ colornm=%?%p1%{0}%=%tblack%;%?%p1%{1}%=%tcyan%;%?%p1%{2}%=%tmagenta%;%?%p1%{3}%=%tyellow%;%?%p1%{4}%=%torange=yellow+magenta%;%?%p1%{5}%=%tgreen=yellow+cyan%;%?%p1%{6}%=%tviolet=magenta+cyan%;%?%p1%{7}%=%tbrown=magenta+black%;,
+
+###################################
+#
+# IBM Proprinter XL:
+#
+# This printer appears to be a superset of the IBM Graphics
+# and IBM Color printers, with a 24-wire printhead. The entry
+# below uses the full capabilities of the superset and printhead.
+# The printer has an Alternate Graphics Mode (AGM) that changes
+# the vertical resolution from 1/216" to 1/180", and the graphics
+# aspect ratio from 5:6 to 1:1. HOWEVER, there does not appear to
+# be a control sequence that switches into this mode--it must be
+# done by hand!
+#
+
+#
+# Basic capabilities (printer not in AGM):
+#
+Gibmxl+basic,
+
+ orc#12,
+ orhi#120,
+ orl#36,
+ orvi#216,
+
+ cub1=\b,
+
+ cpi=%?%p1%{10}%=%t^R%e%p1%{12}%=%t\E:%e%p1%{17}%=%t^O%;,
+ cvr=%?%p1%{0}%>%p1%{256}%<%&%t\E3%p1%c%;,
+
+ is1=^Q^X,
+ is2=^R\EP0\EA\014\E2\EC\102\EO\ER\Eb\E50\EF\EH\EW0\ET\E-0\E_0\E7,
+ is3=\EX\001\120,
+
+ smglp=\EX%p1%{1}%+%c%p2%{1}%+%c,
+
+ use=Gibmg+basic,
+
+#
+# Basic capabilities (printer in AGM):
+#
+Gibmxlagm+basic,
+
+ orl#30,
+ orvi#180,
+
+ is2=^R\EP0\EA\012\E2\EC\102\EO\ER\Eb\E50\EF\EH\EW0\ET\E-0\E_0\E7,
+
+ use=Gibmxl+basic,
+
+#
+# Graphics capabilities (low resolution, 8-pin, 5:6 aspect ratio):
+#
+Gibmxl+low+5x6,
+
+ spinv#72,
+ spinh#60,
+
+# defbi=
+# Set the line spacing to 8/72 inch (9 lines per inch)
+# to get 72 dots per inch vertically (9 lines/" * 8 pins/line).
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 60 dots per inch horizontally this means 6
+# dots per character.
+# Set vertical and horizontal tab stops at the upper left corner
+# of the image, then tab to the upper left corner.
+# Note: $<> is a true null (only works with special Curses routine).
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\EA\010\E2^R\EB%p2%{8}%/%c$<>\ED%p1%{6}%/%c$<>\013\r\t%;,
+ defbi=%?%p5%{1}%=%t\EA\010\E2^R\EB%p2%{8}%/%c$<>\ED%p1%{6}%/%c$<>\013\r\t%;,
+
+ use=Gibmc+low+5x6,
+
+#
+# Graphics capabilities (low resolution, 8-pin, 1:1 aspect ratio):
+#
+Gibmxl+low+1x1,
+
+ spinv#60,
+
+# In AGM the "defbi" cap from Gibmxl+low+5x6 will work. The
+# line spacing will be 8/60 inch to get 60 dots per inch, using
+# the same control sequence.
+
+ use=Gibmxl+low+5x6,
+
+#
+# Graphics capabilities (high resolution, 24-pin, 5:6 aspect ratio):
+#
+# This doesn't work as the pin spacing doesn't get set to
+# 1/216 inch, but stays at 1/180 inch, even out of AGM.
+#
+
+#
+# Graphics capabilities (high resolution, 24-pin, 1:1 aspect ratio):
+#
+Gibmxl+high+1x1,
+
+ npins#24,
+ spinv#180,
+ spinh#180,
+
+ porder=1\,2\,3\,4\,5\,6\,7\,8\,9\,10\,11\,12\,13\,14\,15\,16\,17\,18\,19\,20\,21\,22\,23\,24;0,
+
+ sbim=\E*\047%p1%{256}%m%c%p1%{256}%/%c,
+
+# defbi=
+# Set the line spacing to 8/60 inch (7.5 lines per inch)
+# to get 180 dots per inch vertically (7.5 lines/" * 24 pins/line).
+# This requires the printer or emulation in Alternate Graphics Mode.
+# Set the character spacing to pica (1/10 inch or 10 characters
+# per inch); at 180 dots per inch horizontally this means 18
+# dots per character.
+# Set vertical and horizontal tab stops at the upper left corner
+# of the image, then tab to the upper left corner.
+# Note: $<> is a true null (only works with special Curses routine).
+# THIS ASSUMES WE START AT THE TOP OF THE PAGE! (although
+# maybe not in the first column.)
+ u6=%?%p5%{1}%=%t\EA\010\E2^R\EB%p2%{24}%/%c$<>\ED%p1%{18}%/%c$<>\013\r\t%;,
+ defbi=%?%p5%{1}%=%t\EA\010\E2^R\EB%p2%{24}%/%c$<>\ED%p1%{18}%/%c$<>\013\r\t%;,
+
+ use=Gibmc+low+5x6,
+
diff --git a/usr/src/cmd/lp/terminfo/unknown.ti b/usr/src/cmd/lp/terminfo/unknown.ti
new file mode 100644
index 0000000000..85f95a606e
--- /dev/null
+++ b/usr/src/cmd/lp/terminfo/unknown.ti
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
+# All Rights Reserved
+
+
+#ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */
+unknown,
+ am, gn,
+ cols#80,
+ bel=^G, cr=\r, cud1=\n, ind=\n,
diff --git a/usr/src/cmd/print/Makefile b/usr/src/cmd/print/Makefile
new file mode 100644
index 0000000000..c22b11279c
--- /dev/null
+++ b/usr/src/cmd/print/Makefile
@@ -0,0 +1,106 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/print/Makefile
+#
+
+include ../Makefile.cmd
+
+JAVA_SUBDIRS = printmgr
+
+PRINT_SUBDIRS = \
+ scripts \
+ lpget \
+ lpset \
+ conv_fix \
+ printer-info \
+ ppdmgr \
+ selector \
+ bsd-sysv-commands
+
+SUBDIRS = $(PRINT_SUBDIRS) $(JAVA_SUBDIRS)
+
+ROOTDIRS = $(ROOTLIB)/print
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+strip := TARGET= strip
+_msg := TARGET = _msg
+
+# For testing message catalogs
+_msg_test:= TARGET = _msg_test
+
+POFILE= print.po
+
+.KEEP_STATE:
+
+all install: $(ROOTDIRS) $(SUBDIRS)
+
+#
+# We define our own definition for _msg here because most of these
+# commands have the same PROG names as their counterparts in
+# cmd/lp. Using the _msg rule defined in Makefile.cmd would
+# result in clobbering the cmd/lp message files.
+# To get around this we will define one message file "print.po"
+# for these commands (except java printmgr). To build
+# this file we find all of the .c files and run xgettext on them.
+# Then concatenate this with the scripts.po file.
+#
+_msg: $(MSGDOMAIN) scripts $(JAVA_SUBDIRS)
+ @$(RM) $(POFILE)
+ $(XGETTEXT) -s `/bin/find . -type d -name SCCS -prune -o -type f -name '*.c' -print`
+ @/bin/cat messages.po scripts/scripts.po | sed '/domain/d' > $(POFILE)
+ @$(RM) messages.po
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ /bin/cp $(POFILE) $(MSGDOMAIN)
+
+#
+# Create a message file to test with.
+#
+_msg_test: scripts
+ @$(RM) $(POFILE)
+ $(XGETTEXT) -s -m "xxx" `/bin/find . -print | grep '\.c$$' | sed '/SCCS/d'`
+ @/bin/cat messages.po scripts/scripts.po | sed '/domain/d' > $(POFILE)
+ echo 'domain "SUNW_OST_OSCMD"' > SUNW_OST_OSCMD.po
+ cat $(POFILE) >> SUNW_OST_OSCMD.po
+ msgfmt SUNW_OST_OSCMD.po
+ @$(RM) messages.po $(POFILE) SUNW_OST_OSCMD.po
+
+clean strip cstyle lint: $(SUBDIRS)
+
+clobber: $(SUBDIRS)
+ $(RM) $(POFILE) $(CLOBBERFILES)
+
+$(ROOTDIRS) $(MSGDOMAIN):
+ $(INS.dir)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/print/Makefile.sp b/usr/src/cmd/print/Makefile.sp
new file mode 100644
index 0000000000..ebf97b53c6
--- /dev/null
+++ b/usr/src/cmd/print/Makefile.sp
@@ -0,0 +1,105 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/print/Makefile.sp
+# Common makefile definitions (should be) used by all print(lp) makefiles
+#
+
+include $(SRC)/cmd/Makefile.cmd
+
+LPROOT= $(SRC)/cmd/lp
+NPRTROOT= $(LPROOT)
+ROOTVAR= $(ROOT)/var
+ROOTVARSP= $(ROOT)/var/spool
+ROOTVARSPOOLPRINT= $(ROOTVARSP)/print
+
+ROOTINIT_D= $(ROOTETC)/init.d
+ROOTRC0_D= $(ROOTETC)/rc0.d
+ROOTRCS_D= $(ROOTETC)/rcS.d
+ROOTRC1_D= $(ROOTETC)/rc1.d
+ROOTRC2_D= $(ROOTETC)/rc2.d
+
+
+ROOTETCLP= $(ROOTETC)/lp
+ROOTLIBLP= $(ROOTLIB)/lp
+ROOTBINLP= $(ROOTBIN)/lp
+ROOTLIBLPPOST = $(ROOTLIBLP)/postscript
+ROOTLOCALLP= $(ROOTLIBLP)/local
+ROOTLIBPRINT= $(ROOTLIB)/print
+ROOTLIBPRINTBIN= $(ROOTLIBPRINT)/bin
+
+ROOTUSRUCB= $(ROOT)/usr/ucb
+
+
+#
+# $(EMODES): Modes for executables
+# $(SMODES): Modes for setuid executables
+# $(DMODES): Modes for directories
+#
+EMODES = 0555
+SMODES = 04555
+DMODES = 0755
+
+
+INC = $(ROOT)/usr/include
+INCSYS = $(INC)/sys
+
+LPINC = $(SRC)/include
+#NPRTINC = $(NPRTROOT)/include
+NPRTINC = $(SRC)/lib/print/libprint/common
+LPLIB = $(SRC)/lib
+LDLIBS += -L$(LPLIB)
+
+
+LIBNPRT = -L$(ROOT)/usr/lib -lprint
+
+# lint definitions
+
+LINTFLAGS += -L $(SRC)/lib/print -lprint -lnsl -lsocket
+
+all :=TARGET= all
+install :=TARGET= install
+clean :=TARGET= clean
+clobber :=TARGET= clobber
+lint :=TARGET= lint
+strip :=TARGET= strip
+_msg :=TARGET= _msg
+
+ROOTLIBLPPROG= $(PROG:%=$(ROOTLIBLP)/%)
+ROOTBINLPPROG= $(PROG:%=$(ROOTBINLP)/%)
+ROOTETCLPPROG= $(PROG:%=$(ROOTETCLP)/%)
+ROOTUSRUCBPROG= $(PROG:%=$(ROOTUSRUCB)/%)
+ROOTLOCALLPPROG= $(PROG:%=$(ROOTLOCALLP)/%)
+ROOTLIBLPPOSTPROG= $(PROG:%=$(ROOTLIBLPPOST)/%)
+ROOTLIBPRINTPROG= $(PROG:%=$(ROOTLIBPRINT)/%)
+
+$(ROOTLIBLP)/% \
+$(ROOTBINLP)/% \
+$(ROOTETCLP)/% \
+$(ROOTUSRUCB)/% \
+$(ROOTLOCALLP)/% \
+$(ROOTLIBLPPOST)/% \
+$(ROOTLIBPRINT)/% : %
+ $(INS.file)
diff --git a/usr/src/cmd/print/bsd-sysv-commands/Makefile b/usr/src/cmd/print/bsd-sysv-commands/Makefile
new file mode 100644
index 0000000000..ee6131c805
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/Makefile
@@ -0,0 +1,110 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.sp
+
+UCBPROGS = lpr lpq lprm lpc
+BINPROGS = lp lpstat cancel enable disable $(UCBPROGS)
+SBINPROGS = accept reject lpmove
+
+LIBPRINTPROGS = in.lpd
+
+LIBLPPROGS = $(BINPROGS) $(SBINPROGS)
+
+
+OBJS = $(BINPROGS:=.o) $(SBINPROGS:=.o) $(LIBPRINTPROGS:=.o) common.o
+
+ROOTLIBLPBIN=$(ROOTLIBLP)/bin
+
+ROOTBINPROGS = $(BINPROGS:%=$(ROOTBIN)/%)
+ROOTUSRSBINPROGS = $(SBINPROGS:%=$(ROOTUSRSBIN)/%)
+ROOTLIBPRINTPROGS = $(LIBPRINTPROGS:%=$(ROOTLIBPRINT)/%)
+ROOTLIBLPPROGS = $(LIBLPPROGS:%=$(ROOTLIBLPBIN)/%)
+
+
+FILEMODE = 0555
+
+include ../../Makefile.cmd
+
+MANIFEST= rfc1179.xml
+ROOTMANIFESTDIR= $(ROOTSVCAPPLICATIONPRINT)
+$(ROOTMANIFEST) := FILEMODE= 444
+
+LPLIB = $(SRC)/cmd/lp/lib
+LIBLP = $(LPLIB)/lp/liblp.a
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I.
+CPPFLAGS += -I../../../lib/print/libpapi-common/common
+CPPFLAGS += -I$(ROOT)/usr/include
+CPPFLAGS += -I../../lp/include
+LDLIBS += $(LIBLP) -lpapi -lc
+in.lpd:= CFLAGS += -DSOLARIS_PRIVATE_POST_0_9
+in.lpd:= LDLIBS += -lnsl -lsocket
+
+CERRWARN += -_gcc=-Wno-unused-variable
+CERRWARN += -_gcc=-Wno-uninitialized
+
+all: $(BINPROGS) $(SBINPROGS)
+
+# each program needs common.o as well
+$(BINPROGS) $(SBINPROGS) $(LIBPRINTPROGS): $(BINPROGS:%=%.c) $(SBINPROGS:%=%.c) $(LIBPRINTPROGS:%=%.c) common.o
+ $(LINK.c) -o $@ $@.c common.o $(LDLIBS)
+ $(POST_PROCESS)
+
+# ucb links (lptest is handled in usr/src/cmd/lp/cmd/Makefile)
+ROOTUSRUCB = $(ROOT)/usr/ucb
+ROOTUCBSYMLINKS = $(UCBPROGS:%=$(ROOTUSRUCB)/%)
+$(ROOTUSRUCB)/%: $(ROOTUSRUCB) %
+
+$(ROOTLIBLPBIN)/%: %
+ $(INS.file)
+
+$(ROOTUCBSYMLINKS):
+ $(RM) $@; $(SYMLINK) ../bin/$(@F) $@
+
+# usr/lib links
+ROOTUSRLIBSYMLINKS = $(SBINPROGS:%=$(ROOTLIB)/%)
+$(ROOTLIB)/%: $(ROOTLIB) %
+
+$(ROOTUSRLIBSYMLINKS):
+ $(RM) $@; $(SYMLINK) ../sbin/$(@F) $@
+
+.KEEP_STATE:
+
+install: $(ROOTLIBLPPROGS) \
+ $(ROOTLIBPRINT) $(ROOTLIBPRINTPROGS) $(ROOTMANIFEST) \
+ $(ROOTUCBSYMLINKS) $(ROOTUSRLIBSYMLINKS)
+
+check: $(CHKMANIFEST)
+
+clean:
+ $(RM) $(OBJS)
+
+CLOBBERFILES += $(BINPROGS) $(SBINPROGS) $(LIBPRINTPROGS)
+
+lint:
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/print/bsd-sysv-commands/accept.c b/usr/src/cmd/print/bsd-sysv-commands/accept.c
new file mode 100644
index 0000000000..74f392c9c3
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/accept.c
@@ -0,0 +1,117 @@
+
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: accept.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout,
+ gettext("Usage: %s destination ...\n"),
+ name);
+ exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ int exit_status = 0;
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av, "E")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_ALWAYS;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if (ac == optind)
+ usage(av[0]);
+
+ for (c = optind; c < ac; c++) {
+ char *printer = av[c];
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ exit_status = 1;
+ }
+
+ status = papiPrinterResume(svc, printer);
+ if (status == PAPI_OK) {
+ printf(gettext(
+ "Destination \"%s\" now accepting requests\n"),
+ printer);
+ } else if (status == PAPI_NOT_ACCEPTING) {
+ fprintf(stderr, gettext(
+ "Destination \"%s\" was already "
+ "accepting requests.\n"), printer);
+ exit_status = 1;
+ } else {
+ if (status == PAPI_OPERATION_NOT_SUPPORTED) {
+ fprintf(stderr,
+ verbose_papi_message(svc, status));
+ } else {
+ fprintf(stderr, gettext("accept: %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ exit_status = 1;
+ }
+ }
+
+ papiServiceDestroy(svc);
+ }
+
+ return (exit_status);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/cancel.c b/usr/src/cmd/print/bsd-sysv-commands/cancel.c
new file mode 100644
index 0000000000..23359d9b5e
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/cancel.c
@@ -0,0 +1,255 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+/* $Id: cancel.c 147 2006-04-25 16:51:06Z njacobs $ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout, "Usage: %s [-u user] (printer|request-id ...)\n", name);
+ exit(1);
+}
+
+static int32_t
+get_job_id_requested(papi_job_t job) {
+ int32_t rid = -1;
+
+ papi_attribute_t **list = papiJobGetAttributeList(job);
+ papiAttributeListGetInteger(list, NULL,
+ "job-id-requested", &rid);
+
+ return (rid);
+}
+
+int
+cancel_jobs_for_user(char *user, papi_encryption_t encryption, char *pname) {
+
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ char **printers = NULL;
+ int i, exit_code;
+
+ if (pname == NULL) {
+ status = papiServiceCreate(&svc, NULL, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ printers = interest_list(svc);
+ papiServiceDestroy(svc);
+ } else {
+ list_append(&printers, strdup(pname));
+ }
+
+ if (printers == NULL)
+ exit(0);
+
+ for (i = 0; printers[i] != NULL; i++) {
+ char *printer = printers[i];
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ exit(1);
+ }
+ exit_code = berkeley_cancel_request(svc, stdout, printer, 1,
+ &user);
+
+ papiServiceDestroy(svc);
+ if (exit_code != 0)
+ break;
+ }
+ free(printers);
+ return (exit_code);
+}
+
+int
+main(int ac, char *av[])
+{
+ int exit_code = 0;
+ char *user = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ int c;
+ int32_t rid = -1;
+ int first_dest = 0;
+
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ if (ac == 1)
+ usage(av[0]);
+
+ while ((c = getopt(ac, av, "Eu:")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_REQUIRED;
+ break;
+ case 'u':
+ user = optarg;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ for (c = optind; c < ac; c++) {
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_job_t *jobs = NULL;
+ char *printer = NULL;
+ int32_t id = -1;
+
+ status = papiServiceCreate(&svc, av[c], NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ if (status != PAPI_OK) {
+ if (first_dest == 0) {
+ (void) get_printer_id(av[c], &printer, &id);
+ status = papiServiceCreate(&svc, printer, NULL,
+ NULL, cli_auth_callback, encryption, NULL);
+ }
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer,
+ verbose_papi_message(svc, status));
+ exit(1);
+ }
+ } else {
+ first_dest = 1;
+ printer = av[c];
+ }
+
+#define OUT ((status == PAPI_OK) ? stdout : stderr)
+
+ if (id != -1) { /* it's a job */
+ char *mesg = gettext("cancelled");
+
+ /*
+ * Check if the job-id is job-id-requested
+ * or job-id. If it is job-id-requested then find
+ * corresponding job-id and send it to cancel
+ */
+ rid = job_to_be_queried(svc, printer, id);
+ if (rid < 0) {
+ /*
+ * Either it is a remote job which cannot be
+ * cancelled based on job-id or job-id is
+ * not found
+ */
+ exit_code = 1;
+ fprintf(OUT, "%s-%d: %s\n",
+ printer, id, gettext("not-found"));
+ } else {
+ status = papiJobCancel(svc, printer, rid);
+ if (status == PAPI_NOT_AUTHORIZED) {
+ mesg = papiStatusString(status);
+ exit_code = 1;
+ } else if (status != PAPI_OK) {
+ mesg = gettext(
+ verbose_papi_message(
+ svc, status));
+ exit_code = 1;
+ }
+ fprintf(OUT, "%s-%d: %s\n", printer, id, mesg);
+ }
+
+ } else { /* it's a printer */
+ if (user == NULL) {
+
+ /* Remove first job from printer */
+
+ status = papiPrinterListJobs(svc, printer,
+ NULL, NULL, 0, &jobs);
+
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "ListJobs %s: %s\n"), printer,
+ verbose_papi_message(svc, status));
+ exit_code = 1;
+ }
+
+ if (jobs != NULL && *jobs != NULL) {
+ char *mesg = gettext("cancelled");
+ id = papiJobGetId(*jobs);
+
+ status = papiJobCancel(svc,
+ printer, id);
+
+ if (status == PAPI_NOT_AUTHORIZED) {
+ mesg = papiStatusString(status);
+ exit_code = 1;
+ } else if (status != PAPI_OK) {
+ mesg = gettext(
+ verbose_papi_message(
+ svc, status));
+ exit_code = 1;
+ }
+ /*
+ * If job-id-requested exists for this
+ * job-id then that should be displayed
+ */
+ rid = get_job_id_requested(*jobs);
+ if (rid >= 0)
+ fprintf(OUT, "%s-%d: %s\n",
+ printer, rid, mesg);
+ else
+ fprintf(OUT, "%s-%d: %s\n",
+ printer, id, mesg);
+ }
+ papiJobListFree(jobs);
+
+ } else {
+ /* Purging user's print jobs */
+ exit_code = cancel_jobs_for_user(user,
+ encryption, printer);
+ }
+ }
+ papiServiceDestroy(svc);
+ }
+
+ if (optind == ac)
+ exit_code = cancel_jobs_for_user(user, encryption, NULL);
+
+ return (exit_code);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/common.c b/usr/src/cmd/print/bsd-sysv-commands/common.c
new file mode 100644
index 0000000000..5df4e3b9b7
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/common.c
@@ -0,0 +1,678 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: common.c 162 2006-05-08 14:17:44Z njacobs $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <alloca.h>
+#include <string.h>
+#include <libintl.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <papi.h>
+#include "common.h"
+
+#ifndef HAVE_GETPASSPHRASE /* some systems don't have getpassphrase() */
+#define getpassphrase getpass
+#endif
+
+/* give the most verbose error message to the caller */
+char *
+verbose_papi_message(papi_service_t svc, papi_status_t status)
+{
+ char *mesg;
+
+ mesg = papiServiceGetStatusMessage(svc);
+
+ if (mesg == NULL)
+ mesg = papiStatusString(status);
+
+ return (mesg);
+}
+
+static int
+match_job(int id, char *user, int ac, char *av[])
+{
+ int i;
+
+ for (i = 0; i < ac; i++)
+ if (strcmp("-", av[i]) == 0)
+ return (0); /* "current" user match */
+ else if ((isdigit(av[i][0]) != 0) && (id == atoi(av[i])))
+ return (0); /* job-id match */
+ else if (strcmp(user, av[i]) == 0)
+ return (0); /* user match */
+
+ return (-1);
+}
+
+/*
+ * return 0 : argument passed is job-id && job-id matches
+ * or argument passed is user
+ */
+static int
+match_job_rid(int id, int ac, char *av[])
+{
+ int i;
+
+ for (i = 0; i < ac; i++)
+ if (isdigit(av[i][0]) != 0) {
+ if (id == atoi(av[i]))
+ /* job-id match */
+ return (0);
+ } else
+ /* argument passed is user */
+ return (0);
+ return (-1);
+}
+
+static struct {
+ char *mime_type;
+ char *lp_type;
+} type_map[] = {
+ { "text/plain", "simple" },
+ { "application/octet-stream", "raw" },
+ { "application/octet-stream", "any" },
+ { "application/postscript", "postscript" },
+ { "application/postscript", "ps" },
+ { "application/x-cif", "cif" },
+ { "application/x-dvi", "dvi" },
+ { "application/x-plot", "plot" },
+ { "application/x-ditroff", "troff" },
+ { "application/x-troff", "otroff" },
+ { "application/x-pr", "pr" },
+ { "application/x-fortran", "fortran" },
+ { "application/x-raster", "raster" },
+ { NULL, NULL}
+};
+
+char *
+lp_type_to_mime_type(char *lp_type)
+{
+ int i;
+
+ if (lp_type == NULL)
+ return ("application/octet-stream");
+
+ for (i = 0; type_map[i].lp_type != NULL; i++)
+ if (strcasecmp(type_map[i].lp_type, lp_type) == 0)
+ return (type_map[i].mime_type);
+
+ return (lp_type);
+}
+
+/*
+ * to support job/printer status
+ */
+static char *
+state_string(int state)
+{
+ switch (state) {
+ case 3:
+ return (gettext("idle"));
+ case 4:
+ return (gettext("processing"));
+ case 5:
+ return (gettext("stopped"));
+ default:
+ return (gettext("unknown"));
+ }
+}
+
+static char *_rank_suffixes[] = {
+ "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
+};
+
+static char *
+rank_string(const int rank)
+{
+ static char buf[12];
+
+ if (rank < 0)
+ snprintf(buf, sizeof (buf), gettext("invalid"));
+ else if (rank == 0)
+ snprintf(buf, sizeof (buf), gettext("active"));
+ else if ((rank > 10) && (rank < 14))
+ sprintf(buf, "%dth", rank);
+ else
+ sprintf(buf, "%d%s", rank, _rank_suffixes[rank % 10]);
+
+ return (buf);
+}
+
+static void
+printer_state_line(FILE *fp, papi_printer_t p, int num_jobs, char *name)
+{
+ papi_attribute_t **list = papiPrinterGetAttributeList(p);
+ int state = 0;
+ char *reason = "";
+
+ (void) papiAttributeListGetInteger(list, NULL,
+ "printer-state", &state);
+ (void) papiAttributeListGetString(list, NULL,
+ "printer-state-reasons", &reason);
+ (void) papiAttributeListGetString(list, NULL,
+ "printer-name", &name);
+
+ if ((state != 0x03) || (num_jobs != 0)) {
+ fprintf(fp, "%s: %s", name, state_string(state));
+ if ((state == 0x05) ||
+ (state == 0x06) ||
+ (state == 0x07) ||
+ (state == 0x08)) /* stopped */
+ fprintf(fp, ": %s\n", reason);
+ else
+ fprintf(fp, "\n");
+ } else
+ fprintf(fp, "no entries\n");
+}
+
+static void
+print_header(FILE *fp)
+{
+ fprintf(fp, gettext("Rank\tOwner\t Job\tFile(s)\t\t\t\tTotal Size\n"));
+}
+
+static void
+print_job_line(FILE *fp, int count, papi_job_t job, int fmt, int ac, char *av[])
+{
+ papi_attribute_t **list = papiJobGetAttributeList(job);
+ int copies = 1, id = 0, rank = count, size = 0;
+ char *name = "print job";
+ char *user = "nobody";
+ char *host = "localhost";
+ char *suffix = "k";
+
+ (void) papiAttributeListGetInteger(list, NULL,
+ "job-id", &id);
+ (void) papiAttributeListGetInteger(list, NULL,
+ "job-id-requested", &id);
+ (void) papiAttributeListGetString(list, NULL,
+ "job-originating-user-name", &user);
+ (void) papiAttributeListGetString(list, NULL,
+ "job-originating-host-name", &host);
+
+ /* if we are looking and it doesn't match, return early */
+ if ((ac > 0) && (match_job(id, user, ac, av) < 0))
+ return;
+
+ (void) papiAttributeListGetInteger(list, NULL,
+ "copies", &copies);
+ (void) papiAttributeListGetInteger(list, NULL,
+ "number-of-intervening-jobs", &rank);
+
+ if (papiAttributeListGetInteger(list, NULL, "job-octets", &size)
+ == PAPI_OK)
+ suffix = "bytes";
+ else
+ (void) papiAttributeListGetInteger(list, NULL,
+ "job-k-octets", &size);
+ (void) papiAttributeListGetString(list, NULL,
+ "job-name", &name);
+
+ size *= copies;
+
+ if (fmt == 3) {
+ fprintf(fp, gettext("%s\t%-8.8s %d\t%-32.32s%d %s\n"),
+ rank_string(++rank), user, id, name, size, suffix);
+ } else
+ fprintf(fp, gettext(
+ "\n%s: %s\t\t\t\t[job %d %s]\n\t%-32.32s\t%d %s\n"),
+ user, rank_string(++rank), id, host, name, size,
+ suffix);
+}
+
+/*
+ * to support job cancelation
+ */
+static void
+cancel_job(papi_service_t svc, FILE *fp, char *printer, papi_job_t job,
+ int ac, char *av[])
+{
+ papi_status_t status;
+ papi_attribute_t **list = papiJobGetAttributeList(job);
+ int id = -1;
+ int rid = -1;
+ char *user = "";
+ char *mesg = gettext("cancelled");
+ int i = 0;
+
+ papiAttributeListGetInteger(list, NULL,
+ "job-id", &id);
+ papiAttributeListGetInteger(list, NULL,
+ "job-id-requested", &rid);
+ papiAttributeListGetString(list, NULL,
+ "job-originating-user-name", &user);
+
+ /* if we are looking and it doesn't match, return early */
+ if ((ac > 0) && (match_job(id, user, ac, av) < 0) &&
+ (match_job(rid, user, ac, av) < 0))
+ return;
+
+ /*
+ * A remote lpd job should be cancelled only based on
+ * job-id-requested
+ */
+ if (rid != -1) {
+ if (match_job_rid(rid, ac, av) == -1)
+ /* job-id mismatch */
+ return;
+ }
+
+ status = papiJobCancel(svc, printer, id);
+ if (status != PAPI_OK)
+ mesg = papiStatusString(status);
+
+ if (rid != -1)
+ fprintf(fp, "%s-%d: %s\n", printer, rid, mesg);
+ else
+ fprintf(fp, "%s-%d: %s\n", printer, id, mesg);
+}
+
+int
+berkeley_queue_report(papi_service_t svc, FILE *fp, char *dest, int fmt,
+ int ac, char *av[])
+{
+ papi_status_t status;
+ papi_printer_t p = NULL;
+ papi_job_t *jobs = NULL;
+ char *pattrs[] = { "printer-name", "printer-state",
+ "printer-state-reasons", NULL };
+ char *jattrs[] = { "job-name", "job-octets", "job-k-octets", "job-id",
+ "job-originating-user-name", "job-id-requested",
+ "job-originating-host-name",
+ "number-of-intervening-jobs", NULL };
+ int num_jobs = 0;
+
+ status = papiPrinterQuery(svc, dest, pattrs, NULL, &p);
+ if (status != PAPI_OK) {
+ fprintf(fp, gettext(
+ "Failed to query service for state of %s: %s\n"),
+ dest, verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ status = papiPrinterListJobs(svc, dest, jattrs, PAPI_LIST_JOBS_ALL,
+ 0, &jobs);
+ if (status != PAPI_OK) {
+ fprintf(fp, gettext(
+ "Failed to query service for jobs on %s: %s\n"),
+ dest, verbose_papi_message(svc, status));
+ return (-1);
+ }
+ if (jobs != NULL) {
+ while (jobs[num_jobs] != NULL)
+ num_jobs++;
+ }
+
+ printer_state_line(fp, p, num_jobs, dest);
+ if (num_jobs > 0) {
+ int i;
+
+ if (fmt == 3)
+ print_header(fp);
+ for (i = 0; jobs[i] != NULL; i++)
+ print_job_line(fp, i, jobs[i], fmt, ac, av);
+ }
+
+ papiPrinterFree(p);
+ papiJobListFree(jobs);
+
+ return (num_jobs);
+}
+
+int
+berkeley_cancel_request(papi_service_t svc, FILE *fp, char *dest,
+ int ac, char *av[])
+{
+ papi_status_t status;
+ papi_job_t *jobs = NULL;
+ char *jattrs[] = { "job-originating-user-name", "job-id",
+ "job-id-requested", NULL };
+
+ status = papiPrinterListJobs(svc, dest, jattrs, PAPI_LIST_JOBS_ALL,
+ 0, &jobs);
+
+ if (status != PAPI_OK) {
+ fprintf(fp, gettext("Failed to query service for %s: %s\n"),
+ dest, verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ /* cancel the job(s) */
+ if (jobs != NULL) {
+ int i;
+
+ for (i = 0; jobs[i] != NULL; i++)
+ cancel_job(svc, fp, dest, jobs[i], ac, av);
+ }
+
+ papiJobListFree(jobs);
+
+ return (0);
+}
+
+int
+get_printer_id(char *name, char **printer, int *id)
+{
+ int result = -1;
+
+ if (name != NULL) {
+ char *p = strrchr(name, '-');
+
+ *printer = name;
+ if (p != NULL) {
+ char *s = NULL;
+
+ *id = strtol(p + 1, &s, 10);
+ if (s[0] != '\0')
+ *id = -1;
+ else
+ *p = '\0';
+ result = 0;
+ } else
+ *id = -1;
+ }
+
+ return (result);
+}
+
+/*
+ * strsplit() splits a string into a NULL terminated array of substrings
+ * determined by a seperator. The original string is modified, and newly
+ * allocated space is only returned for the array itself. If more than
+ * 1024 substrings exist, they will be ignored.
+ */
+char **
+strsplit(char *string, const char *seperators)
+{
+ char *list[BUFSIZ],
+ **result;
+ int length = 0;
+
+ if ((string == NULL) || (seperators == NULL))
+ return (NULL);
+
+ (void) memset(list, 0, sizeof (list));
+ for (list[length] = strtok(string, seperators);
+ (list[length] != NULL) && (length < (BUFSIZ - 2));
+ list[length] = strtok(NULL, seperators))
+ length++;
+
+ if ((result = (char **)calloc(length+1, sizeof (char *))) != NULL)
+ (void) memcpy(result, list, length * sizeof (char *));
+
+ return (result);
+}
+
+papi_status_t
+jobSubmitSTDIN(papi_service_t svc, char *printer, char *prefetch, int len,
+ papi_attribute_t **list, papi_job_t *job)
+{
+ papi_status_t status;
+ papi_stream_t stream = NULL;
+ int rc;
+ char buf[BUFSIZ];
+
+ status = papiJobStreamOpen(svc, printer, list, NULL, &stream);
+
+ if (len > 0)
+ status = papiJobStreamWrite(svc, stream, prefetch, len);
+
+ while ((status == PAPI_OK) && ((rc = read(0, buf, sizeof (buf))) > 0))
+ status = papiJobStreamWrite(svc, stream, buf, rc);
+
+ if (status == PAPI_OK)
+ status = papiJobStreamClose(svc, stream, job);
+
+ return (status);
+}
+
+/*
+ * is_postscript() will detect if the file passed in contains postscript
+ * data. A one is returned if the file contains postscript, zero is returned
+ * if the file is not postscript, and -1 is returned if an error occurs
+ */
+#define PS_MAGIC "%!"
+#define PC_PS_MAGIC "^D%!"
+int
+is_postscript_stream(int fd, char *buf, int *len)
+{
+ if ((*len = read(fd, buf, *len)) < 0) {
+ close(fd);
+ return (-1);
+ }
+
+ if ((strncmp(buf, PS_MAGIC, sizeof (PS_MAGIC) - 1) == 0) ||
+ (strncmp(buf, PC_PS_MAGIC, sizeof (PC_PS_MAGIC) - 1) == 0))
+ return (1);
+ else
+ return (0);
+}
+
+int
+is_postscript(const char *file)
+{
+ int rc = -1;
+ int fd;
+
+ if ((fd = open(file, O_RDONLY)) >= 0) {
+ char buf[3];
+ int len = sizeof (buf);
+
+ rc = is_postscript_stream(fd, buf, &len);
+ close(fd);
+ }
+
+ return (rc);
+}
+
+static char **
+all_list(papi_service_t svc)
+{
+ papi_status_t status;
+ papi_printer_t printer = NULL;
+ char *list[] = { "member-names", NULL };
+ char **result = NULL;
+
+ status = papiPrinterQuery(svc, "_all", list, NULL, &printer);
+ if ((status == PAPI_OK) && (printer != NULL)) {
+ papi_attribute_t **attributes =
+ papiPrinterGetAttributeList(printer);
+ if (attributes != NULL) {
+ void *iter = NULL;
+ char *value = NULL;
+
+ for (status = papiAttributeListGetString(attributes,
+ &iter, "member-names", &value);
+ status == PAPI_OK;
+ status = papiAttributeListGetString(attributes,
+ &iter, NULL, &value))
+ list_append(&result, strdup(value));
+ }
+ papiPrinterFree(printer);
+ }
+
+ return (result);
+}
+
+static char **
+printers_list(papi_service_t svc)
+{
+ papi_status_t status;
+ papi_printer_t *printers = NULL;
+ char *keys[] = { "printer-name", NULL };
+ char **result = NULL;
+
+ status = papiPrintersList(svc, keys, NULL, &printers);
+ if ((status == PAPI_OK) && (printers != NULL)) {
+ int i;
+
+ for (i = 0; printers[i] != NULL; i++) {
+ papi_attribute_t **attributes =
+ papiPrinterGetAttributeList(printers[i]);
+ char *name = NULL;
+
+ (void) papiAttributeListGetString(attributes, NULL,
+ "printer-name", &name);
+ if ((name != NULL) && (strcmp(name, "_default") != 0))
+ list_append(&result, strdup(name));
+ }
+ papiPrinterListFree(printers);
+ }
+
+ return (result);
+}
+
+char **
+interest_list(papi_service_t svc)
+{
+ static char been_here;
+ static char **result;
+
+ if (been_here == 0) { /* only do this once */
+ been_here = 1;
+
+ if ((result = all_list(svc)) == NULL)
+ result = printers_list(svc);
+ }
+
+ return (result);
+}
+
+char *
+localhostname()
+{
+ static char *result;
+
+ if (result == NULL) {
+ static char buf[256];
+
+ if (gethostname(buf, sizeof (buf)) == 0)
+ result = buf;
+ }
+
+ return (result);
+}
+
+int
+cli_auth_callback(papi_service_t svc, void *app_data)
+{
+ char prompt[BUFSIZ];
+ char *user, *svc_name, *passphrase;
+
+ /* get the name of the service we are contacting */
+ if ((svc_name = papiServiceGetServiceName(svc)) == NULL)
+ return (-1);
+
+ /* find our who we are supposed to be */
+ if ((user = papiServiceGetUserName(svc)) == NULL) {
+ struct passwd *pw;
+
+ if ((pw = getpwuid(getuid())) != NULL)
+ user = pw->pw_name;
+ else
+ user = "nobody";
+ }
+
+ /* build the prompt string */
+ snprintf(prompt, sizeof (prompt),
+ gettext("passphrase for %s to access %s: "), user, svc_name);
+
+ /* ask for the passphrase */
+ if ((passphrase = getpassphrase(prompt)) != NULL)
+ papiServiceSetPassword(svc, passphrase);
+
+ return (0);
+}
+
+int32_t
+job_to_be_queried(papi_service_t svc, char *printer, int32_t id)
+{
+ papi_job_t *jobs = NULL;
+ papi_status_t status;
+ int ret = -1;
+ char *jattrs[] = { "job-id",
+ "job-id-requested", NULL };
+
+ status = papiPrinterListJobs(svc, printer, jattrs, PAPI_LIST_JOBS_ALL,
+ 0, &jobs);
+
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("Failed to query service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ if (jobs != NULL) {
+ int i = 0;
+
+ for (i = 0; jobs[i] != NULL; i++) {
+ int32_t rid = -1;
+ int32_t jid = -1;
+ papi_attribute_t **list =
+ papiJobGetAttributeList(jobs[i]);
+
+ papiAttributeListGetInteger(list, NULL,
+ "job-id-requested", &rid);
+ papiAttributeListGetInteger(list, NULL,
+ "job-id", &jid);
+
+ /*
+ * check if id matches with either rid or jid
+ */
+ if (rid == id) {
+ /* get the actual id and return it */
+ papiAttributeListGetInteger(list, NULL,
+ "job-id", &id);
+ return (id);
+ } else if (id == jid) {
+ if (rid != -1) {
+ /*
+ * It is a remote lpd job
+ * can be cancelled only
+ * using rid
+ */
+ ret = -1;
+ } else {
+ /*
+ * its local or
+ * remote ipp job
+ */
+ return (id);
+ }
+ }
+ }
+ return (ret);
+ }
+ return (id);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/common.h b/usr/src/cmd/print/bsd-sysv-commands/common.h
new file mode 100644
index 0000000000..a729930bd5
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/common.h
@@ -0,0 +1,70 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _BSD_SYSV_COMMON_H
+#define _BSD_SYSV_COMMON_H
+
+/* $Id: common.h 162 2006-05-08 14:17:44Z njacobs $ */
+
+#include <papi.h>
+
+#include <config-site.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char **strsplit(char *string, const char *seperators);
+extern char *verbose_papi_message(papi_service_t svc, papi_status_t status);
+
+extern int berkeley_cancel_request(papi_service_t svc, FILE *fp, char *dest,
+ int ac, char *av[]);
+
+extern int get_printer_id(char *name, char **printer, int *id);
+
+extern int berkeley_queue_report(papi_service_t svc, FILE *fp, char *dest,
+ int fmt, int ac, char *av[]);
+
+extern papi_status_t jobSubmitSTDIN(papi_service_t svc, char *printer,
+ char *prefetch, int len,
+ papi_attribute_t **list, papi_job_t *job);
+
+extern char **interest_list(papi_service_t svc);
+extern char *localhostname();
+extern char *lp_type_to_mime_type(char *lp_type);
+extern int is_postscript(const char *file);
+extern int is_postscript_stream(int fd, char *buf, int *len);
+
+extern int cli_auth_callback(papi_service_t svc, void *app_data);
+
+extern int32_t job_to_be_queried(papi_service_t svc, char *printer, int32_t id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BSD_SYSV_COMMON_H */
diff --git a/usr/src/cmd/print/bsd-sysv-commands/disable.c b/usr/src/cmd/print/bsd-sysv-commands/disable.c
new file mode 100644
index 0000000000..0b3cb71f0c
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/disable.c
@@ -0,0 +1,163 @@
+
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: disable.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout,
+ gettext("Usage: %s [-c] [-W] [-r reason] destination ...\n"),
+ name);
+ exit(1);
+}
+
+static void
+cancel_active_job(papi_service_t svc, char *dest)
+{
+ papi_status_t status;
+ papi_job_t *j = NULL;
+ char *req_attrs[] = { "job-state", "job-id", NULL };
+
+ status = papiPrinterListJobs(svc, dest, req_attrs, 0, 0, &j);
+ if ((status == PAPI_OK) && (j != NULL)) {
+ int i;
+
+ for (i = 0; j[i] != NULL; j++) {
+ papi_attribute_t **a = papiJobGetAttributeList(j[i]);
+ int state = 0;
+
+ if (a == NULL)
+ continue;
+
+ (void) papiAttributeListGetInteger(a, NULL,
+ "job-state", &state);
+ if (state & 0x082A) { /* If state is RS_ACTIVE */
+ int32_t id = papiJobGetId(j[i]);
+
+ (void) papiJobCancel(svc, dest, id);
+ }
+ }
+ papiJobListFree(j);
+ }
+}
+
+int
+main(int ac, char *av[])
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ int exit_status = 0;
+ int cancel = 0;
+ int pending = 0; /* not implemented */
+ char *reason = NULL;
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av, "EcWr:")) != EOF)
+ switch (c) {
+ case 'c': /* cancel active job first */
+ cancel = 1;
+ break;
+ case 'W': /* wait for active request, not implemented */
+ pending = 1;
+ break;
+ case 'r': /* reason */
+ reason = optarg;
+ break;
+ case 'E':
+ encryption = PAPI_ENCRYPT_NEVER;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if (ac <= optind)
+ usage(av[0]);
+
+ while (optind < ac) {
+ char *printer = av[optind++];
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ exit_status = 1;
+ }
+
+ status = papiPrinterDisable(svc, printer, reason);
+ if (status == PAPI_OK) {
+ printf(gettext("printer \"%s\" now disabled\n"),
+ printer);
+ } else if (status == PAPI_NOT_ACCEPTING) {
+ fprintf(stderr, gettext(
+ "Destination \"%s\" was already disabled.\n"),
+ printer);
+ exit_status = 1;
+ } else {
+ /* The operation is not supported in lpd protocol */
+ if (status == PAPI_OPERATION_NOT_SUPPORTED) {
+ fprintf(stderr,
+ verbose_papi_message(svc, status));
+ } else {
+ fprintf(stderr, gettext("disable: %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ }
+ exit_status = 1;
+ }
+
+ if (cancel != 0)
+ cancel_active_job(svc, printer);
+
+ papiServiceDestroy(svc);
+ }
+
+ return (exit_status);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/enable.c b/usr/src/cmd/print/bsd-sysv-commands/enable.c
new file mode 100644
index 0000000000..c197337e1e
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/enable.c
@@ -0,0 +1,117 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: enable.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout,
+ gettext("Usage: %s destination ...\n"),
+ name);
+ exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ int exit_status = 0;
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av, "E")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_ALWAYS;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if (ac == optind)
+ usage(av[0]);
+
+ for (c = optind; c < ac; c++) {
+ char *printer = av[c];
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ exit_status = 1;
+ }
+
+ status = papiPrinterEnable(svc, printer);
+ if (status == PAPI_OK) {
+ printf(gettext("printer \"%s\" now enabled\n"),
+ printer);
+ } else if (status == PAPI_NOT_ACCEPTING) {
+ fprintf(stderr, gettext(
+ "Destination \"%s\" was already enabled.\n"),
+ printer);
+ exit_status = 1;
+ } else {
+ /* The operation is not supported in lpd protocol */
+ if (status == PAPI_OPERATION_NOT_SUPPORTED) {
+ fprintf(stderr,
+ verbose_papi_message(svc, status));
+ } else {
+ fprintf(stderr, gettext("enable: %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ }
+ exit_status = 1;
+ }
+
+ papiServiceDestroy(svc);
+ }
+
+ return (exit_status);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/in.lpd.c b/usr/src/cmd/print/bsd-sysv-commands/in.lpd.c
new file mode 100644
index 0000000000..1b058ac291
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/in.lpd.c
@@ -0,0 +1,786 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: in.lpd.c 170 2006-05-20 05:58:49Z njacobs $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <syslog.h>
+#include <libintl.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/systeminfo.h>
+
+#include <papi.h>
+#include <uri.h>
+#include "common.h"
+
+#define ACK(fp) { (void) fputc('\0', fp); (void) fflush(fp); }
+#define NACK(fp) { (void) fputc('\1', fp); (void) fflush(fp); }
+
+/*
+ * This file contains the front-end of the BSD Print Protocol adaptor. This
+ * code assumes a BSD Socket interface to the networking side.
+ */
+
+static char *
+remote_host_name(FILE *fp)
+{
+ struct hostent *hp;
+ struct sockaddr_in6 peer;
+ socklen_t peer_len = sizeof (peer);
+ int fd = fileno(fp);
+ int error_num;
+ char tmp_buf[INET6_ADDRSTRLEN];
+ char *hostname;
+
+ /* who is our peer ? */
+ if (getpeername(fd, (struct sockaddr *)&peer, &peer_len) < 0) {
+ if ((errno != ENOTSOCK) && (errno != EINVAL))
+ return (NULL);
+ else
+ return (strdup("localhost"));
+ }
+
+ /* get their name or return a string containing their address */
+ if ((hp = getipnodebyaddr((const char *)&peer.sin6_addr,
+ sizeof (struct in6_addr), AF_INET6,
+ &error_num)) == NULL) {
+ return (strdup(inet_ntop(peer.sin6_family,
+ &peer.sin6_addr, tmp_buf, sizeof (tmp_buf))));
+ }
+
+ hostname = strdup(hp->h_name);
+ if (is_localhost(hp->h_name) != 0)
+ return (strdup("localhost"));
+
+ /* It must be someone else */
+ return (hostname);
+}
+
+static void
+fatal(FILE *fp, char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsyslog(LOG_DEBUG, fmt, ap);
+ vfprintf(fp, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+static void
+cleanup(char ***files, char **cf)
+{
+ if (*files != NULL) {
+ int i;
+
+ for (i = 0; (*files)[i] != NULL; i++) {
+ (void) unlink((*files)[i]);
+ free((*files)[i]);
+ }
+ free(*files);
+ *files = NULL;
+ }
+
+ if (*cf != NULL) {
+ free(*cf);
+ *cf = NULL;
+ }
+}
+
+static papi_attribute_t **
+parse_cf(papi_service_t svc, char *cf, char **files)
+{
+ papi_attribute_t **list = NULL;
+ char previous = NULL;
+ char *entry;
+ int copies_set = 0;
+ int copies = 0;
+
+ for (entry = strtok(cf, "\n"); entry != NULL;
+ entry = strtok(NULL, "\n")) {
+ char *format = NULL;
+
+ /* count the copies */
+ if ((entry[0] >= 'a') && (entry[0] <= 'z') &&
+ (copies_set == 0) && (previous == entry[0]))
+ copies++;
+ else if ((previous >= 'a') && (previous <= 'z'))
+ copies_set = 1;
+ previous = entry[0];
+
+ /* process the control message */
+ switch (entry[0]) {
+ /* RFC-1179 options */
+ case 'J': /* RFC-1179 Banner Job Name */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-name", ++entry);
+ break;
+ case 'C': /* RFC-1179 Banner Class Name */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-class", ++entry);
+ break;
+ case 'L': /* RFC-1179 Banner toggle */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-sheets", "standard");
+ break;
+ case 'T': /* RFC-1179 Title (pr) */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "pr-title", ++entry);
+ break;
+ case 'H': /* RFC-1179 Host */
+ /*
+ * use the host as known by us, not by them
+ *
+ * papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ * "job-originating-host-name", ++entry);
+ */
+ break;
+ case 'P': /* RFC-1179 User */
+ ++entry;
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-originating-user-name", entry);
+ papiServiceSetUserName(svc, entry);
+ break;
+ case 'M': /* RFC-1179 Mail to User */
+ papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-mail", 1);
+ break;
+ case 'W': /* RFC-1179 Width (pr) */
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "pr-width", atoi(++entry));
+ break;
+ case 'I': /* RFC-1179 Indent (pr) */
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "pr-indent", atoi(++entry));
+ break;
+ case 'N': /* RFC-1179 Filename */
+ /* could have HPUX extension embedded */
+ if (entry[1] != ' ') { /* real pathname */
+#ifdef DEBUG
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL,
+ "flist", ++entry);
+#endif
+ } else if (entry[2] == 'O') /* HPUX lp -o options */
+ papiAttributeListFromString(&list,
+ PAPI_ATTR_APPEND, ++entry);
+ break;
+ case 'U': /* RFC-1179 Unlink */
+ break; /* ignored */
+ case '1': /* RFC-1179 TROFF Font R */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-font-r", ++entry);
+ break;
+ case '2': /* RFC-1179 TROFF Font I */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-font-i", ++entry);
+ break;
+ case '3': /* RFC-1179 TROFF Font B */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-font-b", ++entry);
+ break;
+ case '4': /* RFC-1179 TROFF Font S */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-font-s", ++entry);
+ break;
+ case 'f': /* RFC-1179 ASCII file (print) */
+ format = "text/plain";
+ if (is_postscript(files[0]) == 1)
+ format = "application/postscript";
+ break;
+ case 'l': /* RFC-1179 CATV file (print) */
+ format = "application/octet-stream";
+ if (is_postscript(files[0]) == 1)
+ format = "application/postscript";
+ break;
+ case 'o': /* RFC-1179 Postscript file (print) */
+ format = "application/postscript";
+ break;
+ case 'p': /* RFC-1179 PR file (print) */
+ format = "application/x-pr";
+ papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL,
+ "pr-filter", 1);
+ break;
+ case 't': /* RFC-1179 TROFF file (print) */
+ format = "application/x-troff";
+ break;
+ case 'n': /* RFC-1179 DITROFF file (print) */
+ format = "application/x-ditroff";
+ break;
+ case 'd': /* RFC-1179 DVI file (print) */
+ format = "application/x-dvi";
+ break;
+ case 'g': /* RFC-1179 GRAPH file (print) */
+ format = "application/x-plot";
+ break;
+ case 'c': /* RFC-1179 CIF file (print) */
+ format = "application/x-cif";
+ break;
+ case 'v': /* RFC-1179 RASTER file (print) */
+ format = "application/x-raster";
+ break;
+ case 'r': /* RFC-1179 FORTRAN file (print) */
+ format = "application/x-fortran";
+ break;
+ /* Sun Solaris Extensions */
+ case 'O':
+ ++entry;
+ {
+ int rd, wr;
+
+ for (rd = wr = 0; entry[rd] != '\0'; rd++) {
+ if (entry[rd] == '"')
+ continue;
+ if (rd != wr)
+ entry[wr] = entry[rd];
+ wr++;
+ }
+ entry[wr] = '\0';
+
+ papiAttributeListFromString(&list,
+ PAPI_ATTR_APPEND, entry);
+ }
+ break;
+ case '5':
+ ++entry;
+ switch (entry[0]) {
+ case 'f': /* Solaris form */
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL,
+ "form", ++entry);
+ break;
+ case 'H': /* Solaris handling */
+ ++entry;
+ if (strcasecmp(entry, "hold") == 0)
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL,
+ "job-hold-until", "indefinite");
+ else if (strcasecmp(entry, "immediate") == 0)
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL,
+ "job-hold-until", "no-hold");
+ else
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL,
+ "job-hold-until", entry);
+ break;
+ case 'p': /* Solaris notification */
+ papiAttributeListAddBoolean(&list,
+ PAPI_ATTR_EXCL, "rfc-1179-mail", 1);
+ break;
+ case 'P': { /* Solaris page list */
+ char buf[BUFSIZ];
+
+ snprintf(buf, sizeof (buf), "page-ranges=%s",
+ ++entry);
+ papiAttributeListFromString(&list,
+ PAPI_ATTR_EXCL, buf);
+ }
+ break;
+ case 'q': { /* Solaris priority */
+ int i = atoi(++entry);
+
+ i = 100 - (i * 2.5);
+ if ((i < 1) || (i > 100))
+ i = 50;
+ papiAttributeListAddInteger(&list,
+ PAPI_ATTR_EXCL, "job-priority", i);
+ }
+ break;
+ case 'S': /* Solaris character set */
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL, "lp-charset",
+ ++entry);
+ break;
+ case 'T': /* Solaris type */
+ format = lp_type_to_mime_type(++entry);
+ break;
+ case 'y': /* Solaris mode */
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_APPEND, "lp-modes", ++entry);
+ break;
+ default:
+ syslog(LOG_INFO|LOG_DEBUG,
+ "Warning: cf message (%s) ignored",
+ entry);
+ break;
+ }
+ break;
+ /* Undefined Extensions: SCO, Ultrix, AIX, ... */
+
+ default:
+ syslog(LOG_INFO|LOG_DEBUG,
+ "Warning: cf message (%s) ignored", entry);
+ break;
+ }
+
+ if (format != NULL)
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", format);
+ }
+
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "copies", ++copies);
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-sheets", "none");
+
+ return (list);
+}
+
+static papi_status_t
+submit_job(papi_service_t svc, FILE *ifp, char *printer, int rid, char *cf,
+ char **files)
+{
+ papi_attribute_t **list = NULL;
+ papi_status_t status;
+ papi_job_t job = NULL;
+ char *format = "";
+
+ if ((list = parse_cf(svc, cf, files)) != NULL) {
+ /* use the host as known by us, not by them */
+ char *host = remote_host_name(ifp);
+
+ if (host != NULL) {
+ papiAttributeListAddString(&list, PAPI_ATTR_REPLACE,
+ "job-originating-host-name", host);
+ free(host);
+ }
+ if (rid >= 0) {
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "job-id-requested", rid);
+ }
+ }
+
+ status = papiJobSubmit(svc, printer, list, NULL, files, &job);
+ syslog(LOG_DEBUG, "submit: %s", papiStatusString(status));
+ if (status != PAPI_OK) {
+ char *tmp = papiServiceGetStatusMessage(svc);
+
+ syslog(LOG_DEBUG, "submit-detail: %s", tmp ? tmp : "none");
+ }
+ papiJobFree(job);
+
+ return (status);
+}
+
+static char *
+receive_control_file(papi_service_t svc, FILE *ifp, FILE *ofp, int size)
+{
+ char *ptr, *cf_data;
+
+ if ((ptr = cf_data = calloc(1, size + 1)) == NULL) {
+ NACK(ofp);
+ return (NULL);
+ } else
+ ACK(ofp);
+
+ while (size > 0) {
+ int rc;
+
+ if (((rc = fread(ptr, 1, size, ifp)) == 0) &&
+ (feof(ifp) != 0)) {
+ free(cf_data);
+ return (NULL);
+ } else {
+ ptr += rc;
+ size -= rc;
+ }
+ }
+ syslog(LOG_DEBUG, "cf_data(%s)", cf_data);
+
+ if (fgetc(ifp) != 0) {
+ free(cf_data);
+ return (NULL);
+ }
+ ACK(ofp);
+
+ return (cf_data);
+}
+
+static char *
+receive_data_file(FILE *ifp, FILE *ofp, int size)
+{
+ char file[] = "lpdXXXXXX";
+ char buf[BUFSIZ];
+ int fd;
+
+ if ((fd = mkstemp(file)) < 0) {
+ NACK(ofp);
+ return (NULL);
+ } else
+ ACK(ofp);
+
+ while (size > 0) {
+ int rc = ((size > BUFSIZ) ? BUFSIZ : size);
+
+ if (((rc = fread(buf, 1, rc, ifp)) == 0) &&
+ (feof(ifp) != 0)) {
+ close(fd);
+ unlink(file);
+ return (NULL);
+ } else {
+ char *ptr = buf;
+
+ while (rc > 0) {
+ int wrc = write(fd, ptr, rc);
+
+ if (wrc < 0) {
+ close(fd);
+ unlink(file);
+ return (NULL);
+ }
+
+ ptr += wrc;
+ size -= wrc;
+ rc -= wrc;
+ }
+ }
+ }
+ close(fd);
+ if (fgetc(ifp) != 0) {
+ unlink(file);
+ return (NULL);
+ }
+ ACK(ofp);
+
+ return (strdup(file));
+}
+
+static papi_status_t
+berkeley_receive_files(papi_service_t svc, FILE *ifp, FILE *ofp, char *printer)
+{
+ papi_status_t status = PAPI_OK;
+ char *file, **files = NULL; /* the job data files */
+ char *cf = NULL;
+ int rid = 0;
+ char buf[BUFSIZ];
+
+ while (fgets(buf, sizeof (buf), ifp) != NULL) {
+ int size;
+
+ syslog(LOG_DEBUG, "XFER CMD: (%d)%s\n", buf[0], &buf[1]);
+#ifdef DEBUG /* translate [1-3]... messages to \[1-3] to run by hand */
+ if ((buf[0] > '0') && (buf[0] < '4'))
+ buf[0] -= '0';
+#endif
+ switch (buf[0]) {
+ case 0x01: /* Abort */
+ cleanup(&files, &cf);
+ break;
+ case 0x02: { /* Receive control file */
+ if (((cf = strchr(buf, ' ')) != NULL) &&
+ (strlen(cf) > 4)) {
+ while ((*cf != NULL) && (isdigit(*cf) == 0))
+ cf++;
+ rid = atoi(cf);
+ }
+ cf = receive_control_file(svc, ifp, ofp, atoi(&buf[1]));
+ if (cf == NULL) {
+ cleanup(&files, &cf);
+ return (PAPI_BAD_REQUEST);
+ } else if (files != NULL) {
+ status = submit_job(svc, ifp, printer, rid, cf,
+ files);
+ cleanup(&files, &cf);
+ }
+ }
+ break;
+ case 0x03: { /* Receive data file */
+ file = receive_data_file(ifp, ofp, atoi(&buf[1]));
+ if (file == NULL) {
+ cleanup(&files, &cf);
+ return (PAPI_TEMPORARY_ERROR);
+ }
+ list_append(&files, file);
+ }
+ break;
+ default:
+ cleanup(&files, &cf);
+ fatal(ofp, "protocol screwup");
+ break;
+ }
+ }
+
+ if ((cf != NULL) && (files != NULL))
+ status = submit_job(svc, ifp, printer, rid, cf, files);
+
+ cleanup(&files, &cf);
+
+ return (status);
+}
+
+static papi_status_t
+berkeley_transfer_files(papi_service_t svc, FILE *ifp, FILE *ofp,
+ char *printer)
+{
+ papi_status_t status;
+ papi_printer_t p = NULL;
+ char *keys[] = { "printer-is-accepting-jobs", NULL };
+
+ status = papiPrinterQuery(svc, printer, keys, NULL, &p);
+ if ((status == PAPI_OK) && (p != NULL)) {
+ papi_attribute_t **attrs = papiPrinterGetAttributeList(p);
+ char accepting = PAPI_FALSE;
+
+ papiAttributeListGetBoolean(attrs, NULL,
+ "printer-is-accepting-jobs", &accepting);
+
+ if (accepting == PAPI_TRUE) {
+ ACK(ofp);
+ status = berkeley_receive_files(svc, ifp, ofp, printer);
+ } else
+ NACK(ofp);
+
+ papiPrinterFree(p);
+ } else
+ NACK(ofp);
+
+ return (status);
+}
+
+static int
+cyclical_service_check(char *svc_name)
+{
+ papi_attribute_t **list;
+ uri_t *uri = NULL;
+ char *s = NULL;
+
+ /* was there a printer? */
+ if (svc_name == NULL)
+ return (0);
+
+ if ((list = getprinterbyname(svc_name, NULL)) == NULL)
+ return (0); /* if it doesnt' resolve, we will fail later */
+
+ papiAttributeListGetString(list, NULL, "printer-uri-supported", &s);
+ if ((s == NULL) || (strcasecmp(svc_name, s) != 0))
+ return (0); /* they don't match */
+
+ /* is it in uri form? */
+ if (uri_from_string(s, &uri) < 0)
+ return (0);
+
+ if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) {
+ uri_free(uri);
+ return (0);
+ }
+
+ /* is it in lpd form? */
+ if (strcasecmp(uri->scheme, "lpd") != 0) {
+ uri_free(uri);
+ return (0);
+ }
+
+ /* is it the local host? */
+ if (is_localhost(uri->host) != 0) {
+ uri_free(uri);
+ return (0);
+ }
+
+ uri_free(uri);
+ return (1);
+}
+
+
+/*
+ * This is the entry point for this program. The program takes the
+ * following options:
+ * (none)
+ */
+int
+main(int ac, char *av[])
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ FILE *ifp = stdin;
+ FILE *ofp = stdout;
+ int c;
+ char buf[BUFSIZ];
+ char **args;
+ char *printer;
+ char *run_dir = "/var/run/in.lpd";
+ char *run_user = NULL;
+ struct passwd *pw = NULL;
+
+ (void) chdir("/tmp"); /* run in /tmp by default */
+ openlog("bsd-gw", LOG_PID, LOG_LPR);
+
+ while ((c = getopt(ac, av, "Ed:u:")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_ALWAYS;
+ break;
+ case 'd': /* run where they tell you */
+ run_dir = optarg;
+ break;
+ case 'u': /* run as */
+ run_user = optarg;
+ break;
+ default:
+ ;
+ }
+
+ if (run_user != NULL) /* get the requested user info */
+ pw = getpwnam(run_user);
+
+ if (run_dir != NULL) { /* setup the run_dir */
+ (void) mkdir(run_dir, 0700);
+ if (pw != NULL)
+ (void) chown(run_dir, pw->pw_uid, pw->pw_gid);
+ }
+
+ if (pw != NULL) { /* run as the requested user */
+ syslog(LOG_DEBUG, "name: %s, uid: %d, gid: %d",
+ pw->pw_name, pw->pw_uid, pw->pw_gid);
+ initgroups(pw->pw_name, pw->pw_gid);
+ setgid(pw->pw_gid);
+ setuid(pw->pw_uid);
+ }
+
+ if (run_dir != NULL) /* move to the run_dir */
+ if (chdir(run_dir) < 0) {
+ syslog(LOG_DEBUG, "failed to chdir(%s)", run_dir);
+ exit(1);
+ }
+
+ syslog(LOG_DEBUG, "$CWD = %s", getwd(NULL));
+
+ if (fgets(buf, sizeof (buf), ifp) == NULL) {
+ if (feof(ifp) == 0)
+ syslog(LOG_ERR, "Error reading from connection: %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ syslog(LOG_DEBUG, "CMD: (%d)%s\n", buf[0], &buf[1]);
+
+#ifdef DEBUG /* translate [1-5]... messages to \[1-5] to run by hand */
+ if ((buf[0] > '0') && (buf[0] < '6'))
+ buf[0] -= '0';
+#endif
+
+ if ((buf[0] < 1) || (buf[0] > 5)) {
+ fatal(ofp, "Invalid protocol request (%d): %c%s\n",
+ buf[0], buf[0], buf);
+ exit(1);
+ }
+
+ args = strsplit(&buf[1], "\t\n ");
+ printer = *args++;
+
+ if (printer == NULL) {
+ fatal(ofp, "Can't determine requested printer");
+ exit(1);
+ }
+
+ if (cyclical_service_check(printer) != 0) {
+ fatal(ofp, "%s is cyclical\n", printer);
+ exit(1);
+ }
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL, NULL,
+ encryption, NULL);
+ if (status != PAPI_OK) {
+ fatal(ofp, "Failed to contact service for %s: %s\n", printer,
+ verbose_papi_message(svc, status));
+ exit(1);
+ }
+
+ /*
+ * Trusted Solaris can't be trusting of intermediaries. Pass
+ * the socket connection to the print service to retrieve the
+ * sensativity label off of a multi-level port.
+ */
+ (void) papiServiceSetPeer(svc, fileno(ifp));
+
+ switch (buf[0]) {
+ case '\1': /* restart printer */
+ ACK(ofp); /* there is no equivalent */
+ break;
+ case '\2': /* transfer job(s) */
+ status = berkeley_transfer_files(svc, ifp, ofp, printer);
+ break;
+ case '\3': /* show queue (short) */
+ case '\4': { /* show queue (long) */
+ int count;
+
+ for (count = 0; args[count] != 0; count++) {}
+
+ berkeley_queue_report(svc, ofp, printer, buf[0], count, args);
+ }
+ break;
+ case '\5': { /* cancel job(s) */
+ char *user = *args++;
+ char *host = remote_host_name(ifp);
+ int count;
+
+ if (host != NULL) {
+ char buf[BUFSIZ];
+
+ snprintf(buf, sizeof (buf), "%s@%s", user, host);
+ status = papiServiceSetUserName(svc, buf);
+ } else
+ status = papiServiceSetUserName(svc, user);
+
+ for (count = 0; args[count] != 0; count++) {}
+
+ berkeley_cancel_request(svc, ofp, printer, count, args);
+ }
+ break;
+ default:
+ fatal(ofp, "unsupported protocol request (%c), %s",
+ buf[0], &buf[1]);
+ }
+
+ (void) fflush(ofp);
+
+ syslog(LOG_DEBUG, "protocol request(%d) for %s completed: %s",
+ buf[0], printer, papiStatusString(status));
+ if (status != PAPI_OK)
+ syslog(LOG_DEBUG, "detail: %s",
+ verbose_papi_message(svc, status));
+
+ papiServiceDestroy(svc);
+
+ return (0);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/lp.c b/usr/src/cmd/print/bsd-sysv-commands/lp.c
new file mode 100644
index 0000000000..9ec5d0fed2
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/lp.c
@@ -0,0 +1,334 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+/* $Id: lp.c 179 2006-07-17 18:24:07Z njacobs $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#ifdef HAVE_LIBMAGIC /* for mimetype auto-detection */
+#include <magic.h>
+#endif /* HAVE_LIBMAGIC */
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout,
+ gettext("Usage: %s [-c] [-m] [-p] [-s] [-w] [-d destination] "
+ "[-f form-name] [-H special-handling] [-n number] "
+ "[-o option] [-P page-list] [-q priority-level] "
+ "[-S character-set | print-wheel] [-t title] [-v] "
+ "[-T content-type [-r]] [-y mode-list] [file...]\n"),
+ name);
+ exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_attribute_t **list = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ papi_job_t job = NULL;
+ char prefetch[3];
+ int prefetch_len = sizeof (prefetch);
+ char *printer = NULL;
+ char b = PAPI_TRUE;
+ int copy = 0;
+ int silent = 0;
+ int dump = 0;
+ int validate = 0;
+ int modify = -1;
+ int c;
+ uid_t ruid;
+ struct passwd *pw;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ ruid = getuid();
+ if ((pw = getpwuid(ruid)) != NULL)
+ (void) initgroups(pw->pw_name, pw->pw_gid);
+ (void) setuid(ruid);
+
+
+ while ((c = getopt(ac, av, "DEH:P:S:T:cd:f:i:mn:o:pq:rst:Vwy:")) != EOF)
+ switch (c) {
+ case 'H': /* handling */
+ if (strcasecmp(optarg, "hold") == 0)
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL,
+ "job-hold-until", "indefinite");
+ else if (strcasecmp(optarg, "immediate") == 0)
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL,
+ "job-hold-until", "no-hold");
+ else
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_EXCL,
+ "job-hold-until", optarg);
+ break;
+ case 'P': { /* page list */
+ char buf[BUFSIZ];
+
+ snprintf(buf, sizeof (buf), "page-ranges=%s", optarg);
+ papiAttributeListFromString(&list,
+ PAPI_ATTR_EXCL, buf);
+ }
+ break;
+ case 'S': /* charset */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "lp-charset", optarg);
+ break;
+ case 'T': /* type */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format",
+ lp_type_to_mime_type(optarg));
+ break;
+ case 'D': /* dump */
+ dump = 1;
+ break;
+ case 'c': /* copy */
+ copy = 1;
+ break;
+ case 'd': /* destination */
+ printer = optarg;
+ break;
+ case 'f': /* form */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "form", optarg);
+ break;
+ case 'i': /* modify job */
+ if ((get_printer_id(optarg, &printer, &modify) < 0) ||
+ (modify < 0)) {
+ fprintf(stderr,
+ gettext("invalid request id: %s\n"),
+ optarg);
+ exit(1);
+ }
+ break;
+ case 'm': /* mail when complete */
+ papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-mail", 1);
+ break;
+ case 'n': /* copies */
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "copies", atoi(optarg));
+ break;
+ case 'o': /* lp "options" */
+ papiAttributeListFromString(&list,
+ PAPI_ATTR_REPLACE, optarg);
+ break;
+ case 'p': /* Solaris - notification */
+ papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-mail", 1);
+ break;
+ case 'q': { /* priority */
+ int i = atoi(optarg);
+
+ i = 100 - (i * 2.5);
+ if ((i < 1) || (i > 100)) {
+ fprintf(stderr, gettext("UX:lp: "));
+ fprintf(stderr, gettext("ERROR: "));
+ fprintf(stderr, gettext("Bad priority"
+ " value \"%s\"."), optarg);
+ fprintf(stderr, gettext("\n "));
+ fprintf(stderr, gettext("TO FIX"));
+ fprintf(stderr, gettext(": "));
+ fprintf(stderr, gettext("Use an integer value"
+ " from 0 to 39."));
+ fprintf(stderr, gettext("\n"));
+ exit(1);
+ }
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "job-priority", i);
+ }
+ break;
+ case 'r': /* "raw" mode */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format",
+ "application/octet-stream");
+ papiAttributeListAddString(&list, PAPI_ATTR_APPEND,
+ "stty", "raw");
+ break;
+ case 's': /* suppress message */
+ silent = 1;
+ break;
+ case 't': /* title */
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-name", optarg);
+ break;
+ case 'V': /* validate */
+ validate = 1;
+ break;
+ case 'w':
+ papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-mail", 1);
+ break;
+ case 'y': /* lp "modes" */
+ papiAttributeListAddString(&list, PAPI_ATTR_APPEND,
+ "lp-modes", optarg);
+ break;
+ case 'E':
+ encryption = PAPI_ENCRYPT_REQUIRED;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ /* convert "banner", "nobanner" to "job-sheet" */
+ if (papiAttributeListGetBoolean(list, NULL, "banner", &b) == PAPI_OK) {
+ (void) papiAttributeListDelete(&list, "banner");
+ if (b == PAPI_FALSE)
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-sheets", "none");
+ }
+
+ if ((printer == NULL) &&
+ ((printer = getenv("PRINTER")) == NULL) &&
+ ((printer = getenv("LPDEST")) == NULL))
+ printer = DEFAULT_DEST;
+
+ if (((optind + 1) == ac) && (strcmp(av[optind], "-") == 0))
+ optind = ac;
+
+ if (modify == -1) {
+ char *document_format = "text/plain";
+
+ if (optind != ac) {
+ /* get the mime type of the file data */
+#ifdef MAGIC_MIME
+ magic_t ms = NULL;
+
+ if ((ms = magic_open(MAGIC_MIME)) != NULL) {
+ document_format = magic_file(ms, av[optind]);
+ magic_close(ms);
+ }
+#else
+ if (is_postscript(av[optind]) == 1)
+ document_format = "application/postscript";
+#endif
+ } else {
+ if (is_postscript_stream(0, prefetch, &prefetch_len)
+ == 1)
+ document_format = "application/postscript";
+ }
+
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, "copies", 1);
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", document_format);
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-sheets", "standard");
+ }
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL, cli_auth_callback,
+ encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"), printer,
+ verbose_papi_message(svc, status));
+ exit(1);
+ }
+
+ if (dump != 0) {
+ printf("requesting attributes:\n");
+ papiAttributeListPrint(stdout, list, "\t");
+ printf("\n");
+ }
+
+ if (modify != -1)
+ status = papiJobModify(svc, printer, modify, list, &job);
+ else if (optind == ac) /* no file list, use stdin */
+ status = jobSubmitSTDIN(svc, printer, prefetch, prefetch_len,
+ list, &job);
+ else if (validate == 1) /* validate the request can be processed */
+ status = papiJobValidate(svc, printer, list,
+ NULL, &av[optind], &job);
+ else if (copy == 0) /* reference the files in the job, default */
+ status = papiJobSubmitByReference(svc, printer, list,
+ NULL, &av[optind], &job);
+ else /* copy the files before return, -c */
+ status = papiJobSubmit(svc, printer, list,
+ NULL, &av[optind], &job);
+
+ papiAttributeListFree(list);
+
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("%s: %s\n"), printer,
+ verbose_papi_message(svc, status));
+ papiJobFree(job);
+ papiServiceDestroy(svc);
+ exit(1);
+ }
+
+ if (((silent == 0) || (dump != 0)) &&
+ ((list = papiJobGetAttributeList(job)) != NULL)) {
+ int32_t id = -1;
+
+ if (printer == NULL)
+ papiAttributeListGetString(list, NULL,
+ "printer-name", &printer);
+
+ papiAttributeListGetInteger(list, NULL,
+ "job-id-requested", &id);
+ if (id == -1) {
+ papiAttributeListGetInteger(list, NULL, "job-id", &id);
+ }
+
+ printf(gettext("request id is %s-%d "), printer, id);
+ if (ac != optind)
+ printf("(%d file(s))\n", ac - optind);
+ else
+ printf("(standard input)\n");
+
+ if (dump != 0) {
+ printf("job attributes:\n");
+ papiAttributeListPrint(stdout, list, "\t");
+ printf("\n");
+ }
+ }
+
+ papiJobFree(job);
+ papiServiceDestroy(svc);
+
+ return (0);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/lpc.c b/usr/src/cmd/print/bsd-sysv-commands/lpc.c
new file mode 100644
index 0000000000..a4a89e77cc
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/lpc.c
@@ -0,0 +1,561 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lpc.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+typedef int (cmd_handler_t)(papi_service_t, char **);
+
+static papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+
+/* ARGSUSED0 */
+static int
+lpc_exit(papi_service_t svc, char **args)
+{
+ exit(0);
+ /* NOTREACHED */
+ return (0);
+}
+
+static int
+lpc_status(papi_service_t svc, char **args)
+{
+ papi_status_t status;
+ papi_printer_t p = NULL;
+ char *pattrs[] = { "printer-state", "printer-state-reasons",
+ "printer-is-accepting-jobs", NULL };
+ char *destination = args[1];
+
+ status = papiPrinterQuery(svc, destination, pattrs, NULL, &p);
+ if (status == PAPI_OK) {
+ papi_attribute_t **list = papiPrinterGetAttributeList(p);
+ char accepting = 0;
+ int32_t state = 0;
+
+ printf("%s:\n", destination);
+
+ (void) papiAttributeListGetBoolean(list, NULL,
+ "printer-is-accepting-jobs", &accepting);
+ printf(gettext("\tqueueing is %s\n"),
+ (accepting ? gettext("enabled") : gettext("disabled")));
+
+ (void) papiAttributeListGetInteger(list, NULL,
+ "printer-state", &state);
+ printf("\tprinting is %s\n",
+ ((state != 0x05) ? gettext("enabled") :
+ gettext("disabled")));
+
+ if (state != 0x03) { /* !idle */
+ papi_job_t *jobs = NULL;
+ int i = 0;
+
+ (void) papiPrinterListJobs(svc, destination, NULL,
+ PAPI_LIST_JOBS_ALL, 0, &jobs);
+ if (jobs != NULL) {
+ for (i = 0; jobs[i] != NULL; i++);
+ papiJobListFree(jobs);
+ }
+ printf(gettext("\t%d entries in spool area\n"), i);
+ } else
+ printf(gettext("\tno entries\n"));
+
+ if (state == 0x04)
+ printf(gettext("\tdaemon present\n"));
+
+ } else {
+ fprintf(stderr, "%s: %s\n", destination,
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ papiPrinterFree(p);
+
+ return (0);
+}
+
+static int
+lpc_abort(papi_service_t svc, char **args)
+{
+ papi_status_t status;
+ char *destination = args[1];
+
+ if (destination == NULL) {
+ fprintf(stderr, gettext("Usage: abort (destination)\n"));
+ return (-1);
+ }
+
+ status = papiPrinterPause(svc, destination, "paused via lpc abort");
+ if (status == PAPI_OK) {
+ printf(gettext("%s: processing disabled after current job\n"),
+ destination);
+ } else {
+ fprintf(stderr, "%s: %s\n", destination,
+ verbose_papi_message(svc, status));
+ }
+
+ return (0);
+}
+
+static int
+lpc_clean(papi_service_t svc, char **args)
+{
+ papi_status_t status;
+ papi_job_t *jobs = NULL;
+ char *destination = args[1];
+
+ if (destination == NULL) {
+ fprintf(stderr, gettext("Usage: clean (destination)\n"));
+ return (-1);
+ }
+
+ status = papiPrinterPurgeJobs(svc, destination, &jobs);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("clean: %s: %s\n"), destination,
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ if (jobs != NULL) {
+ int i;
+
+ for (i = 0; jobs[i] != NULL; i++)
+ printf(gettext("\t%s-%d: cancelled\n"), destination,
+ papiJobGetId(jobs[i]));
+
+ papiJobListFree(jobs);
+ }
+
+ return (0);
+}
+
+static int
+lpc_disable(papi_service_t svc, char **args)
+{
+ papi_status_t status;
+ char *destination = args[1];
+
+ if (destination == NULL) {
+ fprintf(stderr, gettext("Usage: disable: (destination)\n"));
+ return (-1);
+ }
+
+ status = papiPrinterDisable(svc, destination, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("disable: %s: %s\n"), destination,
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+lpc_enable(papi_service_t svc, char **args)
+{
+ papi_status_t status;
+ char *destination = args[1];
+
+ if (destination == NULL) {
+ fprintf(stderr, gettext("Usage: enable: (destination)\n"));
+ return (-1);
+ }
+
+ status = papiPrinterEnable(svc, destination);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("enable: %s: %s\n"), destination,
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+lpc_restart(papi_service_t svc, char **args)
+{
+ int rc = 0;
+
+ rc += lpc_disable(svc, args);
+ rc += lpc_enable(svc, args);
+
+ return (rc);
+}
+
+static int
+lpc_start(papi_service_t svc, char **args)
+{
+ papi_status_t status;
+ char *destination = args[1];
+
+ if (destination == NULL) {
+ fprintf(stderr, gettext("Usage: start (destination)\n"));
+ return (-1);
+ }
+
+ status = papiPrinterResume(svc, destination);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("start: %s: %s\n"), destination,
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+lpc_stop(papi_service_t svc, char **args)
+{
+ papi_status_t status;
+ char *destination = args[1];
+
+ if (destination == NULL) {
+ fprintf(stderr, gettext("Usage: stop (destination)\n"));
+ return (-1);
+ }
+
+ status = papiPrinterPause(svc, destination, "paused via lpc");
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("stop: %s: %s\n"), destination,
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+lpc_topq(papi_service_t svc, char **args)
+{
+ papi_status_t status;
+ char *destination = args[1];
+ char *idstr = args[2];
+ int32_t id;
+
+ if (destination == NULL || idstr == NULL) {
+ fprintf(stderr, gettext("Usage: topq (destination) (id)\n"));
+ return (-1);
+ }
+ id = atoi(idstr);
+
+ status = papiJobPromote(svc, destination, id);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("topq: %s-%d: %s\n"), destination, id,
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+lpc_up(papi_service_t svc, char **args)
+{
+ int rc = 0;
+
+ rc += lpc_enable(svc, args);
+ rc += lpc_start(svc, args);
+
+ return (rc);
+}
+
+static int
+lpc_down(papi_service_t svc, char **args)
+{
+ int rc = 0;
+
+ rc += lpc_disable(svc, args);
+ rc += lpc_stop(svc, args);
+
+ return (rc);
+}
+
+static int lpc_help(papi_service_t svc, char **args); /* forward reference */
+
+static char help_help[] = "get help on commands";
+static char help_exit[] = "exit lpc";
+static char help_status[] = "show status of daemon and queue";
+static char help_abort[] =
+ "disable print queue terminating any active job processing";
+static char help_clean[] = "remove all jobs from a queue";
+static char help_disable[] = "turn off spooling to a queue";
+static char help_down[] =
+ "turn off queueing and printing for a queue and set a reason";
+static char help_enable[] = "turn on spooling to a queue";
+static char help_restart[] = "restart job processing for a queue";
+static char help_start[] = "turn on printing from a queue";
+static char help_stop[] = "turn off printing from a queue";
+static char help_up[] = "turn on queueing and printing for a queue";
+static char help_topq[] = "put a job at the top of the queue";
+
+static struct {
+ char *cmd;
+ int (*handler)(papi_service_t svc, char **args);
+ char *help_string;
+ int num_args;
+} cmd_tab[] = {
+ { "?", lpc_help, help_help, 0 },
+ { "help", lpc_help, help_help, 0 },
+ { "exit", lpc_exit, help_exit, 0 },
+ { "quit", lpc_exit, help_exit, 0 },
+ { "status", lpc_status, help_status, 1 },
+ { "abort", lpc_abort, help_abort, 1 },
+ { "clean", lpc_clean, help_clean, 1 },
+ { "disable", lpc_disable, help_disable, 1 },
+ { "down", lpc_down, help_down, 2 },
+ { "enable", lpc_enable, help_enable, 1 },
+ { "restart", lpc_restart, help_restart, 1 },
+ { "start", lpc_start, help_start, 1 },
+ { "stop", lpc_stop, help_stop, 1 },
+ { "up", lpc_up, help_up, 1 },
+ { "topq", lpc_topq, help_topq, 2 },
+ { NULL, NULL, NULL, 0 }
+};
+
+static int
+lpc_handler(char *cmd, cmd_handler_t **handler)
+{
+ int i;
+
+ for (i = 0; cmd_tab[i].cmd != NULL; i++)
+ if (strcmp(cmd, cmd_tab[i].cmd) == 0) {
+ *handler = cmd_tab[i].handler;
+ return (cmd_tab[i].num_args);
+ }
+ return (-1);
+}
+
+static char *
+lpc_helptext(char *cmd)
+{
+ int i;
+
+ for (i = 0; cmd_tab[i].cmd != NULL; i++)
+ if (strcmp(cmd, cmd_tab[i].cmd) == 0)
+ return (gettext(cmd_tab[i].help_string));
+ return (NULL);
+}
+
+/* ARGSUSED0 */
+static int
+lpc_help(papi_service_t svc, char **args)
+{
+ if (args[1] == NULL) {
+ int i;
+
+ printf(gettext("Commands are:\n\n"));
+ for (i = 0; cmd_tab[i].cmd != NULL; i++) {
+ printf("\t%s", cmd_tab[i].cmd);
+ if ((i % 7) == 6)
+ printf("\n");
+ }
+ if ((i % 7) != 6)
+ printf("\n");
+ } else {
+ char *helptext = lpc_helptext(args[1]);
+
+ if (helptext == NULL)
+ helptext = gettext("no such command");
+
+ printf("%s: %s\n", args[1], helptext);
+ }
+
+ return (0);
+}
+
+static int
+process_one(int (*handler)(papi_service_t, char **), char **av, int expected)
+{
+ int rc = -1;
+ papi_status_t status = PAPI_OK;
+ papi_service_t svc = NULL;
+ char *printer = av[1];
+
+ if ((printer != NULL) && (expected != 0)) {
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ }
+ }
+
+ if (status == PAPI_OK)
+ rc = handler(svc, av);
+
+ if (svc != NULL)
+ papiServiceDestroy(svc);
+
+ return (rc);
+}
+
+static int
+process_all(int (*handler)(papi_service_t, char **), char **av, int expected)
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ char **printers;
+ int rc = 0;
+
+ status = papiServiceCreate(&svc, NULL, NULL, NULL, NULL,
+ encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("Failed to contact service: %s\n"),
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+
+ if ((printers = interest_list(svc)) != NULL) {
+ int i;
+
+ for (i = 0; printers[i] != NULL; i++) {
+ av[1] = printers[i];
+ rc += process_one(handler, av, expected);
+ }
+ }
+
+ papiServiceDestroy(svc);
+
+ return (rc);
+}
+
+static int
+process(int ac, char **av)
+{
+ int (*handler)(papi_service_t, char **) = NULL;
+ int num_args = -1;
+
+ char *printer = av[1];
+ int rc = -1;
+
+ if ((num_args = lpc_handler(av[0], &handler)) < 0) {
+ printf(gettext("%s: invalid command\n"), av[0]);
+ return (-1);
+ }
+
+ if (((ac == 0) && (num_args == 1)) ||
+ ((printer != NULL) && strcmp(printer, "all") == 0))
+ rc = process_all(handler, av, num_args);
+ else if (num_args < ac) {
+ int i;
+ char *argv[4];
+
+ memset(argv, 0, sizeof (argv));
+ argv[0] = av[0];
+
+ if (strcmp(av[0], "topq") == 0) {
+ argv[1] = av[1];
+ for (i = 2; i <= ac; i++) {
+ argv[2] = av[i];
+ process_one(handler, argv, num_args);
+ }
+ } else
+ for (i = 1; i <= ac; i++) {
+ argv[1] = av[i];
+ process_one(handler, argv, num_args);
+ }
+ } else
+ rc = process_one(handler, av, num_args);
+
+ return (rc);
+}
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout,
+ gettext("Usage: %s [ command [ parameter...]]\n"),
+ name);
+ exit(1);
+}
+
+static void
+lpc_shell()
+{
+ for (;;) {
+ char line[256];
+ char **av = NULL;
+ int ac = 0;
+
+ /* prompt */
+ fprintf(stdout, "lpc> ");
+ fflush(stdout);
+
+ /* get command */
+ if (fgets(line, sizeof (line), stdin) == NULL)
+ exit(1);
+ if ((av = strsplit(line, " \t\n")) != NULL)
+ for (ac = 0; av[ac] != NULL; ac++);
+ else
+ continue;
+
+ if (ac > 0)
+ (void) process(ac - 1, av);
+ free(av);
+ }
+}
+
+int
+main(int ac, char *av[])
+{
+ int result = 0;
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av, "E")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_ALWAYS;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if (optind == ac)
+ lpc_shell();
+ else
+ result = process(ac - optind - 1, &av[optind]);
+
+ return (result);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/lpmove.c b/usr/src/cmd/print/bsd-sysv-commands/lpmove.c
new file mode 100644
index 0000000000..15cb076ef1
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/lpmove.c
@@ -0,0 +1,210 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/* $Id: lpmove.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout,
+ gettext("Usage: %s [request-id] (destination)\n"
+ " %s (source) (destination)\n"), name, name);
+ exit(1);
+}
+
+static int
+move_job(papi_service_t svc, char *src, int32_t id, char *dest)
+{
+ int result = 0;
+ papi_status_t status;
+ char *mesg = gettext("moved");
+
+ status = papiJobMove(svc, src, id, dest);
+ if (status != PAPI_OK) {
+ mesg = (char *)verbose_papi_message(svc, status);
+ result = -1;
+ }
+ fprintf(stderr, gettext("%s-%d to %s: %s\n"), src, id, dest, mesg);
+
+ return (result);
+}
+
+int
+main(int ac, char *av[])
+{
+ int exit_code = 0;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ char *destination = NULL;
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av, "E:")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_REQUIRED;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if (optind >= ac - 1)
+ usage(av[0]);
+
+ destination = av[--ac];
+
+ for (c = optind; c < ac; c++) {
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_job_t *jobs = NULL;
+ char *printer = NULL;
+ int32_t id = -1;
+
+ (void) get_printer_id(av[c], &printer, &id);
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ exit(1);
+ }
+
+ if (id != -1) { /* it's a job */
+ if (move_job(svc, printer, id, destination) < 0)
+ exit_code = 1;
+ } else { /* it's a printer */
+ char message[128];
+ int count = 0;
+
+ snprintf(message, sizeof (message), "moved jobs to %s",
+ destination);
+ status = papiPrinterPause(svc, printer, message);
+ if (status != PAPI_OK) {
+ /*
+ * If the user is denied the permission
+ * to disable then return appropriate msg
+ */
+ char *result = NULL;
+
+ result = papiServiceGetStatusMessage(svc);
+
+ if (result != NULL) {
+ /*
+ * Check if user is denied
+ * the permission
+ */
+ if (strstr(result, "permission denied")
+ != NULL) {
+ /*
+ * user is denied
+ * permission
+ */
+ fprintf(stderr, "UX:lpmove: ");
+ fprintf(stderr,
+ gettext("ERROR: "));
+ fprintf(stderr, gettext("You "
+ "aren't allowed to do"
+ " that."));
+ fprintf(stderr, "\n\t");
+ fprintf(stderr,
+ gettext("TO FIX"));
+ fprintf(stderr, ": ");
+ fprintf(stderr, gettext("You "
+ "must be logged in as "
+ "\"lp\" or \"root\"."));
+ fprintf(stderr, "\n");
+ exit_code = 1;
+ } else {
+ fprintf(stderr, gettext(
+ "Reject %s: %s\n"),
+ printer,
+ verbose_papi_message(
+ svc, status));
+ exit_code = 1;
+ }
+ } else {
+ fprintf(stderr, gettext(
+ "Reject %s: %s\n"),
+ printer,
+ verbose_papi_message(svc, status));
+ exit_code = 1;
+ }
+ } else {
+ printf(gettext(
+ "destination %s is not accepting"\
+ " requests\n"), printer);
+
+ status = papiPrinterListJobs(svc, printer, NULL,
+ 0, 0, &jobs);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("Jobs %s:"\
+ " %s\n"),
+ printer,
+ verbose_papi_message(svc, status));
+ exit_code = 1;
+ }
+
+ printf(gettext("move in progress ...\n"));
+ while ((jobs != NULL) && (*jobs != NULL)) {
+ id = papiJobGetId(*jobs++);
+ if (move_job(svc, printer,
+ id, destination) < 0)
+ exit_code = 1;
+ else
+ count++;
+ }
+ printf(gettext(
+ "total of %d requests moved"\
+ " from %s to %s\n"),
+ count, printer, destination);
+
+ papiJobListFree(jobs);
+ }
+ }
+
+ papiServiceDestroy(svc);
+ }
+
+ return (exit_code);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/lpq.c b/usr/src/cmd/print/bsd-sysv-commands/lpq.c
new file mode 100644
index 0000000000..188a5669d6
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/lpq.c
@@ -0,0 +1,134 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lpq.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout, gettext("Usage: %s [-P printer] (user|id ...)\n"),
+ name);
+ exit(1);
+}
+
+static void
+clear_screen()
+{
+ static char buf[32];
+
+ /* quick and dirty for now, this should be fixed real soon */
+ if (buf[0] == '\0') {
+ FILE *fp = popen("/bin/tput clear", "r");
+ if (fp != NULL) {
+ fgets(buf, sizeof (buf), fp);
+ fclose(fp);
+ }
+ }
+ printf("%s", buf);
+}
+
+int
+main(int ac, char *av[])
+{
+ char *printer = NULL;
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ int format = 3; /* lpq short format */
+ int interval = 0;
+ int num_jobs;
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av, "EP:l")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_REQUIRED;
+ break;
+ case 'P':
+ printer = optarg;
+ break;
+ case 'l':
+ format = 4; /* lpq long format */
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if ((optind < ac) && (av[optind][0] == '+'))
+ interval = atoi(av[optind++]);
+
+ if ((printer == NULL) &&
+ ((printer = getenv("PRINTER")) == NULL) &&
+ ((printer = getenv("LPDEST")) == NULL))
+ printer = DEFAULT_DEST;
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL, cli_auth_callback,
+ encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"), printer,
+ verbose_papi_message(svc, status));
+ papiServiceDestroy(svc);
+ exit(1);
+ }
+
+ do {
+ if (interval != 0)
+ clear_screen();
+
+ num_jobs = berkeley_queue_report(svc, stdout, printer, format,
+ ac - optind, &av[optind]);
+
+ if ((interval != 0) && (num_jobs > 0))
+ sleep(interval);
+ } while ((interval > 0) && (num_jobs > 0));
+
+ papiServiceDestroy(svc);
+
+ return (0);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/lpr.c b/usr/src/cmd/print/bsd-sysv-commands/lpr.c
new file mode 100644
index 0000000000..547e0df36f
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/lpr.c
@@ -0,0 +1,276 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lpr.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+#ifdef HAVE_LIBMAGIC /* for mimetype auto-detection */
+#include <magic.h>
+#endif /* HAVE_LIBMAGIC */
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout,
+ gettext("Usage: %s [-P printer] [-# copies] [-C class] "
+ "[-J job] [-T title] "
+ "[-p [-i indent] [-w width]] "
+ "[-1|-2|-3|-4 font] [-m] [-h] [-s] "
+ "[-filter_option] [file ..]\n"), name);
+ exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_attribute_t **list = NULL;
+ papi_job_t job = NULL;
+ int exit_code = 0;
+ char *printer = NULL;
+ char prefetch[3];
+ int prefetch_len = sizeof (prefetch);
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ int dump = 0;
+ int validate = 0;
+ int remove = 0;
+ int copy = 1; /* default is to copy the data */
+ char *document_format = "text/plain";
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av,
+ "EP:#:C:DVJ:T:w:i:hplrstdgvcfmn1:2:3:4:")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_REQUIRED;
+ break;
+ case 'P':
+ printer = optarg;
+ break;
+ case '#':
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "copies", atoi(optarg));
+ break;
+ case 'C':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-class", optarg);
+ break;
+ case 'D':
+ dump = 1;
+ break;
+ case 'J':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-name", optarg);
+ break;
+ case 'T':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "pr-title", optarg);
+ break;
+ case 'p':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/x-pr");
+ papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL,
+ "pr-filter", 1);
+ break;
+ case 'i':
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "pr-indent", atoi(optarg));
+ break;
+ case 'w':
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL,
+ "pr-width", atoi(optarg));
+ break;
+ case 'h':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-sheets", "none");
+ break;
+ case 'l':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/octet-stream");
+ break;
+ case 'o':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/postscript");
+ break;
+ case 'c':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/x-cif");
+ break;
+ case 'd':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/x-dvi");
+ break;
+ case 'f':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/x-fortran");
+ break;
+ case 'g':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/x-plot");
+ break;
+ case 'n':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/x-ditroff");
+ break;
+ case 't':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/x-troff");
+ break;
+ case 'v':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", "application/x-raster");
+ break;
+ case 'm':
+ papiAttributeListAddBoolean(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-mail", 1);
+ break;
+ case 'r':
+ remove = 1;
+ break;
+ case 's':
+ copy = 0;
+ break;
+ case 'V': /* validate */
+ validate = 1;
+ break;
+ case '1':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-font-r", optarg);
+ break;
+ case '2':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-font-i", optarg);
+ break;
+ case '3':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-font-b", optarg);
+ break;
+ case '4':
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "rfc-1179-font-s", optarg);
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if ((printer == NULL) &&
+ ((printer = getenv("PRINTER")) == NULL) &&
+ ((printer = getenv("LPDEST")) == NULL))
+ printer = DEFAULT_DEST;
+
+ if (((optind + 1) == ac) && (strcmp(av[optind], "-") == 0))
+ optind = ac;
+
+ if (optind != ac) {
+ /* get the mime type of the file data */
+#ifdef MAGIC_MIME
+ magic_t ms;
+
+ if ((ms = magic_open(MAGIC_MIME)) != NULL) {
+ document_format = magic_file(ms, av[optind]);
+ magic_close(ms);
+ }
+#else
+ if (is_postscript(av[optind]) == 1)
+ document_format = "application/postscript";
+#endif
+ } else {
+ if (is_postscript_stream(0, prefetch, &prefetch_len) == 1)
+ document_format = "application/postscript";
+ }
+
+ papiAttributeListAddInteger(&list, PAPI_ATTR_EXCL, "copies", 1);
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "document-format", document_format);
+ papiAttributeListAddString(&list, PAPI_ATTR_EXCL,
+ "job-sheets", "standard");
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL, cli_auth_callback,
+ encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"), printer,
+ verbose_papi_message(svc, status));
+ exit(1);
+ }
+
+ if (validate == 1) /* validate the request can be processed */
+ status = papiJobValidate(svc, printer, list,
+ NULL, &av[optind], &job);
+ else if (optind == ac) /* no file list, use stdin */
+ status = jobSubmitSTDIN(svc, printer, prefetch, prefetch_len,
+ list, &job);
+ else if (copy == 0) /* reference the files in the job, default */
+ status = papiJobSubmitByReference(svc, printer, list,
+ NULL, &av[optind], &job);
+ else /* copy the files before return, -c */
+ status = papiJobSubmit(svc, printer, list,
+ NULL, &av[optind], &job);
+
+ papiAttributeListFree(list);
+
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext("%s: %s\n"), printer,
+ verbose_papi_message(svc, status));
+ papiJobFree(job);
+ papiServiceDestroy(svc);
+ exit(1);
+ }
+
+ if (dump != 0) {
+ list = papiJobGetAttributeList(job);
+ printf("job attributes:\n");
+ papiAttributeListPrint(stdout, list, "\t");
+ printf("\n");
+ }
+
+ papiJobFree(job);
+ papiServiceDestroy(svc);
+
+ return (exit_code);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/lprm.c b/usr/src/cmd/print/bsd-sysv-commands/lprm.c
new file mode 100644
index 0000000000..841a5da811
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/lprm.c
@@ -0,0 +1,101 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lprm.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout, gettext("Usage: %s [-P printer] (user|id ...)\n"),
+ name);
+ exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ char *printer = NULL;
+ int c;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av, "EP:")) != EOF)
+ switch (c) {
+ case 'E':
+ encryption = PAPI_ENCRYPT_REQUIRED;
+ break;
+ case 'P':
+ printer = optarg;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if ((printer == NULL) &&
+ ((printer = getenv("PRINTER")) == NULL) &&
+ ((printer = getenv("LPDEST")) == NULL))
+ printer = DEFAULT_DEST;
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL, cli_auth_callback,
+ encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ papiServiceDestroy(svc);
+ return (1);
+ }
+
+ berkeley_cancel_request(svc, stdout, printer,
+ ac - optind, &av[optind]);
+
+ papiServiceDestroy(svc);
+
+ return (0);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/lpstat.c b/usr/src/cmd/print/bsd-sysv-commands/lpstat.c
new file mode 100644
index 0000000000..6f666bcc03
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/lpstat.c
@@ -0,0 +1,1444 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lpstat.c 173 2006-05-25 04:52:06Z njacobs $ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <papi.h>
+#include <uri.h>
+#include "common.h"
+#include "lp.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout, gettext("Usage: %s [-d] [-r] [-s] [-t] [-a [list]] "
+ "[-c [list]] [-o [list] [-l]] [-R [list] [-l]] "
+ "[-p [list] [-D] [-l]] [-v [list]] [-S [list] [-l]] "
+ "[-f [list] [-l]] [-u list]\n"),
+ name);
+ exit(1);
+}
+
+static char *
+nctime(time_t *t)
+{
+ static char buf[64];
+ struct tm *tm = localtime(t);
+
+ (void) strftime(buf, sizeof (buf), "%c", tm);
+
+ return (buf);
+}
+
+static char *
+printer_name(papi_printer_t printer)
+{
+ papi_attribute_t **attributes = papiPrinterGetAttributeList(printer);
+ char *result = NULL;
+
+ if (attributes != NULL)
+ papiAttributeListGetString(attributes, NULL,
+ "printer-name", &result);
+
+ return (result);
+}
+
+static int
+lpstat_default_printer(papi_encryption_t encryption)
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_printer_t p = NULL;
+ char *name = NULL;
+
+ status = papiServiceCreate(&svc, NULL, NULL, NULL, cli_auth_callback,
+ encryption, NULL);
+ if (status == PAPI_OK) {
+ char *req[] = { "printer-name", NULL };
+
+ status = papiPrinterQuery(svc, DEFAULT_DEST, req, NULL, &p);
+ if (p != NULL)
+ name = printer_name(p);
+ }
+ if (name != NULL)
+ printf(gettext("system default printer: %s\n"), name);
+ else
+ printf(gettext("no system default destination\n"));
+ papiPrinterFree(p);
+ papiServiceDestroy(svc);
+
+ return (0);
+}
+
+static int
+lpstat_service_status(papi_encryption_t encryption)
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ char *name = NULL;
+
+ if (((name = getenv("PAPI_SERVICE_URI")) == NULL) &&
+ ((name = getenv("IPP_SERVER")) == NULL) &&
+ ((name = getenv("CUPS_SERVER")) == NULL))
+ name = DEFAULT_SERVICE_URI;
+
+ status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
+ encryption, NULL);
+ if (status != PAPI_OK) {
+ printf(gettext("scheduler is not running\n"));
+ } else
+ printf(gettext("scheduler is running\n"));
+ papiServiceDestroy(svc);
+
+ return (0);
+}
+
+static char *
+get_device_uri(papi_service_t svc, char *name)
+{
+ papi_status_t status;
+ papi_printer_t p = NULL;
+ char *keys[] = { "device-uri", NULL };
+ char *result = NULL;
+
+ status = papiPrinterQuery(svc, name, keys, NULL, &p);
+ if ((status == PAPI_OK) && (p != NULL)) {
+ papi_attribute_t **attrs = papiPrinterGetAttributeList(p);
+
+ (void) papiAttributeListGetString(attrs, NULL,
+ "device-uri", &result);
+ if (result != NULL)
+ result = strdup(result);
+
+ papiPrinterFree(p);
+ }
+
+ return (result);
+}
+
+static void
+print_description(papi_attribute_t **list, char *printer_name)
+{
+ char *str = "";
+
+ (void) papiAttributeListGetString(list, NULL,
+ "printer-info", &str);
+
+ /*
+ * If no printer-info is read then
+ * by default the printer-info is <printer-name>@<server>
+ */
+ if (str[0] == '\0') {
+ char *uri = NULL;
+ uri_t *u = NULL;
+
+ (void) papiAttributeListGetString(list, NULL,
+ "printer-uri-supported", &uri);
+
+ if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
+ char *nodename = localhostname();
+
+ if ((u->host == NULL) ||
+ (strcasecmp(u->host, "localhost") == 0) ||
+ (strcasecmp(u->host, nodename) == 0))
+ printf(gettext("\tDescription:\n"));
+ else
+ printf(gettext("\tDescription: %s@%s\n"),
+ printer_name, u->host);
+
+ uri_free(u);
+ } else
+ printf(gettext("\tDescription:\n"));
+ } else
+ printf(gettext("\tDescription: %s\n"), str);
+}
+
+static char *report_device_keys[] = { "printer-name", "printer-uri-supported",
+ NULL };
+/* ARGSUSED2 */
+static int
+report_device(papi_service_t svc, char *name, papi_printer_t printer,
+ int verbose, int description)
+{
+ papi_status_t status;
+ papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
+ char *uri = NULL;
+ char *device = NULL;
+ uri_t *u = NULL;
+
+ if (name == NULL) {
+ status = papiAttributeListGetString(attrs, NULL,
+ "printer-name", &name);
+ if (status != PAPI_OK)
+ status = papiAttributeListGetString(attrs, NULL,
+ "printer-uri-supported", &name);
+ }
+
+ if (name == NULL)
+ return (-1);
+
+ (void) papiAttributeListGetString(attrs, NULL,
+ "printer-uri-supported", &uri);
+
+ if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
+ char *nodename = localhostname();
+
+ if ((u->host == NULL) ||
+ (strcasecmp(u->host, "localhost") == 0) ||
+ (strcasecmp(u->host, nodename) == 0))
+ device = get_device_uri(svc, name);
+
+ if (device != NULL) {
+ printf(gettext("device for %s: %s\n"), name, device);
+ return (0);
+ } else if (uri != NULL) {
+ printf(gettext("system for %s: %s (as %s)\n"), name,
+ u->host?u->host:"localhost", uri);
+ return (0);
+ }
+
+ uri_free(u);
+ }
+
+ return (0);
+}
+
+static char *report_accepting_keys[] = { "printer-name",
+ "printer-uri-supported", "printer-is-accepting-jobs",
+ "printer-up-time", "printer-state-time",
+ "lpsched-reject-date", "lpsched-reject-reason", NULL };
+/* ARGSUSED2 */
+static int
+report_accepting(papi_service_t svc, char *name, papi_printer_t printer,
+ int verbose, int description)
+{
+ papi_status_t status;
+ papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
+ time_t curr;
+ char boolean = PAPI_FALSE;
+
+ if (name == NULL) {
+ status = papiAttributeListGetString(attrs, NULL,
+ "printer-name", &name);
+ if (status != PAPI_OK)
+ status = papiAttributeListGetString(attrs, NULL,
+ "printer-uri-supported", &name);
+ }
+ if (name == NULL)
+ return (-1);
+
+ (void) papiAttributeListGetBoolean(attrs, NULL,
+ "printer-is-accepting-jobs", &boolean);
+ (void) time(&curr);
+ (void) papiAttributeListGetDatetime(attrs, NULL,
+ "printer-up-time", &curr);
+ (void) papiAttributeListGetDatetime(attrs, NULL,
+ "printer-state-time", &curr);
+ (void) papiAttributeListGetDatetime(attrs, NULL,
+ "lpsched-reject-date", &curr);
+
+ if (boolean == PAPI_TRUE) {
+ printf(gettext("%s accepting requests since %s\n"),
+ name, nctime(&curr));
+ } else {
+ char *reason = "unknown reason";
+
+ (void) papiAttributeListGetString(attrs, NULL,
+ "lpsched-reject-reason", &reason);
+
+ printf(gettext("%s not accepting requests since %s\n\t%s\n"),
+ name, nctime(&curr), reason);
+ }
+
+ return (0);
+}
+
+static char *report_class_keys[] = { "printer-name", "printer-uri-supported",
+ "member-names", NULL };
+/* ARGSUSED2 */
+static int
+report_class(papi_service_t svc, char *name, papi_printer_t printer,
+ int verbose, int description)
+{
+ papi_status_t status;
+ papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
+ char *member = NULL;
+ void *iter = NULL;
+
+ status = papiAttributeListGetString(attrs, &iter,
+ "member-names", &member);
+ if (status == PAPI_NOT_FOUND) /* it's not a class */
+ return (0);
+
+ if (name == NULL) {
+ status = papiAttributeListGetString(attrs, NULL,
+ "printer-name", &name);
+ if (status != PAPI_OK)
+ status = papiAttributeListGetString(attrs, NULL,
+ "printer-uri-supported", &name);
+ }
+ if (name == NULL)
+ return (-1);
+
+ printf(gettext("members of class %s:\n\t%s\n"), name, member);
+ while (papiAttributeListGetString(attrs, &iter, NULL, &member)
+ == PAPI_OK)
+ printf("\t%s\n", member);
+
+ return (0);
+}
+
+static int
+get_remote_hostname(papi_attribute_t **attrs, char **host)
+{
+ char *uri = NULL;
+ uri_t *u;
+ char *nodename;
+
+ *host = NULL;
+ (void) papiAttributeListGetString(attrs, NULL,
+ "job-originating-host-name", host);
+ (void) papiAttributeListGetString(attrs, NULL,
+ "printer-uri-supported", &uri);
+ if (*host == NULL) {
+ if (uri != NULL) {
+ if (uri_from_string(uri, &u) == 0) {
+ if (u->host == NULL) {
+ uri_free(u);
+ return (0);
+ }
+ *host = strdup(u->host);
+ uri_free(u);
+ } else {
+ return (0);
+ }
+ } else {
+ return (0);
+ }
+ }
+ nodename = localhostname();
+ if ((strcasecmp(*host, "localhost") == 0) ||
+ (strcasecmp(*host, nodename) == 0)) {
+ return (0);
+ }
+ return (1);
+}
+
+static char *report_printer_keys[] = { "printer-name",
+ "printer-uri-supported", "printer-state",
+ "printer-up-time", "printer-state-time",
+ "lpsched-disable-date", "printer-state-reasons",
+ "lpsched-disable-reason", NULL };
+/* ARGSUSED2 */
+static int
+report_printer(papi_service_t svc, char *name, papi_printer_t printer,
+ int verbose, int description)
+{
+ papi_status_t status;
+ papi_attribute_t **attrs = papiPrinterGetAttributeList(printer);
+ time_t curr;
+ int32_t pstat = 0;
+ char *member = NULL;
+ papi_job_t *j = NULL;
+
+ status = papiAttributeListGetString(attrs, NULL,
+ "member-names", &member);
+ if (status == PAPI_OK) /* it's a class */
+ return (0);
+
+ if (name == NULL) {
+ status = papiAttributeListGetString(attrs, NULL,
+ "printer-name", &name);
+ if (status != PAPI_OK)
+ status = papiAttributeListGetString(attrs, NULL,
+ "printer-uri-supported", &name);
+ }
+ if (name == NULL)
+ return (-1);
+
+ printf(gettext("printer %s "), name);
+
+ status = papiAttributeListGetInteger(attrs, NULL,
+ "printer-state", &pstat);
+
+ switch (pstat) {
+ case 0x03: /* idle */
+ printf(gettext("is idle. enabled"));
+ break;
+ case 0x04: /* processing */
+ case 0x06: /* faulted printing */
+ status = papiPrinterListJobs(svc, name, NULL,
+ 0, 0, &j);
+
+ if (status == PAPI_OK) {
+ if (j != NULL) {
+ int i = 0;
+ int32_t jobid = 0;
+ int32_t jstate = 0;
+
+ for (i = 0; j[i] != NULL; ++i) {
+ papi_attribute_t **attr =
+ papiJobGetAttributeList(j[i]);
+
+ papiAttributeListGetInteger(attr,
+ NULL, "job-state", &jstate);
+ papiAttributeListGetInteger(attr,
+ NULL, "job-id", &jobid);
+ /*
+ * For lpd protocol "job-id-requested"
+ * should be read.
+ */
+ papiAttributeListGetInteger(attr,
+ NULL, "job-id-requested", &jobid);
+
+ /*
+ * When lpd protocol is used job-state
+ * cannot be retrieved, therefore
+ * job-state will be 0.
+ * When ipp protocol is used, the
+ * active/printing job-state will be
+ * RS_PRINTING (0x0008) post s10u5.
+ * For pre-s10u5 job-state will be
+ * RS_ACTIVE (0x05). So print only when
+ * the job-state is RS_PRINTING (0x0008)
+ * or RS_ACTIVE (0x05) or 0
+ */
+ if ((jstate == 0x0008) ||
+ (jstate == 0x05) ||
+ (jstate == 0)) {
+ if (pstat == 0x04)
+ printf(gettext
+ ("now printing"\
+ " %s-%d. enabled"),
+ name, jobid);
+ if (pstat == 0x06)
+ printf(gettext
+ ("faulted printing"\
+ " %s-%d. enabled"),
+ name, jobid);
+ break;
+ }
+ }
+ papiJobListFree(j);
+ }
+ }
+ break;
+ case 0x05: /* stopped */
+ printf(gettext("disabled"));
+ break;
+ case 0x07: /* faulted printer */
+ printf(gettext("faulted. enabled"));
+ break;
+ case 0x08: /* waiting for auto retry */
+ printf(gettext("waiting for auto-retry."));
+ break;
+ default:
+ printf(gettext("unknown state(0x%x)."), pstat);
+ break;
+ }
+
+ if (pstat == 0x08)
+ printf(gettext(" available.\n"));
+ else {
+ (void) time(&curr);
+ (void) papiAttributeListGetDatetime(attrs, NULL,
+ "printer-up-time", &curr);
+ (void) papiAttributeListGetDatetime(attrs, NULL,
+ "printer-state-time", &curr);
+ (void) papiAttributeListGetDatetime(attrs, NULL,
+ "lpsched-disable-date", &curr);
+ printf(gettext(" since %s. available.\n"), nctime(&curr));
+ }
+
+ if ((pstat == 0x05) ||
+ (pstat == 0x06) ||
+ (pstat == 0x07) ||
+ (pstat == 0x08)) {
+ char *reason = "unknown reason";
+
+ (void) papiAttributeListGetString(attrs, NULL,
+ "printer-state-reasons", &reason);
+ (void) papiAttributeListGetString(attrs, NULL,
+ "lpsched-disable-reason", &reason);
+ printf(gettext("\t%s\n"), reason);
+ }
+
+ if (verbose == 1) {
+ void *iter;
+ char *str;
+ char *host = NULL;
+
+ if ((get_remote_hostname(attrs, &host)) != 0) {
+ (void) printf(
+ gettext("\tRemote Name: %s\n\tRemote Server: "
+ "%s\n"), name, host);
+ free(host);
+ return (0);
+ }
+ str = "";
+ (void) papiAttributeListGetString(attrs, NULL,
+ "form-ready", &str);
+ printf(gettext("\tForm mounted: %s\n"), str);
+
+ str = "";
+ iter = NULL;
+ (void) papiAttributeListGetString(attrs, &iter,
+ "document-format-supported", &str);
+ printf(gettext("\tContent types: %s"), str);
+ while (papiAttributeListGetString(attrs, &iter, NULL, &str)
+ == PAPI_OK)
+ printf(", %s", str);
+ printf("\n");
+
+ /* Display the printer description */
+ print_description(attrs, name);
+
+ str = "";
+ iter = NULL;
+ (void) papiAttributeListGetString(attrs, &iter,
+ "lpsched-printer-type", &str);
+ printf(gettext("\tPrinter types: %s"), str);
+ while (papiAttributeListGetString(attrs, &iter, NULL, &str)
+ == PAPI_OK)
+ printf(", %s", str);
+ printf("\n");
+
+ str = "";
+ (void) papiAttributeListGetString(attrs, NULL,
+ "lpsched-dial-info", &str);
+ printf(gettext("\tConnection: %s\n"),
+ ((str[0] == '\0') ? gettext("direct") : str));
+
+ str = "";
+ (void) papiAttributeListGetString(attrs, NULL,
+ "lpsched-interface-script", &str);
+ printf(gettext("\tInterface: %s\n"), str);
+
+ str = NULL;
+ (void) papiAttributeListGetString(attrs, NULL,
+ "ppd-file-uri", &str);
+ (void) papiAttributeListGetString(attrs, NULL,
+ "lpsched-ppd-source-path", &str);
+ if (str != NULL)
+ printf(gettext("\tPPD: %s\n"), str);
+
+ str = NULL;
+ (void) papiAttributeListGetString(attrs, NULL,
+ "lpsched-fault-alert-command", &str);
+ if (str != NULL)
+ printf(gettext("\tOn fault: %s\n"), str);
+
+ str = "";
+ (void) papiAttributeListGetString(attrs, NULL,
+ "lpsched-fault-recovery", &str);
+ printf(gettext("\tAfter fault: %s\n"),
+ ((str[0] == '\0') ? gettext("continue") : str));
+
+ str = "(all)";
+ iter = NULL;
+ (void) papiAttributeListGetString(attrs, &iter,
+ "requesting-user-name-allowed", &str);
+ printf(gettext("\tUsers allowed:\n\t\t%s\n"),
+ ((str[0] == '\0') ? gettext("(none)") : str));
+ if ((str != NULL) && (str[0] != '\0'))
+ while (papiAttributeListGetString(attrs, &iter, NULL,
+ &str) == PAPI_OK)
+ printf("\t\t%s\n", str);
+
+ str = NULL;
+ iter = NULL;
+ (void) papiAttributeListGetString(attrs, &iter,
+ "requesting-user-name-denied", &str);
+ if (str != NULL) {
+ printf(gettext("\tUsers denied:\n\t\t%s\n"),
+ ((str[0] == '\0') ? gettext("(none)") : str));
+ if ((str != NULL) && (str[0] != '\0'))
+ while (papiAttributeListGetString(attrs, &iter,
+ NULL, &str) == PAPI_OK)
+ printf("\t\t%s\n", str);
+ }
+
+ str = "none";
+ iter = NULL;
+ (void) papiAttributeListGetString(attrs, &iter,
+ "form-supported", &str);
+ printf(gettext("\tForms allowed:\n\t\t(%s)\n"),
+ ((str[0] == '\0') ? gettext("none") : str));
+ if ((str != NULL) && (str[0] != '\0'))
+ while (papiAttributeListGetString(attrs, &iter, NULL,
+ &str) == PAPI_OK)
+ printf("\t\t(%s)\n", str);
+
+ str = "";
+ iter = NULL;
+ (void) papiAttributeListGetString(attrs, &iter,
+ "media-supported", &str);
+ printf(gettext("\tMedia supported:\n\t\t%s\n"),
+ ((str[0] == '\0') ? gettext("(none)") : str));
+ if ((str != NULL) && (str[0] != '\0'))
+ while (papiAttributeListGetString(attrs, &iter, NULL,
+ &str) == PAPI_OK)
+ printf("\t\t%s\n", str);
+
+ str = "";
+ (void) papiAttributeListGetString(attrs, NULL,
+ "job-sheets-supported", &str);
+ if ((strcasecmp(str, "none")) == 0)
+ str = gettext("page never printed");
+ else if (strcasecmp(str, "optional") == 0)
+ str = gettext("not required");
+ else
+ str = gettext("required");
+
+ printf(gettext("\tBanner %s\n"), str);
+
+
+ str = "";
+ iter = NULL;
+ (void) papiAttributeListGetString(attrs, &iter,
+ "lpsched-print-wheels", &str);
+ printf(gettext("\tCharacter sets:\n\t\t%s\n"),
+ ((str[0] == '\0') ? gettext("(none)") : str));
+ if ((str != NULL) && (str[0] != '\0'))
+ while (papiAttributeListGetString(attrs, &iter, NULL,
+ &str) == PAPI_OK)
+ printf("\t\t%s\n", str);
+
+ printf(gettext("\tDefault pitch:\n"));
+ printf(gettext("\tDefault page size:\n"));
+ printf(gettext("\tDefault port setting:\n"));
+
+ str = "";
+ iter = NULL;
+ (void) papiAttributeListGetString(attrs, &iter,
+ "lpsched-options", &str);
+ if (str != NULL) {
+ printf(gettext("\tOptions: %s"), str);
+ while (papiAttributeListGetString(attrs, &iter, NULL,
+ &str) == PAPI_OK)
+ printf(", %s", str);
+ printf("\n");
+ }
+
+ } else if (description == 1)
+ /* Display printer description */
+ print_description(attrs, name);
+ else if (verbose > 1)
+ papiAttributeListPrint(stdout, attrs, "\t");
+
+ if (verbose > 0)
+ printf("\n");
+
+ return (0);
+}
+
+static int
+printer_query(char *name, int (*report)(papi_service_t, char *, papi_printer_t,
+ int, int), papi_encryption_t encryption,
+ int verbose, int description)
+{
+ int result = 0, i = 0;
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ char **list = getlist(name, LP_WS, LP_SEP);
+
+ if (list == NULL) {
+ list = (char **)malloc(sizeof (char *));
+ list[0] = name;
+ }
+
+ /*
+ * The for loop executes once for every printer
+ * entry in list. If list is NULL that implies
+ * name is also NULL, the loop runs only one time.
+ */
+
+ for (i = 0; name == NULL || list[i] != NULL; i++) {
+ name = list[i];
+
+ status = papiServiceCreate(&svc, name, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ if (status != PAPI_OK) {
+ if (status == PAPI_NOT_FOUND)
+ fprintf(stderr,
+ gettext("%s: unknown printer\n"),
+ name ? name : "(NULL)");
+ else
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ name ? name : "(NULL)",
+ verbose_papi_message(svc, status));
+ papiServiceDestroy(svc);
+ result--;
+ continue;
+ }
+
+ if (name == NULL) { /* all */
+ char **interest = interest_list(svc);
+
+ if (interest != NULL) {
+ int i;
+
+ for (i = 0; interest[i] != NULL; i++)
+ result += printer_query(interest[i],
+ report, encryption, verbose,
+ description);
+ }
+ } else {
+ papi_printer_t printer = NULL;
+ char **keys = NULL;
+
+ /*
+ * Limit the query to only required data
+ * to reduce the need to go remote for
+ * information.
+ */
+ if (report == report_device)
+ keys = report_device_keys;
+ else if (report == report_class)
+ keys = report_class_keys;
+ else if (report == report_accepting)
+ keys = report_accepting_keys;
+ else if ((report == report_printer) && (verbose == 0))
+ keys = report_printer_keys;
+
+ status = papiPrinterQuery(svc, name, keys,
+ NULL, &printer);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to get printer info for %s: %s\n"),
+ name, verbose_papi_message(svc, status));
+ papiServiceDestroy(svc);
+ result--;
+ continue;
+ }
+
+ if (printer != NULL)
+ result += report(svc, name, printer, verbose,
+ description);
+
+ papiPrinterFree(printer);
+ }
+
+ papiServiceDestroy(svc);
+
+ if (name == NULL)
+ break;
+ }
+
+ freelist(list);
+
+ return (result);
+}
+
+static int
+match_user(char *user, char **list)
+{
+ int i;
+
+ for (i = 0; list[i] != NULL; i++) {
+ if (strcmp(user, list[i]) == 0)
+ return (0);
+ }
+
+ return (-1);
+}
+
+static char **users = NULL;
+
+static int
+report_job(char *printer, papi_job_t job, int show_rank, int verbose)
+{
+ papi_attribute_t **attrs = papiJobGetAttributeList(job);
+ time_t clock = 0;
+ char date[24];
+ char request[26];
+ char *user = "unknown";
+ char *host = NULL;
+ int32_t size = 0;
+ int32_t jstate = 0;
+ char User[50];
+
+ char *destination = "unknown";
+ int32_t id = -1;
+ static int check = 0;
+ static char *uri = NULL;
+ static char *puri = NULL; /* printer-uri */
+ static char *pname = NULL; /* printer-name */
+
+ (void) papiAttributeListGetString(attrs, NULL,
+ "job-originating-user-name", &user);
+
+ if ((users != NULL) && (match_user(user, users) < 0))
+ return (0);
+
+ (void) papiAttributeListGetString(attrs, NULL,
+ "job-originating-host-name", &host);
+
+ /*
+ * When lpstat is called for multiple printers
+ * internally the function 'report_job' gets
+ * called multiple times with different printer-names.
+ * The following block of code handles the case when lpstat is
+ * executed for multiple printers. In other words when 'report_job'
+ * is called multiple times for different printers for
+ * one lpstat command
+ * For e.g: lpstat printer1 printer2 printer3
+ */
+ if (pname == NULL) {
+ /*
+ * When lpstat is queried for the first time
+ * pname is NULL so this part of the code gets executed.
+ * Read the attribute "job-printer-uri"
+ * first time
+ */
+ (void) papiAttributeListGetString(attrs, NULL,
+ "job-printer-uri", &uri);
+
+ if (printer != NULL) {
+ /*
+ * Set pname to the printer that is being
+ * queried so that this can be used later
+ * if 'report_job' is called multiple times for
+ * different printers for one lpstat command
+ */
+ pname = printer;
+ }
+
+ if (uri != NULL) {
+ /*
+ * Set puri so that "job-printer-uri" corresponding
+ * to a particular printer can be used later when
+ * lpstat is queried for the same printer as
+ * "job-printer-uri" for a printer is read just once.
+ */
+ puri = strdup(uri);
+ }
+ } else {
+ /*
+ * This part of the code will get executed when
+ * 'report_job' is called more than once for the same
+ * lpstat command
+ */
+ if (printer != NULL) {
+ if (strcasecmp(pname, printer) != 0) {
+ /*
+ * Read the job-printer-uri as
+ * it will be different for
+ * different printers
+ */
+ uri = NULL;
+ (void) papiAttributeListGetString(attrs,
+ NULL, "job-printer-uri", &uri);
+ pname = printer;
+ if (uri != NULL)
+ puri = strdup(uri);
+ else
+ puri = NULL;
+ } else {
+ /*
+ * Same printer queried twice
+ * uri should be the same as
+ * already read in the previous call
+ * to 'report_job'.
+ * For the same printer 'job-printer-uri'
+ * is read just once because only in the
+ * first call it contains the host information
+ */
+ uri = puri;
+ }
+ }
+ }
+
+ if (host) {
+ /* Check if it is local printer or remote printer */
+ uri_t *u = NULL;
+
+ if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
+ char *nodename = localhostname();
+
+ if ((u->host == NULL) ||
+ (strcasecmp(u->host, "localhost") == 0) ||
+ (strcasecmp(u->host, nodename) == 0)) {
+
+ if (strcasecmp(host, nodename) == 0) {
+ /*
+ * Request submitted locally
+ * for the local queue.
+ * Hostname will not be displayed
+ */
+ snprintf(User, sizeof (User), "%s",
+ user);
+ }
+ else
+ snprintf(User, sizeof (User), "%s@%s",
+ user, host);
+ } else if (uri != NULL) {
+ /*
+ * It's a remote printer.
+ * In case of remote printers hostname is
+ * always displayed.
+ */
+ snprintf(User, sizeof (User), "%s@%s",
+ user, host);
+ }
+ uri_free(u);
+ } else {
+ /*
+ * If attribute "job-printer-uri"
+ * cannot be read
+ * by default append the hostname
+ */
+ snprintf(User, sizeof (User), "%s@%s", user, host);
+ }
+ } else {
+ /*
+ * When print server is s10u4 and ipp service is used
+ * "job-originating-hostname" attribute is not set
+ * So get the host information from the uri
+ */
+ uri_t *u = NULL;
+ if ((uri != NULL) && (uri_from_string(uri, &u) == 0)) {
+ if ((u != NULL) && (u->host != NULL))
+ snprintf(User, sizeof (User), "%s@%s",
+ user, u->host);
+ else
+ snprintf(User, sizeof (User), "%s", user);
+
+ uri_free(u);
+ } else
+ snprintf(User, sizeof (User), "%s", user);
+ }
+ (void) papiAttributeListGetInteger(attrs, NULL, "job-k-octets", &size);
+ size *= 1024; /* for the approximate byte size */
+ (void) papiAttributeListGetInteger(attrs, NULL, "job-octets", &size);
+
+ (void) time(&clock);
+ (void) papiAttributeListGetInteger(attrs, NULL,
+ "time-at-creation", (int32_t *)&clock);
+ (void) strftime(date, sizeof (date), "%b %d %R", localtime(&clock));
+
+ (void) papiAttributeListGetString(attrs, NULL,
+ "job-printer-uri", &destination);
+ (void) papiAttributeListGetString(attrs, NULL,
+ "printer-name", &destination);
+ (void) papiAttributeListGetInteger(attrs, NULL,
+ "job-id", &id);
+ (void) papiAttributeListGetInteger(attrs, NULL,
+ "job-id-requested", &id);
+
+
+ snprintf(request, sizeof (request), "%s-%d", printer, id);
+
+ if (show_rank != 0) {
+ int32_t rank = -1;
+
+ (void) papiAttributeListGetInteger(attrs, NULL,
+ "number-of-intervening-jobs", &rank);
+ rank++;
+
+ printf("%3d %-21s %-14s %7ld %s",
+ rank, request, User, size, date);
+ } else
+ printf("%-23s %-14s %7ld %s", request, User, size, date);
+
+ (void) papiAttributeListGetInteger(attrs, NULL,
+ "job-state", &jstate);
+
+ if (jstate == 0x0001)
+ printf(gettext(" being held"));
+ else if (jstate == 0x0800)
+ printf(gettext(" notifying user"));
+ else if (jstate == 0x0040)
+ printf(gettext(" cancelled"));
+ else if (jstate == 0x0010)
+ printf(gettext(" finished printing"));
+ else if (jstate == 0x0008)
+ printf(gettext(" on %s"), destination);
+ else if (jstate == 0x2000)
+ printf(gettext(" held by admin"));
+ else if (jstate == 0x0002)
+ printf(gettext(" being filtered"));
+ else if (jstate == 0x0004)
+ printf(gettext(" filtered"));
+ else if (jstate == 0x0020)
+ printf(gettext(" held for change"));
+
+ if (verbose == 1) {
+ char *form = NULL;
+
+ (void) papiAttributeListGetString(attrs, NULL,
+ "output-device-assigned", &destination);
+ printf("\n\t assigned %s", destination);
+
+ (void) papiAttributeListGetString(attrs, NULL, "form", &form);
+ if (form != NULL)
+ printf(", form %s", form);
+ } else if (verbose > 1) {
+ printf("\n");
+ papiAttributeListPrint(stdout, attrs, "\t");
+ }
+
+ printf("\n");
+
+ return (0);
+}
+
+static int
+job_query(char *request, int (*report)(char *, papi_job_t, int, int),
+ papi_encryption_t encryption, int show_rank, int verbose)
+{
+ int result = 0;
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ char *printer = request;
+ int32_t id = -1;
+ int flag1 = 0;
+ int flag = 1;
+ int print_flag = 0;
+
+ do {
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+
+ if ((status == PAPI_OK) && (printer != NULL))
+ print_flag = 1;
+
+ /* <name>-# printer name does not exist */
+ if (status != PAPI_OK) {
+ /*
+ * Check if <name>-# is a request-id
+ * Once this check is done flag1 is set
+ */
+ if (flag1 == 1)
+ break;
+
+ get_printer_id(printer, &printer, &id);
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ (printer ? printer : "all"),
+ verbose_papi_message(svc, status));
+ return (-1);
+ }
+ }
+
+ if (printer == NULL) { /* all */
+ char **interest = interest_list(svc);
+
+ if (interest != NULL) {
+ int i;
+
+ for (i = 0; interest[i] != NULL; i++)
+ result += job_query(interest[i], report,
+ encryption, show_rank, verbose);
+ }
+ } else if (id == -1) { /* a printer */
+ papi_job_t *jobs = NULL;
+
+ status = papiPrinterListJobs(svc, printer, NULL,
+ 0, 0, &jobs);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to get job list: %s\n"),
+ verbose_papi_message(svc, status));
+ papiServiceDestroy(svc);
+ return (-1);
+ }
+
+ if (jobs != NULL) {
+ int i;
+
+ for (i = 0; jobs[i] != NULL; i++)
+ result += report(printer,
+ jobs[i], show_rank,
+ verbose);
+ }
+
+ papiJobListFree(jobs);
+ } else { /* a job */
+ papi_job_t job = NULL;
+
+ /* Once a job has been found stop processing */
+ flag = 0;
+
+ /*
+ * Job-id could be the job-id requested
+ * Check if it is job-id or job-id-requested
+ */
+ id = job_to_be_queried(svc, printer, id);
+
+ if (id >= 0)
+ status = papiJobQuery(svc, printer, id,
+ NULL, &job);
+ else
+ /* id not found */
+ status = PAPI_NOT_FOUND;
+
+ if (status != PAPI_OK) {
+ if (!print_flag)
+ fprintf(stderr, gettext(
+ "Failed to get job"\
+ " info for %s: %s\n"),
+ request,
+ verbose_papi_message(svc, status));
+ papiServiceDestroy(svc);
+ return (-1);
+ }
+
+ if (job != NULL)
+ result = report(printer, job,
+ show_rank, verbose);
+
+ papiJobFree(job);
+ }
+
+ if (flag) {
+ id = -1;
+ get_printer_id(printer, &printer, &id);
+ if (id == -1)
+ flag = 0;
+ else
+ flag1 = 1;
+ }
+ } while (flag);
+
+ papiServiceDestroy(svc);
+
+ return (result);
+}
+
+static int
+report_form(char *name, papi_attribute_t **attrs, int verbose)
+{
+ papi_status_t status;
+ char *form = NULL;
+ void *iter = NULL;
+
+ for (status = papiAttributeListGetString(attrs, &iter,
+ "form-supported", &form);
+ status == PAPI_OK;
+ status = papiAttributeListGetString(attrs, &iter,
+ NULL, &form)) {
+ if ((name == NULL) || (strcmp(name, form) == 0)) {
+ printf(gettext("form %s is available to you\n"), form);
+ if (verbose != 0) {
+ char *detail = NULL;
+ status = papiAttributeListGetString(attrs, NULL,
+ "form-supported-detail", &detail);
+ if (status == PAPI_OK)
+ printf("%s\n", detail);
+ }
+ }
+ }
+
+ return (0);
+}
+
+static int
+report_print_wheels(char *name, papi_attribute_t **attrs, int verbose)
+{
+ papi_status_t status;
+ char *pw = NULL;
+ void *iter = NULL;
+
+ for (status = papiAttributeListGetString(attrs, &iter,
+ "pw-supported", &pw);
+ status == PAPI_OK;
+ status = papiAttributeListGetString(attrs, &iter, NULL, &pw)) {
+ if ((name == NULL) || (strcmp(name, pw) == 0)) {
+ printf(gettext("charset %s is available\n"), pw);
+ if (verbose != 0) {
+ char *info = NULL;
+ status = papiAttributeListGetString(attrs, NULL,
+ "pw-supported-extra", &info);
+ if (status == PAPI_OK)
+ printf("%s\n", info);
+ }
+ }
+ }
+
+ return (0);
+}
+
+static int
+service_query(char *name, int (*report)(char *, papi_attribute_t **, int),
+ papi_encryption_t encryption, int verbose)
+{
+ int result = 0;
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_attribute_t **attrs = NULL;
+
+ status = papiServiceCreate(&svc, name, NULL, NULL, cli_auth_callback,
+ encryption, NULL);
+ if (status != PAPI_OK) {
+ papiServiceDestroy(svc);
+ return (-1);
+ }
+
+ attrs = papiServiceGetAttributeList(svc);
+ if (attrs != NULL) {
+ result = report(name, attrs, verbose);
+
+ if (verbose > 1) {
+ printf("\n");
+ papiAttributeListPrint(stdout, attrs, "\t");
+ printf("\n");
+ }
+ }
+
+ papiServiceDestroy(svc);
+
+ return (result);
+}
+
+int
+main(int ac, char *av[])
+{
+ int exit_code = 0;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ int rank = 0;
+ int verbose = 0;
+ int description = 0;
+ int c;
+ char **argv;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ argv = (char **)calloc((ac + 1), sizeof (char *));
+ for (c = 0; c < ac; c++) {
+ if ((av[c][0] == '-') && (av[c][1] == 'l') &&
+ (isalpha(av[c][2]) != 0)) {
+ /* preserve old "-l[po...]" behavior */
+ argv[c] = &av[c][1];
+ argv[c][0] = '-';
+ verbose = 1;
+
+ } else
+ argv[c] = av[c];
+ }
+
+ argv[c++] = "--";
+ ac = c;
+
+ /* preprocess argument list looking for '-l' or '-R' so it can trail */
+ while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
+ switch (c) { /* these may or may not have an option */
+ case 'a':
+ case 'c':
+ case 'p':
+ case 'o':
+ case 'R':
+ case 'u':
+ case 'v':
+ case 'l':
+ case 'f':
+ case 'S':
+ if (optarg[0] == '-') {
+ /* this check stop a possible infinite loop */
+ if ((optind > 1) && (argv[optind-1][1] != c))
+ optind--;
+ optarg = NULL;
+ } else if (strcmp(optarg, "all") == 0)
+ optarg = NULL;
+ }
+
+ switch (c) {
+ case 'l':
+ if ((optarg == NULL) || (optarg[0] == '-'))
+ optarg = "1";
+ verbose = atoi(optarg);
+ break;
+ case 'D':
+ description = 1;
+ break;
+ case 'R':
+ rank = 1;
+ break;
+ case 'E':
+ encryption = PAPI_ENCRYPT_REQUIRED;
+ break;
+ default:
+ break;
+ }
+ }
+ optind = 1;
+
+ /* process command line arguments */
+ while ((c = getopt(ac, argv, "LEDf:S:stc:p:a:drs:v:l:o:R:u:")) != EOF) {
+ switch (c) { /* these may or may not have an option */
+ case 'a':
+ case 'c':
+ case 'p':
+ case 'o':
+ case 'R':
+ case 'u':
+ case 'v':
+ case 'l':
+ case 'f':
+ case 'S':
+ if (optarg[0] == '-') {
+ /* this check stop a possible infinite loop */
+ if ((optind > 1) && (argv[optind-1][1] != c))
+ optind--;
+ optarg = NULL;
+ } else if (strcmp(optarg, "all") == 0)
+ optarg = NULL;
+ }
+
+ switch (c) {
+ case 'a':
+ exit_code += printer_query(optarg, report_accepting,
+ encryption, verbose, 0);
+ break;
+ case 'c':
+ exit_code += printer_query(optarg, report_class,
+ encryption, verbose, 0);
+ break;
+ case 'p':
+ exit_code += printer_query(optarg, report_printer,
+ encryption, verbose, description);
+ break;
+ case 'd':
+ exit_code += lpstat_default_printer(encryption);
+ break;
+ case 'r':
+ exit_code += lpstat_service_status(encryption);
+ break;
+ case 'u':
+ if (optarg != NULL)
+ users = strsplit(optarg, ", \n");
+ exit_code += job_query(NULL, report_job,
+ encryption, rank, verbose);
+ if (users != NULL) {
+ free(users);
+ users = NULL;
+ }
+ break;
+ case 'v':
+ exit_code += printer_query(optarg, report_device,
+ encryption, verbose, 0);
+ break;
+ case 'R': /* set "rank" flag in first pass */
+ case 'o':
+ exit_code += job_query(optarg, report_job,
+ encryption, rank, verbose);
+ break;
+ case 'f':
+ exit_code += service_query(optarg, report_form,
+ encryption, verbose);
+ break;
+ case 'S':
+ exit_code += service_query(optarg, report_print_wheels,
+ encryption, verbose);
+ break;
+ case 's':
+ exit_code += lpstat_service_status(encryption);
+ exit_code += lpstat_default_printer(encryption);
+ exit_code += printer_query(NULL, report_class,
+ encryption, verbose, 0);
+ exit_code += printer_query(NULL, report_device,
+ encryption, verbose, 0);
+ exit_code += service_query(optarg, report_form,
+ encryption, verbose);
+ exit_code += service_query(optarg, report_print_wheels,
+ encryption, verbose);
+ break;
+ case 't':
+ exit_code += lpstat_service_status(encryption);
+ exit_code += lpstat_default_printer(encryption);
+ exit_code += printer_query(NULL, report_class,
+ encryption, verbose, 0);
+ exit_code += printer_query(NULL, report_device,
+ encryption, verbose, 0);
+ exit_code += printer_query(NULL, report_accepting,
+ encryption, verbose, 0);
+ exit_code += printer_query(NULL, report_printer,
+ encryption, verbose, 0);
+ exit_code += service_query(optarg, report_form,
+ encryption, verbose);
+ exit_code += service_query(optarg, report_print_wheels,
+ encryption, verbose);
+ exit_code += job_query(NULL, report_job,
+ encryption, rank, verbose);
+ break;
+ case 'L': /* local-only, ignored */
+ case 'l': /* increased verbose level in first pass */
+ case 'D': /* set "description" flag in first pass */
+ case 'E': /* set encryption in the first pass */
+ break;
+ default:
+ usage(av[0]);
+ }
+ }
+ ac--;
+
+ if (ac == 1) { /* report on my jobs */
+ struct passwd *pw = getpwuid(getuid());
+
+ if (pw != NULL)
+ users = strsplit(pw->pw_name, "");
+ exit_code += job_query(NULL, report_job, encryption,
+ rank, verbose);
+ if (users != NULL) {
+ free(users);
+ users = NULL;
+ }
+ } else {
+ for (c = optind; c < ac; c++)
+ exit_code += job_query(argv[c], report_job, encryption,
+ rank, verbose);
+ }
+
+
+ if (exit_code != 0)
+ exit_code = 1;
+
+ return (exit_code);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/reject.c b/usr/src/cmd/print/bsd-sysv-commands/reject.c
new file mode 100644
index 0000000000..2952bafba6
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/reject.c
@@ -0,0 +1,122 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: reject.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <papi.h>
+#include "common.h"
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stdout,
+ gettext("Usage: %s destination ...\n"),
+ name);
+ exit(1);
+}
+
+int
+main(int ac, char *av[])
+{
+ papi_status_t status;
+ papi_service_t svc = NULL;
+ papi_encryption_t encryption = PAPI_ENCRYPT_NEVER;
+ char *reason = NULL;
+ int exit_status = 0;
+ int c = 1;
+
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain("SUNW_OST_OSCMD");
+
+ while ((c = getopt(ac, av, "Er:")) != EOF)
+ switch (c) {
+ case 'r': /* reason */
+ reason = optarg;
+ break;
+ case 'E':
+ encryption = PAPI_ENCRYPT_ALWAYS;
+ break;
+ default:
+ usage(av[0]);
+ }
+
+ if (ac <= optind)
+ usage(av[0]);
+
+ while (optind < ac) {
+ char *printer = av[optind++];
+
+ status = papiServiceCreate(&svc, printer, NULL, NULL,
+ cli_auth_callback, encryption, NULL);
+ if (status != PAPI_OK) {
+ fprintf(stderr, gettext(
+ "Failed to contact service for %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ exit_status = 1;
+ }
+
+ status = papiPrinterPause(svc, printer, reason);
+ if (status == PAPI_OK) {
+ printf(gettext(
+ "Destination \"%s\" will no longer "
+ "accept requests\n"), printer);
+ } else if (status == PAPI_NOT_ACCEPTING) {
+ fprintf(stderr, gettext(
+ "Destination \"%s\" was already not "
+ "accepting requests.\n"), printer);
+ exit_status = 1;
+ } else {
+ /* The operation is not supported in lpd protocol */
+ if (status == PAPI_OPERATION_NOT_SUPPORTED) {
+ fprintf(stderr,
+ verbose_papi_message(svc, status));
+ } else {
+ fprintf(stderr, gettext("reject: %s: %s\n"),
+ printer, verbose_papi_message(svc, status));
+ }
+ exit_status = 1;
+ }
+
+ papiServiceDestroy(svc);
+ }
+
+ return (exit_status);
+}
diff --git a/usr/src/cmd/print/bsd-sysv-commands/rfc1179.xml b/usr/src/cmd/print/bsd-sysv-commands/rfc1179.xml
new file mode 100644
index 0000000000..b6783bca28
--- /dev/null
+++ b/usr/src/cmd/print/bsd-sysv-commands/rfc1179.xml
@@ -0,0 +1,110 @@
+<?xml version='1.0'?>
+<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
+
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWpsr:rfc1179'>
+
+<service
+ name='application/print/rfc1179'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <restarter>
+ <service_fmri value='svc:/network/inetd:default' />
+ </restarter>
+
+ <dependency
+ name='lpsched'
+ grouping='require_all'
+ restart_on='refresh'
+ type='service'>
+ <service_fmri value='svc:/application/print/server' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='inetd_start'
+ exec='/usr/lib/print/in.lpd -u lp -d /var/run/in.lpd'
+ timeout_seconds='0'>
+ <method_context>
+ <method_credential user='root' group='lp' />
+ </method_context>
+ </exec_method>
+
+
+ <exec_method
+ type='method'
+ name='inetd_disable'
+ exec=':kill'
+ timeout_seconds='0'>
+ </exec_method>
+
+ <property_group name='inetd' type='framework'>
+ <stability value='Evolving' />
+ <propval name='endpoint_type' type='astring' value='stream' />
+ <propval name='name' type='astring' value='printer' />
+ <propval name='wait' type='boolean' value='false' />
+ <propval name='isrpc' type='boolean' value='false' />
+ <propval name='proto' type='astring' value='tcp6' />
+ </property_group>
+
+ <property_group name='general' type='framework'>
+ <!-- to start/stop rfc1179 listening -->
+ <propval name='action_authorization' type='astring'
+ value='solaris.print.admin' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.print.admin' />
+ </property_group>
+
+ <property_group name='firewall_context' type='com.sun,fw_definition'>
+ <propval name='ipf_method' type='astring'
+ value='/lib/svc/method/print-svc ipfilter svc:/application/print/server:default' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ BSD print protocol adapter
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='in.lpd' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/print/conv_fix/Makefile b/usr/src/cmd/print/conv_fix/Makefile
new file mode 100644
index 0000000000..cac80619e0
--- /dev/null
+++ b/usr/src/cmd/print/conv_fix/Makefile
@@ -0,0 +1,69 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/client/conv_fix/Makefile
+#
+
+include ../Makefile.sp
+
+PROG= conv_fix
+
+SRCS= $(PROG).c
+
+OBJS= $(SRCS:.c=.o)
+
+ROOTLIBPRINTPROG= $(PROG:%=$(ROOTLIBPRINT)/%)
+
+FILEMODE= 0555
+
+CPPFLAGS += -I$(NPRTINC)
+
+CERRWARN += -_gcc=-Wno-implicit-function-declaration
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTLIBPRINTPROG)
+
+$(ROOTLIBPRINT)/%: %
+ $(INS.file)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint:
+ $(LINT.c) $(PROG).c $(LDLIBS)
+
+cstyle:
+ cstyle $(SRCS)
+
+_msg:
+ @echo "Messages are made in usr/src/cmd/print"
+
+clean:
+ $(RM) $(OBJS)
+
+clobber: clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
diff --git a/usr/src/cmd/print/conv_fix/conv_fix.c b/usr/src/cmd/print/conv_fix/conv_fix.c
new file mode 100644
index 0000000000..2833b106bb
--- /dev/null
+++ b/usr/src/cmd/print/conv_fix/conv_fix.c
@@ -0,0 +1,149 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <errno.h>
+
+extern char *optarg;
+
+/*
+ * FUNCTION:
+ * static char *_file_getline(FILE *fp)
+ * INPUT:
+ * FILE *fp - file pointer to read from
+ * OUTPUT:
+ * char *(return) - an entry from the stream
+ * DESCRIPTION:
+ * This routine will read in a line at a time. If the line ends in a
+ * newline, it returns. If the line ends in a backslash newline, it
+ * continues reading more. It will ignore lines that start in # or
+ * blank lines.
+ */
+static char *
+_file_getline(FILE *fp)
+{
+ char entry[BUFSIZ], *tmp;
+ int size;
+
+ size = sizeof (entry);
+ tmp = entry;
+
+ /* find an entry */
+ while (fgets(tmp, size, fp)) {
+ if ((tmp == entry) && ((*tmp == '#') || (*tmp == '\n'))) {
+ continue;
+ } else {
+ if ((*tmp == '#') || (*tmp == '\n')) {
+ *tmp = NULL;
+ break;
+ }
+
+ size -= strlen(tmp);
+ tmp += strlen(tmp);
+
+ if (*(tmp-2) != '\\')
+ break;
+
+ size -= 2;
+ tmp -= 2;
+ }
+ }
+
+ if (tmp == entry)
+ return (NULL);
+ else
+ return (strdup(entry));
+}
+
+int
+main(int ac, char *av[])
+{
+ int c;
+ char file[80], ofile[80];
+ char *cp;
+ FILE *fp, *fp2;
+
+ (void) setlocale(LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ while ((c = getopt(ac, av, "f:o:")) != EOF)
+
+ switch (c) {
+ case 'f':
+ (void) strlcpy(file, optarg, sizeof (file));
+ break;
+ case 'o':
+ (void) strlcpy(ofile, optarg, sizeof (ofile));
+ break;
+ default:
+ (void) fprintf(stderr, gettext(
+ "Usage: %s [-f file] [-o output file]\n"),
+ av[0]);
+ return (1);
+ }
+
+ if ((fp = fopen(file, "r")) != NULL) {
+ int fd;
+
+ fd = open(ofile, O_RDWR|O_APPEND);
+ if ((fd < 0) && (errno == ENOENT))
+ fd = open(ofile, O_RDWR|O_CREAT|O_EXCL, 0644);
+
+ if (fd < 0) {
+ (void) fprintf(stderr,
+ gettext("Error trying to open file.\n"));
+ return (1);
+ }
+
+ lseek(fd, 0, SEEK_END);
+
+ if ((fp2 = fdopen(fd, "a")) != NULL) {
+ while ((cp = _file_getline(fp)) != NULL) {
+ (void) fprintf(fp2, "%s", cp);
+ }
+ return (0);
+ } else {
+ (void) fprintf(stderr,
+ gettext("Error trying to open file.\n"));
+ return (1);
+ }
+ } else {
+ (void) fprintf(stderr,
+ gettext("Error trying to open file.\n"));
+ return (1);
+ }
+}
diff --git a/usr/src/cmd/print/lpget/Makefile b/usr/src/cmd/print/lpget/Makefile
new file mode 100644
index 0000000000..db4d15b2b1
--- /dev/null
+++ b/usr/src/cmd/print/lpget/Makefile
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/client/lpget/Makefile
+#
+
+include ../Makefile.sp
+
+PROG= lpget
+
+SRCS= $(PROG).c
+
+OBJS= $(SRCS:.c=.o)
+
+ROOTBINPROG= $(PROG:%=$(ROOTBIN)/%)
+
+FILEMODE= 0511
+
+CPPFLAGS += -I$(NPRTINC)
+LDLIBS += $(LIBNPRT)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTBIN) $(ROOTBINPROG)
+
+$(ROOTBIN):
+ $(INS.dir)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint:
+ $(LINT.c) $(PROG).c $(LDLIBS)
+
+cstyle:
+ cstyle $(SRCS)
+
+_msg:
+ @echo "Messages are made in usr/src/cmd/print"
+
+clean:
+ $(RM) $(OBJS)
+
+clobber: clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
diff --git a/usr/src/cmd/print/lpget/lpget.c b/usr/src/cmd/print/lpget/lpget.c
new file mode 100644
index 0000000000..5c19480ae1
--- /dev/null
+++ b/usr/src/cmd/print/lpget/lpget.c
@@ -0,0 +1,174 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <locale.h>
+#ifndef SUNOS_4
+#include <libintl.h>
+#endif
+
+#include <ns.h>
+#include <list.h>
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+extern char *getenv(const char *);
+
+
+static void
+Usage(char *name)
+{
+ (void) fprintf(stderr,
+ gettext("Usage: %s [-k key] [list|(printer) ...]\n"),
+ name);
+ exit(1);
+}
+
+static int
+display_kvp(char *key, char *value)
+{
+ int rc = -1;
+
+ if (value != NULL) {
+ rc = 0;
+ (void) printf("\n\t%s=%s", key, value);
+ } else
+ (void) printf(gettext("\n\t%s - undefined"), key);
+
+ return (rc);
+}
+
+
+static int
+display_value(ns_printer_t *printer, char *name, char **keys)
+{
+ int rc = -1;
+
+ if (printer != NULL) {
+ rc = 0;
+ (void) printf("%s:", name);
+ if (keys != NULL) {
+ while (*keys != NULL) {
+ char *string = ns_get_value_string(*keys,
+ printer);
+ rc += display_kvp(*keys, string);
+ keys++;
+ }
+ } else {
+ ns_kvp_t **list = printer->attributes;
+
+ for (list = printer->attributes;
+ (list != NULL && *list != NULL); list++) {
+ char *string;
+ if (((*list)->key[0] == '\t') ||
+ ((*list)->key[0] == ' '))
+ continue;
+
+ string = ns_get_value_string((*list)->key,
+ printer);
+ rc += display_kvp((*list)->key, string);
+ }
+ }
+ (void) printf("\n");
+ } else
+ (void) printf(gettext("%s: Not Found\n"), name);
+
+ return (rc);
+}
+
+
+/*
+ * main() calls the appropriate routine to parse the command line arguments
+ * and then calls the local remove routine, followed by the remote remove
+ * routine to remove jobs.
+ */
+int
+main(int ac, char *av[])
+{
+ char *program;
+ int c;
+ char **keys = NULL;
+ char *ns = NULL;
+ int exit_code = 0;
+
+ (void) setlocale(LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ if ((program = strrchr(av[0], '/')) == NULL)
+ program = av[0];
+ else
+ program++;
+
+ openlog(program, LOG_PID, LOG_LPR);
+ while ((c = getopt(ac, av, "k:t:n:")) != EOF)
+ switch (c) {
+ case 'k':
+ case 't':
+ keys = (char **)list_append((void **)keys,
+ (void *)optarg);
+ break;
+ case 'n':
+ ns = optarg;
+ break;
+ default:
+ Usage(program);
+ }
+
+ if (optind >= ac)
+ Usage(program);
+
+ ns = normalize_ns_name(ns);
+
+ while (optind < ac) {
+ char *name = av[optind++];
+
+ if (strcmp(name, "list") == 0) {
+ ns_printer_t **printers = ns_printer_get_list(ns);
+
+ while (printers != NULL && *printers != NULL) {
+ exit_code += display_value(*printers,
+ (*printers)->name, keys);
+ printers++;
+ }
+ } else
+ exit_code = display_value(ns_printer_get_name(name, ns),
+ name, keys);
+
+
+ }
+ return (exit_code);
+}
diff --git a/usr/src/cmd/print/lpset/Makefile b/usr/src/cmd/print/lpset/Makefile
new file mode 100644
index 0000000000..7b81c117b2
--- /dev/null
+++ b/usr/src/cmd/print/lpset/Makefile
@@ -0,0 +1,69 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/lp/client/lpset/Makefile
+#
+
+include ../Makefile.sp
+
+PROG= lpset
+
+SRCS= $(PROG).c
+
+OBJS= $(SRCS:.c=.o)
+
+ROOTBINPROG= $(PROG:%=$(ROOTBIN)/%)
+
+FILEMODE= 04511
+
+CPPFLAGS += -I$(NPRTINC)
+CERRWARN += -_gcc=-Wno-implicit-function-declaration
+LDLIBS += $(LIBNPRT) -lsecdb
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTBIN) $(ROOTBINPROG)
+
+$(ROOTBIN):
+ $(INS.dir)
+
+strip:
+ $(STRIP) $(PROG)
+
+lint:
+ $(LINT.c) $(PROG).c $(LDLIBS)
+
+cstyle:
+ cstyle $(SRCS)
+
+_msg:
+ @echo "Messages are made in usr/src/cmd/print"
+
+clean:
+ $(RM) $(OBJS)
+
+clobber: clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
diff --git a/usr/src/cmd/print/lpset/lpset.c b/usr/src/cmd/print/lpset/lpset.c
new file mode 100644
index 0000000000..6cb6b05a8a
--- /dev/null
+++ b/usr/src/cmd/print/lpset/lpset.c
@@ -0,0 +1,544 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <syslog.h>
+#include <errno.h>
+#include <locale.h>
+#ifndef SUNOS_4
+#include <libintl.h>
+#endif
+#include <pwd.h>
+#include <alloca.h>
+
+#include <ns.h>
+#include <list.h>
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+extern char *getenv(const char *);
+
+static void _decode_ldapResult(int result, char *printerName);
+
+static int
+authorized()
+{
+ struct passwd *pw;
+ uid_t uid;
+ gid_t *list;
+ int len;
+ int maxgrp;
+
+ if ((uid = getuid()) == 0)
+ return (1); /* "root" is authorized */
+
+ if (((pw = getpwnam("lp")) != NULL) && (uid == pw->pw_uid))
+ return (1); /* "lp" is authorized */
+
+ if ((pw = getpwuid(uid)) == NULL)
+ return (0); /* intruders are not authorized */
+
+ if (chkauthattr("solaris.print.admin", pw->pw_name) == 1)
+ return (1); /* "solaris.print.admin" is authorized */
+
+ /* How many supplemental groups do we have? */
+ maxgrp = getgroups(0, NULL);
+ list = alloca(maxgrp * sizeof (gid_t));
+
+ if ((len = getgroups(maxgrp, list)) != -1)
+ while (len-- > 0)
+ if (list[len] == 14)
+ return (1); /* group 14 is authorized */
+
+ return (0); /* nobody else is authorized */
+}
+
+static void
+Usage(char *name)
+{
+ (void) fprintf(stderr,
+ gettext("Usage: %s [-n files | ldap] [-x] "
+ "[-h ldaphost] [-D binddn] [-w passwd] "
+ "[-a key=value] [-d key] (printer)\n"),
+ name);
+ exit(1);
+}
+
+
+/*
+ * main() calls the appropriate routine to parse the command line arguments
+ * and then calls the local remove routine, followed by the remote remove
+ * routine to remove jobs.
+ */
+int
+main(int ac, char *av[])
+{
+ int result = 0;
+ int delete_printer = 0;
+ int c;
+ char *program = NULL,
+ *printer = NULL,
+ *host = NULL,
+ *binddn = NULL,
+ *passwd = NULL,
+ *ins = NULL,
+ *ons = "files";
+ char **changes = NULL;
+ ns_cred_t *cred = NULL;
+ ns_printer_t *printer_obj = NULL;
+
+ (void) setlocale(LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ if ((program = strrchr(av[0], '/')) == NULL)
+ program = av[0];
+ else
+ program++;
+
+ openlog(program, LOG_PID, LOG_LPR);
+
+ if (ac < 2)
+ Usage(program);
+
+ while ((c = getopt(ac, av, "a:d:D:h:n:r:w:x")) != EOF)
+ switch (c) {
+ case 'd':
+ if (strchr(optarg, '=') != NULL)
+ Usage(program);
+ /* FALLTHRU */
+ case 'a':
+ changes = (char **)list_append((void**)changes,
+ (void *)strdup(optarg));
+ break;
+ case 'D':
+ binddn = optarg;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'n':
+ ons = optarg;
+ break;
+ case 'r':
+ ins = optarg;
+ break;
+ case 'w':
+ passwd = optarg;
+ break;
+ case 'x':
+ delete_printer++;
+ break;
+ default:
+ Usage(program);
+ }
+
+ if (optind != ac-1)
+ Usage(program);
+
+ /*
+ * Check required options have been given: [ -x | [ -a | -d ]]
+ */
+ if ((changes == NULL) && (delete_printer == 0)) {
+ Usage(program);
+ }
+
+ printer = av[optind];
+
+ if (strchr(printer, ':') != NULL) {
+ (void) fprintf(stderr, gettext(
+ "POSIX-Style names are not valid destinations (%s)\n"),
+ printer);
+ return (1);
+ }
+
+ ins = normalize_ns_name(ins);
+ ons = normalize_ns_name(ons);
+ if (ins == NULL)
+ ins = ons;
+
+ /* check / set the name service for writing */
+ if (strcasecmp("user", ons) == 0) {
+ (void) setuid(getuid());
+ ons = "user";
+ } else if (strcasecmp("files", ons) == 0) {
+ if (authorized() == 0) {
+ (void) fprintf(stderr, gettext(
+ "Permission denied: not authorized\n"));
+ return (1);
+ }
+ ons = "files";
+ } else if (strcasecmp("ldap", ons) == 0) {
+ if ((cred = calloc(1, sizeof (*cred))) == NULL) {
+ (void) fprintf(stderr,
+ gettext("could not initialize credential\n"));
+ return (1);
+ }
+
+ if (binddn == NULL) {
+ (void) fprintf(stderr,
+ gettext("Distinguished Name is required.\n"));
+ return (1);
+ }
+
+ if (passwd == NULL) {
+ passwd = getpassphrase(gettext("Bind Password:"));
+ }
+
+ /*
+ * Setup LDAP bind credentials, so that it uses
+ * the default ldap port, and the NS domain for this
+ * ldapclient box. Note: passwdType is currently not
+ * used but once the ldap native function can select
+ * secure or insure password it will pass the user selected
+ * security type.
+ */
+ cred->passwd = passwd;
+ cred->passwdType = NS_PW_INSECURE; /* use default */
+ cred->binddn = binddn;
+ cred->host = host;
+ cred->port = 0; /* use default */
+ cred->domainDN = NULL; /* use default */
+
+ ons = "ldap";
+ (void) setuid(getuid());
+ } else {
+ (void) fprintf(stderr,
+ gettext("%s is not a supported name service.\n"),
+ ons);
+ return (1);
+ }
+
+ if (strcasecmp(NS_SVC_LDAP, ons) != 0) {
+
+ /* Naming Service is not LDAP */
+
+ /* get the printer object */
+ if ((printer_obj = ns_printer_get_name(printer, ins)) == NULL) {
+ if (delete_printer != 0) {
+ (void) fprintf(stderr, gettext
+ ("%s: unknown printer\n"), printer);
+ return (1);
+ }
+ if ((printer_obj = calloc(1, sizeof (*printer_obj)))
+ == NULL) {
+ (void) fprintf(stderr, gettext(
+ "could not initialize printer object\n"));
+ return (1);
+ }
+ printer_obj->name = strdup(printer);
+ }
+
+ printer_obj->source = ons;
+
+ if (cred != NULL) {
+ printer_obj->cred = cred;
+ }
+
+ /* make the changes to it */
+ while (changes != NULL && *changes != NULL) {
+ int has_equals = (strchr(*changes, '=') != NULL);
+ char *p, *key = NULL, *value = NULL;
+
+ key = *(changes++);
+
+ for (p = key; ((p != NULL) && (*p != NULL)); p++)
+ if (*p == '=') {
+ *p = NULL;
+ value = ++p;
+ break;
+ } else if (*p == '\\')
+ p++;
+
+ if ((value != NULL) && (*value == NULL))
+ value = NULL;
+
+ if ((key != NULL) && (key[0] != NULL)) {
+ if ((value == NULL) &&
+ (ns_get_value(key, printer_obj) == NULL) &&
+ (has_equals == 0)) {
+ fprintf(stderr,
+ gettext("%s: unknown attribute\n"),
+ key);
+ result = 1;
+ } else
+ (void) ns_set_value_from_string(key, value,
+ printer_obj);
+ }
+ }
+ if (delete_printer != 0)
+ printer_obj->attributes = NULL;
+
+ /* write it back */
+ if (ns_printer_put(printer_obj) != 0) {
+ (void) fprintf(stderr,
+ gettext("Failed to write into %s database\n"),
+ ons);
+ result = 1;
+ }
+ }
+
+ else {
+ /*
+ * Naming Service is LDAP
+ *
+ * Action the request by calling ns ldap functions to
+ * add, modify or delete the printer object.
+ */
+
+ if ((printer_obj = calloc(1, sizeof (*printer_obj))) == NULL) {
+ (void) fprintf(stderr, gettext(
+ "could not initialize printer object\n"));
+ return (1);
+ }
+
+ if ((cred != NULL) && (printer_obj != NULL)) {
+ printer_obj->name = strdup(printer);
+ printer_obj->cred = cred;
+ printer_obj->cred->domainDN = NULL; /* use default */
+ printer_obj->source = ons;
+ printer_obj->nsdata = malloc(sizeof (NS_LDAPDATA));
+
+ if (printer_obj->nsdata != NULL) {
+ /*
+ * Update the LDAP directory for this printer
+ */
+
+ if (delete_printer != 0) {
+ /* Delete the printer object */
+ ((NS_LDAPDATA *)
+ (printer_obj->nsdata))->attrList
+ = NULL;
+ } else {
+ /* Add or modify the printer object */
+ ((NS_LDAPDATA *)
+ (printer_obj->nsdata))->attrList =
+ changes;
+ }
+
+ result = ns_printer_put(printer_obj);
+ if (result != 0) {
+ /* display LDAP specific message */
+ _decode_ldapResult(result, printer);
+
+ (void) fprintf(stderr, gettext(
+ "Failed to update %s database\n"), ons);
+ result = 1;
+ }
+
+ free(printer_obj->nsdata);
+ }
+
+ else {
+ _decode_ldapResult(NSL_ERR_MEMORY, NULL);
+ result = 1;
+ }
+ }
+
+ else {
+ result = 1;
+ (void) fprintf(stderr,
+ gettext("Error - no LDAP credentials\n"));
+ }
+
+ if (printer_obj != NULL) {
+ if (printer_obj->name != NULL) {
+ free(printer_obj->name);
+ }
+ free(printer_obj);
+ }
+
+ }
+
+ return (result);
+} /* main */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _decode_ldapResult()
+ *
+ * Description: Decode the ldap_put_printer specific error codes and display
+ * the appropriate error message.
+ *
+ * Parameters:
+ * Input: int result - contains the NSL_RESULT codes
+ * char *printerName - name of printer
+ * Output: None
+ *
+ * Returns: void
+ *
+ * *****************************************************************************
+ */
+
+static void
+_decode_ldapResult(int result, char *printerName)
+
+{
+ NSL_RESULT lresult = (NSL_RESULT)result;
+
+ /* ------------- */
+
+ switch (lresult)
+ {
+ case NSL_OK:
+ {
+ break;
+ }
+
+ case NSL_ERR_INTERNAL:
+ {
+ (void) fprintf(stderr,
+ gettext("Unexpected software error\n"));
+ break;
+ }
+
+ case NSL_ERR_ADD_FAILED:
+ {
+ (void) fprintf(stderr, "%s %s\n",
+ gettext("Failed to add printer:"), printerName);
+ break;
+ }
+
+ case NSL_ERR_MOD_FAILED:
+ {
+ (void) fprintf(stderr, "%s %s\n",
+ gettext("Failed to modify printer:"),
+ printerName);
+ break;
+ }
+
+ case NSL_ERR_DEL_FAILED:
+ {
+ (void) fprintf(stderr, "%s %s\n",
+ gettext("Failed to delete printer:"),
+ printerName);
+ break;
+ }
+
+
+ case NSL_ERR_UNKNOWN_PRINTER:
+ {
+ (void) fprintf(stderr, "%s %s\n",
+ gettext("Unknown printer:"), printerName);
+ break;
+ }
+
+ case NSL_ERR_CREDENTIALS:
+ {
+ (void) fprintf(stderr, "%s\n",
+ gettext("Missing LDAP credential information for printer:"));
+ break;
+ }
+
+ case NSL_ERR_CONNECT:
+ {
+ (void) fprintf(stderr, "%s\n",
+ gettext("Failed to connect to LDAP server"));
+ break;
+ }
+
+ case NSL_ERR_BIND:
+ {
+ (void) fprintf(stderr, gettext("LDAP bind failed\n"));
+ break;
+ }
+
+ case NSL_ERR_RENAME:
+ {
+ (void) fprintf(stderr, "%s %s\n",
+ gettext("Object rename not allowed for printer:"),
+ printerName);
+ break;
+ }
+
+ case NSL_ERR_KVP:
+ {
+ (void) fprintf(stderr, "%s",
+ gettext("Setting sun-printer-kvp attribute is "
+ "not supported through this command.\n"));
+ break;
+ }
+
+ case NSL_ERR_BSDADDR:
+ {
+ (void) fprintf(stderr, "%s",
+ gettext("Setting sun-printer-bsdaddr attribute is "
+ "not supported through this command.\n"
+ "Use the bsaddr attribute instead.\n"));
+ break;
+ }
+
+ case NSL_ERR_PNAME:
+ {
+ (void) fprintf(stderr, "%s",
+ gettext("Setting printer-name attribute is "
+ "not supported through this command.\n"));
+ break;
+ }
+
+ case NSL_ERR_MEMORY:
+ {
+ (void) fprintf(stderr,
+ gettext("Memory allocation error\n"));
+ break;
+ }
+
+ case NSL_ERR_MULTIOP:
+ {
+ (void) fprintf(stderr,
+ gettext("Delete and add operation on the "
+ "same key attribute is not allowed\n"));
+ break;
+ }
+
+ case NSL_ERR_NOTALLOWED:
+ {
+ (void) fprintf(stderr,
+ gettext("KVP attribute is not allowed\n"));
+ break;
+ }
+
+ default:
+ {
+ (void) fprintf(stderr,
+ gettext("Error code = %d\n"), result);
+ break;
+ }
+ }
+
+} /* _decode_ldapResult */
diff --git a/usr/src/cmd/print/ppdmgr/Makefile b/usr/src/cmd/print/ppdmgr/Makefile
new file mode 100644
index 0000000000..ab8f07b46e
--- /dev/null
+++ b/usr/src/cmd/print/ppdmgr/Makefile
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+MANIFEST= ppd-cache-update.xml
+SVCMETHOD= ppd-cache-update
+
+include ../Makefile.sp
+
+ROOTMANIFESTDIR= $(ROOTSVCAPPLICATIONPRINT)
+$(ROOTMANIFEST):= FILEMODE= 444
+
+ROOTVARLP= $(ROOTVAR)/lp
+ROOTVARLPPPD= $(ROOTVARLP)/ppd
+ROOTVARLPPPDCACHES= $(ROOTVARLPPPD)/caches
+
+$(ROOTVARLP):= DIRMODE= 775
+
+.KEEP_STATE:
+
+all:
+install: $(ROOTMANIFEST) $(ROOTSVCMETHOD) \
+ $(ROOTVARLP) $(ROOTVARLPPPD) $(ROOTVARLPPPDCACHES)
+check: $(CHKMANIFEST)
+clean:
+clobber:
+lint:
+
+$(ROOTVARLP) $(ROOTVARLPPPD) $(ROOTVARLPPPDCACHES):
+ $(INS.dir)
+
+include $(SRC)/cmd/Makefile.targ
diff --git a/usr/src/cmd/print/ppdmgr/ppd-cache-update b/usr/src/cmd/print/ppdmgr/ppd-cache-update
new file mode 100644
index 0000000000..585f747c3f
--- /dev/null
+++ b/usr/src/cmd/print/ppdmgr/ppd-cache-update
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+. /lib/svc/share/smf_include.sh
+
+case "$1" in
+'start')
+ if [ -x /usr/sbin/ppdmgr ] ; then
+ /usr/sbin/ppdmgr -u -R all -L all
+ fi
+ ;;
+*)
+ echo "Usage: $0 start"
+ exit 1
+ ;;
+esac
+exit $SMF_EXIT_OK
diff --git a/usr/src/cmd/print/ppdmgr/ppd-cache-update.xml b/usr/src/cmd/print/ppdmgr/ppd-cache-update.xml
new file mode 100644
index 0000000000..67ade9b999
--- /dev/null
+++ b/usr/src/cmd/print/ppdmgr/ppd-cache-update.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+-->
+<!--
+ Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ ident "%Z%%M% %I% %E% SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+-->
+
+<service_bundle type='manifest' name='SUNWppm:ppd-cache-update'>
+
+<service
+ name='application/print/ppd-cache-update'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <single_instance />
+
+ <!--
+ This service writes to/reads from /tmp, /var, and /usr.
+ -->
+ <dependency
+ name='filesystem'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/filesystem/minimal' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/ppd-cache-update start'
+ timeout_seconds='0'>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':true'
+ timeout_seconds='3'>
+ </exec_method>
+
+ <property_group name='startd' type='framework'>
+ <propval name='duration' type='astring' value='transient' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ ppd cache update
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='ppdmgr' section='1M'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/cmd/print/printer-info/Makefile b/usr/src/cmd/print/printer-info/Makefile
new file mode 100644
index 0000000000..1aed6ba8f5
--- /dev/null
+++ b/usr/src/cmd/print/printer-info/Makefile
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.sp
+
+ROOTLIBLPBIN = $(ROOTLIBLP)/bin
+
+PROG = printer-info
+SRCS = $(PROG).c
+OBJECTS = $(PROG).o
+
+ROOTPROG= $(PROG:%=$(ROOTLIBLPBIN)/%)
+$(ROOTPROG) := FILEMODE=555
+
+CERRWARN += -_gcc=-Wno-implicit-function-declaration
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(ROOTLIBLPBIN):
+ $(INS.dir)
+
+$(ROOTLIBLPBIN)/%: %
+ $(INS.file)
+
+install: all $(ROOTLIBLPBIN) $(ROOTPROG)
+
+$(PROGRAM): $(OBJECTS)
+ $(CC) $(CFLAGS) -o $@ $(OBJECTS)
+
+clean:
+ $(RM) $(PROG) *.o
+
+cstyle:
+ cstyle $(SRCS)
+
+clobber: clean
+
+strip lint:
+
+
+
+
+
+
diff --git a/usr/src/cmd/print/printer-info/printer-info.c b/usr/src/cmd/print/printer-info/printer-info.c
new file mode 100644
index 0000000000..a469c5194d
--- /dev/null
+++ b/usr/src/cmd/print/printer-info/printer-info.c
@@ -0,0 +1,196 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/prnio.h>
+#include <fcntl.h>
+
+#define COMMAND_SET_MAX 16 /* more than 16 command sets is not likely */
+#define NP(x) (x ? x : "")
+
+typedef struct {
+ char *manufacturer;
+ char *model;
+ char *description;
+ char *class;
+ char *command_set[COMMAND_SET_MAX];
+} printer_description_t;
+
+int
+get_printer_description(char *path, printer_description_t *info)
+{
+ int fd, rc;
+ struct prn_1284_device_id id;
+ char buf[BUFSIZ];
+ char *s, *iter = NULL;
+
+ /* open the device */
+ if ((fd = open(path, O_RDWR)) < 0)
+ return (fd);
+
+ /* get the 1284 device id */
+ memset(&id, 0, sizeof (id));
+ memset(&buf, 0, sizeof (buf));
+ id.id_len = sizeof (buf);
+ id.id_data = buf;
+
+ rc = ioctl(fd, PRNIOC_GET_1284_DEVID, &id);
+ /* close(fd); */
+ if (rc < 0)
+ return (rc);
+
+ memset(info, 0, sizeof (*info));
+
+ /* parse the 1284 device id string */
+ for (s = (char *)strtok_r(buf, ";\n", &iter); s != NULL;
+ s = (char *)strtok_r(NULL, ";\n", &iter)) {
+ char *t, *u, *iter2 = NULL;
+
+ if ((t = (char *)strtok_r(s, ":\n", &iter2)) == NULL)
+ continue;
+
+ if ((u = (char *)strtok_r(NULL, ":\n", &iter2)) == NULL)
+ continue;
+
+ if ((strcasecmp(t, "MFG") == 0) ||
+ (strcasecmp(t, "MANUFACTURER") == 0))
+ info->manufacturer = strdup(u);
+ else if ((strcasecmp(t, "MDL") == 0) ||
+ (strcasecmp(t, "MODEL") == 0))
+ info->model = strdup(u);
+ else if ((strcasecmp(t, "DES") == 0) ||
+ (strcasecmp(t, "DESCRIPTION") == 0))
+ info->description = strdup(u);
+ else if ((strcasecmp(t, "CLS") == 0) ||
+ (strcasecmp(t, "CLASS") == 0))
+ info->class = strdup(u);
+ else if ((strcasecmp(t, "CMD") == 0) ||
+ (strcasecmp(t, "COMMAND SET") == 0)) {
+ /* this should be more dynamic, I got lazy */
+ char *v, *iter3 = NULL;
+ int i = 0;
+
+ for (v = (char *)strtok_r(u, ",\n", &iter3);
+ ((v != NULL) && (i < COMMAND_SET_MAX));
+ v = (char *)strtok_r(NULL, ",\n", &iter3))
+ info->command_set[i++] = strdup(v);
+ }
+ }
+
+ return (0);
+}
+
+static void
+usage(char *name)
+{
+ char *program;
+
+ if ((program = strrchr(name, '/')) == NULL)
+ program = name;
+ else
+ program++;
+
+ printf("Usage: %s [-aMmdCc] (path) ...\n", program);
+}
+
+int
+main(int ac, char *av[])
+{
+ int rc;
+ int manufacturer = 0, model = 0, description = 0, command_set = 0,
+ class = 0;
+
+ while ((rc = getopt(ac, av, "aMmdCc")) != EOF)
+ switch (rc) {
+ case 'a':
+ manufacturer++;
+ model++;
+ description++;
+ command_set++;
+ class++;
+ break;
+ case 'M':
+ manufacturer++;
+ break;
+ case 'm':
+ model++;
+ break;
+ case 'd':
+ description++;
+ break;
+ case 'C':
+ command_set++;
+ break;
+ case 'c':
+ class++;
+ break;
+ default:
+ usage(av[0]);
+ exit(1);
+ }
+
+ if (optind >= ac) {
+ usage(av[0]);
+ exit(1);
+ }
+
+ while (optind < ac) {
+ char *path = av[optind++];
+ printer_description_t info;
+
+ rc = get_printer_description(path, &info);
+ if (rc == 0) {
+ printf("%s:\n", path);
+ if (manufacturer != 0)
+ printf("\tManufacturer: %s\n",
+ NP(info.manufacturer));
+ if (model != 0)
+ printf("\tModel: %s\n",
+ NP(info.model));
+ if (description != 0)
+ printf("\tDescription: %s\n",
+ NP(info.description));
+ if (class != 0)
+ printf("\tClass: %s\n",
+ NP(info.class));
+ if (command_set != 0) {
+ int i;
+
+ printf("\tCommand set:\n");
+ for (i = 0; info.command_set[i] != NULL; i++)
+ printf("\t\tcmd[%d]: %s\n", i,
+ info.command_set[i]);
+ }
+ } else
+ perror(path);
+ }
+ return (rc);
+}
diff --git a/usr/src/cmd/print/printmgr/Makefile b/usr/src/cmd/print/printmgr/Makefile
new file mode 100644
index 0000000000..ef82fd7feb
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/Makefile
@@ -0,0 +1,87 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Makefile for print manager
+#
+PROG = pmserver.jar pmclient.jar
+
+include $(SRC)/cmd/Makefile.cmd
+
+SUBDIRS = com bin
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+ROOTDIRS = $(ROOT)/usr/sadm/admin \
+ $(ROOT)/usr/sadm/admin/printmgr \
+ $(ROOT)/usr/sadm/admin/printmgr/classes
+
+ROOTBIN = $(ROOT)/usr/sadm/admin/printmgr/classes
+ROOTBINPROG = $(PROG:%=$(ROOTBIN)/%)
+
+$(ROOTBINPROG):= FILEMODE = 644
+
+.KEEP_STATE:
+
+all: $(SUBDIRS)
+install: $(SUBDIRS) $(ROOTDIRS) $(ROOTBINPROG) .WAIT links
+
+links:
+ $(RM) $(ROOTUSRSBIN)/printmgr
+ $(SYMLINK) ../../usr/sadm/admin/bin/printmgr \
+ $(ROOTUSRSBIN)/printmgr
+
+clean clobber: $(SUBDIRS)
+ -$(RM) $(PROG)
+
+lint _msg: $(SUBDIRS)
+
+strip:
+
+$(PROG): FRC
+ @if [ $@ = "pmclient.jar" ]; \
+ then $(JAR) cf $@ \
+ com/sun/admin/pm/client/*class \
+ com/sun/admin/pm/client/images/*gif 2>/dev/null; \
+ else $(JAR) cf $@ \
+ com/sun/admin/pm/server/*class 2>/dev/null; \
+ fi
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+$(ROOTDIRS):
+ $(INS.dir)
+
+$(ROOTBIN)/%: %
+ $(INS.file)
+
+FRC:
diff --git a/usr/src/cmd/print/printmgr/bin/Makefile b/usr/src/cmd/print/printmgr/bin/Makefile
new file mode 100644
index 0000000000..2964b6306f
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/bin/Makefile
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Makefile for print manager wrapper script
+#
+include $(SRC)/cmd/Makefile.cmd
+
+PROG = printmgr
+
+ROOTBIN = $(ROOT)/usr/sadm/admin/bin
+
+ROOTBINPROG = $(PROG:%=$(ROOTBIN)/%)
+
+ROOTDIRS = $(ROOT)/usr/sadm/admin \
+ $(ROOT)/usr/sadm/admin/bin
+
+.KEEP_STATE:
+
+all: $(PROG)
+install: all $(ROOTDIRS) $(ROOTBINPROG)
+
+$(ROOTBIN)/%: %
+ $(INS.file)
+
+$(ROOTDIRS):
+ $(INS.dir)
+
+lint strip _msg:
+
+clean clobber:
+ -$(RM) $(PROG)
diff --git a/usr/src/cmd/print/printmgr/bin/printmgr.sh b/usr/src/cmd/print/printmgr/bin/printmgr.sh
new file mode 100644
index 0000000000..c12d71cd86
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/bin/printmgr.sh
@@ -0,0 +1,38 @@
+#! /usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+PMDIR="/usr/sadm/admin/printmgr"
+CLSDIR="${PMDIR}/classes"
+L10NDIR="/usr/share/lib/locale"
+
+CLASSPATH="${L10NDIR}:${CLSDIR}/pmclient.jar:${CLSDIR}/pmserver.jar"
+LD_LIBRARY_PATH="${PMDIR}/lib"
+
+export CLASSPATH LD_LIBRARY_PATH
+
+exec /usr/java/bin/java com.sun.admin.pm.client.pmTop $1
diff --git a/usr/src/cmd/print/printmgr/com/Makefile b/usr/src/cmd/print/printmgr/com/Makefile
new file mode 100644
index 0000000000..78a71dc67e
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/Makefile
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# Makefile for print manager
+#
+include $(SRC)/cmd/Makefile.cmd
+
+SUBDIRS = sun
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+all install clean clobber lint _msg: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/print/printmgr/com/sun/Makefile b/usr/src/cmd/print/printmgr/com/sun/Makefile
new file mode 100644
index 0000000000..9bfd4551f3
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/Makefile
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# Makefile for print manager
+#
+include $(SRC)/cmd/Makefile.cmd
+
+SUBDIRS = admin
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+all install clean clobber lint _msg: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/Makefile b/usr/src/cmd/print/printmgr/com/sun/admin/Makefile
new file mode 100644
index 0000000000..08b0c55bec
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/Makefile
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# Makefile for print manager
+#
+include $(SRC)/cmd/Makefile.cmd
+
+SUBDIRS = pm
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+all install clean clobber lint _msg: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/Makefile b/usr/src/cmd/print/printmgr/com/sun/admin/pm/Makefile
new file mode 100644
index 0000000000..efbf6fee75
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/Makefile
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# Makefile for print manager
+#
+include $(SRC)/cmd/Makefile.cmd
+
+SUBDIRS = server client
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+_msg := TARGET= _msg
+
+all install clean clobber lint _msg: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/BST.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/BST.java
new file mode 100644
index 0000000000..5bdd31d333
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/BST.java
@@ -0,0 +1,327 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * BST.java
+ * Simple binary search tree implementation for help articles
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+import java.util.*;
+import com.sun.admin.pm.server.*;
+
+
+public class BST extends Object {
+
+ // these should be protected...
+ public BST left = null;
+ public BST right = null;
+ public BST parent = null;
+ public BSTItem data;
+
+ static public int comparisons;
+
+ public BST(BSTItem theItem) {
+ // Debug.info("HELP: New BST(" + theItem + ")");
+
+ left = right = null;
+ data = theItem;
+ }
+
+
+ public BST() {
+ this(new BSTItem("", null));
+ }
+
+ public BST insert(String key, Object data) {
+ return insert(new BSTItem(key, data));
+ }
+
+
+ // normal bst insertion
+ public BST insert(BSTItem theItem) {
+
+ int comp = data.compare(theItem);
+ BST node = null;
+
+ if (comp == 0) {
+ Debug.info("HELP: Duplicate insert: " +
+ theItem.toString());
+ } else if (comp > 0) {
+ if (left != null)
+ left.insert(theItem);
+ else
+ left = node = new BST(theItem);
+ } else if (comp < 0) {
+ if (right != null)
+ right.insert(theItem);
+ else
+ right = node = new BST(theItem);
+ }
+
+ return node;
+ }
+
+
+ public BST find_tree(String newKey) {
+ return find_tree(newKey, true);
+ }
+
+ public BSTItem find(String newKey) {
+ return find(newKey, true);
+ }
+
+
+ public BST find_tree(String newKey, boolean exactMatch) {
+ /*
+ * Debug.info("HELP: Finding " +(exactMatch ? "exact " : "partial ") +
+ * newKey);
+ */
+
+ BST rv = null;
+ int comp = data.compare(newKey, exactMatch);
+
+ ++comparisons;
+
+ if (comp > 0) {
+ if (left != null)
+ rv = left.find_tree(newKey, exactMatch);
+ } else if (comp < 0) {
+ if (right != null)
+ rv = right.find_tree(newKey, exactMatch);
+ } else {
+ rv = this;
+ // Debug.info("HELP: Found " + newKey + " in " + data);
+ }
+
+ return rv;
+ }
+
+ public BSTItem find(String newKey, boolean exactMatch) {
+ Debug.info("HELP: Finding " +(exactMatch ? "exact " : "partial ") +
+ newKey);
+
+ BSTItem rv = null;
+ int comp = data.compare(newKey, exactMatch);
+
+ ++comparisons;
+
+ if (comp > 0) {
+ if (left != null)
+ rv = left.find(newKey, exactMatch);
+ } else if (comp < 0) {
+ if (right != null)
+ rv = right.find(newKey, exactMatch);
+ } else {
+ Debug.info("HELP: Found " + newKey + " in " + data);
+ rv = this.data;
+ }
+
+ return rv;
+ }
+
+
+
+ public void traverse() {
+ if (left != null)
+ left.traverse();
+ Debug.info("HELP: Traverse: " + data);
+ if (right != null)
+ right.traverse();
+ }
+
+ public void traverse_right() {
+ Debug.info("HELP: Traverse: " + data);
+ if (right != null)
+ right.traverse();
+ }
+
+
+ public void traverse_find(String key) {
+ if (left != null)
+ left.traverse_find(key);
+ if (data.compare(key, false) < 0)
+ return;
+ Debug.info("HELP: Traverse_find: " + data.key);
+ if (right != null)
+ right.traverse_find(key);
+ }
+
+ // empty search string is a wildcard...
+ public void traverse_find_vector(Vector v, String key) {
+ /*
+ * Debug.info("HELP: traverse_find_vector: node " +
+ * data.key + "[" +(left!=null?left.data.key:"null") + "]" +
+ * "[" +(right!=null ?right.data.key:"null") + "]" +
+ * " seeking " + key);
+ */
+ int c = 0;
+
+ if (key.length() > 0)
+ c = data.compare(key, false);
+
+ /*
+ * Debug.info("HELP: traverse_find_vector: compare " +
+ * data.key + " to "+ key + " = " + c);
+ */
+
+ if (c >= 0 && left != null)
+ left.traverse_find_vector(v, key);
+
+ if (c == 0) {
+ // Debug.info("HELP: traverse_find_vector: adding " + data.key);
+ v.addElement(data.data);
+ }
+
+ if (c <= 0) {
+ if (right != null)
+ right.traverse_find_vector(v, key);
+ }
+ }
+
+
+ public void dump() {
+ Debug.info("HELP: \nDump: this = " + data.key);
+
+ if (left != null)
+ Debug.info("HELP: Dump: left = " + left.data.key);
+ else
+ Debug.info("HELP: Dump: left = null");
+
+
+ if (right != null)
+ Debug.info("HELP: Dump: right = " + right.data.key);
+ else
+ Debug.info("HELP: Dump: right = null");
+
+ if (left != null)
+ left.dump();
+ if (right != null)
+ right.dump();
+
+ }
+
+ public static void main(String args[]) {
+ BSTItem root = new BSTItem("Root");
+ BSTItem a = new BSTItem("Alpha");
+ BSTItem b = new BSTItem("Bravo");
+ BSTItem c = new BSTItem("Charlie");
+ BSTItem d = new BSTItem("Delta");
+ BSTItem e = new BSTItem("Echo");
+ BSTItem x = new BSTItem("Xray");
+ BSTItem aa = new BSTItem("aspect");
+ BSTItem ab = new BSTItem("assess");
+ BSTItem ad = new BSTItem("assist");
+ BSTItem ae = new BSTItem("asphalt");
+ BSTItem af = new BSTItem("asap");
+ BSTItem ag = new BSTItem("adroit");
+ BSTItem ah = new BSTItem("adept");
+ BSTItem ai = new BSTItem("asdf");
+
+ BST bst = new BST(root);
+
+ BST.comparisons = 0;
+ bst.insert(a);
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ BST.comparisons = 0;
+ bst.insert(x);
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ BST.comparisons = 0;
+ bst.insert(e);
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ BST.comparisons = 0;
+ bst.insert(c);
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ BST.comparisons = 0;
+ bst.insert(b);
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ BST.comparisons = 0;
+ bst.insert(d);
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+
+ bst.insert(aa);
+ bst.insert(ab);
+ bst.insert(ad);
+ bst.insert(ae);
+ bst.insert(af);
+ bst.insert(ag);
+ bst.insert(ah);
+ bst.insert(ai);
+
+ bst.traverse();
+
+ BST.comparisons = 0;
+ bst.find("Echo");
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ BST.comparisons = 0;
+ bst.find("Xray");
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ BST.comparisons = 0;
+ bst.find("Delta");
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ BST.comparisons = 0;
+ bst.find("Root");
+ System.out.println(BST.comparisons +
+ " comparisons\n");
+ bst.find("Alpha");
+
+ bst.dump();
+ if (bst.left != null)
+ bst.left.dump();
+ if (bst.right != null)
+ bst.right.dump();
+
+ {
+ Debug.info("HELP: Looking for a");
+ BST result = bst.find_tree("a", false);
+ result.traverse_find("a");
+
+ Debug.info("HELP: Looking for as");
+ result = result.find_tree("as", false);
+ result.traverse_find("as");
+
+ Debug.info("HELP: Looking for ass");
+ result = result.find_tree("ass", false);
+ result.traverse_find("ass");
+
+ Debug.info("HELP: Looking for ad");
+ result = bst.find_tree("ad", false);
+ result.traverse_find("ad");
+ }
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/BSTItem.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/BSTItem.java
new file mode 100644
index 0000000000..0ad3b5f8fe
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/BSTItem.java
@@ -0,0 +1,109 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * BSTItem.java
+ * Simple binary search tree implementation for help articles
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+import com.sun.admin.pm.server.*;
+
+public class BSTItem extends Object {
+ public String key;
+ public Object data;
+ public int handle = UNINITIALIZED;
+
+ static int serial = 0;
+ static final int UNINITIALIZED = -1;
+
+ public BSTItem(String newKey) {
+ this(newKey, null);
+ }
+
+ public BSTItem(String newKey, Object obj) {
+ key = newKey.toLowerCase();
+ data = obj;
+ handle = serial++;
+ }
+
+ public String toString() {
+ return new String("Item " + key + " (" + handle + ")");
+ }
+
+ public int compare(BSTItem otherItem, boolean exact) {
+
+ return compare(otherItem.key, exact);
+ }
+
+
+ public int compare(BSTItem otherItem) {
+ return compare(otherItem, true);
+ }
+
+ public int compare(String otherKey) {
+ return compare(otherKey, true);
+ }
+
+
+ public int compare(String otherKey, boolean exact) {
+
+ /*
+ * System.out.println(this.toString() + " comparing " +
+ * (exact ? "exact" : "partial") + " to " + otherKey);
+ */
+
+ int rv = 0;
+
+ if (otherKey != null && otherKey != "")
+ rv = exact ?
+ key.compareTo(otherKey) :
+ compareSub(otherKey.toLowerCase());
+
+ /*
+ * System.out.println(
+ * "Compare: " + key + " to " + otherKey + " -> " + rv);
+ */
+
+ return rv;
+ }
+
+
+ public int compareSub(String s) {
+ Debug.info("HELP: compareSub: " + key + " to " + s);
+
+ int rv = 0;
+ try {
+ rv = key.substring(0, s.length()).compareTo(s);
+ } catch (Exception x) {
+ Debug.info("HELP: compareSub caught: " + x);
+ rv = -1;
+ }
+ return rv;
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/Constants.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/Constants.java
new file mode 100644
index 0000000000..12ffe37f5d
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/Constants.java
@@ -0,0 +1,75 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Comment which describes the contents of this file.
+ *
+ * Constants.java
+ * Common constants for Printer Manager
+ */
+
+package com.sun.admin.pm.client;
+
+/*
+ * pmConstants.java
+ * defines constants used with print manager
+ */
+
+public interface Constants
+{
+ // Buttons
+ int OK = 1;
+ int APPLY = 2;
+ int RESET = 3;
+ int CANCEL = 4;
+ int HELP = 5;
+
+ // Buttons for user access list
+ int ADD = 6;
+ int DELETE = 7;
+
+ // Printer type to add/modify
+ int ADDLOCAL = 1;
+ int ADDNETWORK = 2;
+ int MODIFYATTACHED = 3;
+ int MODIFYREMOTE = 4;
+ int MODIFYNETWORK = 5;
+
+ // Printer connection types
+ int ATTACHED = 1;
+ int NETWORK = 2;
+
+ // Useful Constants
+ int MAXPNAMELEN = 20;
+
+ // Combo Listener
+ int PORT = 1;
+ int TYPE = 2;
+ int MAKE = 3;
+ int MODEL = 4;
+ int PPD = 5;
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/Makefile b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/Makefile
new file mode 100644
index 0000000000..f80827be30
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/Makefile
@@ -0,0 +1,144 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Makefile for Java Print Manager client
+#
+include $(SRC)/Makefile.master
+include $(SRC)/cmd/Makefile.cmd
+
+
+CLASSPATH= $(SRC)/cmd/print/printmgr
+
+CLASSFILES = Constants.class \
+ pmAuthOptions.class \
+ pmHelpFrame.class \
+ pmTop.class \
+ pmResources.class \
+ pmCopyright.class \
+ pmUtility.class \
+ pmCalls.class \
+ pmLoad.class \
+ pmDelete.class \
+ pmAccess.class \
+ pmButtonScreen.class \
+ pmInstallScreen.class \
+ pmInstallPrinter.class \
+ pmOKCancelDialog.class \
+ pmMessageDialog.class \
+ pmLogin.class \
+ pmLogDisplay.class \
+ pmHelpDetailPanel.class \
+ pmHelpContent.class \
+ pmHelpController.class \
+ pmHelpDetailPanel.class \
+ pmHelpIndexPanel.class \
+ pmHelpItem.class \
+ pmHelpRepository.class \
+ pmHelpSearchPanel.class \
+ BST.class \
+ BSTItem.class \
+ pmGuiException.class \
+ pmHelpException.class \
+ pmAddAccessFailedException.class \
+ pmAddPrinterFailedException.class \
+ pmIncompleteFormException.class \
+ pmLoginFailedException.class \
+ pmModifyPrinterFailedException.class \
+ pmPrinterExistsException.class \
+ pmDeleteFailedException.class \
+ pmMustBeRemoteServerException.class \
+ pmUserCancelledException.class \
+ pmNullSelectedPrinterException.class \
+ pmNeedPPDCacheException.class \
+ pmCacheMissingPPDException.class \
+ pmFindFrame.class \
+ pmAboutBox.class \
+ pmFrame.class \
+ pmButton.class \
+ pmTextField.class \
+ pmAuthOptions.class \
+ pmOther.class
+
+JAVAFILES = $(CLASSFILES:.class=.java)
+
+MSGDIRS = $(ROOT)/usr/share/lib/locale \
+ $(ROOT)/usr/share/lib/locale/com \
+ $(ROOT)/usr/share/lib/locale/com/sun \
+ $(ROOT)/usr/share/lib/locale/com/sun/admin \
+ $(ROOT)/usr/share/lib/locale/com/sun/admin/pm \
+ $(ROOT)/usr/share/lib/locale/com/sun/admin/pm/client
+
+MSGDIR = $(ROOT)/usr/share/lib/locale/com/sun/admin/pm/client
+MSGJAVAFILES = pmResources.java pmHelpResources.java
+MSGFILES = $(MSGJAVAFILES:%=$(MSGDIR)/%)
+
+$(MSGFILES):= FILEMODE = 644
+
+CLEANFILES= *.class pmHelpResources.java pmCopyright.java \
+ helptools/*.class helptools/parsehelp
+CLOBBERFILES=
+
+#
+# raw-text help files
+#
+HELPFILES= ./raw-help/*.rawhlp
+
+#
+# text file containing comments to be bound into the help resource bundle
+#
+HELP_COMMENTS=./help-l10n-comments.txt
+
+install all: pmCopyright.java $(CLASSFILES) help
+
+pmCopyright.java: pm_gen_copyright
+ $(SH) ./pm_gen_copyright
+
+#
+# pmHelpResources.java is generated by parsing raw help text
+#
+pmHelpResources.java: $(HELP_COMMENTS) \
+ $$(HELPFILES) \
+ helptools/parseMain.class \
+ helptools/parsehelp
+ $(RM) pmHelpResources.*
+ helptools/parsehelp -C $(HELP_COMMENTS) -D $(CLASSPATH) \
+ -J $(JAVA_ROOT) $(HELPFILES)
+
+help: pmHelpResources.class
+
+_msg: $(MSGDIRS) help $(MSGFILES)
+
+$(MSGDIR)/%: %
+ $(INS.file)
+
+$(MSGDIRS):
+ $(INS.dir)
+
+jstyle:
+ jstyle $(JAVAFILES)
+
+lint:
+clean:
+ $(RM) $(CLEANFILES)
+clobber: clean
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/help-l10n-comments.txt b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/help-l10n-comments.txt
new file mode 100644
index 0000000000..d7440d8460
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/help-l10n-comments.txt
@@ -0,0 +1,242 @@
+
+CDDL HEADER START
+
+The contents of this file are subject to the terms of the
+Common Development and Distribution License (the "License").
+You may not use this file except in compliance with the License.
+
+You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+or http://www.opensolaris.org/os/licensing.
+See the License for the specific language governing permissions
+and limitations under the License.
+
+When distributing Covered Code, include this CDDL HEADER in each
+file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+If applicable, add the following below this CDDL HEADER, with the
+fields enclosed by brackets "[]" replaced with your own identifying
+information: Portions Copyright [yyyy] [name of copyright owner]
+
+CDDL HEADER END
+
+Localization Notes for the Oracle Solaris Print Manager
+3/16/99
+
+1. Overview
+ The help documentation tree consists of a collection of Articles,
+ each relating to a specific dialog, message, procedure, or
+ other topic. The text, keywords, and metadata comprising the
+ entire set of Articles is delivered in a single (large)
+ ResourceBundle per locale.
+
+ Each article consists of several parts, all of which must be
+ defined within the ResourceBundle. These parts are called Tag,
+ Title, Content, Keywords, and See-Also. Title, Content, and
+ Keywords must be localized while Tag and See-Also must not.
+
+ The Tag is an identifier unique to each Article. The application
+ uses Tags to refer to specific Articles. The ResourceBundle uses
+ each Article's Tag to form the keys which identify the
+ strings comprising the Article.
+
+ The strings used as keys to identify the various parts of the
+ articles in the ResourceBundle are in the form of a dotted pair,
+ where the left side identifies the Tag of the Article to which
+ this string belongs and the right side describes which part of
+ that Article the string embodies.
+
+ The suffixes used to identify the Tag, Title, Content, Keywords,
+ and See-Also parts of a help article's resources are ".tag",
+ ".title", ".content", ".keyword", and ".seealso" respectively.
+
+ Examples: The key "ToAddPrinter.title" is associated with a
+ localizable string that represents the title of the article whose
+ tag is "ToAddPrinter". The key "ToDeletePrinter.content" refers to
+ a localizable string which contains the content of the help article
+ itself.
+
+
+2. Structure of Help Articles
+
+2.1 Tags
+ Each Article is associated with a unique identifier called a Tag.
+ Tags are used internally and are never directly visible to users.
+
+ A Tag is a case-sensitive string of alphanumeric 7-bit ASCII
+ characters containing no embedded whitespace or punctuation.
+
+ For convenience, an article's Tag is usually formed by taking the
+ title and removing whitespace and punctuation; for example,
+ the article titled "Troubleshooting Printer Problems" might have
+ the Tag "TroubleShootingPrinterProblems". Note that this is a
+ mnemonic device only and in no way engenders a dependency between
+ the non-localizable Tag, which must be embedded in the
+ application's source code, and the article's title itself, which
+ must be localized.
+
+ *TAGS ARE NOT TO BE LOCALIZED!*
+
+
+2.2 Title and Content
+ Each Article must contain a Title and some Content.
+
+ The Title is an arbitrary localizable string which will be
+ presented to the user upon viewing its associated Article.
+
+ The Content of an Article consists of a block of localizable text
+ which may contain a limited set of embedded HTML tags (subject to
+ restrictions described below).
+
+ Since the Content is displayed in a window whose size may be
+ adjusted by the user, its layout cannot be completely controlled by
+ the author. The Help display relies on word-wrapping and HTML
+ formatting to ensure correct appearance.
+
+ The viewable Content of an Article is authored in a tiny subset of
+ HTML which can be reliably rendered in the Help component. The
+ intention is to provide a simple facility for controlling the
+ appearance of the text and for handling paragraph and line breaks.
+
+ The supported capabilities are:
+
+ . Emphasize sections of text by bolding: <b> ... </b>
+
+ . Line breaks: <br>
+
+ . Paragraph breaks: <p>
+
+ No other HTML tags should be embedded in the Content as they
+ may not produce the expected results. No hyperlinks or images
+ are supported!
+
+ Note that while the content itself may be localized, the HTML tags
+ embedded within the content should be left in ASCII.
+
+ *BOTH TITLE AND CONTENT MUST BE LOCALIZED!*
+
+
+2.3 Keywords
+
+ Users may search the collection of help articles by specifying one
+ or more keywords (in the locale's representation) which are matched
+ against the set of Articles. Those articles whose keyword list has
+ one or more matches with the user's list will then be viewable.
+
+ Each Article may specify a (possibly empty) list of keywords
+ separated by whitespace and containing no commas or punctuation.
+ The whitespace in this list of keywords is used only to separate
+ individual keywords.
+
+ Each Keyword in the list must be a string of localizable
+ alphanumeric text containing no whitespace (punctuation marks such
+ as "-" may be OK).
+
+ *KEYWORDS MUST BE LOCALIZED!*
+
+
+2.4 See-Also
+
+ Each article may refer to other Articles by presenting the user
+ with a "See-Also" list when the Article is viewed. This user's
+ view of this list contains the Titles of the specified articles,
+ and clicking a title causes that article to be presented.
+
+ The See-Also list associated with a particular Article consists of
+ a (possibly empty) list containing Tags of other articles separated
+ by whitespace and containing no commas or punctuation. The list of
+ Titles corresponding to these Tags will be displayed to the user in
+ the same order that it appears in the definition of the Article.
+
+ *SEE-ALSO ITEMS ARE NOT TO BE LOCALIZED!*
+
+
+3. Notes on Representation of Content
+
+ The internal representation of the Content component of each
+ article is as a single (long) Java String.
+
+ Java permits the static initialization of Strings to use
+ catenation on the right-hand side of the assignment.
+ For example, the Java statements
+ String s = "foo bar";
+ and
+ String s = "foo" + " " + bar;
+ will result in an identical assignment.
+
+ Since the HTML rendering process which displays the resource to
+ the user ignores whitespace and line breaks, the initializations
+ of Content strings in the Help ResourceBundle exploit this approach
+ to make the code more readable and facilitate the localization
+ process.
+
+ Note that the breaking up of the Content string into source lines is
+ transparent to the application; details of the source file's
+ appearance can change across localizations (assuming that tag names
+ are maintained correctly).
+
+ As an example, consider the ResourceBundle entry which defines the
+ Content portion of a help article whose tag is "ToDeletePrinter".
+ This entry might appear in the ResourceBundle source as
+
+ { "ToDeletePrinter.content",
+
+ "This is some help content which would extend across several " +
+ "lines of text if it were all in a single long string. " +
+ "Since we can separate the one long string into several " +
+ "short ones, " +
+ "the source file is much more easily readable. "
+ }
+
+
+4. Previewing Help Article Content
+
+ It is possible to use an ordinary HTML browser to view the Content of
+ all the help Articles in a ResourceBundle. To do so requires the
+ extraction and formatting of the strings in the ResourceBundle which
+ comprise the Content portions of all included Articles.
+
+ One approach is to create a simple script which acts as a filter; its
+ input is the pmHelpResources.java ResourceBundle source file and its
+ output is a stream of HTML which can be saved to a file and viewed in
+ a browser.
+
+ The use of such a script can facilitate the localization process by
+ enabling localization teams to view a particular version of the
+ ResourceBundle as work on it progresses.
+
+ An example of a script which performs the required formatting and
+ extraction is as follows:
+
+ -----------------------
+ #!/bin/ksh
+ #
+ # Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ # All rights reserved.
+ #
+ # This filter accepts a pmHelpResources.java file as input
+ # and produces formatted HTML as output.
+ #
+
+ while read line; do
+ echo "$line" | grep '^.*{".*\.tag"' > /dev/null
+ if [[ $? == 0 ]]; then
+ print -n "<br> <h2> "
+ print -n `echo "$line" | sed s/'\.'/\ / | \
+ sed s/\"/\ /g | awk '{print \$2}'`
+ print " </h2>"
+ fi
+
+ echo "$line" | grep '^\".*+$' | sed s/^\"//g | sed s/\"\ +\$//
+
+ done
+ -----------------------
+
+ Usage of this script (assuming it is named 'extract') would be:
+ % extract < pmHelpResources.java > content.html
+
+
+5. Support
+
+ For further assistance please contact:
+ Claude Noshpitz, clauden@eng.sun.com.
+
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helpTest.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helpTest.java
new file mode 100644
index 0000000000..8af71ace2a
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helpTest.java
@@ -0,0 +1,196 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * helpTest.java
+ * Test harness for help subsystem
+ */
+
+package com.sun.admin.pm.client;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.JPanel;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.*;
+import com.sun.admin.pm.server.*;
+
+class helpTest {
+ static private pmHelpFrame helpFrame = null;
+
+ public static void main(String args[]) {
+
+ Debug.setDebugLevel(Debug.ERROR);
+
+ JFrame frame = new JFrame("Help Test Tool");
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {System.exit(0); }
+ });
+
+ helpFrame = new pmHelpFrame();
+ helpFrame.setLocation(180, 180);
+
+
+ JList theList = new JList();
+ theList.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
+ JList l = (JList) e.getSource();
+ int i = l.locationToIndex(e.getPoint());
+ Debug.message("doubleclick index: " + i);
+ if (i >= 0) {
+ String s = (String) l.getModel().getElementAt(i);
+ Debug.message("doubleclick: " + s);
+ helpFrame.showHelp(s);
+ }
+ }
+ }
+ });
+
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.getViewport().setView(theList);
+
+ JPanel tp = new JPanel();
+ tp.setLayout(new GridBagLayout());
+ GridBagConstraints pc = new GridBagConstraints();
+ pc.insets = new Insets(5, 5, 0, 5);
+ // pc.fill = GridBagConstraints.HORIZONTAL;
+ pc.weightx = 1.0;
+ pc.anchor = GridBagConstraints.WEST;
+ pc.gridx = 0;
+ pc.gridy = GridBagConstraints.RELATIVE;
+
+ tp.add(new JLabel("Double-click a tag to load it."), pc);
+ pc.insets = new Insets(0, 5, 5, 5);
+ tp.add(new JLabel(""), pc);
+
+ JPanel p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(5, 5, 5, 5);
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.gridheight = 1;
+ c.gridx = 0;
+ c.gridy = 0;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+
+ c.anchor = GridBagConstraints.NORTH;
+ p.add(tp, c);
+
+ JPanel pp = new JPanel();
+ pp.setLayout(new BorderLayout());
+ pp.add(scrollPane, "Center");
+
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridheight = 0;
+ c.weighty = 1.0;
+ c.weightx = 0.0;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor = GridBagConstraints.EAST;
+
+ p.add(pp, c);
+
+ p.setBorder(BorderFactory.createEtchedBorder());
+
+ frame.getContentPane().add("Center", p);
+
+ helpTestButtonPanel bp = new helpTestButtonPanel();
+ frame.getContentPane().add("South", bp);
+
+ p = new JPanel();
+ Vector v = new Vector();
+
+ ResourceBundle bundle = null;
+
+ try {
+ bundle = ResourceBundle.getBundle(
+ "com.sun.admin.pm.client.pmHelpResources");
+ } catch (MissingResourceException e) {
+ System.out.println("Could not load pmHelpResources file");
+ System.exit(-1);
+ }
+
+ Enumeration e = bundle.getKeys();
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+ if (key.endsWith(".tag")) {
+ String tagName = null;
+ try {
+ tagName = bundle.getString(key);
+ } catch (MissingResourceException x) {
+ System.out.println("Unable to find tag for " + key);
+ continue;
+ }
+ v.addElement(tagName);
+ }
+ }
+
+ theList.setListData(v);
+ theList.removeSelectionInterval(
+ theList.getMinSelectionIndex(),
+ theList.getMaxSelectionIndex());
+ // theList.addSelectionInterval(3, 5);
+ // theList.disable();
+
+ frame.pack();
+ frame.setVisible(true);
+ frame.repaint();
+ System.err.println("Hello from main");
+
+ }
+
+ public void showHelpItem(String tag) {
+ helpFrame.showHelp(tag);
+ }
+
+}
+
+ class helpTestButtonPanel extends JPanel {
+ JButton dismiss;
+
+ public helpTestButtonPanel() {
+ add(dismiss = new JButton("Done"));
+ dismiss.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ System.exit(0);
+ }
+ });
+ }
+ }
+
+
+
+
+
+
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/extract b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/extract
new file mode 100644
index 0000000000..b05f85fd20
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/extract
@@ -0,0 +1,43 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+# Copyright (c) 1999, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# This filter accepts a pmHelpResources.java file as input
+# and produces formatted HTML as output.
+#
+
+while read line; do
+ echo "$line" | grep '^.*{".*\.tag"' > /dev/null
+ if [[ $? == 0 ]]; then
+ print -n "<br> <h2> "
+ print -n `echo "$line" | sed s/'\.'/\ / | \
+ sed s/\"/\ /g | awk '{print \$2}'`
+ print " </h2>"
+ fi
+
+ echo "$line" | grep '^\".*+$' | sed s/^\"//g | sed s/\"\ +\$//
+
+done
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/parseMain.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/parseMain.java
new file mode 100644
index 0000000000..4dbb34bb4e
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/parseMain.java
@@ -0,0 +1,811 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+import java.io.*;
+import java.util.*;
+import java.lang.*;
+
+
+class ResourceWriter {
+
+ BufferedWriter theWriter = null;
+ String theTag = null;
+
+ static final String NL = new String("\n");
+ static final String LOCALIZE = new String("// LOCALIZE");
+ static final String NOLOCALIZE = new String("// DO NOT LOCALIZE");
+ static final String INDENT = new String(" ");
+ static final String INDENT_2 = new String(INDENT + INDENT);
+ static final String COMMENTBLOCK_START = new String("/*");
+ static final String COMMENTBLOCK_END = new String(" */");
+ static final String COMMENTLINE_START = new String(" * ");
+
+ public ResourceWriter(BufferedWriter w) {
+ theWriter = w;
+ }
+
+ public void close() throws IOException {
+ theWriter.flush();
+ theWriter.close();
+ }
+
+ protected void writenl(String s) throws IOException {
+ theWriter.write(s, 0, s.length());
+ theWriter.newLine();
+ }
+
+ protected void write(String s) throws IOException {
+ theWriter.write(s, 0, s.length());
+ }
+
+ public void fileheader() throws IOException {
+ writenl("/* ");
+ writenl(" * GENERATED CODE");
+ writenl(" *");
+ writenl(" * Copyright 1999 Sun Microsystems, Inc.");
+ writenl(" * All rights reserved.");
+ writenl(" *");
+ writenl(" */");
+ writenl("");
+ writenl("package com.sun.admin.pm.client;");
+ writenl("import java.util.*;");
+ }
+
+ public void classheader(String className) throws IOException {
+ writenl("public class " + className +
+ " extends ListResourceBundle {");
+ writenl(INDENT +
+ "static final Object[][] pmHelpBundlecontents = {");
+ }
+
+ public void footer() throws IOException {
+ writenl(INDENT + "};");
+ writenl(INDENT + "public Object[][] getContents() {");
+ writenl(INDENT_2 + "return pmHelpBundlecontents;");
+ writenl(INDENT + "}");
+ writenl("}");
+ }
+
+
+ public void setTag(String tag) throws IOException {
+ theTag = new String(tag);
+ }
+
+ public void tag(String tag) throws IOException {
+ if (tag != null) {
+ writenl(NL + INDENT_2 + NOLOCALIZE);
+ writenl(INDENT_2 +
+ "{\"" + theTag + ".tag\", \"" + tag + "\"},");
+ }
+ }
+
+ public void title(String title) throws IOException {
+ if (title != null) {
+ writenl(NL + INDENT_2 + LOCALIZE);
+ writenl(INDENT_2 +
+ "{\"" + theTag + ".title\", \"" + title + "\"},");
+ }
+ }
+
+ public void seealso(String seealso) throws IOException {
+ if (seealso != null) {
+ writenl(NL + INDENT_2 + NOLOCALIZE);
+ writenl(INDENT_2 +
+ "{\"" + theTag + ".seealso\", \"" + seealso + "\"},");
+ }
+ }
+
+ public void keywords(String keywords) throws IOException {
+ if (keywords != null) {
+ writenl(NL + INDENT_2 + LOCALIZE);
+ writenl(INDENT_2 +
+ "{\"" + theTag + ".keywords\", \"" + keywords + "\"},");
+ }
+ }
+
+ public void content(Vector content) throws IOException {
+ if (content == null)
+ return;
+
+ writenl(NL + INDENT_2 + LOCALIZE);
+ writenl(INDENT_2 + "{\"" + theTag + ".content\",");
+
+ Enumeration e = content.elements();
+ while (e.hasMoreElements()) {
+ String s = (String) e.nextElement();
+ if (s.length() == 0) {
+ if (e.hasMoreElements())
+ continue;
+ else {
+ writenl(INDENT_2 + " \"\"\n },");
+ break;
+ }
+ }
+ String endOfLine = (e.hasMoreElements() ?
+ " +" :
+ "\n },");
+ writenl(INDENT_2 + " \"" + s + " \"" + endOfLine);
+ }
+ }
+
+ public void delimiter() throws IOException {
+ writenl(NL);
+ }
+
+ public void commentStart() throws IOException {
+ writenl(COMMENTBLOCK_START);
+ }
+
+ public void commentEnd() throws IOException {
+ writenl(COMMENTBLOCK_END);
+ }
+
+ public void comment(String s) throws IOException {
+ writenl(COMMENTLINE_START + s);
+ }
+}
+
+
+
+
+class Article {
+ String theTitle;
+ String theKeywords;
+ String theSeeAlso;
+ Vector theContent;
+ String theTag;
+
+ Reader r;
+
+ public void read(Reader theReader) {
+ r = theReader;
+
+ Tag theTag = null;
+
+ try {
+ while (true) {
+ theTag = readNextTag();
+ Debug.message("Article read: " + theTag);
+
+ if (theTag instanceof CommentTag) {
+ Debug.message("Comment ignored");
+ } else if (theTag instanceof TitleTag) {
+ theTitle = theTag.content;
+ } else if (theTag instanceof ContentTag) {
+ theContent = theTag.contentVector;
+ } else if (theTag instanceof SeeAlsoTag) {
+ theSeeAlso = theTag.content;
+ } else if (theTag instanceof KeywordsTag) {
+ theKeywords = theTag.content;
+ } else {
+ Debug.message("Unknown tag: " + theTag);
+ }
+ }
+ } catch (IOException x) {
+ Debug.message("Article read caught " + x);
+ }
+
+
+ }
+
+
+ int localread() throws IOException {
+ int ch = r.read();
+ if (ch == -1) {
+ Debug.message("localread: eof");
+ throw new IOException();
+ }
+ // Debug.message("localread: " + ch);
+ return ch;
+ }
+
+
+ /*
+ * read the word within tagOpen/tagClose pair
+ */
+ String readTagName() throws IOException {
+ String rv = null;
+ int ch;
+ StringBuffer b = new StringBuffer();
+
+ while (true)
+ if (localread() == HelpSyntax.tagOpen)
+ break;
+
+ Debug.message("readTagName: got a tagOpen");
+
+ while (true) {
+ ch = localread();
+ if (ch == HelpSyntax.tagClose)
+ break;
+ else
+ b.append((char) ch);
+ }
+
+ Debug.message("readTagName: " + (new String(b)).trim());
+ return (new String(b)).trim();
+ }
+
+
+ Tag readNextTag() throws IOException {
+ Tag rv = null;
+ int ch;
+ StringBuffer b;
+
+ String tag = readTagName();
+ Debug.message("readNextTag name: " + tag);
+
+ if (tag.equalsIgnoreCase(HelpSyntax.tagTitle)) {
+ rv = new TitleTag();
+ rv.read(r);
+ } else if (tag.equalsIgnoreCase(HelpSyntax.tagKeywords)) {
+ rv = new KeywordsTag();
+ rv.read(r);
+ } else if (tag.equalsIgnoreCase(HelpSyntax.tagSeeAlso)) {
+ rv = new SeeAlsoTag();
+ rv.read(r);
+ } else if (tag.equalsIgnoreCase(HelpSyntax.tagContent)) {
+ rv = new ContentTag();
+ rv.readMultipleLines(r);
+ } else {
+ Debug.message("Bad tag: " + tag);
+ }
+ return rv;
+ }
+
+
+ public String toString() {
+ return new String("Title <" + theTitle +
+ "> Keywords <" + theKeywords +
+ "> See-Also <" + theSeeAlso +
+ "> Content <" + theContent + ">");
+ }
+}
+
+
+class HelpSyntax {
+ public final static int tagOpen = '<';
+ public final static int tagClose = '>';
+ public final static String startComment = "!-";
+ public final static String endComment = "--";
+ public final static String tagContent = "CONTENT";
+ public final static String tagTitle = "TITLE";
+ public final static String tagSeeAlso = "SEEALSO";
+ public final static String tagKeywords = "KEYWORDS";
+}
+
+class ParseException extends Exception {
+}
+
+class BadTagException extends ParseException {
+}
+
+class SyntaxErrorException extends ParseException {
+}
+
+abstract class Tag {
+ String content;
+ Vector contentVector;
+ protected String name;
+ protected boolean escapeQuotes = false;
+
+ public Tag(String s) {
+ content = s;
+ }
+
+ public Tag() {
+ this(null);
+ }
+
+ public String toString() {
+ return new String(this.getClass().getName() + ": " + content);
+ }
+
+ // respect line spacing, stuff contentVector
+ public void readMultipleLines(Reader r) throws IOException {
+ int ch;
+ StringBuffer b = new StringBuffer();
+ Vector v = new Vector();
+ boolean spaced = false;
+
+ while (true) {
+ ch = r.read();
+ if (ch == -1)
+ break;
+
+ if (ch == '\n') {
+ v.addElement(new String(b));
+ b = new StringBuffer();
+ continue;
+ }
+
+ if (Character.isWhitespace((char) ch)) {
+ if (spaced == false) {
+ b.append(" ");
+ spaced = true;
+ }
+ continue;
+ }
+
+ if (escapeQuotes && ch == '\"') {
+ b.append("\\\"");
+ continue;
+ }
+
+ spaced = false;
+ if (ch == HelpSyntax.tagOpen) {
+ boolean localspaced = false;
+ boolean localopen = true;
+ Debug.message("Tag: got a tagOpen");
+
+ StringBuffer tmp = new StringBuffer();
+ while ((ch = r.read()) != HelpSyntax.tagClose) {
+ if (Character.isWhitespace((char) ch)) {
+ if (localspaced == false) {
+ tmp.append(" ");
+ localspaced = true;
+ }
+ continue;
+ }
+ tmp.append((char) ch);
+ }
+
+ String t = new String(tmp);
+
+ if ((t.trim()).equalsIgnoreCase("/" + this.name)) {
+ Debug.message("Tag: close tag = " + t);
+ break;
+ } else {
+ Debug.message("Tag: ignoring bad close tag = " + t);
+ b.append((char) HelpSyntax.tagOpen);
+ b.append(t);
+ b.append((char) HelpSyntax.tagClose);
+ }
+ } else {
+ b.append((char)ch);
+ }
+ }
+ contentVector = v;
+ Debug.message("Tag: contentVector = " + contentVector);
+ }
+
+ // catenate input lines, eliminating whitespace
+ public void read(Reader r) throws IOException {
+ int ch;
+ StringBuffer b = new StringBuffer();
+ boolean spaced = false;
+
+ while (true) {
+ ch = r.read();
+ if (ch == -1)
+ break;
+
+ if (Character.isWhitespace((char) ch)) {
+ if (spaced == false) {
+ b.append(" ");
+ spaced = true;
+ }
+ continue;
+ }
+
+ if (escapeQuotes && ch == '\"') {
+ b.append("\\\"");
+ continue;
+ }
+
+ spaced = false;
+ if (ch == HelpSyntax.tagOpen) {
+ boolean localspaced = false;
+ boolean localopen = true;
+ Debug.message("Tag: got a tagOpen");
+
+ StringBuffer tmp = new StringBuffer();
+ while ((ch = r.read()) != HelpSyntax.tagClose) {
+ if (Character.isWhitespace((char) ch)) {
+ if (localspaced == false) {
+ tmp.append(" ");
+ localspaced = true;
+ }
+ continue;
+ }
+ tmp.append((char) ch);
+ }
+
+ String t = new String(tmp);
+
+ if ((t.trim()).equalsIgnoreCase("/" + this.name)) {
+ Debug.message("Tag: close tag = " + t);
+ break;
+ } else {
+ Debug.message("Tag: ignoring bad close tag = " + t);
+ b.append((char) HelpSyntax.tagOpen);
+ b.append(t);
+ b.append((char) HelpSyntax.tagClose);
+ }
+ } else {
+ b.append((char)ch);
+ }
+ }
+ content = (new String(b)).trim();
+ Debug.message("Tag: content = " + content);
+ }
+}
+
+class TitleTag extends Tag {
+ public TitleTag() {
+ name = HelpSyntax.tagTitle;
+ }
+}
+
+class SeeAlsoTag extends Tag {
+ public SeeAlsoTag() {
+ name = HelpSyntax.tagSeeAlso;
+ }
+}
+
+class ContentTag extends Tag {
+ public ContentTag() {
+ name = HelpSyntax.tagContent;
+ escapeQuotes = true;
+ }
+}
+
+class CommentTag extends Tag {
+ public CommentTag() {
+ name = null;
+ }
+}
+
+class KeywordsTag extends Tag {
+ public KeywordsTag() {
+ name = HelpSyntax.tagKeywords;
+ escapeQuotes = true;
+ }
+}
+
+
+
+class parseMain {
+
+ static String outputFileName = "pmHelpResources.java";
+ static String commentFileName = "comments.txt";
+ static int firstFile = 0;
+
+ // returns -1 if error, 0 otherwise
+ protected static int parseArgs(String[] args) {
+ int rv = 0;
+ int i;
+
+ for (i = 0; i < args.length; ++i) {
+ if (args[i].compareTo("-d") == 0) {
+ if (args[i].length() > 2) {
+ outputFileName = args[i].substring(2);
+ } else {
+ outputFileName = args[++i];
+ }
+ } else if (args[i].compareTo("-c") == 0) {
+ if (args[i].length() > 2) {
+ commentFileName = args[i].substring(2);
+ } else {
+ commentFileName = args[++i];
+ }
+ } else if (args[i].compareTo("-v") == 0) {
+ Debug.setDebugLevel(Debug.WARNING);
+ } else
+ break; // unknown arg ==> list of files starts
+
+ }
+
+ firstFile = i;
+
+ /*
+ * System.out.println("outputFileName = " + outputFileName +
+ * " commentFileName = " + commentFileName +
+ * " firstFile = " + firstFile);
+ */
+
+ return rv;
+ }
+
+
+ public static void main(String args[]) {
+ FileReader f = null;
+ FileWriter fw = null;
+ String filename = null;
+
+ Debug.setDebugLevel(Debug.ERROR);
+
+ // validate command line
+ if (args.length == 0) {
+ System.err.println("At least one filename required.");
+ System.exit(-1);
+ }
+
+ if (parseArgs(args) < 0)
+ System.exit(-1);
+
+
+ outputFileName = outputFileName.trim();
+
+ Debug.warning("Writing to " + outputFileName);
+
+ try {
+
+ // create output file
+ fw = new FileWriter(outputFileName);
+ BufferedWriter w = new BufferedWriter(fw);
+ ResourceWriter rw = new ResourceWriter(w);
+
+ // imports and package statement
+ rw.fileheader();
+
+ // comment block
+ File commentFile = new File(commentFileName);
+ if (commentFile.exists()) {
+ rw.delimiter();
+ rw.commentStart();
+ BufferedReader comments =
+ new BufferedReader(new FileReader(commentFileName));
+ String commentLine;
+ while ((commentLine = comments.readLine()) != null)
+ rw.comment(commentLine);
+ comments.close();
+ rw.commentEnd();
+ rw.delimiter();
+ } else {
+ Debug.error("Comment file " + commentFileName +
+ " not found.");
+ }
+
+ // create class name w/o extension or leading path
+ File cf = new File(outputFileName);
+ String className = cf.getName();
+
+ // class name is output filename w/o extension
+ int dotIndex = className.indexOf(".");
+ if (dotIndex < 0)
+ dotIndex = className.length();
+
+ className = className.substring(0, dotIndex);
+
+ // class definition
+ rw.classheader(className);
+
+ // iterate over input files
+ for (int i = firstFile; i < args.length; ++i) {
+ filename = args[i];
+ Debug.warning("Reading file " + filename);
+
+ try {
+ f = new FileReader(filename);
+ } catch (Exception x) {
+ Debug.fatal(x.toString());
+ return;
+ }
+
+ BufferedReader r = new BufferedReader(f);
+
+ Article a = new Article();
+ a.read(r);
+ // System.out.println(a);
+
+ // process the Article
+
+ String tagName = filenameToTag(filename);
+ Debug.warning("Creating tag " + tagName);
+
+ // HTML syntax checking on content
+ if (!validHTMLSyntax(a.theContent))
+ throw new IOException(
+ "Bad HTML syntax in article " + tagName);
+
+
+ rw.setTag(tagName);
+ rw.tag(tagName);
+ rw.seealso(a.theSeeAlso);
+ rw.title(a.theTitle);
+ rw.keywords(a.theKeywords);
+ rw.content(a.theContent);
+ rw.delimiter();
+ }
+
+ rw.footer();
+ rw.close();
+ w.close();
+ } catch (IOException x) {
+ Debug.fatal(x.toString());
+
+ // try to unlink the broken output file
+ boolean unlink = true;
+
+ try {
+ fw.close();
+ } catch (IOException xx) {
+ Debug.error(xx.toString());
+ unlink = false;
+ }
+
+ if (unlink) {
+ File theFile = new File(outputFileName);
+
+ Debug.warning("Deleting file " + outputFileName);
+
+ if (theFile.exists())
+ theFile.delete();
+ }
+
+ System.exit(-2);
+ }
+ }
+
+
+ // return true if no syntax errors found
+ static boolean validHTMLSyntax(String s) {
+
+ if (s == null)
+ return true;
+
+ // check only for <b>..</b> pairs
+
+ String src = s.toLowerCase(); // html tags are case-neutral
+
+ int i;
+
+ int opens = 0;
+ for (i = src.indexOf("<b>");
+ i != -1;
+ i = src.indexOf("<b>", i + 1))
+ ++opens;
+
+ int closes = 0;
+ for (i = src.indexOf("</b>");
+ i != -1;
+ i = src.indexOf("</b>", i + 1))
+ ++closes;
+
+ // System.out.println("syntax: " + opens + " " + closes);
+
+ return opens == closes;
+
+ }
+
+ // return true if no syntax errors found
+ static boolean validHTMLSyntax(Vector v) {
+ String s = new String();
+ Enumeration e = v.elements();
+ while (e.hasMoreElements())
+ s = s + (String) e.nextElement();
+ return validHTMLSyntax(s);
+ }
+
+ /*
+ * extract the tag name from a filename, possibly containing
+ * a fully qualified path as well as a complex extension.
+ */
+ static String filenameToTag(String filename) {
+
+ // the help tag is the filename exclusive of path or extensions
+
+ File f = new File(filename);
+ String s = f.getName();
+ int period = s.indexOf('.');
+ // System.out.println("filename: " + s);
+ if (period < 0)
+ period = filename.length();
+ // System.out.println("period = " + period);
+ return s.substring(0, period);
+ }
+
+
+}
+
+class Debug {
+
+ /**
+ * Log a highest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void fatal(String s) {
+ printIf(s, FATAL);
+ }
+
+ /**
+ * Log a highest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void error(String s) {
+ printIf(s, ERROR);
+ }
+
+ /**
+ * Log a highest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void warning(String s) {
+ printIf(s, WARNING);
+ }
+
+ /**
+ * Log a highest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void message(String s) {
+ printIf(s, MESSAGE);
+ }
+
+ /**
+ * Log a highest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void setDebugLevel(int lvl) {
+ if (lvl < ALL || lvl > NONE)
+ return;
+
+ globalDebugLevel = lvl;
+ }
+
+ private static void printIf(String s, int lvl) {
+ if (lvl < globalDebugLevel)
+ return;
+ DebugPrint(s);
+ }
+
+ // here is where we could hide syslog or file destination...
+ private static void DebugPrint(String s) {
+ System.out.println(s); // for now
+ }
+
+
+ /**
+ * Verbosity level to suppress all messages.
+ */
+ static public final int NONE = 5;
+
+ /**
+ * Verbosity level to log only highest-priority messages.
+ */
+ static public final int FATAL = 4;
+
+ /**
+ * Verbosity level to log high- and highest-priority messages.
+ */
+ static public final int ERROR = 3;
+
+ /**
+ * Verbosity level to log medium-, high-, and
+ * highest-priority messages.
+ */
+ static public final int WARNING = 2;
+
+ /**
+ * Verbosity level to log low-, medium-, high-, and
+ * highest-priority messages.
+ */
+ static public final int MESSAGE = 1;
+
+ /**
+ * Verbosity level to log all messages.
+ */
+ static public final int ALL = 0;
+
+ private static int globalDebugLevel = ERROR;
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/parsehelp.sh b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/parsehelp.sh
new file mode 100644
index 0000000000..b2050c4ef3
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/helptools/parsehelp.sh
@@ -0,0 +1,83 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+# Copyright (c) 1999, by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# Helper script for processing raw help files.
+# Parameters:
+# -D <classpath> appends <classpath> to $CLASSPATH
+# -J <java_dir> uses <java_dir>/bin/java. Default is /usr/java.
+# -V enable verbose runtime messages
+
+
+if [[ $# == 0 ]]; then
+ echo "One or more raw help files must be specified."
+ echo "Usage:"
+ echo " $0 [-D classpath] [-J java_home_dir] [-V] [-C comment_file] [-d destination-file] raw-help-file [raw-help-file]"
+ exit -1
+fi
+
+while getopts "D:J:C:V" opt; do
+
+ case $opt in
+ D) DARG=$OPTARG;;
+
+ J) JARG=$OPTARG;;
+
+ C) COMMENT="-c "$OPTARG;;
+
+ V) VERBOSE="-v";;
+
+ esac
+done
+
+shift $(($OPTIND - 1))
+
+#echo "DARG: $DARG JARG: $JARG"
+#echo "num left: " $#
+#echo "args: $*"
+
+if [[ x$JARG == x ]]; then
+ # echo "Using default java"
+ JAVA_HOME="/usr/java"
+else
+ JAVA_HOME=$JARG
+fi
+
+DIR=$DARG
+
+
+#PATH="$JAVA_HOME/bin:/usr/bin:/usr/sbin:/sbin:.:$PATH"
+THREADS_FLAG="native"
+CLASSPATH=":.:./helptools:$DIR"
+
+# echo "Path: $PATH"
+# echo "CLASSPATH: $CLASSPATH"
+# echo "Java: $JAVA_HOME/bin/java"
+
+echo "Processing raw help files..."
+# $JAVA_HOME/bin/java -fullversion
+$JAVA_HOME/bin/java -classpath $CLASSPATH parseMain $COMMENT $VERBOSE $*
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/images/appicon.gif b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/images/appicon.gif
new file mode 100644
index 0000000000..76918b6467
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/images/appicon.gif
Binary files differ
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAboutBox.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAboutBox.java
new file mode 100644
index 0000000000..fe840bc5af
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAboutBox.java
@@ -0,0 +1,117 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmAboutBox.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+
+import com.sun.admin.pm.server.*;
+
+
+public class pmAboutBox extends pmFrame {
+ public pmButton cancel = null;
+ String title = pmUtility.getResource("About.Solaris.Print.Manager");
+ String copyright = new String(pmUtility.getResource("info_copyright1")
+ + pmUtility.getCopyrightResource("copyright_year")
+ + pmUtility.getResource("info_copyright2"));
+ String version = pmUtility.getResource("info_version");
+ String appname = pmUtility.getResource("info_name");
+ String contents = new String(appname + "\n" +
+ version + "\n\n" +
+ copyright + "\n");
+
+ public pmAboutBox() {
+
+ super(pmUtility.getResource("About.Solaris.Print.Manager"));
+
+ cancel = new pmButton(pmUtility.getResource("Cancel"));
+ cancel.setMnemonic(pmUtility.getIntResource("Cancel.mnemonic"));
+ cancel.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ hideAboutBox();
+ }
+ });
+
+ // Create a regular text field.
+ JTextArea textArea = new JTextArea(contents);
+ Font f = new pmJTextField().getFont();
+ Font fb = new Font(f.getName(), f.PLAIN, f.getSize());
+ textArea.setOpaque(false);
+ textArea.setFont(fb);
+ textArea.setLineWrap(true);
+ textArea.setWrapStyleWord(true);
+ textArea.setEditable(false);
+ textArea.setDisabledTextColor(Color.blue);
+
+ JPanel j1 = new JPanel();
+ j1.setBorder(new EmptyBorder(10, 10, 10, 10));
+ j1.setLayout(new BorderLayout());
+ JScrollPane areaScrollPane = new JScrollPane(textArea);
+ areaScrollPane.setPreferredSize(new Dimension(270, 175));
+ j1.add(areaScrollPane, BorderLayout.CENTER);
+
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setBorder(new EmptyBorder(0, 0, 10, 10));
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
+ buttonPanel.add(cancel);
+
+ JPanel bottomPanel = new JPanel(new BorderLayout());
+ bottomPanel.add(buttonPanel, BorderLayout.SOUTH);
+
+ Container contentPane = getContentPane();
+ contentPane.add(j1, BorderLayout.CENTER);
+ contentPane.add(bottomPanel, BorderLayout.SOUTH);
+
+ // default button is cancel
+ cancel.setAsDefaultButton();
+
+ // handle Esc as cancel
+ getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("HELP: cancel action");
+ hideAboutBox();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ pack();
+ repaint();
+
+ }
+
+ public void hideAboutBox() {
+ this.setVisible(false);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAccess.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAccess.java
new file mode 100644
index 0000000000..13b4c42bf4
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAccess.java
@@ -0,0 +1,518 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Comment which describes the contents of this file.
+ *
+ * pmAccess.java
+ * Add Access To Printer handling
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.Vector;
+import javax.swing.JPanel;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+/*
+ * Window for Edit -> Add Access to a Printer
+ */
+
+public class pmAccess extends pmButtonScreen {
+ JComboBox portCombo;
+ pmFrame frame = new pmFrame(
+ pmUtility.getResource("SPM:Add.Access.To.Printer"));
+ pmTextField pnameText;
+ pmTextField snameText;
+ pmTextField descText;
+ Boolean makedefault;
+ JCheckBox defaultp;
+ Printer newpr = null;
+ pmTop mytop;
+ String printer = null;
+ String server = null;
+
+ String cmdLog = null;
+ String errorLog = null;
+ String warnLog = null;
+
+
+ final static int OK = 1;
+ final static int APPLY = 2;
+ final static int RESET = 3;
+ final static int CANCEL = 4;
+ final static int HELP = 5;
+
+ public pmAccess(pmTop mytop) {
+
+ // ensure that pmButton hashtable gets cleaned up
+ frame.setClearButtonsOnClose(true);
+
+ setLayout(new BorderLayout());
+
+ this.mytop = mytop;
+
+ // Build the Frame
+ centerPanel();
+ southPanel();
+
+ /*
+ * let's try doing this in Show...
+ *
+ * // default button is always OK, for now...
+ * frame.getRootPane().setDefaultButton(okButton);
+ *
+ * okButton.setAsDefaultButton();
+ */
+
+ // handle Esc as cancel
+ this.registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ actioncancelButton();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ // enable the pmFrame to set focus to our default comp on activation
+ frame.setDefaultComponent(pnameText);
+
+
+ // following is test code, I think...
+ Component glass = frame.getGlassPane();
+
+ glass.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent k) {
+ Debug.info("Glass: " + k);
+ }
+ public void keyReleased(KeyEvent k) {
+ Debug.info("Glass: " + k);
+ }
+ public void keyTyped(KeyEvent k) {
+ Debug.info("Glass: " + k);
+ }
+ });
+
+ }
+
+ public void centerPanel() {
+ // Build center panel
+ JPanel center = new JPanel();
+ center.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ // define center constraints
+ c.insets = new Insets(8, 5, 5, 5);
+ c.gridheight = 1;
+ c.gridwidth = 1;
+
+ // build center components
+ // Create
+ c.gridx = 0;
+ c.weightx = c.weighty = 0.0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+
+ // Build the labels
+ c.gridy = 0;
+ center.add(new JLabel
+ (pmUtility.getResource("Printer.Name:")), c);
+ c.gridy = 1;
+ center.add(new JLabel
+ (pmUtility.getResource("Printer.Server:")), c);
+ c.gridy = 2;
+ center.add(new JLabel
+ (pmUtility.getResource("Description:")), c);
+ c.gridy = 3;
+ center.add(new JLabel
+ (pmUtility.getResource("Option:")), c);
+
+ // Build the text fields
+ // Common constraints
+ c.gridx = 1;
+ c.ipadx = 15;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = c.weighty = 1.0;
+
+ c.gridy = 0;
+ pnameText = new pmTextField(14);
+
+ center.add(pnameText, c);
+
+ c.gridy = 1;
+ snameText = new pmTextField(25);
+ center.add(snameText, c);
+
+ c.gridy = 2;
+ descText = new pmTextField(25);
+ center.add(descText, c);
+
+ // Add Choice Menus - ComboBox
+ c.weightx = c.weighty = 0.0;
+ c.gridy = 3;
+
+ defaultp = new JCheckBox(
+ pmUtility.getResource("Default.Printer"));
+ center.add(defaultp, c);
+
+ add("Center", center);
+ }
+
+ public void createAccess() throws pmGuiException {
+ boolean getHostOk = true;
+ String description = "";
+
+ newpr = new Printer(mytop.ns);
+ Debug.message("CLNT: createAccess()");
+ pmCalls.debugShowPrinter(newpr);
+ printer = pnameText.getText().trim();
+ server = snameText.getText().trim();
+ description = descText.getText();
+
+ if (printer.equals("")) {
+ pnameText.requestFocus();
+ Debug.message("CLNT:pmAccess:Printer name required.");
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("Printer.name.required."));
+ }
+
+ if (!Valid.remotePrinterName(printer)) {
+ pnameText.requestFocus();
+ Debug.message("CLNT:pmAccess:Printer name invalid: " + printer);
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("Printer.name.invalid."));
+ }
+
+ if (server.equals("")) {
+ snameText.requestFocus();
+ Debug.message("CLNT:pmAccess:Server name required.");
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("Server.name.required."));
+ }
+
+ if (!Valid.serverName(server)) {
+ snameText.requestFocus();
+ Debug.message("CLNT:pmAccess:Server name invalid.");
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("Server.name.invalid."));
+ }
+
+ try {
+ if (server.equals(mytop.host.getLocalHostName()) ||
+ server.equals("localhost")) {
+ snameText.requestFocus();
+ getHostOk = false;
+ }
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT: pmAccess:createAccess:getLocalHostName exception");
+ throw new pmGuiException(
+ pmUtility.getResource(
+ "Could.not.get.local.hostname " + e));
+ }
+
+ if (!getHostOk) {
+ Debug.warning(
+ "CLNT: pmAccess:createAccess:Server name required.");
+ throw new pmMustBeRemoteServerException(
+ pmUtility.getResource("Server.name.required."));
+ }
+
+ boolean exist;
+ try {
+ exist = PrinterUtil.exists(printer, mytop.ns);
+ } catch (Exception e) {
+ throw new pmGuiException(e.toString());
+ }
+
+ if (exist) {
+ throw new pmPrinterExistsException();
+ }
+
+ if (mytop.ns.getNameService().equals("nis") == true ||
+ mytop.ns.getNameService().equals("ldap") == true) {
+ try {
+ if (!mytop.ns.isAuth()) {
+ pmUtility.doLogin(mytop, frame);
+ }
+ } catch (pmUserCancelledException e) {
+ Debug.message("CLNT:pmAccess:user cancelled login");
+ throw new pmUserCancelledException(
+ pmUtility.getResource(
+ "User.cancelled.login."));
+ } catch (pmGuiException e) {
+ Debug.message(
+ "CLNT:pmAccess:login nis/ldap failed: " + e);
+ throw new pmLoginFailedException();
+ } catch (Exception e) {
+ Debug.message(
+ "CLNT:pmAccess:login nis/ldap failed: " + e);
+ throw new pmLoginFailedException();
+ }
+ }
+
+ Debug.message("CLNT:pmAccess:checkbox: " + defaultp.isSelected());
+
+ // Check for confirmation option
+ if (((mytop.getConfirmOption() == true) && (confirmAction() == true))
+ || (mytop.getConfirmOption() == false)) {
+
+ // Set the printer attributes
+ newpr.setPrinterName(printer);
+ newpr.setPrintServer(server);
+ newpr.setComment(description);
+ if (defaultp.isSelected())
+ newpr.setIsDefaultPrinter(true);
+
+ frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+ boolean failed = false;
+ try {
+ newpr.addRemotePrinter();
+ } catch (Exception e) {
+ failed = true;
+ Debug.warning(
+ "CLNT:pmAccess:addRemotePrinter caught:" + e);
+ }
+
+ frame.setCursor(Cursor.getDefaultCursor());
+
+ gatherLogs();
+ dumpLogs("CLNT:pmAccess:createAccess()");
+
+ pmCalls.debugShowPrinter(newpr);
+
+ mytop.setLogData(cmdLog, errorLog, warnLog);
+ mytop.showLogData(
+ pmUtility.getResource("Add.Access.To.Printer"));
+
+ mytop.pmsetPrinterList();
+ mytop.clearSelected();
+ mytop.listTable.clearSelection();
+
+ if (failed)
+ throw new pmAddAccessFailedException(errorLog);
+
+ }
+ }
+
+ public void clearAccessInput() {
+ try {
+ pnameText.setText("");
+ snameText.setText("");
+ descText.setText("");
+ if (defaultp.isSelected())
+ defaultp.doClick();
+ } catch (Exception e) {
+ // ignore???
+ // throw new pmGuiException("pmAccess: Error clearAccessInput: " + e);
+ Debug.warning("CLNT:pmAccess: Error clearAccessInput: " + e);
+ }
+ }
+
+
+
+ public boolean confirmAction() {
+ if (mytop.getConfirmOption() == true) {
+ pmOKCancelDialog d = new pmOKCancelDialog(frame,
+ pmUtility.getResource("Action.Confirmation"),
+ pmUtility.getResource(
+ "Continue.creating.access.for.this.printer?"));
+ d.setVisible(true);
+ if (d.getValue() != JOptionPane.OK_OPTION) {
+ pmMessageDialog m = new pmMessageDialog(frame,
+ pmUtility.getResource("Warning"),
+ pmUtility.getResource("Operation.Cancelled"));
+ m.setVisible(true);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void gatherLogs() {
+ cmdLog = newpr.getCmdLog();
+ errorLog = newpr.getErrorLog();
+ warnLog = newpr.getWarnLog();
+ }
+
+
+ void dumpLogs(String who) {
+ Debug.message(who);
+ Debug.message(who + " command: " + cmdLog);
+ Debug.message(who + " warnings: " + warnLog);
+ Debug.message(who + " errors: " + errorLog);
+ }
+
+ // returns true if success, false otherwise
+ boolean doAction() {
+ boolean rv = false;
+
+ try {
+ createAccess();
+ rv = true; // only if it didn't throw!
+ } catch (pmIncompleteFormException ix) {
+ Debug.warning(
+ "CLNT:pmAccess:incomplete form " + ix.getMessage());
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ ix.getMessage(),
+ mytop,
+ "AddAccessFailed");
+ m.setVisible(true);
+ } catch (pmPrinterExistsException ex) {
+ Debug.warning("CLNT:pmAccess:printer exists");
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource("The.specified.printer.already.exists."));
+ m.setVisible(true);
+ } catch (pmMustBeRemoteServerException rx) {
+ Debug.warning("CLNT:pmAccess:server must be remove.");
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "The.server.must.be.a.remote.server."),
+ mytop,
+ "RemoteServer");
+ m.setVisible(true);
+
+ } catch (pmLoginFailedException lx) {
+ Debug.warning("CLNT:pmAccess:Required login failed");
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource("Required.login.failed."),
+ mytop,
+ "LoginFailed");
+ m.setVisible(true);
+
+ } catch (pmAddAccessFailedException ax) {
+ Debug.warning(
+ "CLNT:pmAccess:add access failed " + ax.getMessage());
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ ax.getMessage(),
+ mytop,
+ "AddAccessFailed");
+ m.setVisible(true);
+
+ } catch (pmUserCancelledException cx) {
+ Debug.message(
+ "CLNT:pmAccess:createAccess: User cancelled namespace login");
+ } catch (pmGuiException gx) {
+ Debug.warning(
+ "CLNT:pmAccess:Application Error" + gx.getMessage());
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Application.Error"),
+ gx.getMessage());
+ m.setVisible(true);
+
+ } finally {
+ // clearAccessInput();
+ }
+ return rv;
+ }
+
+
+ public void pmScreendispose() {
+ frame.dispose();
+ }
+
+ public void actionokButton() {
+ Debug.message("CLNT:pmAccess:actionokButton()");
+
+ if (doAction() == true) {
+ clearAccessInput();
+ mytop.pmsetdefaultpLabel();
+ frame.setVisible(false);
+ frame.repaint();
+ // frame.dispose();
+ mytop.scrollPane.revalidate();
+ mytop.scrollPane.repaint();
+ } else {
+ Debug.message("CLNT: pmAccess: doAction is false");
+ }
+
+ }
+
+ public void actionapplyButton() {
+ Debug.message("CLNT:pmAccess:actionapplyButton()");
+
+ if (doAction() == true) {
+ mytop.pmsetdefaultpLabel();
+ mytop.scrollPane.revalidate();
+ mytop.scrollPane.repaint();
+
+ }
+ }
+
+
+ public void actionresetButton() {
+ Debug.message("CLNT:pmAccess:actionresetButton()");
+ clearAccessInput();
+ pnameText.requestFocus();
+ }
+
+ public void actioncancelButton() {
+ Debug.message("CLNT:pmAccess:actioncancelButton()");
+ clearAccessInput();
+ frame.setVisible(false);
+ frame.repaint();
+ // frame.dispose();
+ }
+
+ public void actionhelpButton() {
+ Debug.message("CLNT:pmAccess:actionhelpButton()");
+ mytop.showHelpItem("AddAccess");
+ }
+
+
+ public void Show() {
+
+ frame.getContentPane().add("North", this);
+ frame.pack();
+ frame.setVisible(true);
+ frame.repaint();
+
+ frame.toFront();
+ frame.requestFocus();
+
+ okButton.setAsDefaultButton();
+ pnameText.requestFocus();
+ Debug.message("CLNT:pmAccess:Show()");
+
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAddAccessFailedException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAddAccessFailedException.java
new file mode 100644
index 0000000000..40899aaf91
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAddAccessFailedException.java
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmAddAccessFailedException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmAddAccessFailedException extends pmGuiException {
+ public pmAddAccessFailedException(String s) {
+ super(s);
+ }
+ public pmAddAccessFailedException() {
+ super();
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAddPrinterFailedException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAddPrinterFailedException.java
new file mode 100644
index 0000000000..c952484b08
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAddPrinterFailedException.java
@@ -0,0 +1,40 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmAddPrinterFailedException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmAddPrinterFailedException extends pmGuiException {
+ public pmAddPrinterFailedException(String s) {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAuthOptions.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAuthOptions.java
new file mode 100644
index 0000000000..456fd87850
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmAuthOptions.java
@@ -0,0 +1,423 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmAuthOptions.java
+ * Prompt for root password from printmgr.
+ * This a helper for printmgr which echoes YES, NO, or CANCEL to stdout.
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import com.sun.admin.pm.server.*;
+
+
+public class pmAuthOptions {
+
+ public static void main(String[] args) {
+
+ boolean done = false;
+ String rv = "CANCEL";
+
+ pmAuthMessage o = new pmAuthMessage(null,
+ pmUtility.getResource("Authentication.required"),
+ pmUtility.getResource("Root.access.is.required"));
+ o.setVisible(true);
+ switch (o.getValue()) {
+ case JOptionPane.YES_OPTION:
+ break;
+
+ case JOptionPane.NO_OPTION:
+ System.out.println("NO");
+ System.exit(0);
+ break;
+
+ case JOptionPane.CANCEL_OPTION:
+ default:
+ System.out.println("CANCEL");
+ System.exit(0);
+ break;
+ }
+
+ while (!done) {
+ pmAuthLogin d = new pmAuthLogin(null,
+ pmUtility.getResource("Root.authentication"),
+ pmUtility.getResource("Enter.root.password"));
+ d.setVisible(true);
+ if (d.getValue() != JOptionPane.OK_OPTION)
+ done = true;
+ else {
+ boolean ok = false;
+ String pw = new String(d.getPassword());
+ try {
+ PrinterUtil.checkRootPasswd(pw);
+ ok = true;
+ } catch (Exception x) {
+
+ }
+ if (!ok) {
+ pmOKCancelDialog m = new pmOKCancelDialog(null,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource("Invalid.password"));
+ m.setVisible(true);
+ if (m.getValue() != JOptionPane.OK_OPTION)
+ done = true;
+ } else {
+ done = true;
+ rv = "YES";
+ }
+ }
+ }
+
+ System.out.println(rv);
+ System.exit(0);
+ }
+
+
+}
+
+
+/*
+ */
+
+class pmAuthLogin extends pmDialog {
+ private String theTag = null;
+
+ protected pmButton okButton = null;
+ protected pmButton cancelButton = null;
+
+ public pmAuthLogin(JFrame f, String title, String msg) {
+
+ super(f, title, true); // modal
+
+ JLabel l;
+ JPanel p;
+
+ // initialize constraints
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.insets = new Insets(10, 10, 10, 10);
+ c.anchor = GridBagConstraints.EAST;
+
+ // top panel contains the desired message
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ l = new JLabel(msg, SwingConstants.CENTER);
+ p.add(l, c);
+ this.getContentPane().add(p, "North");
+
+
+ // middle panel contains username and password
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ l = new JLabel(pmUtility.getResource("Hostname:"),
+ SwingConstants.RIGHT);
+ p.add(l, c);
+
+ l = new JLabel(pmUtility.getResource("Password:"),
+ SwingConstants.RIGHT);
+ p.add(l, c);
+
+ passwordField = new JPasswordField(12);
+ passwordField.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ okPressed();
+ }
+ });
+ l.setLabelFor(passwordField);
+
+ // for consistency, don't implement this until all are...
+ // l.setDisplayedMnemonic(
+ // pmUtility.getIntResource("Password.mnemonic"));
+
+ c.gridx = 1;
+ c.weightx = 1.0;
+
+ c.anchor = GridBagConstraints.WEST;
+
+ String hostname = null;
+ try {
+ hostname = (java.net.InetAddress.getLocalHost()).getHostName();
+ } catch (java.net.UnknownHostException uhx) {
+ System.out.println(uhx);
+ }
+
+ l = new JLabel(hostname, SwingConstants.LEFT);
+ p.add(l, c);
+
+
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridy = GridBagConstraints.RELATIVE;
+
+ p.add(passwordField, c);
+ passwordField.setEchoChar('*');
+
+ this.getContentPane().add(p, "Center");
+
+ // bottom panel contains buttons
+ c.gridx = 0;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+
+ JPanel thePanel = new JPanel();
+
+ okButton = new pmButton(
+ pmUtility.getResource("OK"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("OK.mnemonic"));
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ okPressed();
+ }
+ });
+ thePanel.add(okButton, c);
+
+ cancelButton = new pmButton(
+ pmUtility.getResource("Cancel"));
+ cancelButton.setMnemonic(
+ pmUtility.getIntResource("Cancel.mnemonic"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ cancelPressed();
+ }
+ });
+ thePanel.add(cancelButton, c);
+
+ this.getContentPane().add(thePanel, "South");
+
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ returnValue = JOptionPane.CANCEL_OPTION;
+ setVisible(false);
+ }
+ });
+
+ // handle Esc as cancel in any case
+ this.getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ cancelPressed();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ // lay out the dialog
+ this.pack();
+
+ // set focus and defaults after packing...
+ // this.getRootPane().setDefaultButton(okButton);
+ okButton.setAsDefaultButton();
+
+ passwordField.requestFocus();
+ }
+
+ public int getValue() {
+ return returnValue;
+ }
+
+
+ public void okPressed() {
+ returnValue = JOptionPane.OK_OPTION;
+ setVisible(false);
+ }
+
+ public void cancelPressed() {
+ returnValue = JOptionPane.CANCEL_OPTION;
+ setVisible(false);
+ }
+
+
+ public void clearPressed() {
+ passwordField.setText("");
+ }
+
+ public char[] getPassword() {
+ return passwordField.getPassword();
+ }
+
+
+ public JPasswordField passwordField = null;
+
+ protected int returnValue = JOptionPane.CANCEL_OPTION;
+
+}
+
+
+class pmAuthMessage extends pmDialog {
+ private String theTag = null;
+
+ protected pmButton authButton = null;
+ protected pmButton cancelButton = null;
+ protected pmButton contButton = null;
+
+ public pmAuthMessage(JFrame f, String title, String msg) {
+
+ super(f, title, true); // modal
+
+ JPanel p;
+
+ // initialize constraints
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.insets = new Insets(10, 10, 10, 10);
+ c.anchor = GridBagConstraints.EAST;
+
+ // top panel contains the desired message
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+
+ JList l = new JList() {
+ public boolean isFocusable() {
+ return false;
+ }
+ };
+ // pathetic hacks to make the list look the same as a label
+ JLabel tmp = new JLabel();
+ l.setBackground(tmp.getBackground());
+ l.setForeground(tmp.getForeground());
+ l.setFont(tmp.getFont());
+ tmp = null;
+ Vector v = new Vector();
+ if (msg != null) {
+ StringTokenizer st = new StringTokenizer(msg, "\n", false);
+ try {
+ while (st.hasMoreTokens())
+ v.addElement(st.nextToken());
+ } catch (Exception x) {
+ }
+ l.setListData(v);
+ }
+
+
+ p.add(l, c);
+ this.getContentPane().add(p, "North");
+
+
+ // bottom panel contains buttons
+ c.gridx = 0;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+
+ JPanel thePanel = new JPanel();
+
+ authButton = new pmButton(pmUtility.getResource("Authenticate"));
+ authButton.setMnemonic(
+ pmUtility.getIntResource("Authenticate.mnemonic"));
+ authButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ authPressed();
+ }
+ });
+ thePanel.add(authButton, c);
+
+ contButton = new pmButton(pmUtility.getResource("Continue"));
+ contButton.setMnemonic(pmUtility.getIntResource("Continue.mnemonic"));
+ contButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ contPressed();
+ }
+ });
+ thePanel.add(contButton, c);
+
+ cancelButton = new pmButton(pmUtility.getResource("Cancel"));
+ cancelButton.setMnemonic(pmUtility.getIntResource("Cancel.mnemonic"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ cancelPressed();
+ }
+ });
+ thePanel.add(cancelButton, c);
+
+ this.getContentPane().add(thePanel, "South");
+
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ returnValue = JOptionPane.CANCEL_OPTION;
+ setVisible(false);
+ }
+ });
+
+ // handle Esc as cancel in any case
+ this.getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ cancelPressed();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ // lay out the dialog
+ this.pack();
+
+ // set focus and defaults after packing...
+ authButton.setAsDefaultButton();
+
+ }
+
+ public int getValue() {
+ return returnValue;
+ }
+
+
+ public void authPressed() {
+ returnValue = JOptionPane.YES_OPTION;
+ setVisible(false);
+ }
+
+ public void cancelPressed() {
+ returnValue = JOptionPane.CANCEL_OPTION;
+ setVisible(false);
+ }
+
+
+ public void contPressed() {
+ returnValue = JOptionPane.NO_OPTION;
+ setVisible(false);
+ }
+
+ protected int returnValue = JOptionPane.CANCEL_OPTION;
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmButton.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmButton.java
new file mode 100644
index 0000000000..1c14c5642e
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmButton.java
@@ -0,0 +1,216 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmButton.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+/*
+ * strategy:
+ * Keep a hashtable of root panes and their associated default buttons.
+ * Note that there is at present no way to remove a root pane entry
+ * from the table...
+ *
+ * Ideally there should be an interface to allow objects to
+ * remove themselves before disappearing.
+ */
+
+public class pmButton extends JButton {
+
+ // static JButton defaultButton = null;
+
+ // map root panes to their true default buttons
+ static Hashtable map = new Hashtable();
+
+ public static Hashtable getHashtable() {
+ return map;
+ }
+
+ /*
+ * make this button the default on this root pane
+ * retunrs true if success, false o/w
+ */
+ boolean makeDefaultButton() {
+ return makeDefaultButton(this);
+ }
+
+ /*
+ * make b the default on this root pane
+ * returns true if success, false otherwise
+ */
+ boolean makeDefaultButton(JButton b) {
+ JRootPane r = this.getRootPane();
+
+ if (r == null) {
+ Debug.info("BUTTON: null root panel");
+ return false;
+ }
+
+ if (b == null) {
+ Debug.info("BUTTON: makeDefaultButton null on " + r);
+ }
+
+ /*
+ * Debug.info("\nBUTTON: makeDefaultButton " +
+ * (b == null ? "null" : b.getText()) +
+ * " on " + r + "\n");
+ */
+
+ if (b != null && b.isDefaultCapable() == false) {
+ Debug.info("BUTTON: false isDefaultCapable on " + r);
+ return false;
+ }
+
+ // unfocus the old default, if it's different
+ JButton oldb;
+ if ((oldb = r.getDefaultButton()) != null && oldb != b) {
+ oldb.setFocusPainted(false);
+ }
+
+ /*
+ * Debug.info("\nBUTTON: makeDefaultButton: old button was " +
+ * (oldb == null ? "null" : oldb.getText()) + "\n");
+ */
+
+ r.setDefaultButton(b);
+
+ return true;
+ }
+
+
+ public pmButton(String s) {
+ super(s);
+
+ this.addFocusListener(new FocusAdapter() {
+
+ // upon gaining focus: make this the root pane's default
+ public void focusGained(FocusEvent e) {
+ if (e.isTemporary()) {
+ /*
+ * Debug.info("BUTTON: " + getText() +
+ * " gained temp - ignoring");
+ */
+ return;
+ }
+
+ Debug.info("BUTTON: " + getText() + " gained");
+
+ if (makeDefaultButton())
+ setFocusPainted(true);
+
+ }
+
+ // upon losing focus: make 'true' default the default
+ public void focusLost(FocusEvent e) {
+ if (e.isTemporary()) {
+ /*
+ * Debug.info("BUTTON: " + getText() +
+ * " lost temp - ignoring");
+ */
+ return;
+ }
+
+ Debug.info("BUTTON: " + getText() + " lost");
+
+ /*
+ * i thought it might make sense to test for the
+ * next focusable comp, but what if focus is being
+ * lost as the result of a mouse click??
+ */
+
+ makeDefaultButton((JButton) map.get(getRootPane()));
+ // setFocusPainted(false);
+ }
+
+ });
+ }
+
+ // make this the true default for this root pane
+ void setAsDefaultButton() {
+ setAsDefaultButton(this);
+ }
+
+ // make b the true default for this root pane
+ void setAsDefaultButton(JButton b) {
+ JRootPane r = getRootPane();
+
+ /*
+ * Debug.message("BUTTON: setAsDefaultButton " +
+ * (b == null ? "null" : b.getText()) +
+ * " root = " + r);
+ */
+
+ // setting default to null removes state
+ if (b == null)
+ map.remove(r);
+ else
+ map.put(r, b); // creates a new entry if needed
+ makeDefaultButton(b);
+ }
+
+
+ // clean up component about to be removed
+ void unreference() {
+ JRootPane r = getRootPane();
+ map.remove(r);
+ }
+
+ public static void unreference(JComponent c) {
+ JRootPane r = c.getRootPane();
+ map.remove(r);
+ }
+
+ public static void unreference(JRootPane r) {
+ map.remove(r);
+ }
+
+
+ static boolean enableMnemonics = false;
+
+ static void setEnableMnemonics(boolean m) {
+ enableMnemonics = m;
+ }
+
+ public void setMnemonic(int mnemonic) {
+ setMnemonic((char)mnemonic);
+ }
+
+ public void setMnemonic(char mnemonic) {
+ if (enableMnemonics)
+ super.setMnemonic(mnemonic);
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmButtonScreen.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmButtonScreen.java
new file mode 100644
index 0000000000..de18335be2
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmButtonScreen.java
@@ -0,0 +1,175 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmButtonsScreen.java
+ * Common dialog superclass
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JPanel;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+/*
+ * Screen class for JPanels
+ */
+
+public class pmButtonScreen extends JPanel {
+
+ final static int OK = 1;
+ final static int APPLY = 2;
+ final static int RESET = 3;
+ final static int CANCEL = 4;
+ final static int HELP = 5;
+
+ pmButton okButton;
+ pmButton applyButton;
+ pmButton resetButton;
+ pmButton cancelButton;
+ pmButton helpButton;
+
+
+ public void southPanel() {
+
+ JPanel south = new JPanel();
+
+ south.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridheight = 1;
+ c.gridwidth = 1;
+ c.weightx = c.weighty = 0.0;
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.gridy = 0;
+
+ okButton = new pmButton(
+ pmUtility.getResource("OK"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("OK.mnemonic"));
+
+ applyButton = new pmButton(
+ pmUtility.getResource("Apply"));
+ applyButton.setMnemonic(
+ pmUtility.getIntResource("Apply.mnemonic"));
+
+ resetButton = new pmButton(
+ pmUtility.getResource("Reset"));
+ resetButton.setMnemonic(
+ pmUtility.getIntResource("Reset.mnemonic"));
+
+ cancelButton = new pmButton(
+ pmUtility.getResource("Cancel"));
+ cancelButton.setMnemonic(
+ pmUtility.getIntResource("Cancel.mnemonic"));
+
+ helpButton = new pmButton(
+ pmUtility.getResource("Help"));
+ helpButton.setMnemonic(
+ pmUtility.getIntResource("Help.mnemonic"));
+
+ okButton.addActionListener(new ButtonListener(OK));
+ applyButton.addActionListener(new ButtonListener(APPLY));
+ resetButton.addActionListener(new ButtonListener(RESET));
+ cancelButton.addActionListener(new ButtonListener(CANCEL));
+ helpButton.addActionListener(new ButtonListener(HELP));
+
+ c.insets = new Insets(15, 5, 10, 5);
+ c.gridx = 0;
+ south.add(okButton, c);
+ c.gridx = 1;
+ south.add(applyButton, c);
+ c.gridx = 2;
+ south.add(resetButton, c);
+ c.gridx = 3;
+ south.add(cancelButton, c);
+ c.gridx = 4;
+ south.add(helpButton, c);
+
+ add("South", south);
+ }
+
+ class ButtonListener implements ActionListener {
+ int activeButton;
+
+ // Constructor
+
+ public ButtonListener(int aButton)
+ {
+ activeButton = aButton;
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ switch (activeButton) {
+ case OK:
+ actionokButton();
+ break;
+ case APPLY:
+ actionapplyButton();
+ break;
+ case RESET:
+ actionresetButton();
+ break;
+ case CANCEL:
+ actioncancelButton();
+ break;
+ case HELP:
+ actionhelpButton();
+ break;
+ }
+ }
+ }
+
+ public void actionokButton()
+ {
+ }
+
+ public void actionapplyButton()
+ {
+ }
+
+ public void actionresetButton()
+ {
+ }
+
+ public void actioncancelButton()
+ {
+ }
+
+ public void actionhelpButton()
+ {
+ }
+
+
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmCacheMissingPPDException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmCacheMissingPPDException.java
new file mode 100644
index 0000000000..4a2b171f68
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmCacheMissingPPDException.java
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmInstallPrinter.java
+ * Install and Modify Printer implementation
+ *
+ * pmCacheMissingPPDException
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+public class pmCacheMissingPPDException extends pmGuiException {
+ public pmCacheMissingPPDException(String s) {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmCalls.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmCalls.java
new file mode 100644
index 0000000000..5503d90a97
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmCalls.java
@@ -0,0 +1,158 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmCalls.java
+ * Debug messages
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.applet.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+/*
+ * Class of calls to backend
+ */
+
+public class pmCalls {
+
+/*
+ * Debugging routines
+ */
+
+ public static void testout(String out) {
+ Debug.info(out);
+ }
+
+ public static void debugShowPrinter(Printer p) {
+ Debug.info("CLNT: debugShowPrinter");
+
+ if (p.getPrinterName() != null) {
+ Debug.info("CLNT: printer " +
+ p.getPrinterName());
+ }
+
+ if (p.getPrintServer() != null)
+ Debug.info("CLNT: server " +
+ p.getPrintServer());
+
+ if (p.getPrinterType() != null)
+ Debug.info("CLNT: printer type " +
+ p.getPrinterType());
+
+ if (p.getComment() != null)
+ Debug.info("CLNT: Comment " +
+ p.getComment());
+
+ if (p.getDevice() != null)
+ Debug.info("CLNT: Device " +
+ p.getDevice());
+
+ if (p.getMake() != null)
+ Debug.info("CLNT: Make " +
+ p.getMake());
+ else
+ Debug.info("CLNT: Make is null");
+
+ if (p.getModel() != null)
+ Debug.info("CLNT: Model " +
+ p.getModel());
+ else
+ Debug.info("CLNT: Model is null");
+
+ if (p.getPPD() != null)
+ Debug.info("CLNT: PPD " +
+ p.getPPD());
+ else
+ Debug.info("CLNT: PPD is null");
+
+ if (p.getNotify() != null)
+ Debug.info("CLNT: Notify " +
+ p.getNotify());
+
+ if (p.getBanner() != null)
+ Debug.info("CLNT: Banner " + p.getBanner());
+
+ if (p.getProtocol() != null)
+ Debug.info("CLNT: Protocol " +
+ p.getProtocol());
+
+ if (p.getDestination() != null)
+ Debug.info("CLNT: Destination " +
+ p.getDestination());
+
+ if (p.getFileContents() != null) {
+
+ String filedata[] = p.getFileContents();
+ String filecontents = new String();
+
+ Debug.info("CLNT: File Contents: ");
+
+ if (filedata != null) {
+ for (int i = 0; i < filedata.length; i++) {
+ Debug.info(" " + filedata[i]);
+ }
+ }
+ }
+
+ if (p.getNotify() != null) {
+ Debug.info("CLNT: Fault Notification: " + p.getNotify());
+ }
+
+ String ua[] = p.getUserAllowList();
+ Debug.info("CLNT: UserAllowList ");
+ if (ua != null) {
+ for (int i = 0; i < ua.length; i++) {
+ Debug.info(" " + ua[i]);
+ }
+ }
+
+ Debug.info("CLNT: getIsDefaultPrinter is " + p.getIsDefaultPrinter());
+
+ }
+
+ public static void debugshowPrinterList(NameService ns) {
+
+ String[] list;
+
+ try {
+ list = PrinterUtil.getPrinterList(ns);
+ for (int i = 0; i < list.length; i++)
+ Debug.info("CLNT: " + list[i]);
+ } catch (Exception e) {
+ Debug.info("CLNT: debugshowPrinterList(): exception " + e);
+ }
+
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDelete.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDelete.java
new file mode 100644
index 0000000000..4e138209b8
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDelete.java
@@ -0,0 +1,183 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmDelete.java
+ * Delete Printer implementation
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JPanel;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+/*
+ * Window for Edit -> Delete
+ */
+
+// public class pmDelete extends JPanel {
+public class pmDelete {
+
+ Printer newpr = null;
+ pmTop mytop = null;
+
+ public pmDelete(pmTop mytop)
+ {
+ this.mytop = mytop;
+ newpr = new Printer(mytop.ns);
+
+ Debug.message("CLNT: pmDelete");
+
+ if (mytop.selectedPrinter.equals("")) {
+ Debug.warning("CLNT: pmDelete:error: selectedPrinter empty");
+ // Display error window
+ actioncancelButton();
+ }
+
+ pmOKCancelDialog d = new pmOKCancelDialog(
+ mytop.parentFrame,
+ pmUtility.getResource("SPM:Delete.Printer"),
+ pmUtility.getResource("Please.confirm.deletion.of.printer") +
+ mytop.selectedPrinter, false);
+ d.setVisible(true);
+
+ if (d.getValue() != JOptionPane.OK_OPTION)
+ actioncancelButton();
+ else {
+ try {
+ actionokButton();
+ } catch (pmUserCancelledException ce) {
+ Debug.message("CLNT: pmDelete:okButton: Login cancelled");
+ } catch (pmLoginFailedException de) {
+ pmMessageDialog m = new pmMessageDialog(
+ mytop.parentFrame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource("Required.login.failed."),
+ mytop,
+ "LoginFailed");
+ m.setVisible(true);
+ } catch (pmGuiException ge) {
+ pmMessageDialog m = new pmMessageDialog(
+ mytop.parentFrame,
+ pmUtility.getResource("Application.Error"),
+ ge.toString());
+ m.setVisible(true);
+ }
+ }
+
+ }
+
+ public void actionokButton() throws pmGuiException {
+ int ret;
+ String cmd = null;
+ String warn = null;
+ String err = null;
+
+ Debug.message("CLNT: pmDelete actionokButton()");
+
+ // handle authentication if needed
+ if (mytop.ns.getNameService().equals("nis") == true ||
+ mytop.ns.getNameService().equals("ldap") == true) {
+ try {
+ if (!mytop.ns.isAuth()) {
+ pmUtility.doLogin(mytop, mytop.parentFrame);
+ }
+ } catch (pmUserCancelledException e) {
+ Debug.message("CLNT: pmDelete:User cancelled login");
+ throw new pmUserCancelledException(
+ pmUtility.getResource("User.Cancelled.Login"));
+ } catch (pmGuiException e) {
+ Debug.warning("CLNT: pmDelete:login for nis/ldap failed");
+ throw new pmLoginFailedException(
+ pmUtility.getResource("Login.Authorization.Failed"));
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmDelete:login for nis/ldap failed");
+ throw new pmLoginFailedException(
+ pmUtility.getResource("Login.Authorization.Failed"));
+ }
+ }
+
+ newpr.setPrinterName(mytop.selectedPrinter);
+
+ // delete the printer
+ boolean failed = false;
+ try {
+ newpr.deletePrinter();
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmDelete:deletePrinter exception " + e);
+ failed = true;
+ }
+
+ cmd = newpr.getCmdLog();
+ warn = newpr.getWarnLog();
+ err = newpr.getErrorLog();
+
+ Debug.message("CLNT: pmDelete: delete cmd = " + cmd);
+ Debug.message("CLNT: pmDelete: delete err = " + err);
+ Debug.message("CLNT: pmDelete: delete warn = " + warn);
+
+ if (failed) {
+ pmMessageDialog m = new pmMessageDialog(
+ mytop.parentFrame,
+ pmUtility.getResource("Error"),
+ ((err == null) ?
+ pmUtility.getResource(
+ "Printer.delete.operation.failed.") :
+ err),
+ mytop,
+ "DeletePrinterFailed");
+ m.setVisible(true);
+
+ } else {
+ Debug.message("CLNT: pmDelete return from deletePrinter ok");
+
+ // Deletion successful, change the table
+ if (mytop.selectedRow >= 0) {
+ // update table
+ mytop.pmsetPrinterList();
+ mytop.clearSelected();
+ mytop.listTable.clearSelection();
+ mytop.pmsetdefaultpLabel();
+ } else {
+ Debug.warning("CLNT: pmDelete:selectedRow invalid: " +
+ mytop.selectedRow);
+ }
+ }
+ mytop.setLogData(cmd, err, warn);
+ mytop.showLogData(pmUtility.getResource("Delete.Printer"));
+ }
+
+
+ public void actioncancelButton() {
+ Debug.message("CLNT: pmDelete: actioncancelButton()");
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDeleteFailedException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDeleteFailedException.java
new file mode 100644
index 0000000000..88237fd948
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDeleteFailedException.java
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmDeleteFailedException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmDeleteFailedException extends pmGuiException {
+ public pmDeleteFailedException(String s) {
+ super(s);
+ }
+ public pmDeleteFailedException() {
+ super();
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDialog.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDialog.java
new file mode 100644
index 0000000000..87a9adbdf8
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDialog.java
@@ -0,0 +1,125 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright(c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmDialog.java
+ * Extends JDialog to provide for better default location.
+ */
+
+package com.sun.admin.pm.client;
+
+import java.net.*;
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.*;
+
+import com.sun.admin.pm.server.Debug;
+
+public class pmDialog extends JDialog implements pmDialogConstraints {
+
+ public pmDialog(Frame owner) {
+ this(owner, null, false);
+ }
+
+ public pmDialog(Frame owner, boolean modal) {
+ this(owner, null, modal);
+ }
+
+ public pmDialog(Frame owner, String title) {
+ this(owner, title, false);
+ }
+
+ public pmDialog(Frame f, String title, boolean modal) {
+
+ super(f, title, modal);
+
+ // determine a nice location relative to parent frame
+ Point newLocation = new Point(0, 0); // default
+
+ if (f == null) {
+ // centered on screen
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ newLocation = new Point(screenSize.width / 2 - xoffset,
+ screenSize.height / 2 - yoffset);
+
+ } else {
+ // centered over parent frame
+ Rectangle parentBounds = f.getBounds();
+ newLocation = new Point(
+ parentBounds.x + parentBounds.width / 2 - xoffset,
+ parentBounds.y + parentBounds.height / 2 - yoffset);
+ f.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ Debug.info("dialog Window closing");
+ cleanupButtons();
+ }
+ public void windowClosed(WindowEvent e) {
+ Debug.info("dialog Window closed");
+ cleanupButtons();
+ }
+ public void windowDeactivated(WindowEvent e) {
+ Debug.info("dialog Window deactivated");
+ // possible java bug: too many of these events generated!
+ // cleanupButtons();
+ }
+ });
+ }
+ setLocation(newLocation);
+
+ // cannot set dialog icons under 1.1....
+ /*
+ * try {
+ * String iconName = new String("images/appicon.gif");
+ * Class thisClass = this.getClass();
+ * URL iconUrl = thisClass.getResource(iconName);
+ * if (iconUrl == null)
+ * Debug.warning("Unable to resolve URL for icon " + iconName);
+ * else {
+ * Toolkit tk = Toolkit.getDefaultToolkit();
+ * Image img = tk.getImage(iconUrl);
+ * // this.setIconImage(img);
+ * }
+ * } catch (Exception x) {
+ * Debug.warning(x.toString());
+ * }
+ */
+
+ }
+
+ public void cleanupButtons() {
+ // drop this rootPane from pmButton's hashtable
+ pmButton.unreference(this.getRootPane());
+ }
+
+ public void setVisible(boolean b) {
+ if (b == false)
+ cleanupButtons();
+ super.setVisible(b);
+ }
+
+}
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDialogConstraints.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDialogConstraints.java
new file mode 100644
index 0000000000..f7a90727c1
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmDialogConstraints.java
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright(c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmDialogConstraints.java
+ * Location constants for pmDialogs.
+ */
+
+package com.sun.admin.pm.client;
+
+public interface pmDialogConstraints {
+
+ /*
+ * These are offsets from origin of a pmDialog's parent frame
+ * at which to place the newly created dialog.
+ */
+ static final int xoffset = 100;
+ static final int yoffset = 80;
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmFindFrame.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmFindFrame.java
new file mode 100644
index 0000000000..ad54f0a6b8
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmFindFrame.java
@@ -0,0 +1,221 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmFindFrame.java
+ * Find Printer dialog implementation
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JPanel;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+public class pmFindFrame extends pmFrame {
+
+ JLabel statusText = null;
+ pmButton okButton = null;
+ pmButton cancelButton = null;
+ pmButton helpButton = null;
+ pmTop theTop = null;
+
+ String label = pmUtility.getResource("Enter.name.of.printer.to.find");
+ String helpTag = "ToFindPrinter";
+
+ public pmFindFrame(pmTop t) {
+
+ super(pmUtility.getResource("SPM:Find.Printer"));
+
+ setLocation(100, 100);
+
+ theTop = t;
+
+
+ JLabel l;
+ JPanel p;
+
+ // initialize constraints
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.insets = new Insets(10, 10, 5, 10);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0;
+
+ // top panel contains the message
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ l = new JLabel(label, SwingConstants.LEFT);
+ p.add(l, c);
+
+ getContentPane().add(p, "North");
+
+ // middle panel contains "other" text field
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ printerName = new pmTextField(30);
+ printerName.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ okPressed();
+ }
+ });
+ l.setLabelFor(printerName);
+
+ c.gridx = 1;
+ c.gridy = 0;
+ c.weightx = 1.0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = new Insets(0, 10, 5, 10);
+
+ p.add(printerName, c);
+
+ statusText = new JLabel(" ", SwingConstants.LEFT);
+
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridx = 0;
+ c.gridwidth = 2;
+
+ c.insets = new Insets(5, 10, 5, 10);
+ p.add(statusText, c);
+
+ getContentPane().add(p, "Center");
+
+ // bottom panel contains buttons
+ c.gridx = 0;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = new Insets(5, 10, 10, 10);
+
+ JPanel thePanel = new JPanel();
+
+ okButton = new pmButton(
+ pmUtility.getResource("Find"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("Find.mnemonic"));
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ okPressed();
+ }
+ });
+ thePanel.add(okButton, c);
+
+ cancelButton = new pmButton(
+ pmUtility.getResource("Dismiss"));
+ cancelButton.setMnemonic(
+ pmUtility.getIntResource("Dismiss.mnemonic"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ cancelPressed();
+ }
+ });
+ thePanel.add(cancelButton, c);
+
+ helpButton = new pmButton(
+ pmUtility.getResource("Help"));
+ helpButton.setMnemonic(
+ pmUtility.getIntResource("Help.mnemonic"));
+ helpButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ theTop.showHelpItem(helpTag);
+ }
+ });
+ thePanel.add(helpButton, c);
+
+ getContentPane().add(thePanel, "South");
+
+ // lay out the dialog
+ pack();
+
+ // handle Esc as dismiss in any case
+ getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ cancelPressed();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+
+ // set focus to initial field, depending on which action is tbd
+ // this seems to work best after pack()
+
+ /*
+ * frame.setVisible(true);
+ * frame.repaint();
+ */
+
+ // getRootPane().setDefaultButton (okButton);
+ okButton.setAsDefaultButton();
+
+ printerName.requestFocus();
+
+ // enable improved focus handling
+ setDefaultComponent(printerName);
+
+ }
+
+
+ public void okPressed() {
+ Debug.message("CLNT: pmFindFrame:okPressed():" +
+ printerName.getText());
+
+ String name = printerName.getText();
+ boolean result = theTop.findPrinterInList(name.trim());
+ if (!result)
+ statusText.setText(new String(
+ pmUtility.getResource("Unable.to.find.printer") + name));
+ else
+ statusText.setText(" ");
+
+ // pmFindPanel.this.frame.setVisible (false);
+
+ }
+
+ public void cancelPressed() {
+ Debug.message("CLNT: pmFindFrame: cancelPressed()");
+ statusText.setText(" ");
+ printerName.setText("");
+ pmFindFrame.this.setVisible(false);
+
+ }
+
+ public pmTextField printerName = null;
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmFrame.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmFrame.java
new file mode 100644
index 0000000000..ec37480473
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmFrame.java
@@ -0,0 +1,133 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmFrame.java
+ * Extends JFrame to support better focus handling
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.net.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+class pmFrame extends JFrame {
+
+ // this comp gets focus on frame open
+ Component defaultComponent = null;
+
+ // file path of icon; this does not provide for localization
+ private static final String iconName = "images/appicon.gif";
+
+ // if true, clean up pmButton state on frame close
+ private boolean clearButtonsOnClose;
+
+ public pmFrame(String s) {
+ super(s);
+
+ // default: do NOT clear default button state when frame is closed
+ clearButtonsOnClose = false;
+
+ this.addFocusListener(new FocusListener() {
+ public void focusGained(FocusEvent e) {
+ Debug.message("CLNT: pmFrame focus gained: " + e);
+ if (defaultComponent != null) {
+ Debug.message("CLNT: pmFrame focus to default comp");
+ defaultComponent.requestFocus();
+ } else
+ Debug.message("CLNT: pmFrame no default comp");
+ }
+ public void focusLost(FocusEvent e) {
+ Debug.message("CLNT: frame focus lost: " + e);
+ }
+ });
+
+ this.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ Debug.info("frame Window closing");
+ cleanupButtons();
+ }
+ public void windowClosed(WindowEvent e) {
+ Debug.info("frame Window closed");
+ cleanupButtons();
+ }
+ });
+
+ try {
+ Class thisClass = this.getClass();
+ URL iconUrl = thisClass.getResource(iconName);
+ // System.out.println("Icon: " + iconUrl);
+ if (iconUrl == null)
+ Debug.warning("Unable to resolve URL for icon " + iconName);
+ else {
+ Toolkit tk = Toolkit.getDefaultToolkit();
+ Image img = tk.getImage(iconUrl);
+ this.setIconImage(img);
+ }
+
+ } catch (Exception x) {
+ Debug.warning(x.toString());
+ }
+ }
+
+
+ public void setDefaultComponent(Component c) {
+ defaultComponent = c;
+ }
+
+
+ // If the frame is a minimized icon, make it un-minimized first
+ public void setVisible(boolean isVisible) {
+ if (isVisible == true) {
+ try {
+ // this will fail in jdk 1.1 but work fine in 1.2
+ setState(NORMAL);
+ } catch (Exception ssx) {
+ // restores an iconified window in JDK 1.1
+ removeNotify();
+ addNotify();
+ }
+ } else
+ cleanupButtons();
+ super.setVisible(isVisible);
+ }
+
+ public void cleanupButtons() {
+ // drop this rootPane from pmButton's hashtable
+ if (clearButtonsOnClose)
+ pmButton.unreference(this.getRootPane());
+ }
+
+ protected void setClearButtonsOnClose(boolean b) {
+ clearButtonsOnClose = b;
+ }
+
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmGuiException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmGuiException.java
new file mode 100644
index 0000000000..f4dfccae58
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmGuiException.java
@@ -0,0 +1,55 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmGuiException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+public class pmGuiException extends Exception {
+
+ String s = null;
+
+ public pmGuiException(String s) {
+ super(s);
+
+ }
+
+ public pmGuiException() {
+ super();
+
+ }
+
+// XXX use localized strings
+ public String getLocalizedMessage() {
+ return getMessage();
+
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpContent.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpContent.java
new file mode 100644
index 0000000000..27919cbde5
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpContent.java
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHelpContent.java
+ * Wrapper for content of help articles
+ */
+
+package com.sun.admin.pm.client;
+
+class pmHelpContent extends Object {
+ private String text;
+
+ public pmHelpContent(String content) {
+ text = content;
+ }
+
+ public pmHelpContent(pmHelpContent other) {
+ text = new String(other.text);
+ }
+
+ public String toString() {
+ return text;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpController.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpController.java
new file mode 100644
index 0000000000..320d470254
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpController.java
@@ -0,0 +1,101 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHelpController.java
+ * Help subsystem implementation
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.io.*;
+import javax.swing.JPanel;
+import javax.swing.border.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+class pmHelpController {
+
+ public pmHelpFrame frame = null;
+
+ /*
+ * request presentation of the specified help item.
+ */
+ public void showHelpItem(String tag) {
+ Debug.info("HELP: controller.showHelpitem " + tag);
+ if (tag != null) {
+ pmHelpItem item = viewPanel.loadItemForTag(tag);
+ outerPanel.setSelectedComponent(viewPanel);
+ }
+ }
+
+ public void showHelpItem(pmHelpItem item) {
+ if (item != null)
+ showHelpItem(item.tag);
+ }
+
+ JTabbedPane outerPanel;
+ pmHelpDetailPanel viewPanel;
+ pmHelpIndexPanel indexPanel;
+ pmHelpSearchPanel searchPanel;
+
+ Vector history;
+
+ public JTabbedPane getTopPane() {
+ return outerPanel;
+ }
+
+ public pmHelpController(pmHelpFrame f) {
+
+ frame = f;
+
+ outerPanel = new JTabbedPane();
+
+ viewPanel = new pmHelpDetailPanel(this);
+ indexPanel = new pmHelpIndexPanel(this);
+ searchPanel = new pmHelpSearchPanel(this);
+
+ outerPanel.add(pmUtility.getResource("View"), viewPanel);
+ outerPanel.add(pmUtility.getResource("Index"), indexPanel);
+ outerPanel.add(pmUtility.getResource("Search"), searchPanel);
+
+ pmHelpRepository.populateHelpItemDB();
+ pmHelpRepository.populateHelpKeywordDB();
+ pmHelpRepository.populateHelpTitleDB();
+
+ indexPanel.queryPanel.handleText(""); // prime it... ugly.
+
+ history = new Vector();
+
+ frame.setDefaultComponent(outerPanel);
+ }
+
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpDetailPanel.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpDetailPanel.java
new file mode 100644
index 0000000000..434670f508
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpDetailPanel.java
@@ -0,0 +1,597 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright(c) 1999 - 2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHelpDetailPanel.java
+ * View a help article
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.io.*;
+import java.net.URL;
+import javax.swing.JPanel;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+class pmHelpLoc {
+ public pmHelpItem item;
+ public Point pos;
+
+ public pmHelpLoc(pmHelpItem i) {
+ this(i, new Point(0, 0));
+ }
+
+ public pmHelpLoc(pmHelpItem i, Point p) {
+ item = i;
+ pos = p;
+ }
+
+ public pmHelpLoc() {
+ this(null, new Point(0, 0));
+ }
+}
+
+public class pmHelpDetailPanel extends JPanel {
+
+ pmHelpController controller;
+ pmHelpSeeAlsoPanel seeAlsoPanel;
+ pmHelpViewPanel viewPanel;
+
+ pmHelpLoc history[];
+ int historyIndex;
+ int historyLast;
+
+ static final int MAX_HISTORY_ITEMS = 101;
+
+ public pmHelpDetailPanel(pmHelpController ctrl) {
+
+ controller = ctrl;
+
+ // build subpanels
+ seeAlsoPanel = new pmHelpSeeAlsoPanel(this);
+ viewPanel = new pmHelpViewPanel(this);
+
+ // lay out top panel
+ this.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.insets = new Insets(5, 5, 5, 5);
+
+ c.gridwidth = GridBagConstraints.REMAINDER;
+
+ c.gridx = 0;
+ c.gridy = 0;
+
+ c.gridheight = 2; // GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1.0;
+ c.weighty = 6.0;
+ c.insets = new Insets(5, 5, 0, 5);
+ this.add(viewPanel, c);
+
+ c.gridy = GridBagConstraints.RELATIVE;
+ // c.gridheight = GridBagConstraints.REMAINDER;
+ c.gridheight = 0;
+ c.weighty = 0.0;
+ c.weightx = 1.0;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor = GridBagConstraints.WEST;
+ c.insets = new Insets(0, 5, 5, 5);
+ this.add(seeAlsoPanel, c);
+
+ this.setBorder(BorderFactory.createEtchedBorder());
+
+ history = new pmHelpLoc[MAX_HISTORY_ITEMS];
+ historyIndex = 0;
+ historyLast = 0;
+
+ // manage focus when we are tabbed or un-tabbed
+ controller.outerPanel.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent e) {
+ JTabbedPane tp = (JTabbedPane) e.getSource();
+ Debug.info("HELP: Tab event!");
+ if (!(tp.getSelectedComponent() instanceof
+ com.sun.admin.pm.client.pmHelpDetailPanel)) {
+ Debug.info("HELP: Tab event: resetting default");
+ /*
+ * controller.frame.getRootPane().
+ * setDefaultButton(
+ * controller.frame.dismiss);
+ */
+ if (controller.frame.dismiss != null)
+ controller.frame.dismiss.
+ setAsDefaultButton();
+ }
+ }
+ });
+
+ addFocusListener(new FocusAdapter() {
+ public void focusGained(FocusEvent e) {
+ Debug.info("HELP: detailPanel gained focus");
+ if (controller.frame.dismiss != null)
+ controller.frame.dismiss.
+ setAsDefaultButton();
+
+ }
+ });
+ }
+
+ // ask parent controller to show item
+ public void showItem(String tag) {
+ controller.showHelpItem(tag);
+ }
+
+ public void showHistoryBackItem() {
+ Debug.message("HELP: showHistoryBackItem: index = " +
+ historyIndex + " last = " +
+ historyLast +
+ "\n\thistory = " +
+ history);
+
+ // assuming item already visible, preserve its position
+ history[historyIndex].pos = viewPanel.getPos();
+
+ Debug.info("back: pos is " + history[historyIndex].pos);
+
+ if (historyIndex > 1) {
+ pmHelpLoc l = history [--historyIndex];
+ pmHelpItem item = l.item;
+ Point p = l.pos;
+ loadItem(item, p);
+ }
+ viewPanel.setNavButtons(historyIndex, historyLast);
+ }
+
+ public void showHistoryForwardItem() {
+ Debug.message("HELP: showHistoryForwardItem: index = " +
+ historyIndex +
+ " last = " + historyLast +
+ "\n\thistory = " + history);
+
+ // assuming already an item visible, preserve its position
+ history[historyIndex].pos = viewPanel.getPos();
+
+ Debug.info("HELP: fwd: pos is " + history[historyIndex].pos);
+
+ if (historyIndex < historyLast) {
+ pmHelpLoc l = history [++historyIndex];
+ pmHelpItem item = l.item;
+ Point p = l.pos;
+ loadItem(item, p);
+ }
+ viewPanel.setNavButtons(historyIndex, historyLast);
+ }
+
+
+ /*
+ * load the help item
+ * internal
+ */
+ protected pmHelpItem loadItem(pmHelpItem item) {
+ return loadItem(item, new Point(0, 0));
+ }
+
+ protected pmHelpItem loadItem(pmHelpItem item, Point pos) {
+ Debug.message("HELP: View: loadItem " + item.tag);
+ seeAlsoPanel.setItems(item.seealso);
+
+ Debug.info("loadItem: pos is " + pos);
+
+ viewPanel.setItem(item.title, item.content);
+ viewPanel.setPos(pos);
+ return item;
+ }
+
+
+ /*
+ * load the help item corresponding to the specified tag
+ * external - called from helpController
+ * note that this is how see-also items are loadedes
+ */
+ public pmHelpItem loadItemForTag(String tag) {
+
+ pmHelpItem item;
+
+ if (tag == null ||
+ (item = pmHelpRepository.helpItemForTag(tag)) == null) {
+ Debug.warning("HELP: View: item not found");
+ loadEmptyItem(tag);
+ return null;
+ }
+
+ Debug.info("loadItem(before): index = " + historyIndex +
+ ", last = " + historyLast);
+
+ // if there's already an item visible, preserve its position
+ if (historyIndex != 0 && historyLast != 0)
+ history[historyIndex].pos = viewPanel.getPos();
+
+ loadItem(item);
+
+ Debug.info("HELP: loadItemForTag: index = " + historyIndex +
+ " last = " + historyLast + "\n\thistory = " +
+ history);
+
+ /*
+ * make the new item the latest in history.
+ * if the history length is maxed out, the new item
+ * will replace the item that's currently last.
+ */
+
+ if (historyIndex < history.length - 1) {
+ // init pos to 0,0
+ history [++historyIndex] = new pmHelpLoc(item);
+ } else {
+ // replace last item
+ history [historyIndex] = new pmHelpLoc(item);
+ }
+ historyLast = historyIndex;
+
+ viewPanel.setNavButtons(historyIndex, historyLast);
+
+ Debug.info("loadItem(after): index = " + historyIndex +
+ ", last = " + historyLast);
+ return item;
+ }
+
+ private void loadEmptyItem(String itm) {
+ String msg = new String(
+ pmUtility.getResource("Item.not.found:") + itm);
+ viewPanel.setItem(msg, new pmHelpContent(
+ pmUtility.getResource("No.information.available.")));
+ seeAlsoPanel.setItems(null);
+ }
+
+}
+
+
+
+class pmHelpSeeAlsoPanel extends JPanel {
+
+ pmHelpDetailPanel parentPanel = null;
+ Vector seeAlsoItems = null;
+ JComboBox theComboBox = null;
+ pmButton selectButton = null;
+
+ private void layoutBox() {
+
+ JPanel p = new JPanel();
+ p.setLayout(new BorderLayout(5, 0));
+
+ p.add(new JPanel(), "North");
+ p.add(new JPanel(), "South");
+
+ p.add(new JLabel(
+ pmUtility.getResource("See.also:")), "West");
+
+ theComboBox = new JComboBox();
+
+ Font f = theComboBox.getFont();
+ Font fb = new Font(f.getName(), f.PLAIN, f.getSize());
+ theComboBox.setFont(fb);
+
+ theComboBox.setPreferredSize(
+ new Dimension(200, theComboBox.getPreferredSize().height));
+ theComboBox.setMinimumSize(
+ new Dimension(20, theComboBox.getPreferredSize().height));
+ theComboBox.setMaximumSize(
+ new Dimension(300, theComboBox.getPreferredSize().height));
+ theComboBox.setEnabled(false);
+
+ /*
+ * theComboBox.addActionListener(new ActionListener() {
+ * public void actionPerformed(ActionEvent e) {
+ * JComboBox src = (JComboBox) e.getSource();
+ * System.out.println("Combo: action = " +
+ * e.getActionCommand());
+ * System.out.println("Combo: mod = " +
+ * e.getModifiers());
+ * System.out.println("Combo: param = " +
+ * e.paramString());
+ * System.out.println("Combo: item = " +
+ * src.getSelectedItem());
+ * }
+ * });
+ */
+
+ p.add(theComboBox, "Center");
+
+ selectButton = new pmButton(
+ pmUtility.getResource("Show"));
+ selectButton.setMnemonic(
+ pmUtility.getIntResource("Show.mnemonic"));
+ selectButton.setEnabled(false);
+
+ p.add(selectButton, "East");
+ selectButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ pmHelpItem i = (pmHelpItem) theComboBox.getSelectedItem();
+ Debug.message("HELP: got button: item is " + i);
+ // parentPanel.loadItemForTag(i.tag);
+ parentPanel.showItem(i.tag);
+ }
+ });
+
+ JPanel pp = new JPanel();
+ pp.setLayout(new BorderLayout(5, 0));
+ pp.add(p, "Center");
+
+ this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+ this.add(Box.createHorizontalStrut(10));
+ this.add(pp);
+ this.add(Box.createHorizontalStrut(10));
+ this.add(Box.createHorizontalGlue());
+
+ }
+
+ public pmHelpSeeAlsoPanel(pmHelpDetailPanel p) {
+ parentPanel = p;
+ layoutBox();
+ this.setBorder(BorderFactory.createEtchedBorder());
+ }
+
+
+ /*
+ * set the titles of the pmHelpItems whose tags are
+ * passed into see-also combo box
+ */
+ public void setItems(Vector tags) {
+ clearItems();
+
+ if (tags == null)
+ return;
+
+ Enumeration e = tags.elements();
+ while (e.hasMoreElements()) {
+ pmHelpItem i =
+ pmHelpRepository.helpItemForTag((String) e.nextElement());
+ if (i != null)
+ theComboBox.addItem(i);
+ }
+
+ selectButton.setEnabled(true);
+ theComboBox.setEnabled(true);
+
+
+ // repaint();
+ }
+
+
+ public void clearItems() {
+ if (theComboBox.getItemCount() > 0)
+ theComboBox.removeAllItems();
+ selectButton.setEnabled(false);
+ theComboBox.setEnabled(false);
+ }
+
+}
+
+
+class pmHelpViewPanel extends JPanel {
+ // JTextArea helpView;
+ JEditorPane helpView;
+ JScrollPane scrollPane;
+ pmHelpHelpOnPanel titlePanel;
+ pmHelpDetailPanel parentPanel;
+ pmButton backButton;
+ pmButton forwardButton;
+
+ public pmHelpViewPanel(pmHelpDetailPanel par) {
+ parentPanel = par;
+
+ // helpView = new JTextArea(10, 32);
+ // helpView.setLineWrap(true);
+
+ helpView = new JEditorPane();
+
+ helpView.setContentType("text/html");
+ helpView.setEditable(false);
+ helpView.setEnabled(false);
+ helpView.setDisabledTextColor(Color.blue);
+
+ scrollPane = new JScrollPane(helpView);
+
+ this.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(5, 10, 5, 10);
+ c.gridwidth = GridBagConstraints.REMAINDER;
+
+ c.gridx = 0;
+ c.gridy = 0;
+
+ c.gridheight = 1;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0;
+ // c.weighty = 1.0;
+ c.weighty = 0.05;
+
+ titlePanel = new pmHelpHelpOnPanel();
+ this.add(titlePanel, c);
+
+ c.gridy = 1;
+ c.gridheight = 1;
+
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.weightx = 1.0;
+ c.weighty = 6.0;
+ c.fill = GridBagConstraints.BOTH;
+ c.insets = new Insets(5, 10, 5, 10);
+ // c.insets = new Insets(5, 5, 5, 5); // NEW
+ this.add(scrollPane, c);
+
+ this.setBorder(BorderFactory.createEtchedBorder());
+
+ /*
+ */
+ try {
+ helpView.setPage(new URL("file:///test.html"));
+ } catch (Exception x) {
+ Debug.info("setPage caught: " + x);
+ }
+ /*
+ */
+
+ // navigation buttons
+ JPanel p = new JPanel();
+ p.setLayout(new GridBagLayout());
+ GridBagConstraints pc = new GridBagConstraints();
+ // pc.insets = new Insets(2, 2, 2, 2);
+ // pc.fill = GridBagConstraints.HORIZONTAL;
+ pc.weightx = 1.0;
+ pc.weighty = 1.0;
+ pc.gridx = 0;
+ pc.anchor = GridBagConstraints.WEST;
+
+ backButton = new pmButton(
+ pmUtility.getResource("Back"));
+ backButton.setMnemonic(
+ pmUtility.getIntResource("Back.mnemonic"));
+ p.add(backButton, pc);
+ backButton.setEnabled(false);
+ backButton.setDefaultCapable(false);
+ backButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ parentPanel.showHistoryBackItem();
+ }
+ });
+
+
+ pc.gridx = 1;
+ pc.anchor = GridBagConstraints.EAST;
+
+ forwardButton = new pmButton(
+ pmUtility.getResource("Forward"));
+ forwardButton.setMnemonic(
+ pmUtility.getIntResource("Forward.mnemonic"));
+ p.add(forwardButton, pc);
+ forwardButton.setEnabled(false);
+ forwardButton.setDefaultCapable(false);
+ forwardButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ parentPanel.showHistoryForwardItem();
+ }
+ });
+
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridheight = 1; // GridBagConstraints.REMAINDER;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.weightx = 1.0;
+ // c.weighty = 1.0;
+ c.weighty = 0.05; // NEW
+
+ c.fill = GridBagConstraints.BOTH;
+ c.insets = new Insets(0, 10, 5, 10);
+ // c.insets = new Insets(0, 10, 5, 10);
+ c.insets = new Insets(5, 10, 5, 10);
+ // NEW
+
+ add(p, c);
+
+ }
+
+
+ public void setItem(String title, pmHelpContent content) {
+ helpView.setText(content.getText());
+ // scrollPane.getViewport().setViewPosition(new Point(0, 0));
+ titlePanel.helpTopic.setText(title);
+ }
+
+ public void setPos(Point p) {
+ scrollPane.getViewport().setViewPosition(p);
+ }
+
+ public Point getPos() {
+ return scrollPane.getViewport().getViewPosition();
+ }
+
+ public void setNavButtons(int index, int last) {
+ Debug.message("HELP: NavButtons " + index + " " + last);
+
+ if (last > index)
+ forwardButton.setEnabled(true);
+ else
+ forwardButton.setEnabled(false);
+
+ if (index > 1 && last > 1)
+ backButton.setEnabled(true);
+ else
+ backButton.setEnabled(false);
+ }
+
+}
+
+
+class pmJTextField extends JTextField {
+ public boolean isFocusable() {
+ return false;
+ }
+}
+
+class pmHelpHelpOnPanel extends JPanel {
+
+ pmJTextField helpTopic;
+
+ public pmHelpHelpOnPanel() {
+
+ helpTopic = new pmJTextField();
+ helpTopic.setEditable(false);
+ helpTopic.setText("Default help topic");
+ helpTopic.setBackground(Color.white);
+
+ Font f = helpTopic.getFont();
+ Font fb = new Font(f.getName(), Font.BOLD, f.getSize());
+ helpTopic.setFont(fb);
+
+ this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+ JPanel p = new JPanel();
+ p.setLayout(new BorderLayout(5, 0));
+ p.add(new JLabel(
+ pmUtility.getResource("Help.on:")),
+ "West");
+ p.add(helpTopic, "Center");
+
+ JPanel pp = new JPanel();
+ pp.setLayout(new BorderLayout(0, 0));
+ pp.add(p, "Center");
+
+ // this.add(Box.createHorizontalStrut(5));
+ this.add(pp);
+ // this.add(Box.createHorizontalStrut(5));
+ this.add(Box.createHorizontalGlue());
+
+
+ // this.setBorder(BorderFactory.createEtchedBorder());
+
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpException.java
new file mode 100644
index 0000000000..0079965950
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpException.java
@@ -0,0 +1,38 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHelpException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmHelpException extends Exception {
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpFrame.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpFrame.java
new file mode 100644
index 0000000000..094782a99f
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpFrame.java
@@ -0,0 +1,101 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright(c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHelpFrame.java
+ * Container for help subsystem GUI
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.io.*;
+import javax.swing.JPanel;
+import javax.swing.border.*;
+import javax.swing.*;
+import com.sun.admin.pm.server.*;
+
+
+public class pmHelpFrame extends pmFrame {
+
+ protected pmHelpController theController = null;
+ public pmButton dismiss = null; // expose for default button hacks
+
+ public pmHelpFrame() {
+ super(pmUtility.getResource("SPM:Help"));
+
+ theController = new pmHelpController(this);
+ getContentPane().add("Center", theController.getTopPane());
+
+ dismiss = new pmButton(
+ pmUtility.getResource("Dismiss"));
+ dismiss.setMnemonic(
+ pmUtility.getIntResource("Dismiss.mnemonic"));
+ dismiss.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ hideHelp();
+ }
+ });
+
+ JPanel p = new JPanel();
+ p.add(dismiss);
+
+ getContentPane().add("South", p);
+
+ this.pack();
+ this.setVisible(false);
+ this.repaint();
+
+ // default button is dismiss
+ // getRootPane().setDefaultButton(dismiss);
+ dismiss.setAsDefaultButton();
+
+ // handle Esc as dismiss
+ getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("HELP: dismiss action");
+ hideHelp();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+ }
+
+
+ public void hideHelp() {
+ this.setVisible(false);
+ }
+
+
+ public void showHelp(String tag) {
+ theController.showHelpItem(tag);
+ this.setVisible(true);
+ this.repaint();
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpIndexPanel.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpIndexPanel.java
new file mode 100644
index 0000000000..f97728cc7a
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpIndexPanel.java
@@ -0,0 +1,383 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright(c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHelpIndexPanel.java
+ * Search help titles
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.JPanel;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+public class pmHelpIndexPanel extends JPanel {
+
+ pmHelpController controller;
+ pmHelpIndexQueryPanel queryPanel;
+ pmHelpIndexResultPanel resultPanel;
+ JLabel textPanels[];
+
+ public pmHelpIndexPanel(pmHelpController ctrl) {
+ controller = ctrl;
+
+ // build subpanels
+ queryPanel = new pmHelpIndexQueryPanel(this);
+ resultPanel = new pmHelpIndexResultPanel(this);
+
+ textPanels = new JLabel[4];
+ textPanels[0] = new JLabel(
+ pmUtility.getResource("To.search.the.index..."));
+ textPanels[1] = new JLabel(
+ pmUtility.getResource("type.your.query.below..."));
+
+ // lay out top panel
+ this.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(5, 5, 5, 5);
+ c.gridwidth = GridBagConstraints.REMAINDER;
+
+ c.gridx = 0;
+ c.gridy = 0;
+
+ c.gridheight = 1; // GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+
+ JPanel p = new JPanel();
+ p.setLayout(new GridBagLayout());
+ GridBagConstraints pc = new GridBagConstraints();
+ pc.insets = new Insets(5, 5, 0, 5);
+ // pc.fill = GridBagConstraints.HORIZONTAL;
+ pc.weightx = 1.0;
+ pc.anchor = GridBagConstraints.WEST;
+ pc.gridx = 0;
+ pc.gridy = GridBagConstraints.RELATIVE;
+
+ p.add(textPanels[0], pc);
+ pc.insets = new Insets(0, 5, 5, 5);
+ p.add(textPanels[1], pc);
+ // p.add(textPanels[2]);
+
+ this.add(p, c);
+
+ p = new JPanel();
+ p.setLayout(new BorderLayout());
+ p.add(queryPanel, "North");
+ p.add(resultPanel, "Center");
+ p.setBorder(BorderFactory.createEtchedBorder());
+
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridheight = 0;
+ c.weighty = 1.0;
+ c.weightx = 0.0;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor = GridBagConstraints.EAST;
+
+ this.add(p, c);
+
+ this.setBorder(BorderFactory.createEtchedBorder());
+
+
+ // figure out when we are un-tabbed
+ controller.outerPanel.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent e) {
+ JTabbedPane tp = (JTabbedPane) e.getSource();
+ Debug.info("HELP: Tab event!");
+ if (!(tp.getSelectedComponent() instanceof
+ com.sun.admin.pm.client.pmHelpIndexPanel)) {
+ Debug.info("HELP: Tab event: resetting default");
+ /*
+ * controller.frame.getRootPane().
+ * setDefaultButton(
+ * controller.frame.dismiss);
+ */
+ } else {
+ // allow tab to retain focus
+ // queryPanel.query.requestFocus();
+ }
+ }
+ });
+
+
+ }
+
+
+ // place item titles in search result panel
+ public void setSearchResults(Vector items) {
+ Vector v = new Vector();
+
+ if (items.size() == 0) {
+ resultPanel.setListEmpty(true);
+ v.addElement(pmUtility.getResource("Nothing.matched."));
+ } else {
+ Enumeration e = items.elements();
+ while (e.hasMoreElements()) {
+ pmHelpItem i = (pmHelpItem) e.nextElement();
+ v.addElement(i);
+ }
+ resultPanel.setListEmpty(false);
+ }
+
+ resultPanel.setResultList(v);
+ }
+
+}
+
+
+
+class pmHelpIndexResultPanel extends JPanel {
+
+ JList resultList = null;
+ pmButton selectButton = null;
+ pmHelpIndexPanel parentPanel = null;
+ protected boolean listEmpty = true;
+
+
+ public pmHelpIndexResultPanel(pmHelpIndexPanel p) {
+
+ parentPanel = p;
+
+ this.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(10, 10, 10, 10);
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = c.weighty = 0.0;
+ c.gridx = 0;
+ c.gridy = 0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+
+ JLabel promptLabel = new JLabel(
+ pmUtility.getResource("Matching.entries:"));
+/*
+ * MNEMONIC
+ * promptLabel.setDisplayedMnemonic(
+ * pmUtility.getIntResource("Matching.entries:.mnemonic"));
+ */
+
+ this.add(promptLabel, c);
+
+ c.gridy = 1;
+ c.anchor = GridBagConstraints.WEST;
+
+ selectButton = new pmButton(
+ pmUtility.getResource("Show"));
+ selectButton.setMnemonic(
+ pmUtility.getIntResource("Show.mnemonic"));
+
+ selectButton.setEnabled(false);
+
+ this.add(selectButton, c);
+
+ selectButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ pmHelpItem selectedItem = (pmHelpItem)
+ resultList.getSelectedValue();
+ Debug.message("Selected " + selectedItem);
+ parentPanel.controller.showHelpItem(selectedItem);
+ }
+ });
+
+ Vector resultItems = null;
+ try {
+ // resultItems = pmHelpIndexQueryPanel.helpDB.getPartialMatch("");
+ resultItems = pmHelpRepository.helpItemsForString("");
+ } catch (pmHelpException x) {
+ Debug.message("pmHelpIndexResultpanel init: " + x);
+ resultItems = new Vector();
+ resultItems.addElement(
+ pmUtility.getResource("Nothing.matched."));
+ }
+
+ resultList = new JList(resultItems);
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.getViewport().setView(resultList);
+ resultList.setVisibleRowCount(8);
+
+ promptLabel.setLabelFor(resultList);
+
+ resultList.addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ if (!listEmpty) {
+ selectButton.setEnabled(true);
+ /*
+ * parentPanel.controller.frame.
+ * getRootPane().setDefaultButton(selectButton);
+ */
+ selectButton.setAsDefaultButton();
+
+ }
+ }});
+
+ resultList.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
+ JList l = (JList) e.getSource();
+ int i = l.locationToIndex(e.getPoint());
+ Debug.message("doubleclick index: " + i);
+ if (!listEmpty && i >= 0) {
+ pmHelpItem item =
+ (pmHelpItem) l.getModel().getElementAt(i);
+ Debug.message("doubleclick: " + item.tag);
+ parentPanel.controller.showHelpItem(item);
+ }
+ }
+ }
+ });
+
+ c.gridwidth = 1; // 2;
+ c.gridx = 1;
+ c.gridy = 0;
+ c.weightx = c.weighty = 1.0;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor = GridBagConstraints.EAST;
+
+ this.add(scrollPane, c);
+
+ }
+
+ void setResultList(Vector v) {
+
+ resultList.setListData(v);
+
+ resultList.setSelectedValue(v.elementAt(0), true);
+ }
+
+ void setListEmpty(boolean e) {
+ listEmpty = e;
+ selectButton.setEnabled(false);
+ /*
+ * parentPanel.controller.frame.getRootPane().
+ * setDefaultButton(parentPanel.controller.frame.dismiss);
+ */
+ if (parentPanel.controller.frame.dismiss != null)
+ parentPanel.controller.frame.dismiss.
+ setAsDefaultButton();
+ }
+
+}
+
+
+class pmHelpIndexQueryPanel extends JPanel {
+
+ JTextField query;
+ pmHelpIndexPanel parentPanel;
+
+ public pmHelpIndexQueryPanel(pmHelpIndexPanel p) {
+
+ parentPanel = p;
+
+ this.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(10, 10, 10, 10);
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = c.weighty = 0.0;
+ c.anchor = GridBagConstraints.WEST;
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.insets = new Insets(10, 10, 10, 10);
+
+ JLabel promptLabel =
+ new JLabel(pmUtility.getResource("Search.help.index.for:"));
+/*
+ * MNEMONIC
+ * promptLabel.setDisplayedMnemonic(
+ * pmUtility.getIntResource("Search.help.index.for:.mnemonic"));
+ */
+
+ this.add(promptLabel, c);
+
+ query = new JTextField();
+ query.setEditable(true);
+ query.setText("");
+
+ promptLabel.setLabelFor(query);
+
+ query.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.info("HELP: Action!");
+ parentPanel.resultPanel.selectButton.doClick();
+ }
+ });
+
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.gridx = 1;
+ c.weightx = 1.0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.EAST;
+
+ this.add(query, c);
+
+ DocumentListener d = new DocumentListener() {
+ public void changedUpdate(DocumentEvent e) {
+ // ignore
+ }
+
+ public void insertUpdate(DocumentEvent e) {
+ handleText(query.getText());
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ handleText(query.getText());
+ }
+ };
+
+ query.getDocument().addDocumentListener(d);
+ }
+
+ public void handleText(String txt) {
+
+ Debug.message("Got text " + txt);
+
+ Vector v = null;
+
+ try {
+ // v = helpDB.getPartialMatch(txt);
+ v = pmHelpRepository.helpItemsForString(txt);
+ } catch (pmHelpException x) {
+ Debug.warning("handleText: " + x);
+ }
+ parentPanel.setSearchResults(v);
+
+ }
+
+ // belongs in controller?
+ // static pmHelpRepository helpDB = new pmHelpRepository();
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpItem.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpItem.java
new file mode 100644
index 0000000000..94dab47210
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpItem.java
@@ -0,0 +1,92 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHelpItem
+ * Abstraction of a help article
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import com.sun.admin.pm.server.*;
+
+class pmHelpItem extends Object {
+ String title;
+ String tag;
+ Vector keywords;
+ Vector seealso;
+ pmHelpContent content;
+
+ public pmHelpItem(String theTag) {
+ tag = theTag;
+ title = null;
+ keywords = null;
+ seealso = null;
+ content = null;
+ }
+
+ public String toString() {
+ /*
+ * String s = new String("Item: " + tag + "\n");
+ * s += ("\ttitle: " + title + "\n");
+ * s += ("\tkeywords: " + keywords + "\n");
+ * s += ("\tseealso: " + seealso + "\n");
+ * s += ("\tcontent: " + content + "\n");
+ */
+ return title;
+ }
+
+
+ public void setTag(String s) {
+ if (tag != null)
+ tag = new String(s);
+ }
+
+ public void setTitle(String s) {
+ if (s != null)
+ title = new String(s);
+ }
+
+ public void setKeywords(Vector v) {
+ if (v != null)
+ keywords = (Vector) v.clone();
+ }
+
+ public void setSeeAlso(Vector v) {
+ if (v != null)
+ seealso = (Vector) v.clone();
+ }
+
+ public void setContent(pmHelpContent c) {
+ if (c != null)
+ content = new pmHelpContent(c);
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpRepository.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpRepository.java
new file mode 100644
index 0000000000..45698ff0d5
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpRepository.java
@@ -0,0 +1,294 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 1999-2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmHelpRepository.java
+ * Database of help articles
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import com.sun.admin.pm.server.*;
+
+
+
+/*
+ * The help repository manages three distinct databases.
+ *
+ * helpItemDB: String tag -> pmHelpItem
+ * Returns a pmHelpItem given its unique tag.
+ * Used to resolve a reference from the app.
+ *
+ * helpKeywordDB: String -> Vector(of pmHelpItems)
+ * Returns a Vector containing all pmHelpItems whose `keywords'
+ * property contains the specifed keyword.
+ *
+ * helpTitleDB: String -> Vector (of pmHelpItems)
+ * Returns a Vector containing all pmHelpItems whose `title'
+ * property is a partial match for the specified string.
+ */
+
+final class pmHelpRepository {
+
+ private static Hashtable helpItemDB = null;
+ private static Hashtable helpKeywordDB = null;
+ private static BST helpTitleDB = null;
+
+
+ // database of HelpItems, by tag string
+ static void populateHelpItemDB() {
+ helpItemDB = new Hashtable();
+ loadHelpItemDB();
+ // Debug.message("HELP: helpItemDB: " + helpItemDB);
+ }
+
+ // database of Vectors of HelpItems, by keyword string
+ static void populateHelpKeywordDB() {
+ if (helpItemDB == null)
+ return;
+
+ /*
+ * Strategy:
+ * for each item
+ * for each keyword
+ * if kw not in db
+ * add ititem.tag
+ * add item to keyword entry
+ */
+
+ helpKeywordDB = new Hashtable();
+
+ Vector v = null;
+ Enumeration items = helpItemDB.elements();
+ while (items.hasMoreElements()) {
+ pmHelpItem item = (pmHelpItem) items.nextElement();
+ Enumeration keywords = item.keywords.elements();
+ while (keywords.hasMoreElements()) {
+ String keyword = (String) keywords.nextElement();
+ v = (Vector) helpKeywordDB.get(keyword);
+ if (v == null)
+ helpKeywordDB.put(keyword, v = new Vector());
+ v.addElement(item);
+ }
+ }
+
+ // Debug.message("HELP: KeywordDB: " + helpKeywordDB);
+ }
+
+
+ // database of HelpItems, by (partial) title string
+ static void populateHelpTitleDB() {
+ if (helpItemDB == null)
+ return;
+
+ /*
+ * strategy:
+ * assume itemDB is loaded
+ * for each item in itemDB
+ * create an entry in titleDB
+ */
+
+ helpTitleDB = new BST();
+
+ Enumeration items = helpItemDB.elements();
+ while (items.hasMoreElements()) {
+ pmHelpItem item = (pmHelpItem) items.nextElement();
+ helpTitleDB.insert(item.title, item);
+ }
+ }
+
+
+ static public pmHelpItem helpItemForTag(String tag) {
+ if (helpItemDB == null || tag == null)
+ return null;
+ return (pmHelpItem) helpItemDB.get(tag);
+ }
+
+ static public Vector helpItemsForKeyword(String keyword) {
+ if (helpKeywordDB == null)
+ return null;
+
+ return (Vector) helpKeywordDB.get(keyword.toLowerCase());
+ }
+
+
+ static public Vector helpItemsForString(String partialTitle)
+ throws pmHelpException {
+
+ Debug.info("HELP: helpItemsForString: " + partialTitle);
+
+ if (helpTitleDB == null)
+ return new Vector();
+
+ Vector v = new Vector();
+ helpTitleDB.traverse_find_vector(v, partialTitle);
+
+ Debug.info("HELP: helpItemsForString: vector contains " +
+ v.size() + " items");
+
+ return v;
+ }
+
+
+
+
+ // this should go in utils...
+ public static String getResource(String key) {
+ String keyvalue = null;
+ ResourceBundle bundle = null;
+
+ Debug.message("HELP: getResource(" + key + ")");
+
+ try {
+ try {
+ bundle = ResourceBundle.getBundle(
+ "com.sun.admin.pm.client.pmHelpResources");
+ } catch (MissingResourceException e) {
+ Debug.fatal("HELP: Could not load pmHelpResources file");
+ }
+
+ try {
+ keyvalue = bundle.getString(key);
+ } catch (MissingResourceException e) {
+ keyvalue = bundle.getString("Missing:") + key;
+ Debug.error("HELP: Missing: " + key);
+ }
+ } catch (Exception other) {
+ Debug.error("HELP: getResource(" + key + ") : " + other);
+ }
+
+ return keyvalue;
+ }
+
+
+ // from resources, presumably
+ static public void loadHelpItemDB() {
+
+ // Debug.setDebugLevel(new pmHelpRepository(), Debug.ALL);
+
+ /*
+ * strategy:
+ * for each tag name (from pmHelpTagNameEnumerator):
+ * get the property values from the resource bundle
+ */
+
+ Debug.message("HELP: Starting help item load");
+
+ ResourceBundle bundle = null;
+
+ try {
+ bundle = ResourceBundle.getBundle(
+ "com.sun.admin.pm.client.pmHelpResources");
+ } catch (MissingResourceException e) {
+ Debug.fatal("HELP: Could not load pmHelpResources file");
+ return;
+ }
+ Enumeration e = bundle.getKeys();
+ while (e.hasMoreElements()) {
+ String key = (String) e.nextElement();
+ if (key.endsWith(".tag")) {
+ String tagName = null;
+ try {
+ tagName = bundle.getString(key);
+ } catch (MissingResourceException x) {
+ Debug.warning("HELP: Unable to find tag for " + key);
+ continue;
+ }
+
+ Debug.message("HELP: Making new item " + tagName);
+
+ pmHelpItem item = new pmHelpItem(tagName);
+
+ String theTitle = getResource(tagName + ".title");
+ item.setTitle(theTitle);
+
+ item.setContent(new pmHelpContent(
+ getResource(tagName + ".content")));
+
+ Vector v = null;
+ StringTokenizer st = null;
+
+ String s = getResource(tagName + ".seealso");
+ if (s != null) {
+ v = new Vector();
+ st = new StringTokenizer(s);
+ while (st.hasMoreTokens())
+ v.addElement(st.nextToken());
+ item.setSeeAlso(v);
+ }
+
+ v = new Vector();
+ s = getResource(tagName + ".keywords");
+ if (s != null) {
+ st = new StringTokenizer(s);
+ while (st.hasMoreTokens()) {
+ String word = st.nextToken();
+ String quotelessWord = word.replace('\"', ' ');
+ v.addElement(quotelessWord.trim());
+ }
+ } else
+ Debug.warning("HELP: Item " + tagName +
+ " keywords is empty");
+
+
+ // insert item's title words into its keywords
+ st = new StringTokenizer(theTitle);
+ while (st.hasMoreTokens()) {
+ String word = (st.nextToken()).toLowerCase();
+
+ // ignore useless words
+ if (ignoreKeyTitleWords.indexOf(word) != -1) {
+ Debug.message("HELP: ignoring " + word +
+ " from " + theTitle);
+ continue;
+ }
+
+ Debug.message("HELP: adding " + word +
+ " from " + theTitle);
+
+ v.addElement(word);
+ }
+
+ item.setKeywords(v);
+
+
+ Debug.message("HELP: New item: " + item);
+
+ helpItemDB.put(item.tag, item);
+ }
+ }
+ }
+
+
+ // these words are not to be treated as keywords when they appear in title
+ static final private String
+ /* JSTYLED */
+ ignoreKeyTitleWords = pmUtility.getResource("help.ignore.words");
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpSearchPanel.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpSearchPanel.java
new file mode 100644
index 0000000000..03c0aefeba
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmHelpSearchPanel.java
@@ -0,0 +1,451 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright(c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHelpSearchPanel.java
+ * Search help keywords
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.JPanel;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+public class pmHelpSearchPanel extends JPanel {
+
+ pmHelpController controller;
+ pmHelpSearchQueryPanel queryPanel;
+ pmHelpSearchResultPanel resultPanel;
+ JLabel textPanels[];
+
+ public pmHelpSearchPanel(pmHelpController ctrl) {
+ controller = ctrl;
+
+ // build subpanels
+ queryPanel = new pmHelpSearchQueryPanel(this);
+ resultPanel = new pmHelpSearchResultPanel(this);
+
+ textPanels = new JLabel[4];
+ textPanels[0] = new JLabel(
+ pmUtility.getResource("To.find.help.articles..."));
+ textPanels[1] = new JLabel(
+ pmUtility.getResource("enter.keywords.below..."));
+
+ // lay out top panel
+ this.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(5, 5, 5, 5);
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridheight = 1; // GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.BOTH;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+
+ JPanel p = new JPanel();
+ p.setLayout(new GridBagLayout());
+ GridBagConstraints pc = new GridBagConstraints();
+ pc.insets = new Insets(5, 5, 0, 5);
+ // pc.fill = GridBagConstraints.HORIZONTAL;
+ pc.weightx = 1.0;
+ pc.anchor = GridBagConstraints.WEST;
+ pc.gridx = 0;
+ pc.gridy = GridBagConstraints.RELATIVE;
+
+ p.add(textPanels[0], pc);
+ pc.insets = new Insets(0, 5, 5, 5);
+ p.add(textPanels[1], pc);
+ // p.add(textPanels[2]);
+
+ this.add(p, c);
+
+
+ p = new JPanel();
+ p.setLayout(new BorderLayout());
+ queryPanel.setBorder(BorderFactory.createEtchedBorder());
+ p.add(queryPanel, "North");
+ resultPanel.setBorder(BorderFactory.createEtchedBorder());
+ p.add(resultPanel, "Center");
+ // p.setBorder(BorderFactory.createEtchedBorder());
+
+ c.gridy = 1;
+ // new stuff
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridheight = 0;
+ c.weighty = 1.0;
+ c.weightx = 0.0;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor = GridBagConstraints.EAST;
+ // end new stuff
+
+ this.add(p, c);
+ this.setBorder(BorderFactory.createEtchedBorder());
+
+
+ // figure out when we are tabbed or un-tabbed
+ controller.outerPanel.addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent e) {
+ JTabbedPane tp = (JTabbedPane) e.getSource();
+ Debug.info("HELP: Tab event!");
+ if (!(tp.getSelectedComponent() instanceof
+ com.sun.admin.pm.client.pmHelpSearchPanel)) {
+ Debug.info("HELP: Tab event: resetting default");
+ /*
+ * controller.frame.getRootPane().
+ * setDefaultButton(
+ * controller.frame.dismiss);
+ */
+ /*
+ * System.out.println(controller);
+ * System.out.println(controller.frame);
+ * System.out.println(controller.frame.dismiss);
+ */
+
+ if (controller.frame.dismiss != null)
+ controller.frame.dismiss.
+ setAsDefaultButton();
+ } else {
+ // better to have the tab itself keep focus.
+ // queryPanel.query.requestFocus();
+ }
+ }
+ });
+
+ }
+
+
+ // place item titles in search result panel
+ public void setSearchResults(Vector items) {
+ Vector v = new Vector();
+
+ if (items.size() == 0) {
+ resultPanel.setListEmpty(true);
+ v.addElement(pmUtility.getResource("Nothing.matched."));
+ } else {
+ Enumeration e = items.elements();
+ while (e.hasMoreElements()) {
+ pmHelpItem i = (pmHelpItem) e.nextElement();
+ v.addElement(i);
+ }
+ resultPanel.setListEmpty(false);
+ }
+ resultPanel.setResultList(v);
+ }
+}
+
+
+
+class pmHelpSearchResultPanel extends JPanel {
+
+ JList resultList = null;
+ pmButton selectButton = null;
+ pmHelpSearchPanel parentPanel = null;
+ protected boolean listEmpty = true;
+
+
+ public pmHelpSearchResultPanel(pmHelpSearchPanel par) {
+
+ parentPanel = par;
+
+ this.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(10, 10, 10, 10);
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = c.weighty = 0.0;
+ c.gridx = 0;
+ c.gridy = 0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+
+ JLabel promptLabel = new JLabel(
+ pmUtility.getResource("Search.Results:"));
+/*
+ * MNEMONIC
+ * promptLabel.setDisplayedMnemonic(
+ * pmUtility.getIntResource("Search.Results:.mnemonic"));
+ */
+
+ this.add(promptLabel, c);
+
+ selectButton = new pmButton(
+ pmUtility.getResource("Show"));
+ selectButton.setMnemonic(
+ pmUtility.getIntResource("Show.mnemonic"));
+
+ selectButton.setEnabled(false);
+
+ selectButton.addActionListener(new ActionListener() {
+ // load the selected item into view panel
+ public void actionPerformed(ActionEvent e) {
+ pmHelpItem selectedItem = (pmHelpItem)
+ resultList.getSelectedValue();
+ Debug.info("HELP: Selected " + selectedItem);
+ parentPanel.controller.showHelpItem(selectedItem);
+
+ }
+ });
+
+ c.gridy = 1;
+ c.anchor = GridBagConstraints.SOUTHWEST;
+ this.add(selectButton, c);
+
+
+ Vector resultItems = new Vector();
+
+ resultList = new JList(resultItems);
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.getViewport().setView(resultList);
+ resultList.setVisibleRowCount(8);
+
+ promptLabel.setLabelFor(resultList);
+
+ resultList.addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ if (!listEmpty) {
+ selectButton.setEnabled(true);
+ /*
+ * parentPanel.controller.frame.
+ * getRootPane().setDefaultButton(selectButton);
+ */
+ selectButton.setAsDefaultButton();
+
+ }
+ }});
+
+
+ resultList.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (e.getClickCount() == 2) {
+ JList l = (JList) e.getSource();
+ int i = l.locationToIndex(e.getPoint());
+ Debug.info("HELP: doubleclick index: " + i);
+ if (!listEmpty && i >= 0) {
+ pmHelpItem item = (pmHelpItem) l.getModel().
+ getElementAt(i);
+ Debug.info("HELP: doubleclick: " + item.tag);
+ parentPanel.controller.showHelpItem(item);
+ }
+ }
+ }
+ });
+
+
+ c.gridwidth = 2;
+ c.gridx = 1;
+ c.gridy = 0;
+ c.weightx = c.weighty = 1.0;
+ c.fill = GridBagConstraints.BOTH;
+ c.anchor = GridBagConstraints.WEST;
+
+ this.add(scrollPane, c);
+
+ }
+
+ public void setResultList(Vector v) {
+ resultList.setListData(v);
+ resultList.setSelectedValue(v.elementAt(0), true);
+
+ }
+
+ void setListEmpty(boolean e) {
+ listEmpty = e;
+ selectButton.setEnabled(false);
+ /*
+ * parentPanel.controller.frame.getRootPane().
+ * setDefaultButton(parentPanel.controller.frame.dismiss);
+ */
+ parentPanel.controller.frame.dismiss.setAsDefaultButton();
+
+ }
+
+
+}
+
+
+class pmHelpSearchQueryPanel extends JPanel {
+
+ JTextField query;
+ pmButton search;
+ pmHelpSearchPanel parentPanel = null;
+
+ public pmHelpSearchQueryPanel(pmHelpSearchPanel par) {
+
+ parentPanel = par;
+
+ this.setLayout(new GridBagLayout());
+
+ GridBagConstraints c = new GridBagConstraints();
+ c.insets = new Insets(10, 10, 10, 10);
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = c.weighty = 0.0;
+ c.anchor = GridBagConstraints.WEST;
+
+ c.gridx = 0;
+ c.gridy = 0;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+
+ JLabel promptLabel =
+ new JLabel(pmUtility.getResource("Keywords:"));
+/*
+ * MNEMONIC
+ * promptLabel.setDisplayedMnemonic(
+ * pmUtility.getIntResource("Keywords:.mnemonic"));
+ */
+
+ this.add(promptLabel, c);
+
+ search = new pmButton(
+ pmUtility.getResource("Find"));
+ search.setMnemonic(
+ pmUtility.getIntResource("Find.mnemonic"));
+
+ search.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ // parse the keyword strings
+ Vector v = null;
+ StringTokenizer st = null;
+ String s = query.getText();
+ if (s != null) {
+ v = new Vector();
+ st = new StringTokenizer(s);
+ while (st.hasMoreTokens())
+ v.addElement(st.nextToken());
+ v = getItemsForKeywords(v);
+ parentPanel.setSearchResults(v);
+
+ if (v != null && v.size() != 0) {
+ Debug.info("HELP: search vector full");
+ parentPanel.resultPanel.resultList.requestFocus();
+ } else {
+ Debug.info("HELP: search vector empty");
+ }
+ }
+
+ }
+ });
+
+ c.fill = GridBagConstraints.NONE;
+ c.gridx = 2;
+ c.gridy = 0; // GridBagConstraints.RELATIVE;
+ this.add(search, c);
+
+ query = new JTextField();
+ query.setEditable(true);
+ query.setText(" ");
+
+ promptLabel.setLabelFor(query);
+
+ query.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.info("HELP: Action!");
+ pmHelpSearchQueryPanel.this.search.doClick();
+ }
+ });
+
+ query.getDocument().addDocumentListener(new DocumentListener() {
+ public void changedUpdate(DocumentEvent e) {
+ // ignore
+ }
+
+ public void insertUpdate(DocumentEvent e) {
+ // make search the default button
+ Debug.info("HELP: search doc inserted update");
+ pmHelpSearchQueryPanel.this.search.setEnabled(true);
+ /*
+ * parentPanel.controller.frame.
+ * getRootPane().setDefaultButton(
+ * pmHelpSearchQueryPanel.this.search);
+ */
+ if (pmHelpSearchQueryPanel.this.search != null)
+ pmHelpSearchQueryPanel.this.search.
+ setAsDefaultButton();
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ Debug.info("HELP: search doc removed update");
+ // restore the default button
+ if (query.getText().length() == 0) {
+ /*
+ * parentPanel.controller.frame.
+ * getRootPane().setDefaultButton(
+ * parentPanel.controller.frame.dismiss);
+ */
+ if (parentPanel.controller.frame.dismiss != null)
+ parentPanel.controller.frame.dismiss.
+ setAsDefaultButton();
+ }
+ }
+ });
+
+
+
+ c.gridwidth = 1; // GridBagConstraints.REMAINDER;
+ c.gridx = 1;
+ c.weightx = 1.0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.EAST;
+
+ this.add(query, c);
+
+ }
+
+
+ Vector getItemsForKeywords(Vector keywords) {
+ Vector result = new Vector();
+
+ Debug.info("HELP: getItemsForKeywords: " + keywords);
+
+ Enumeration words = keywords.elements();
+ while (words.hasMoreElements()) {
+ String s = (String) words.nextElement();
+ Vector newItems = pmHelpRepository.helpItemsForKeyword(s);
+ Debug.info("HELP: getItemsForKeywords new items: " + newItems);
+
+ if (newItems != null) {
+ Enumeration items = newItems.elements();
+ while (items.hasMoreElements()) {
+ pmHelpItem i = (pmHelpItem) items.nextElement();
+ Debug.info("HELP: getItemsForKeywords result: " + result);
+ Debug.info("HELP: getItemsForKeywords item: " + i);
+
+ if (!result.contains(i))
+ result.addElement(i);
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmIncompleteFormException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmIncompleteFormException.java
new file mode 100644
index 0000000000..48926b44e8
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmIncompleteFormException.java
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmIncompleteFormException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmIncompleteFormException extends pmGuiException {
+ public pmIncompleteFormException(String s) {
+ super(s);
+ }
+ public pmIncompleteFormException() {
+ super();
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmInstallPrinter.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmInstallPrinter.java
new file mode 100644
index 0000000000..e24f1425d1
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmInstallPrinter.java
@@ -0,0 +1,2194 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Install and Modify Printer implementation
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Vector;
+import javax.swing.JPanel;
+import javax.swing.*;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.table.AbstractTableModel;
+
+import com.sun.admin.pm.server.*;
+
+
+/*
+ * Window for Edit -> Install Printer
+ */
+
+public class pmInstallPrinter extends pmInstallScreen {
+
+ int action;
+ pmTop myTop;
+ pmFrame frame;
+ JScrollPane scrollPane;
+ String printer = null;
+ String server = null;
+ String description = null;
+ String port = null;
+ String ptype = null;
+ String fcontents = null;
+ String make = null;
+ String model = null;
+ String ppd = null;
+ String ppdfile = null;
+ String oldmake = new String("oldmake");
+ String oldmodel = new String("oldmodel");
+ String faultn = null;
+ String banner = null;
+ String destination = null;
+ String protocol = null;
+ String useraccesslist[] = null;
+ String oldptype = null;
+ String olddevice = null;
+ Printer workingPrinter;
+
+ JList accessList;
+ JScrollPane ascrollPane;
+ accessListModel accessModel;
+
+ String helpTag = null;
+
+ String cmdLog = null;
+ String errorLog = null;
+ String warnLog = null;
+
+ String actionName = null;
+
+ // where to place initial focus
+ Component defaultComponent = null;
+
+ boolean usePPD;
+ boolean useLocalhost;
+
+ public pmInstallPrinter(pmTop myTop, int action) throws pmGuiException {
+ boolean failed = false;
+ boolean cacheerr = false;
+ boolean ppdincacheerr = false;
+
+ this.myTop = myTop;
+ this.action = action;
+ workingPrinter = new Printer(myTop.ns);
+
+ usePPD = myTop.getUsePPD();
+ useLocalhost = myTop.getUseLocalhost();
+
+ switch (action) {
+
+ case Constants.ADDLOCAL:
+
+ Debug.message("CLNT:pmInstPr: ADD LOCAL");
+ frame = new pmFrame(
+ pmUtility.getResource("SPM:New.Attached.Printer"));
+ if (pmMisc.isppdCachefile() && usePPD) {
+ helpTag = "InstallLocalPPD";
+ } else {
+ helpTag = "InstallLocal";
+ }
+ actionName =
+ pmUtility.getResource("New.Attached.Printer");
+ break;
+
+ case Constants.ADDNETWORK:
+
+ Debug.message("CLNT:pmInstPr: ADD NETWORK");
+ frame = new pmFrame(
+ pmUtility.getResource("SPM:New.Network.Printer"));
+ if ((pmMisc.isppdCachefile()) && (usePPD)) {
+ helpTag = "InstallNetworkPPD";
+ } else
+ helpTag = "InstallNetwork";
+ actionName = pmUtility.getResource("New.Network.Printer");
+ break;
+
+ case Constants.MODIFYATTACHED:
+
+ Debug.message("CLNT:pmInstPr: MODIFY ATTACHED");
+ frame = new pmFrame(
+ pmUtility.getResource("SPM:Modify.Printer.Properties"));
+ workingPrinter.setPrinterName(myTop.selectedPrinter);
+
+ failed = false;
+ try {
+ workingPrinter.getPrinterDetails();
+
+ } catch (pmNeedPPDCacheException e) {
+ cacheerr = true;
+ Debug.message("CLNT:pmInstPr:ModifyAttached caught: " + e);
+
+ } catch (pmCacheMissingPPDException e) {
+ ppdincacheerr = true;
+ Debug.message("CLNT:pmInstPr:ModifyAttached caught: " + e);
+
+ } catch (Exception e) {
+ failed = true;
+ Debug.message("CLNT:pmInsPr:ModifyAttached caught:" + e);
+ }
+
+ gatherLogs(workingPrinter);
+
+ if (cacheerr) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "Cannot.modify.this.queue;ppdcache.file.missing."));
+
+ m.setVisible(true);
+
+ throw new pmGuiException("No ppdcache file");
+ }
+
+ if (ppdincacheerr) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "Cannot.modify.this.queue;PPD.file.not.in.ppdcache."));
+
+ m.setVisible(true);
+
+ throw new pmGuiException("PPD file not in ppdcache");
+ }
+
+ if (failed) {
+ // error popup?
+ // throw something?
+ }
+
+ pmCalls.debugShowPrinter(workingPrinter);
+ dumpLogs("ModifyAttached()");
+
+ if (workingPrinter.getPPD() != null)
+ helpTag = "ModifyPPD";
+ else
+ helpTag = "Modify";
+
+ // helpTag = "ModifyAttached";
+
+ actionName = pmUtility.getResource("Modify.Printer.Properties");
+ break;
+
+ case Constants.MODIFYNETWORK:
+
+ Debug.message("CLNT:pmInstPr: MODIFY NETWORK");
+ frame = new pmFrame(
+ pmUtility.getResource("SPM:Modify.Printer.Properties"));
+ workingPrinter.setPrinterName(myTop.selectedPrinter);
+
+ workingPrinter.setPrinterName(myTop.selectedPrinter);
+ failed = false;
+
+ try {
+ workingPrinter.getPrinterDetails();
+ } catch (Exception e) {
+ failed = true;
+ Debug.message("CLNT:pmInstPr:ModifyNetwork caught " + e);
+ }
+
+ gatherLogs(workingPrinter);
+
+ if (failed) {
+ // error popup?
+ // throw new pmGuiException();
+ }
+
+ pmCalls.debugShowPrinter(workingPrinter);
+ dumpLogs("ModifyNetwork()");
+
+ if (workingPrinter.getPPD() != null)
+ helpTag = "ModifyPPD";
+ else
+ helpTag = "Modify";
+ // helpTag = "ModifyNetwork";
+
+ actionName = pmUtility.getResource("Modify.Printer.Properties");
+
+ break;
+
+ case Constants.MODIFYREMOTE:
+ Debug.message("CLNT:pmInstPr: MODIFY REMOTE");
+ frame = new pmFrame(
+ pmUtility.getResource("SPM:Modify.Printer.Properties"));
+
+ workingPrinter.setPrinterName(myTop.selectedPrinter);
+
+ failed = false;
+ try {
+ workingPrinter.getPrinterDetails();
+ } catch (Exception e) {
+ failed = true;
+ Debug.warning("CLNT:pmInstPr:ModifyRemote caught " + e);
+ }
+ gatherLogs(workingPrinter);
+
+ if (failed) {
+ // error popup?
+ // throw something?
+ }
+
+
+ if (workingPrinter.getPPD() != null)
+ helpTag = "ModifyPPD";
+ else
+ helpTag = "Modify";
+ // helpTag = "ModifyRemote";
+
+ actionName = pmUtility.getResource("Modify.Printer.Properties");
+ break;
+
+ }
+
+ // ensure that pmButton hashtable gets cleaned up
+ frame.setClearButtonsOnClose(true);
+
+ setLayout(new BorderLayout());
+
+ // Build the Screen
+ northPanel();
+ if (action != Constants.MODIFYREMOTE) {
+ centerPanel();
+ }
+
+ southPanel();
+
+ // default button is always OK, for now...
+ // frame.getRootPane().setDefaultButton (okButton);
+ // okButton.setAsDefaultButton ();
+
+ // handle Esc as cancel
+ this.registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ actioncancelButton();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ if (action == Constants.ADDLOCAL || action == Constants.ADDNETWORK) {
+ defaultComponent = pnameText;
+ } else {
+ defaultComponent = descText;
+ }
+
+ frame.setDefaultComponent(defaultComponent);
+
+ defaultComponent.addFocusListener(new FocusListener() {
+ public void focusGained(FocusEvent e) {
+ Debug.info("\ncomponent focus gained: " + e);
+ }
+ public void focusLost(FocusEvent e) {
+ Debug.info("\ncomponent focus lost: " + e);
+ }
+ });
+
+ }
+
+
+ public class accessListModel extends AbstractListModel {
+ int numColumns;
+ Vector data;
+ Vector access = new Vector(1, 1);
+
+ public accessListModel() {
+ numColumns = getColumnCount();
+ }
+
+ public void addaccessList(String data[]) {
+
+ for (int i = 0; i < data.length; i++) {
+ access.addElement(data[i]);
+
+ }
+ }
+
+ public void addaccessList(String data) {
+ access.addElement(data);
+ }
+
+ public boolean isduplicate(String d) {
+ if (access == null)
+ return false;
+ else
+ return access.contains(d);
+ }
+
+ public void removeRow(int row) {
+ access.removeElementAt(row);
+ }
+
+ public void removeListEntries() {
+ access.removeAllElements();
+ }
+
+ public int getRowCount() {
+ return access.size();
+ }
+
+ public int getSize() {
+ return access.size();
+ }
+
+ public int getColumnCount() {
+ return 1;
+ }
+
+ public void addRow(Vector row) {
+ access.addElement(row);
+ }
+
+ public Object getValueAt(int row) {
+ return access.elementAt(row);
+ }
+
+ public Object getElementAt(int row) {
+ return access.elementAt(row);
+ }
+
+ public Object getValueAt(int row, int col) {
+ return access.elementAt(row);
+ }
+
+ public void setValueAt(String value, int row) {
+ access.setElementAt(value, row);
+ }
+
+ public Vector getAccessList() {
+ return access;
+ }
+
+ public void accesstoArray(String[] target) {
+ access.copyInto(target);
+ }
+
+ }
+
+ public void centerPanel() {
+ JPanel center = new JPanel();
+
+ accessModel = new accessListModel();
+ accessList = new JList(accessModel);
+ accessList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+
+ center.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ ListSelectionModel rowSelectModel = accessList.getSelectionModel();
+ rowSelectModel.addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ ListSelectionModel accessSM =
+ (ListSelectionModel)e.getSource();
+ }
+ });
+
+ c.insets = new Insets(5, 5, 5, 5);
+
+ // Create the label
+ c.gridx = 0;
+ c.gridy = 0;
+ labelConstraints(c);
+ center.add(new JLabel
+ (pmUtility.getResource("User.Access.List:")), c);
+
+ // Create User Access List
+ String[] tmp = workingPrinter.getUserAllowList();
+
+
+ if (tmp == null) {
+ accessModel.addaccessList("all");
+ } else {
+ accessModel.addaccessList(tmp);
+ }
+
+ ascrollPane = new JScrollPane(accessList);
+
+ c.gridwidth = 2;
+ c.gridx = 1;
+ c.weightx = c.weighty = 1.0;
+ c.fill = GridBagConstraints.BOTH;
+ center.add(ascrollPane, c);
+
+ // Create Textfield
+ c.gridx = 1;
+ c.gridy = 1;
+ c.ipadx = 15;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = c.weighty = 1.0;
+ userText = new pmTextField(25);
+ center.add(userText, c);
+
+ // Add the Add/Delete Buttons
+ c.gridx = 1;
+ c.gridy = 2;
+
+ adButtons(c);
+
+ c.gridwidth = 1;
+ center.add(addButton, c);
+
+ c.gridx = 2;
+ center.add(deleteButton, c);
+
+ add("Center", center);
+
+ }
+
+ public void northPanel() {
+ JPanel north = new JPanel();
+ north.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ northPanelConstraints(c);
+
+ // Define the constraints and create the labels
+
+ // All Add/Modify
+ labelConstraints(c);
+ c.gridx = 0;
+ c.gridy = 0;
+ printernameLabel(north, c);
+ c.gridy++;
+ servernameLabel(north, c);
+ c.gridy++;
+ descriptionLabel(north, c);
+ c.gridy++;
+
+ // Add printers, modify local
+ if (action != Constants.MODIFYREMOTE) {
+
+ if ((action == Constants.ADDLOCAL) ||
+ (action == Constants.MODIFYATTACHED)) {
+ printerportLabel(north, c);
+ c.gridy++;
+ }
+
+ if ((action == Constants.ADDLOCAL) ||
+ (action == Constants.ADDNETWORK)) {
+ if ((pmMisc.isppdCachefile()) && (usePPD)) {
+ printermakeLabel(north, c);
+ c.gridy++;
+ printermodelsLabel(north, c);
+ c.gridy++;
+ ppdcontentsLabel(north, c);
+ } else {
+ printertypeLabel(north, c);
+ c.gridy++;
+ filecontentsLabel(north, c);
+ }
+ }
+
+ if ((action == Constants.MODIFYATTACHED) ||
+ (action == Constants.MODIFYNETWORK)) {
+
+ // Show make/model/ppd or type/contents
+
+ if (workingPrinter.getPPD() != null) {
+
+ printermakeLabel(north, c);
+ c.gridy++;
+ printermodelsLabel(north, c);
+ c.gridy++;
+ ppdcontentsLabel(north, c);
+ } else {
+ printertypeLabel(north, c);
+ c.gridy++;
+ filecontentsLabel(north, c);
+ }
+ }
+
+ c.gridy++;
+ faultnotLabel(north, c);
+ c.gridy++;
+
+ if (action == Constants.ADDNETWORK ||
+ action == Constants.MODIFYNETWORK) {
+ destinationLabel(north, c);
+ c.gridy++;
+ protocolLabel(north, c);
+ c.gridy++;
+ }
+
+ optionsLabel(north, c);
+ c.gridy++;
+ bannerLabel(north, c);
+ } else {
+ optionLabel(north, c);
+ }
+
+ // Define the constraints and create the fields
+
+ // Add printers
+ c.gridx = 1;
+ c.gridy = 0;
+
+ // Printer Name and Server Name
+ if ((action == Constants.ADDLOCAL) ||
+ (action == Constants.ADDNETWORK)) {
+
+ TextFieldConstraints(c);
+ printernameTextField(north, c);
+ c.gridy++;
+ labelConstraints(c);
+ try {
+ north.add(new JLabel(
+ myTop.host.getLocalHostName()), c);
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT:pmInstPr:getLocalHostName exception " + e);
+ north.add(new JLabel(" "), c);
+ }
+ c.gridy++;
+ } else {
+ labelConstraints(c);
+ north.add(new JLabel(myTop.selectedPrinter), c);
+ c.gridy++;
+ labelConstraints(c);
+ north.add(new JLabel(myTop.selprinterServer), c);
+ c.gridy++;
+ }
+
+ // Description
+ TextFieldConstraints(c);
+ descriptionField(north, c);
+ if (action == Constants.MODIFYATTACHED ||
+ action == Constants.MODIFYNETWORK ||
+ action == Constants.MODIFYREMOTE) {
+ if (workingPrinter.getComment() != null)
+ descText.setText(workingPrinter.getComment());
+ }
+ c.gridy++;
+
+ if (action != Constants.MODIFYREMOTE) {
+ if (action == Constants.ADDLOCAL) {
+ comboboxConstraints(c);
+ printerportField(north, c);
+ c.gridy++;
+
+ } else if (action == Constants.MODIFYATTACHED) {
+ labelConstraints(c);
+ north.add(new JLabel(workingPrinter.getDevice()), c);
+ c.gridy++;
+ }
+
+ comboboxConstraints(c);
+
+ if ((action == Constants.ADDLOCAL) ||
+ (action == Constants.ADDNETWORK)) {
+ if ((pmMisc.isppdCachefile()) && (usePPD)) {
+ printermakeField(north, c);
+ c.gridy++;
+ printermodelsField(north, c);
+ c.gridy++;
+ ppdcontentsField(north, c);
+ } else {
+ printertypeField(north, c);
+ c.gridy++;
+ filecontentsField(north, c);
+ }
+ }
+
+ if ((action == Constants.MODIFYATTACHED) ||
+ (action == Constants.MODIFYNETWORK)) {
+
+ if (workingPrinter.getPPD() != null) {
+
+ printermakeField(north, c);
+ c.gridy++;
+ printermodelsField(north, c);
+ c.gridy++;
+ ppdcontentsField(north, c);
+
+ setMake();
+ setModel();
+ setPPD();
+
+ } else {
+ // display with printer type and file contents
+
+ printertypeField(north, c);
+ setPrinterType();
+
+ c.gridy++;
+
+ filecontentsField(north, c);
+ setType();
+ }
+ }
+
+ c.gridy++;
+
+ faultnotField(north, c);
+ if (action == Constants.MODIFYATTACHED ||
+ action == Constants.MODIFYNETWORK) {
+
+ setFault();
+ }
+ c.gridy++;
+
+ if (action == Constants.ADDNETWORK ||
+ action == Constants.MODIFYNETWORK) {
+
+ TextFieldConstraints(c);
+ destinationField(north, c);
+ c.gridy++;
+ comboboxConstraints(c);
+ protocolField(north, c);
+ c.gridy++;
+ if (action == Constants.MODIFYNETWORK)
+ setNetworkInfo();
+ }
+
+ optionsConstraints(c);
+ optionsFields(north, c);
+ if (action == Constants.MODIFYATTACHED ||
+ action == Constants.MODIFYNETWORK) {
+ if (workingPrinter.getIsDefaultPrinter()) {
+ defaultp.doClick();
+ }
+ setBanner();
+ }
+ } else {
+ optionsConstraints(c);
+ defaultoptionField(north, c);
+ if (workingPrinter.getIsDefaultPrinter()) {
+ defaultp.doClick();
+ }
+ }
+
+ add("North", north);
+ }
+
+ public void setNetworkInfo() {
+ String p = workingPrinter.getProtocol();
+
+ if (p != null) {
+ if (p.equals("bsd"))
+ protocolCombo.setSelectedItem("BSD");
+ else if (p.equals("tcp"))
+ protocolCombo.setSelectedItem("TCP");
+ else if (p.equals("uri"))
+ protocolCombo.setSelectedItem("URI");
+
+ }
+
+ if (destText != null)
+ destText.setText(workingPrinter.getDestination());
+ }
+
+ public void setMake() {
+ String make = workingPrinter.getMake();
+ if (make != null) {
+ makeCombo.setSelectedItem(make);
+ }
+ }
+ public void setModel() {
+ String model = workingPrinter.getModel();
+ if (model != null)
+ modelCombo.setSelectedItem(model);
+ }
+ public void setPPD() {
+ String ppd = workingPrinter.getPPD();
+ if (ppd != null)
+ ppdCombo.setSelectedItem(ppd);
+ }
+
+ public void setFault() {
+ String fault = workingPrinter.getNotify();
+
+ if (fault == null || fault == "none")
+ faultCombo.setSelectedItem(
+ pmUtility.getResource("None"));
+
+ else if (fault.equals("write"))
+ faultCombo.setSelectedItem(
+ pmUtility.getResource("Write.to.Superuser"));
+
+ else if (fault.equals("mail"))
+ faultCombo.setSelectedItem(
+ pmUtility.getResource("Mail.to.Superuser"));
+ else {
+ faultCombo.addItem(fault);
+ faultCombo.setSelectedItem(fault);
+ }
+ }
+
+ public void setBanner() {
+ String banner = workingPrinter.getBanner();
+
+ if (banner == null)
+ bannerCombo.setSelectedItem(
+ pmUtility.getResource("Always.Print.Banner"));
+
+ else if (banner.equals("never"))
+ bannerCombo.setSelectedItem(
+ pmUtility.getResource("Never.Print.Banner"));
+
+ else if (banner.equals("always"))
+ bannerCombo.setSelectedItem(
+ pmUtility.getResource("Always.Print.Banner"));
+
+ else if (banner.equals("optional"))
+ bannerCombo.setSelectedItem(
+ pmUtility.getResource("User.Selectable.Default.On"));
+ }
+
+ public void setType() {
+ // lpadmin can combine things like: simple,any ...
+
+ String filedata[] = workingPrinter.getFileContents();
+ String filecontents = new String();
+
+ if (filedata == null) {
+ fileCombo.setSelectedItem(
+ pmUtility.getResource("None"));
+ } else {
+ for (int i = 0; i < filedata.length; i++) {
+ if (i > 0 && filedata[i] != null)
+ filecontents = filecontents.concat(",");
+
+ filecontents = filecontents.concat(filedata[i]);
+ }
+ Debug.message("CLNT:pmInstPr:setType: filecontents = " +
+ filecontents);
+
+ if (filecontents.equals("postscript")) {
+ fileCombo.setSelectedItem(pmUtility.getResource(
+ "PostScript"));
+ } else if (filecontents.equals("application/postscript")) {
+ fileCombo.setSelectedItem(pmUtility.getResource(
+ "PostScript"));
+
+ } else if (filecontents.equals("simple")) {
+ fileCombo.setSelectedItem(pmUtility.getResource("ASCII"));
+ } else if (filecontents.equals("text/plain")) {
+ fileCombo.setSelectedItem(pmUtility.getResource("ASCII"));
+
+ } else if (filecontents.equals("postscript,simple")) {
+ fileCombo.setSelectedItem(pmUtility.getResource(
+ "Both.PostScript.and.ASCII"));
+ } else if (filecontents.equals("simple,postscript")) {
+ fileCombo.setSelectedItem(pmUtility.getResource(
+ "Both.PostScript.and.ASCII"));
+ } else if (filecontents.equals(
+ "text/plain,application/postscript")) {
+ fileCombo.setSelectedItem(pmUtility.getResource(
+ "Both.PostScript.and.ASCII"));
+
+ } else if (filecontents.equals("none")) {
+ fileCombo.setSelectedItem(
+ pmUtility.getResource("None"));
+ } else if (filecontents.equals("any")) {
+ fileCombo.setSelectedItem(
+ pmUtility.getResource("Any"));
+ } else if (filecontents.equals("application/octet-stream")) {
+ fileCombo.setSelectedItem(
+ pmUtility.getResource("Any"));
+ } else {
+ Debug.message(
+ "CLNT:pmInstPr:setType()unknown file contents type");
+ fileCombo.addItem(filecontents);
+ fileCombo.setSelectedItem(filecontents);
+ }
+ }
+ }
+
+ public void setPrinterType() {
+ int x = 0;
+ String type = workingPrinter.getPrinterType();
+ Debug.message(
+ "CLNT:pmInstPrsetPrinterType(): printer type is " + type);
+
+ if (type == null)
+ return;
+
+ if (type.equals("PS")) {
+ typeCombo.setSelectedItem("PostScript");
+ } else if (type.equals("hplaser")) {
+ typeCombo.setSelectedItem("HP Printer");
+ } else if (type.equals("PSR")) {
+ typeCombo.setSelectedItem("Reverse PostScript");
+ } else if (type.equals("epson2500")) {
+ typeCombo.setSelectedItem("Epson 2500");
+ } else if (type.equals("ibmproprinter")) {
+ typeCombo.setSelectedItem("IBM ProPrinter");
+ } else if (type.equals("qume5")) {
+ typeCombo.setSelectedItem("Qume Sprint 5");
+ } else if (type.equals("daisy")) {
+ typeCombo.setSelectedItem("Daisy");
+ } else if (type.equals("diablo")) {
+ typeCombo.setSelectedItem("Diablo");
+ } else if (type.equals("datagraphix")) {
+ typeCombo.setSelectedItem("Datagraphix");
+ } else if (type.equals("la100")) {
+ typeCombo.setSelectedItem("DEC LA100");
+ } else if (type.equals("ln03")) {
+ typeCombo.setSelectedItem("DEC LN03");
+ } else if (type.equals("decwriter")) {
+ typeCombo.setSelectedItem("Dec Writer");
+ } else if (type.equals("ti800")) {
+ typeCombo.setSelectedItem("Texas Instruments 800");
+ } else {
+ typeCombo.addItem(type);
+ typeCombo.setSelectedItem(type);
+ Debug.message(
+ "CLNT:pmInstPr:setPrinterType(): user defined type " +
+ type);
+ }
+
+ }
+
+ public void getMakeModelPPD() throws pmGuiException {
+ if (pmMisc.isppdCachefile()) {
+ getMake();
+
+ model = (String)modelCombo.getSelectedItem();
+ ppd = (String)ppdCombo.getSelectedItem();
+ }
+ }
+
+ public void getTypeContents() throws pmGuiException {
+ ptype = (String)typeCombo.getSelectedItem();
+ fcontents = (String)fileCombo.getSelectedItem();
+ }
+
+ public void getFault() throws pmGuiException {
+ faultn = (String)faultCombo.getSelectedItem();
+ }
+
+ public void getBanner() throws pmGuiException {
+ banner = (String)bannerCombo.getSelectedItem();
+ }
+
+ public void getPrinterServer() throws pmGuiException {
+
+ // Printer Name is a required field.
+ printer = pnameText.getText();
+ if (printer.equals("")) {
+ pnameText.requestFocus();
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("Printer.name.required."));
+ }
+
+ if (!Valid.localPrinterName(printer)) {
+ pnameText.requestFocus();
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("Printer.name.invalid."));
+ }
+
+ server = null;
+ try {
+ if ((useLocalhost))
+ server = "localhost";
+ else
+ server = myTop.host.getLocalHostName();
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT:pmInstPr:getLocalHostName exception " + e);
+ }
+
+ Debug.message(
+ "CLNT:pmInstPr:getPrinterServer(): printer is: " + printer);
+ Debug.message(
+ "CLNT:pmInstPr:getPrinterServer(): server is: " + server);
+
+ }
+
+ public void getPort() throws pmGuiException {
+ port = (String)portCombo.getSelectedItem();
+ if (port.equals(pmUtility.getResource("Not.Selected"))) {
+ portCombo.requestFocus();
+ throw new pmIncompleteFormException
+ (pmUtility.getResource(
+ "Printer.Port.Selection.required"));
+ }
+ Debug.message("CLNT:pmInstPr:getPort(): port is: " + port);
+ }
+
+ public void getMake() throws pmGuiException {
+ make = (String)makeCombo.getSelectedItem();
+ if (make.equals(pmUtility.getResource("Not.Selected"))) {
+ makeCombo.requestFocus();
+ throw new pmIncompleteFormException
+ (pmUtility.getResource(
+ "Printer.Make.Selection.required"));
+ }
+ Debug.message("CLNT:pmInstPr:getMake(): make is: " + make);
+ }
+
+ public void getNetworkInfo() throws pmIncompleteFormException {
+ destination = destText.getText();
+ if (destination.equals("")) {
+ destText.requestFocus();
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("Destination.required."));
+ }
+
+ if (!Valid.destination(destination)) {
+ destText.requestFocus();
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("Destination.invalid."));
+ }
+
+ protocol = (String)protocolCombo.getSelectedItem();
+ port = new String("/dev/null");
+ Debug.message(
+ "CLNT:pmInstPr:getNetworkInfo(): destination is: " +
+ destination);
+ Debug.message(
+ "CLNT:pmInstPr:getNetworkInfo(): protocol is: " + protocol);
+ }
+
+ public void getDescription() {
+
+ String messy;
+
+ messy = descText.getText();
+ description = messy.trim();
+ Debug.message(
+ "CLNT:pmInstPr:getDescription():description: " + "<" +
+ description + ">");
+
+ if (workingPrinter.getComment() == null && description.equals(""))
+ description = null;
+
+ }
+
+ public void getUserAccess() {
+
+ if (accessModel.getRowCount() != 0) {
+ useraccesslist = new String[accessModel.getRowCount()];
+ accessModel.accesstoArray(useraccesslist);
+ } else {
+ useraccesslist = null;
+ }
+ }
+
+ public String gui2lpptype(String t) {
+ String lp;
+
+ if (t != null) {
+ if (t.equals("PostScript"))
+ lp = new String("PS");
+ else if (t.equals("HP Printer"))
+ lp = new String("hplaser");
+ else if (t.equals("Reverse PostScript"))
+ lp = new String("PSR");
+ else if (t.equals("Epson 2500"))
+ lp = new String("epson2500");
+ else if (t.equals("IBM ProPrinter"))
+ lp = new String("ibmproprinter");
+ else if (t.equals("Qume Sprint 5"))
+ lp = new String("qume5");
+ else if (t.equals("Daisy"))
+ lp = new String("daisy");
+ else if (t.equals("Diablo"))
+ lp = new String("diablo");
+ else if (t.equals("Datagraphix"))
+ lp = new String("datagraphix");
+ else if (t.equals("DEC LA100"))
+ lp = new String("la100");
+ else if (t.equals("DEC LN03"))
+ lp = new String("ln03");
+ else if (t.equals("Dec Writer"))
+ lp = new String("decwriter");
+ else if (t.equals("Texas Instruments 800"))
+ lp = new String("ti800");
+ else {
+ Debug.message(
+ "CLNT:pmIns:gui2lptype: printer type unknown: " + t);
+ lp = new String(t);
+ }
+ } else {
+ Debug.message("CLNT:pmInstPr:gui2lptype: input printer type null");
+ lp = new String("");
+ }
+
+ return lp;
+ }
+
+ public String[] gui2lpfcontents(String f) {
+
+ String[] lp = null;
+
+ if (f != null) {
+ if (f.equals(pmUtility.getResource("PostScript"))) {
+ lp = new String[1];
+ lp[0] = new String("postscript");
+ } else if (f.equals(pmUtility.getResource("ASCII"))) {
+ lp = new String[1];
+ lp[0] = new String("simple");
+ } else if (f.equals(pmUtility.getResource(
+ "Both.PostScript.and.ASCII"))) {
+ lp = new String[2];
+ lp[0] = new String("simple");
+ lp[1] = new String("postscript");
+ } else if (f.equals(pmUtility.getResource("Any"))) {
+ lp = new String[1];
+ lp[0] = new String("any");
+ } else if (f.equals(pmUtility.getResource("None"))) {
+ lp = new String[1];
+ lp[0] = new String("none");
+ }
+ } else {
+ Debug.message(
+ "CLNT:pmInstPr:gui2lpfcontents(): input string null");
+ }
+
+ return lp;
+ }
+
+ public String gui2lpfaultn(String n) {
+ String lp = null;
+ if (n != null) {
+ if (n.equals(pmUtility.getResource("Write.to.Superuser")))
+ lp = new String("write");
+ else if (n.equals(pmUtility.getResource("Mail.to.Superuser")))
+ lp = new String("mail");
+ else if (n.equals(pmUtility.getResource("None")))
+ lp = new String("none");
+
+ } else {
+ Debug.message(
+ "CLNT:pmInstPr:gui2lpfaultn():input faultnotify null");
+ }
+ return lp;
+ }
+
+ public String gui2lpprotocol(String p) {
+ String lp = null;
+ if (p.equals("TCP"))
+ lp = new String("tcp");
+ else if (p.equals("BSD"))
+ lp = new String("bsd");
+ else if (p.equals("URI"))
+ lp = new String("uri");
+ else {
+ Debug.message(
+ "CLNT:pmInstPr:gui2lpprotocol: protocol is empty");
+ }
+ return lp;
+ }
+
+ public String gui2lpbanner(String p) {
+ String lp = null;
+ if (p.equals(pmUtility.getResource("Always.Print.Banner")))
+ lp = new String("always");
+ else if (p.equals(pmUtility.getResource("Never.Print.Banner")))
+ lp = new String("never");
+ else if (p.equals(pmUtility.getResource("User.Selectable.Default.On")))
+ lp = new String("optional");
+ else {
+ Debug.message(
+ "CLNT:pmInstPr:gui2lpbanner(): banner is empty");
+ }
+
+ if (lp != null)
+ Debug.message(
+ "CLNT:pmInstPr:gui2lpbanner(): banner is " + lp);
+ return lp;
+
+ }
+
+ public void updatePrinter() {
+ if (workingPrinter != null) {
+ if (printer != null)
+ workingPrinter.setPrinterName(printer);
+ if (server != null) {
+ workingPrinter.setPrintServer(server);
+ }
+ if (description != null)
+ workingPrinter.setComment(description);
+ if ((port != null) &&
+ (!port.equals(pmUtility.getResource("Not.Selected"))))
+ workingPrinter.setDevice(port);
+ if (make != null) {
+ workingPrinter.setMake(make);
+ }
+ if (model != null) {
+ workingPrinter.setModel(model);
+ }
+ if (ppd != null) {
+ workingPrinter.setPPD(ppd);
+ }
+
+ workingPrinter.setUsePPD(usePPD);
+
+ if (ptype != null)
+ workingPrinter.setPrinterType(gui2lpptype(ptype));
+ if (fcontents != null)
+ workingPrinter.setFileContents(gui2lpfcontents(fcontents));
+ if (faultn != null)
+ workingPrinter.setNotify(gui2lpfaultn(faultn));
+ if (destination != null)
+ workingPrinter.setDestination(destination);
+ if (protocol != null)
+ workingPrinter.setProtocol(gui2lpprotocol(protocol));
+ if (useraccesslist != null)
+ workingPrinter.setUserAllowList(useraccesslist);
+ else {
+ String[] a = new String[1];
+ a[0] = new String("none");
+ workingPrinter.setUserAllowList(a);
+ }
+
+ if (defaultp != null)
+ workingPrinter.setIsDefaultPrinter(defaultp.isSelected());
+
+ if (banner != null)
+ workingPrinter.setBanner(gui2lpbanner(banner));
+
+ } else {
+ Debug.warning(
+ "CLNT:pmInstPr:updatePrinter(): workingPrinter null");
+ }
+ }
+
+
+ void gatherLogs(Printer p) {
+ cmdLog = p.getCmdLog();
+ errorLog = p.getErrorLog();
+ warnLog = p.getWarnLog();
+ }
+
+
+ void dumpLogs(String who) {
+ Debug.message(who);
+ Debug.message(who + " command: " + cmdLog);
+ Debug.message(who + " warnings: " + warnLog);
+ Debug.message(who + " errors: " + errorLog);
+ }
+
+
+ public void doAddLocal() throws pmGuiException {
+
+ try {
+ getPrinterServer();
+ getDescription();
+ getPort();
+ if ((pmMisc.isppdCachefile()) && (usePPD)) {
+ getMakeModelPPD();
+ } else {
+ getTypeContents();
+ }
+ getFault();
+ getBanner();
+ getUserAccess();
+ updatePrinter();
+
+ } catch (pmIncompleteFormException ie) {
+ throw new pmIncompleteFormException(ie.getMessage());
+ }
+
+
+ boolean exist;
+ boolean failed = false;
+
+ // exists could throw an exception from the underyling cmds...
+ try {
+ exist = PrinterUtil.exists(printer, myTop.ns);
+ } catch (Exception e) {
+ throw new pmGuiException();
+ }
+
+ if (exist) {
+ throw new pmPrinterExistsException();
+ }
+
+ try {
+ workingPrinter.addLocalPrinter();
+ } catch (Exception e) {
+ failed = true;
+ } finally {
+ gatherLogs(workingPrinter);
+ pmCalls.debugShowPrinter(workingPrinter);
+ dumpLogs("doAddLocal()");
+ if (failed)
+ throw new pmAddPrinterFailedException(errorLog);
+ }
+
+ }
+
+
+ public void doAddNetwork() throws pmGuiException {
+ try {
+ getPrinterServer();
+ getDescription();
+ getNetworkInfo();
+ if ((pmMisc.isppdCachefile()) && (usePPD)) {
+ getMakeModelPPD();
+ } else {
+ getTypeContents();
+ }
+ getFault();
+ getBanner();
+ getUserAccess();
+ updatePrinter();
+ } catch (pmIncompleteFormException ie) {
+ throw new pmIncompleteFormException(ie.getMessage());
+ }
+
+ boolean exist = false;
+
+ try {
+ exist = PrinterUtil.exists(printer, myTop.ns);
+ } catch (Exception e) {
+ Debug.message(
+ "CLNT:pmInstPr:doAddNetwork:printer exists " + e);
+ throw new pmGuiException();
+ }
+
+ if (exist) {
+ Debug.message(
+ "CLNT:pmInstPr:Trying to add existing printer: " + printer);
+ throw new pmPrinterExistsException();
+ }
+
+ boolean failed = false;
+ try {
+ workingPrinter.addLocalPrinter();
+ } catch (Exception e) {
+ failed = true;
+ } finally {
+ gatherLogs(workingPrinter);
+ pmCalls.debugShowPrinter(workingPrinter);
+ dumpLogs("doAddNetwork()");
+ if (failed)
+ throw new pmAddPrinterFailedException(errorLog);
+ }
+ }
+
+
+ public void doModifyLocalAttached() throws pmGuiException {
+ getDescription();
+ getFault();
+ getBanner();
+
+ if (workingPrinter.getPPD() != null) {
+ getMakeModelPPD();
+ } else {
+ getTypeContents();
+ }
+ getUserAccess();
+ updatePrinter();
+
+ boolean failed = false;
+ try {
+ workingPrinter.modifyPrinter();
+ } catch (Exception e) {
+ Debug.warning("CLNT:doModifyLocalAttached: " + e);
+ failed = true;
+ } finally {
+ gatherLogs(workingPrinter);
+ pmCalls.debugShowPrinter(workingPrinter);
+ dumpLogs("doModifyLocalAttached()");
+ if (failed)
+ throw new pmModifyPrinterFailedException(errorLog);
+ }
+
+ }
+
+ public void doModifyLocalNetwork() throws pmGuiException {
+ getDescription();
+ getNetworkInfo();
+ getFault();
+ getBanner();
+ if (workingPrinter.getPPD() != null) {
+ getMakeModelPPD();
+ } else {
+ getTypeContents();
+ }
+ getUserAccess();
+ updatePrinter();
+
+ boolean failed = false;
+ try {
+ workingPrinter.modifyPrinter();
+ } catch (Exception e) {
+ Debug.warning("CLNT:pmInstPr:doModifyLocalNetwork: " + e);
+ failed = true;
+ } finally {
+ gatherLogs(workingPrinter);
+ pmCalls.debugShowPrinter(workingPrinter);
+ dumpLogs("doModifyLocalNetwork()");
+ if (failed)
+ throw new pmModifyPrinterFailedException(errorLog);
+ }
+
+ }
+
+
+ public void doModifyRemote() throws pmGuiException {
+ getDescription();
+ updatePrinter();
+
+ boolean failed = false;
+ try {
+ workingPrinter.modifyPrinter();
+ } catch (Exception e) {
+ Debug.warning("CLNT:doModifyRemote: " + e);
+ failed = true;
+ } finally {
+ gatherLogs(workingPrinter);
+ pmCalls.debugShowPrinter(workingPrinter);
+ dumpLogs("doModifyRemote()");
+ if (failed)
+ throw new pmModifyPrinterFailedException(errorLog);
+ }
+
+ }
+
+
+ public void doClearFields() {
+
+ if (pnameText != null)
+ pnameText.setText("");
+ if (snameText != null)
+ snameText.setText("");
+ if (descText != null)
+ descText.setText("");
+ if (portCombo != null)
+ portCombo.setSelectedIndex(0);
+ if (makeCombo != null)
+ makeCombo.setSelectedIndex(0);
+ if (modelCombo != null)
+ modelCombo.setSelectedIndex(0);
+ if (ppdCombo != null)
+ ppdCombo.setSelectedIndex(0);
+ if (typeCombo != null)
+ typeCombo.setSelectedIndex(0);
+ if (faultCombo != null)
+ faultCombo.setSelectedIndex(0);
+ if (protocolCombo != null)
+ protocolCombo.setSelectedIndex(0);
+ if (destText != null)
+ destText.setText("");
+
+ if (defaultp.isSelected())
+ defaultp.doClick();
+
+ if (bannerCombo != null)
+ bannerCombo.setSelectedIndex(0);
+
+ accessModel.removeListEntries();
+ accessModel.addaccessList("all");
+ }
+
+ public void doResetFields() {
+
+ if (workingPrinter != null) {
+ try {
+ if (workingPrinter.getComment() != null)
+ descText.setText(workingPrinter.getComment());
+ else
+ descText.setText("");
+ } catch (Exception e) {
+ Debug.message(
+ "CLNT:pmInstallPr:doResetFields(): getComment() " +
+ "Exception: " + e);
+ }
+
+ if (action == Constants.ADDLOCAL ||
+ action == Constants.ADDNETWORK ||
+ action == Constants.MODIFYATTACHED) {
+ try {
+ portCombo.setSelectedItem(workingPrinter.getDevice());
+ } catch (Exception e) {
+ Debug.message(
+ "CLNT:pmInsPr:doResetFields(): getDevice() " +
+ "Exception: " + e);
+ }
+ }
+
+ if (action != Constants.MODIFYREMOTE) {
+ if (workingPrinter.getPPD() != null) {
+ setMake();
+ setModel();
+ setPPD();
+ } else {
+ setPrinterType();
+ setType();
+ }
+
+ setFault();
+
+ if (action == Constants.MODIFYNETWORK)
+ setNetworkInfo();
+
+ try {
+ accessModel.removeListEntries();
+ accessModel.addaccessList(
+ workingPrinter.getUserAllowList());
+ accessList.setListData(accessModel.getAccessList());
+ accessList.ensureIndexIsVisible(0);
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT:InstPr:doResetFields(): addaccessList() " +
+ "Exception: " + e);
+ } finally {
+ accessList.clearSelection();
+ }
+
+
+
+ // selected and banner object out of sync
+ setBanner();
+ }
+
+ // selected and printer object out of sync
+ if ((defaultp.isSelected() &&
+ !workingPrinter.getIsDefaultPrinter()) ||
+
+ (!defaultp.isSelected() &&
+ workingPrinter.getIsDefaultPrinter()))
+
+ defaultp.doClick();
+
+ }
+ }
+
+
+
+ public boolean isactionModify() {
+
+ if (action == Constants.MODIFYATTACHED ||
+ action == Constants.MODIFYNETWORK ||
+ action == Constants.MODIFYREMOTE)
+
+ return true;
+ else
+ return false;
+ }
+
+ public void doReset() {
+ Debug.message("CLNT:pmInsPr:doReset()");
+ if (action == Constants.ADDLOCAL ||
+ action == Constants.ADDNETWORK) {
+
+ doClearFields();
+ } else {
+ doResetFields();
+ }
+
+ // as a side effect, the OK button will regain default status
+ if (defaultComponent != null)
+ defaultComponent.requestFocus();
+ }
+
+ public void doAction() throws pmGuiException {
+
+ // if nameservice, check for login
+
+ if (myTop.ns.getNameService().equals("nis") == true ||
+ myTop.ns.getNameService().equals("ldap") == true) {
+ try {
+ if (!myTop.ns.isAuth()) {
+ pmUtility.doLogin(myTop, frame);
+ }
+ } catch (pmUserCancelledException e) {
+ throw new pmLoginFailedException(
+ pmUtility.getResource("User.cancelled.login."));
+ } catch (pmGuiException ge) {
+ Debug.message("CLNT:pmInstPr: Required login failed.");
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource("Required.login.failed."),
+ myTop,
+ "LoginFailed");
+ m.setVisible(true);
+ Debug.message("CLNT:pmInstPr:required login failed.");
+ throw new pmLoginFailedException(
+ pmUtility.getResource("Required.login.failed."));
+ } catch (Exception e) {
+ Debug.message("CLNT:pmInstPr:login exception: " + e);
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource("Required.login.failed."),
+ myTop,
+ "LoginFailed");
+ m.setVisible(true);
+ throw new pmLoginFailedException(
+ pmUtility.getResource("Required.login.failed."));
+ }
+ }
+
+ frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+
+ Debug.message("CLNT:pmInstPr:doAction: action " + action);
+
+ // Check for confirmation option
+ if (((myTop.getConfirmOption() == true) && (confirmAction() == true))
+ || (myTop.getConfirmOption() == false)) {
+
+ try {
+
+ switch (action) {
+
+ case Constants.ADDLOCAL:
+ doAddLocal();
+ break;
+ case Constants.ADDNETWORK:
+ doAddNetwork();
+ break;
+ case Constants.MODIFYATTACHED:
+ workingPrinter.getPrinterDetails();
+ Debug.message(
+ "CLNT:pmInstPr:Printer Details: server is " +
+ workingPrinter.getPrintServer());
+ doModifyLocalAttached();
+ break;
+ case Constants.MODIFYNETWORK:
+ // add dest and protocol
+ workingPrinter.getPrinterDetails();
+ Debug.message("CLNT:pmInstPr:Printer Details: server is " +
+ workingPrinter.getPrintServer());
+ doModifyLocalNetwork();
+ break;
+ case Constants.MODIFYREMOTE:
+ workingPrinter.getPrinterDetails();
+ doModifyRemote();
+ break;
+ }
+
+ } catch (pmIncompleteFormException fe) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ fe.getMessage()); // "FormError"
+ m.setVisible(true);
+ throw new pmIncompleteFormException();
+ } catch (pmPrinterExistsException ee) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "The.specified.printer.already.exists."));
+ m.setVisible(true);
+ } catch (pmNullSelectedPrinterException ne) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "The.selected.printer.does.not.exist."));
+ m.setVisible(true);
+ cleanup();
+ // frame.dispose();
+ } catch (pmAddPrinterFailedException ae) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ ae.getMessage(),
+ myTop,
+ "AddPrinterFailed");
+ m.setVisible(true);
+
+ } catch (pmModifyPrinterFailedException me) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ me.getMessage(),
+ myTop,
+ "ModifyFailed");
+ m.setVisible(true);
+ } catch (pmGuiException ge) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Application.Error"),
+ ge.toString());
+ m.setVisible(true);
+
+ } catch (pmCmdFailedException cfe) {
+ String msg = cfe.getMessage();
+ if (msg == null || msg.length() == 0)
+ msg = pmUtility.getResource(
+ "error.message.command-failed");
+
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Command.Failed.Error"),
+ msg);
+ m.setVisible(true);
+
+ } catch (Exception e) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Unknown.Application.Error"),
+ e.toString());
+ m.setVisible(true);
+
+ } finally {
+ frame.setCursor(Cursor.getDefaultCursor());
+ myTop.setLogData(cmdLog, errorLog, warnLog);
+ myTop.showLogData(actionName);
+ }
+
+ // Update the list of printers
+ myTop.pmsetPrinterList();
+ }
+
+ }
+
+ public boolean confirmAction() {
+ if (myTop.getConfirmOption() == true) {
+ pmOKCancelDialog d = new pmOKCancelDialog(frame,
+ pmUtility.getResource("Action.Confirmation"),
+ pmUtility.getResource(
+ "Continue.action.for.this.printer?"));
+ d.setVisible(true);
+ if (d.getValue() != JOptionPane.OK_OPTION) {
+ pmMessageDialog m =
+ new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Warning"),
+ pmUtility.getResource("Operation.Cancelled"));
+ m.setVisible(true);
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+ public void actionportCombo() {
+ Debug.message("CLNT:pmInstPr:actionportCombo()");
+ port = (String)portCombo.getSelectedItem();
+ if (port.equals(pmUtility.getResource("Other..."))) {
+ pmOther o = new pmOther(
+ frame,
+ pmUtility.getResource("SPM:Specify.Printer.Port"),
+ pmUtility.getResource("Enter.printer.port.or.file"),
+ myTop,
+ "PrinterPort");
+
+ o.setVisible(true);
+ if (o.getValue() == JOptionPane.OK_OPTION) {
+ port = o.deviceName.getText();
+ int idx = portCombo.getItemCount();
+ try {
+ if (!port.equals("") && Valid.device(port)) {
+ portCombo.insertItemAt(
+ port, (idx > 0) ? idx -1 : idx);
+ portCombo.setSelectedItem(port);
+ } else if (!port.equals("")) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "Device.missing.or.not.writeable."),
+ myTop,
+ "PrinterPort"); // "InvalidDevice"
+ m.setVisible(true);
+ if (olddevice == null)
+ portCombo.setSelectedIndex(0);
+ else
+ portCombo.setSelectedItem(olddevice);
+ } else {
+ if (olddevice == null)
+ portCombo.setSelectedIndex(0);
+ else
+ portCombo.setSelectedItem(olddevice);
+ }
+ } catch (Exception de) {
+ Debug.warning(
+ "CLNT:pmInstPr:error validating device" + de);
+ }
+
+ } else { // Cancelled out of Other window
+ if (olddevice == null)
+ portCombo.setSelectedIndex(0);
+ else
+ portCombo.setSelectedItem(olddevice);
+ }
+ }
+ olddevice = (String)portCombo.getSelectedItem();
+ if (!port.equals(pmUtility.getResource("Not.Selected"))) {
+ portCombo.removeItem(pmUtility.getResource("Not.Selected"));
+ if ((pmMisc.isppdCachefile()) && (usePPD)) {
+ String makemodel[] = null;
+ String tmake;
+ int idx;
+ String models[] = null;
+ int i;
+
+ makemodel = PrinterUtil.getProbePrinter(olddevice);
+ if (makemodel != null) {
+ if ((makemodel[0] != null) &&
+ (!makemodel[0].equals(null))) {
+
+ idx = (makemodel[0]).indexOf(" ");
+
+ Debug.message(
+ "CLNT: makemodel[0] = " + makemodel[0]);
+ Debug.message(
+ "CLNT: makemodel[1] = " + makemodel[1]);
+
+ if (idx != -1)
+ tmake = new String(makemodel[0].substring(0, idx));
+ else
+ tmake = new String(makemodel[0]);
+
+ // Some Manufacturers have multiple names
+ // Collapse them
+ if ((tmake.equals("hp")) ||
+ (tmake.equals("Hewlett-Packard")) ||
+ (tmake.equals("HEWLETT-PACKARD")))
+ tmake = new String("HP");
+
+ if ((tmake.equals("MINOLTA-QMS")) ||
+ (tmake.equals("MINOLTA")))
+ tmake = new String("Minolta");
+
+ if ((tmake.equals("OKI")) ||
+ (tmake.equals("OKI DATA CORP")))
+ tmake = new String("Okidata");
+
+ if (tmake.equals("XEROX"))
+ tmake = new String("Xerox");
+
+ if (tmake.equals("EPSON"))
+ tmake = new String("Epson");
+
+ Debug.message("CLNT:pmInstPr:Probe:make: " + tmake);
+
+ if ((makemodel[1] != null) &&
+ (!makemodel[1].equals(null))) {
+
+ Debug.message(
+ "CLNT:pmInstPr:Probe:model: " + makemodel[1]);
+
+ try {
+ models = PrinterUtil.getModelsList(
+ tmake.trim());
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT:pmInstPr:getModelsList: exception" + e);
+ }
+
+ boolean havemodel = false;
+ boolean addmake = false;
+
+ if (models == null) {
+ Debug.warning(
+ "CLNT:pmInstPr:Probe:no models for "
+ + tmake);
+ } else {
+ for (i = 0; i < models.length; i++) {
+ if (models[i].equalsIgnoreCase(
+ makemodel[1].trim())) {
+ havemodel = true;
+ }
+ }
+ // Some Printers do not preceed the model
+ // name with the Make. If fail, try adding
+ // Make to front of model
+ if (!havemodel) {
+ for (i = 0; i < models.length; i++) {
+ if (models[i].equalsIgnoreCase(
+ tmake.trim() +
+ " " + makemodel[1].trim())) {
+ havemodel = true;
+ addmake = true;
+
+ }
+ }
+ }
+
+ if (havemodel) {
+ makeCombo.setSelectedItem(tmake);
+ if (!addmake) {
+ modelCombo.setSelectedItem(makemodel[1]);
+ Debug.message("CLNT:pmInstPr:model is " +
+ makemodel[1]);
+ } else {
+ modelCombo.setSelectedItem(tmake.trim() +
+ " " + makemodel[1]);
+ Debug.message("CLNT:pmInstPr:model is " +
+ tmake.trim() + " " + makemodel[1]);
+ }
+
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void actiontypeCombo() {
+
+ Debug.message("CLNT:pmInstPr:actiontypeCombo()");
+ ptype = (String)typeCombo.getSelectedItem();
+
+ if (ptype.equals(pmUtility.getResource("Other..."))) {
+ pmOther o = new pmOther(
+ frame,
+ pmUtility.getResource("SPM:Specify.Printer.Type"),
+ pmUtility.getResource("Enter.printer.type:"),
+ myTop,
+ "PrinterType");
+ o.setVisible(true);
+ if (o.getValue() == JOptionPane.OK_OPTION) {
+ ptype = o.deviceName.getText();
+ int idx = typeCombo.getItemCount();
+ try {
+ if (!ptype.equals("") && Valid.printerType(ptype)) {
+ typeCombo.insertItemAt(
+ ptype, (idx > 0) ? idx -1 : idx);
+ typeCombo.setSelectedItem(ptype);
+ } else if (!ptype.equals("")) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "Invalid.printer.type."),
+ myTop,
+ "PrinterType");
+ m.setVisible(true);
+ if (oldptype == null)
+ typeCombo.setSelectedIndex(0);
+ else
+ typeCombo.setSelectedItem(oldptype);
+ } else {
+ if (oldptype == null)
+ typeCombo.setSelectedIndex(0);
+ else
+ typeCombo.setSelectedItem(oldptype);
+ }
+
+ } catch (Exception pte) {
+ Debug.message(
+ "CLNT:pmInstPr:error validating printertype"
+ + pte);
+ }
+
+ } else { // Cancelled out of Other window
+ if (oldptype == null)
+ typeCombo.setSelectedIndex(0);
+ else
+ typeCombo.setSelectedItem(oldptype);
+ }
+ }
+ oldptype = (String)typeCombo.getSelectedItem();
+ }
+
+ // Printer make has been selected
+ public void actionmakeCombo() {
+ int i;
+
+ make = (String)makeCombo.getSelectedItem();
+ if (!make.equals(pmUtility.getResource("Not.Selected")))
+ makeCombo.removeItem(pmUtility.getResource("Not.Selected"));
+
+
+ if (!oldmake.equals(make))
+ modelCombo.removeAllItems();
+
+ oldmake = make;
+ }
+
+
+ // Get Model
+ public void actionmodelCombo() {
+ int i;
+ String models[] = null;
+
+ if (!oldmake.equals(make)) {
+ try {
+ models = PrinterUtil.getModelsList(make);
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT:pmInstPr:actionmodelCombo: exception" + e);
+ }
+
+ if (models == null) {
+ Debug.warning(
+ "CLNT:pmInstPr:actionmodelCombo:no models for "
+ + make);
+ modelCombo.removeAllItems();
+ modelCombo.addItem(pmUtility.getResource(
+ "No.Models.Found"));
+ } else {
+ for (i = 0; i < models.length; i++)
+ modelCombo.addItem(models[i]);
+ }
+ }
+
+ model = (String)modelCombo.getSelectedItem();
+ if (!oldmodel.equals(model))
+ ppdCombo.removeAllItems();
+
+ oldmodel = model;
+ }
+
+
+ public void actionppdCombo() {
+ int i;
+ int rec = -1;
+ int idx = -1;
+ String ppds[] = null;
+
+ if (!oldmodel.equals(model)) {
+
+ try {
+ ppds = PrinterUtil.getPPDList(make, model);
+
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT:pmInstPr:actionmodelCombo: exception" +e);
+ }
+
+ // Get the ppd files list
+ // If a recommended ppd is in the list, display it first
+ if (ppds == null) {
+ Debug.warning(
+ "CLNT:pmInstPr:actionmodelCombo: no ppds for " +
+ make + "/" + model);
+ ppdCombo.addItem(
+ pmUtility.getResource("No.PPD.Files.Found"));
+ } else {
+ for (i = 0; i < ppds.length; i++) {
+ ppdCombo.addItem(ppds[i]);
+ rec = ppds[i].indexOf("recommended");
+ if (rec != -1)
+ idx = i;
+ }
+
+ if (idx != -1)
+ ppdCombo.setSelectedIndex(idx);
+ }
+ }
+
+ ppd = (String)ppdCombo.getSelectedItem();
+
+ if (!ppd.equals(""))
+ ppdCombo.removeItem("");
+
+ }
+
+
+ public void actionaddButton() {
+
+ String tmp = null;
+ String trimtmp;
+ Debug.message("CLNT:pmInstPr:actionaddButton()");
+ try {
+ tmp = userText.getText();
+ } catch (Exception e) {
+ Debug.message(
+ "CLNT:pmInstPr:actionaddButton:UserAccessList empty");
+ }
+
+ if (tmp == null || tmp.equals("") || tmp.trim().equals("")) {
+ Debug.message("CLNT:pmInstPr:no username to add");
+ } else {
+ trimtmp = tmp.trim();
+ if (accessModel.isduplicate(trimtmp))
+ Debug.message("CLNT:pmInstPr:duplicate user");
+
+ else if (!Valid.user(trimtmp)) {
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource("Invalid.username"));
+ // "FormError"
+ m.setVisible(true);
+
+ } else {
+ if (accessModel.getRowCount() > 0 &&
+ (accessModel.getElementAt(0).equals("all") ||
+ accessModel.getElementAt(0).equals("none")))
+ accessModel.removeRow(0);
+
+ if (trimtmp.equals("all") ||
+ trimtmp.equals("none")) {
+ accessModel.removeListEntries();
+ }
+
+ accessModel.addaccessList(trimtmp);
+ accessList.setListData(accessModel.getAccessList());
+ int rw = accessModel.getRowCount();
+ accessList.setSelectedIndex(rw - 1);
+ accessList.ensureIndexIsVisible(rw -1);
+ }
+
+ }
+ userText.setText("");
+ userText.requestFocus();
+
+ ascrollPane.revalidate();
+ ascrollPane.repaint();
+
+ frame.repaint();
+ }
+
+ public void actiondeleteButton() {
+ Debug.message("CLNT:pmInstPr:actiondeleteButton()");
+ int row;
+ int rcount;
+ int idx;
+
+ row = accessList.getSelectedIndex();
+ rcount = accessModel.getRowCount();
+
+ if ((row >= 0 && rcount > 0) && (!accessList.isSelectionEmpty())) {
+ accessModel.removeRow(row);
+ rcount = accessModel.getRowCount();
+ if (rcount != 0) {
+ if (row == rcount)
+ accessList.setSelectedIndex(row - 1);
+ idx = accessList.getFirstVisibleIndex();
+ if (idx > 0 && idx < rcount)
+ accessList.ensureIndexIsVisible(idx - 1);
+ }
+ }
+ userText.requestFocus();
+ frame.repaint();
+ }
+
+
+ // For ok/cancel
+ public void cleanup() {
+
+ if (action == Constants.ADDLOCAL) {
+ myTop.localinstallView = null;
+ }
+
+ if (action == Constants.ADDNETWORK) {
+ myTop.networkinstallView = null;
+ }
+
+ }
+
+ public void pmScreendispose() {
+ frame.dispose();
+ }
+
+ public void actionokButton() {
+
+ Debug.message("CLNT:pmInstPr:actionokButton()");
+ boolean incomplete = false;
+
+ try {
+ doAction();
+ } catch (pmLoginFailedException le) {
+ // User already notified
+ Debug.message("CLNT:pmInstPr:pmLoginFailedException caught");
+ } catch (pmIncompleteFormException fe) {
+ // User already notified
+ incomplete = true;
+ } catch (pmGuiException ge) {
+ Debug.message("CLNT:pmInstPr:login Exception, task cancelled");
+ }
+
+ if (!incomplete) {
+ cleanup();
+ myTop.pmsetdefaultpLabel();
+ Debug.message("CLNT:pmInstPr:actionokbutton(): work done");
+ pmCalls.debugShowPrinter(workingPrinter);
+ frame.setVisible(false);
+ frame.repaint();
+ // frame.dispose();
+ myTop.scrollPane.revalidate();
+ myTop.scrollPane.repaint();
+ }
+ }
+
+ public void actionapplyButton() {
+
+ Debug.message("CLNT:pmInstPr:actionapplyButton()");
+
+ try {
+ doAction();
+ } catch (pmLoginFailedException le) {
+ // User already notified
+ Debug.message("CLNT:pmInstPr:pmLoginFailedException caught");
+ } catch (pmGuiException ge) {
+ Debug.message("CLNT:pmInstPr:login Exception, task cancelled");
+ }
+
+ myTop.pmsetdefaultpLabel();
+ Debug.message("CLNT:pmInstPr:actionapplybutton(): work done");
+ pmCalls.debugShowPrinter(workingPrinter);
+ myTop.scrollPane.revalidate();
+ myTop.scrollPane.repaint();
+ }
+
+
+ public void actionresetButton() {
+ Debug.message("CLNT:pmInstPr:actionresetButton()");
+ doReset();
+ frame.repaint();
+ }
+
+ public void actioncancelButton() {
+ Debug.message("CLNT:pmInstPr:actioncancelButton()");
+ cleanup();
+ frame.setVisible(false);
+ frame.repaint();
+ // frame.dispose();
+ }
+
+ public void actionhelpButton() {
+ Debug.message("CLNT:pmInstPr:actionhelpButton()");
+ myTop.showHelpItem(helpTag);
+ }
+
+ public void Show() {
+
+ Debug.message("CLNT:pmInstPr:Show()");
+ frame.getContentPane().add("North", this);
+ frame.pack();
+ frame.setVisible(true);
+ frame.repaint();
+
+ // set focus to initial field, depending on which action is tbd
+ // this seems to work best after pack()
+
+ // default button is always OK, for now...
+ // frame.getRootPane().setDefaultButton (okButton);
+ okButton.setAsDefaultButton();
+
+
+ Debug.info("Show: default comp is " + defaultComponent);
+ if (defaultComponent != null) {
+ defaultComponent.requestFocus();
+ }
+
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmInstallScreen.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmInstallScreen.java
new file mode 100644
index 0000000000..5527d4913b
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmInstallScreen.java
@@ -0,0 +1,494 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmInstallScreen.java
+ * Create add/modify GUI
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Vector;
+import javax.swing.JPanel;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+/*
+ * Screen for Installing/Modifying local and network printers
+ */
+
+public class pmInstallScreen extends pmButtonScreen {
+
+ pmTextField pnameText;
+ pmTextField snameText;
+ pmTextField descText;
+ pmTextField userText;
+ JComboBox portCombo;
+ JComboBox faultCombo;
+
+// For printers configured without using make/model/PPD files
+ JComboBox fileCombo;
+ JComboBox typeCombo;
+
+// For printers configured using make/model/PPD files
+ JComboBox ppdCombo;
+ JComboBox makeCombo;
+ JComboBox modelCombo;
+
+ pmTextField destText;
+ JComboBox protocolCombo;
+ JCheckBox defaultp;
+ JComboBox bannerCombo;
+ pmButton addButton;
+ pmButton deleteButton;
+ JList userList;
+ Vector userData;
+
+ public pmInstallScreen() {}
+
+
+ public void printernameLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Printer.Name:")), c);
+ }
+ public void printernameTextField(JPanel north, GridBagConstraints c) {
+ pnameText = new pmTextField(14);
+ north.add(pnameText, c);
+ }
+ public void printernameStaticField(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Printer.Server:")), c);
+ }
+
+ public void servernameLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Printer.Server:")), c);
+ }
+ public void servernameTextField(JPanel north, GridBagConstraints c) {
+ snameText = new pmTextField(30);
+ north.add(snameText, c);
+ }
+ public void servernameStaticField(JPanel north, GridBagConstraints c) {
+ }
+
+ public void descriptionLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Description:")), c);
+ }
+ public void descriptionField(JPanel north, GridBagConstraints c) {
+ descText = new pmTextField(25);
+ north.add(descText, c);
+ }
+
+ public void printerportLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Printer.Port:")), c);
+ }
+
+ public void devnullLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel("/dev/null"));
+ }
+
+ public void printerportField(JPanel north, GridBagConstraints c) {
+
+ String devices[];
+ int i;
+
+ try {
+ devices = PrinterUtil.getDeviceList();
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmAccess:getDeviceList caught " + e);
+ devices = new String[1];
+ devices[0] = "";
+ }
+ portCombo = new JComboBox(devices);
+ portCombo.insertItemAt(pmUtility.getResource("Not.Selected"), 0);
+ portCombo.setSelectedIndex(0);
+
+ portCombo.addItem(pmUtility.getResource("Other..."));
+ portCombo.addActionListener(new ComboListener(Constants.PORT));
+
+ north.add(portCombo, c);
+
+ }
+ public void printertypeLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Printer.Type:")), c);
+ }
+ public void printertypeField(JPanel north, GridBagConstraints c) {
+ typeCombo = new JComboBox();
+ typeCombo.addItem("PostScript");
+ typeCombo.addItem("HP Printer");
+ typeCombo.addItem("Reverse PostScript");
+ typeCombo.addItem("Epson 2500");
+ typeCombo.addItem("IBM ProPrinter");
+ typeCombo.addItem("Qume Sprint 5");
+ typeCombo.addItem("Daisy");
+ typeCombo.addItem("Diablo");
+ typeCombo.addItem("Datagraphix");
+ typeCombo.addItem("DEC LA100");
+ typeCombo.addItem("DEC LN03");
+ typeCombo.addItem("Dec Writer");
+ typeCombo.addItem("Texas Instruments 800");
+ typeCombo.addItem(pmUtility.getResource("Other..."));
+ typeCombo.addActionListener(new ComboListener(Constants.TYPE));
+ north.add(typeCombo, c);
+ }
+
+ public void filecontentsLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("File.Contents:")), c);
+ }
+ public void filecontentsField(JPanel north, GridBagConstraints c) {
+ fileCombo = new JComboBox();
+ fileCombo.addItem(pmUtility.getResource("PostScript"));
+ fileCombo.addItem(pmUtility.getResource("ASCII"));
+ fileCombo.addItem(
+ pmUtility.getResource("Both.PostScript.and.ASCII"));
+ fileCombo.addItem(pmUtility.getResource("None"));
+ fileCombo.addItem(pmUtility.getResource("Any"));
+ north.add(fileCombo, c);
+ }
+
+
+ public void printermakeLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Printer.Make:")), c);
+ }
+ public void printermakeField(JPanel north, GridBagConstraints c) {
+
+ String makes[];
+
+ try {
+ makes = PrinterUtil.getMakesList();
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmAccess:getMakeList caught" +e);
+ makes = new String[1];
+ makes[0] = "";
+ }
+
+ makeCombo = new JComboBox(makes);
+ makeCombo.insertItemAt(
+ pmUtility.getResource("Not.Selected"), 0);
+ makeCombo.setSelectedIndex(0);
+
+
+ makeCombo.addActionListener(new ComboListener(Constants.MAKE));
+ north.add(makeCombo, c);
+ }
+
+ public void printermodelsLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Printer.Model:")), c);
+ }
+
+ public void printermodelsField(JPanel north, GridBagConstraints c) {
+ String models[];
+ modelCombo = new JComboBox();
+ modelCombo.addItem(" ");
+ modelCombo.addActionListener(
+ new ComboListener(Constants.MODEL));
+ north.add(modelCombo, c);
+ }
+
+ public void ppdcontentsLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Printer.Driver:")), c);
+ }
+ public void ppdcontentsField(JPanel north, GridBagConstraints c) {
+ ppdCombo = new JComboBox();
+ ppdCombo.addItem(" ");
+ ppdCombo.addActionListener(new ComboListener(Constants.PPD));
+ north.add(ppdCombo, c);
+ }
+
+ public void faultnotLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Fault.Notification:")), c);
+ }
+ public void faultnotField(JPanel north, GridBagConstraints c) {
+ faultCombo = new JComboBox();
+
+ faultCombo.addItem(pmUtility.getResource("Write.to.Superuser"));
+ faultCombo.addItem(pmUtility.getResource("Mail.to.Superuser"));
+ faultCombo.addItem(pmUtility.getResource("None"));
+ north.add(faultCombo, c);
+ }
+
+ public void destinationLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Destination:")), c);
+ }
+ public void destinationField(JPanel north, GridBagConstraints c) {
+ destText = new pmTextField(25);
+ north.add(destText, c);
+ }
+
+ public void protocolLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Protocol:")), c);
+ }
+ public void protocolField(JPanel north, GridBagConstraints c) {
+ protocolCombo = new JComboBox();
+ protocolCombo.addItem("BSD");
+ protocolCombo.addItem("TCP");
+ protocolCombo.addItem("URI");
+ north.add(protocolCombo, c);
+ }
+
+ public void optionsLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Options:")), c);
+ }
+
+ public void bannerLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Banner:")), c);
+ }
+
+ public void optionLabel(JPanel north, GridBagConstraints c) {
+ north.add(new JLabel
+ (pmUtility.getResource("Option:")), c);
+ }
+
+ public void optionsFields(JPanel north, GridBagConstraints c) {
+ defaultp = new JCheckBox(
+ pmUtility.getResource("Default.Printer"));
+
+ north.add(defaultp, c);
+
+ c.gridy++;
+ bannerCombo = new JComboBox();
+ bannerCombo.addItem(pmUtility.getResource
+ ("Always.Print.Banner"));
+ bannerCombo.addItem(pmUtility.getResource
+ ("User.Selectable.Default.On"));
+ bannerCombo.addItem(pmUtility.getResource
+ ("Never.Print.Banner"));
+
+ north.add(bannerCombo, c);
+ }
+
+ public void defaultoptionField(JPanel north, GridBagConstraints c) {
+ defaultp = new JCheckBox(
+ pmUtility.getResource("Default.Printer"));
+
+ north.add(defaultp, c);
+ }
+
+ public void northPanelConstraints(GridBagConstraints c) {
+ c.weightx = c.weighty = 0.0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ c.insets = new Insets(8, 5, 5, 5);
+ c.gridheight = 1;
+ c.gridwidth = 1;
+ }
+
+ public void labelConstraints(GridBagConstraints c) {
+ c.weightx = c.weighty = 0.0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ }
+ public void TextFieldConstraints(GridBagConstraints c) {
+ c.ipadx = 15;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ // c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = c.weighty = 1.0;
+ }
+ public void comboboxConstraints(GridBagConstraints c) {
+ c.weightx = c.weighty = 0.0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ }
+
+ public void optionsConstraints(GridBagConstraints c) {
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = c.weighty = 0.0;
+ }
+
+ class ComboListener implements ActionListener {
+ int activeCombo;
+
+ // Constructor
+ public ComboListener(int aCombo)
+ {
+ activeCombo = aCombo;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+
+ switch (activeCombo)
+ {
+ case Constants.PORT:
+ actionportCombo();
+ break;
+
+ case Constants.TYPE:
+ actiontypeCombo();
+ break;
+
+ case Constants.MAKE:
+ actionmakeCombo();
+ break;
+
+ case Constants.MODEL:
+ actionmodelCombo();
+ break;
+
+ case Constants.PPD:
+ actionppdCombo();
+ break;
+
+ }
+ }
+ }
+
+ public void actionportCombo() {}
+
+ public void actiontypeCombo() {}
+
+ public void actionmakeCombo() {}
+
+ public void actionmodelCombo() {}
+
+ public void actionppdCombo() {}
+
+ class adddelButtonListener implements ActionListener
+ {
+ int activeButton;
+
+ public adddelButtonListener(int aButton)
+ {
+ activeButton = aButton;
+ }
+
+ public void actionPerformed(ActionEvent e) {
+
+ switch (activeButton)
+ {
+ case Constants.ADD:
+ actionaddButton();
+ break;
+ case Constants.DELETE:
+ actiondeleteButton();
+ break;
+ }
+ }
+ }
+
+ public void actionaddButton() {}
+
+ public void actiondeleteButton() {}
+
+ public void useraccessLabel(JPanel center, GridBagConstraints c) {
+ center.add(new JLabel
+ (pmUtility.getResource("User.Access.List:")), c);
+ }
+
+ public void adButtons(GridBagConstraints c) {
+
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+
+ addButton = new pmButton(pmUtility.getResource("Add"));
+ deleteButton = new pmButton(pmUtility.getResource("Delete"));
+ addButton.addActionListener(
+ new adddelButtonListener(Constants.ADD));
+ deleteButton.addActionListener(
+ new adddelButtonListener(Constants.DELETE));
+ }
+
+ public void xxcenterPanel() {
+
+ JPanel center = new JPanel();
+ center.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.insets = new Insets(15, 15, 15, 15);
+ c.anchor = GridBagConstraints.WEST;
+
+ // Create the label
+ c.gridx = 0;
+ c.gridy = 0;
+ c.fill = GridBagConstraints.NONE;
+ c.weightx = c.weighty = 0.0;
+ c.anchor = GridBagConstraints.NORTHWEST;
+ center.add(new JLabel
+ (pmUtility.getResource("User.Access.List:")), c);
+
+ // Create the User Access List as JList
+ userList = new JList();
+ JScrollPane scrollPane = new JScrollPane();
+ scrollPane.getViewport().setView(userList);
+
+ c.gridwidth = 2;
+ c.gridx = 1;
+ c.weightx = c.weighty = 1.0;
+ c.fill = GridBagConstraints.BOTH;
+ center.add(scrollPane, c);
+
+ // Create the text field for adding users
+ c.gridx = 1;
+ c.gridy = 1;
+ c.ipadx = 15;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.WEST;
+ c.weightx = c.weighty = 1.0;
+
+ userText = new pmTextField(25);
+ center.add(userText, c);
+
+ // Create the add/delete buttons
+ c.gridx = 1;
+ c.gridy = 2;
+
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+
+ addButton = new pmButton(pmUtility.getResource("Add"));
+ deleteButton = new pmButton(pmUtility.getResource("Delete"));
+ addButton.addActionListener(
+ new adddelButtonListener(Constants.ADD));
+ deleteButton.addActionListener(
+ new adddelButtonListener(Constants.DELETE));
+
+
+ c.gridwidth = 1;
+ center.add(addButton, c);
+
+ c.gridx = 2;
+ center.add(deleteButton, c);
+
+ add("Center", center);
+
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLoad.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLoad.java
new file mode 100644
index 0000000000..802eb54a88
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLoad.java
@@ -0,0 +1,275 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmLoad.java
+ * Load a Naming Context implementation
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JPanel;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+public class pmLoad extends JPanel {
+
+ final static int OK = 1;
+ final static int APPLY = 2;
+ final static int RESET = 3;
+ final static int CANCEL = 4;
+ final static int HELP = 5;
+
+ final static int NIS = 6;
+ final static int NONE = 7;
+
+ pmFrame frame = new pmFrame(
+ pmUtility.getResource("SPM:Select.Naming.Service"));
+ JComboBox nameserviceCombo = new JComboBox();
+ pmTop mytop = null;
+ int resetIndex;
+
+ pmButton okButton = null;
+ pmButton cancelButton = null;
+ pmButton resetButton = null;
+ pmButton helpButton = null;
+
+
+ public pmLoad(pmTop mytop) {
+ this.mytop = mytop;
+
+ Debug.message("CLNT:pmLoad()");
+ setLayout(new BorderLayout());
+ resetIndex = mytop.actionindex;
+
+ northPanel();
+ southPanel();
+
+
+ }
+
+ public void northPanel() {
+ JPanel north = new JPanel();
+ north.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+ c.weightx = c.weighty = 0.0;
+ c.fill = GridBagConstraints.NONE;
+ c.anchor = GridBagConstraints.WEST;
+ c.insets = new Insets(15, 15, 5, 15);
+ c.gridheight = 1;
+ c.gridwidth = 1;
+
+ c.gridy = 1;
+ c.gridx = 0;
+ north.add(new JLabel
+ (pmUtility.getResource("Naming.Service:")), c);
+
+ c.gridy = 1;
+ c.gridx = 2;
+ c.ipadx = 15;
+
+ nameserviceCombo.addItem("files");
+
+ if (mytop.nisns != null)
+ nameserviceCombo.addItem("NIS");
+
+ if (mytop.ldapns != null)
+ nameserviceCombo.addItem("LDAP");
+
+ nameserviceCombo.setSelectedIndex(mytop.actionindex);
+ north.add(nameserviceCombo, c);
+
+ nameserviceCombo.addActionListener(new nsListener());
+ nameserviceCombo.addItemListener(mytop.new topnsListener());
+
+ add("North", north);
+
+ }
+
+ class nsListener implements ActionListener {
+ public nsListener() {}
+
+ public void actionPerformed(ActionEvent e)
+ {
+ mytop.actionindex = nameserviceCombo.getSelectedIndex();
+ if (mytop.actionindex == 0) {
+ Debug.message("CLNT:pmLoad:0: NONE");
+ } else if (mytop.actionindex == 1) {
+ Debug.message("CLNT:pmLoad:1: NIS");
+ } else if (mytop.actionindex == 4) {
+ Debug.message("CLNT:pmLoad:2: LDAP");
+ }
+ };
+ }
+
+ public void southPanel() {
+ JPanel south = new JPanel();
+
+ south.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridheight = 1;
+ c.gridwidth = 1;
+ c.weightx = c.weighty = 1.0;
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.insets = new Insets(15, 15, 15, 15);
+ c.gridy = 0;
+
+ okButton = new pmButton(
+ pmUtility.getResource("OK"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("OK.mnemonic"));
+
+ resetButton = new pmButton(
+ pmUtility.getResource("Reset"));
+ resetButton.setMnemonic(
+ pmUtility.getIntResource("Reset.mnemonic"));
+
+ cancelButton = new pmButton(
+ pmUtility.getResource("Cancel"));
+ cancelButton.setMnemonic(
+ pmUtility.getIntResource("Cancel.mnemonic"));
+
+ helpButton = new pmButton(
+ pmUtility.getResource("Help"));
+ helpButton.setMnemonic(
+ pmUtility.getIntResource("Help.mnemonic"));
+
+ okButton.addActionListener(new ButtonListener(OK));
+ resetButton.addActionListener(new ButtonListener(RESET));
+ cancelButton.addActionListener(new ButtonListener(CANCEL));
+ helpButton.addActionListener(new ButtonListener(HELP));
+
+ c.gridx = 0;
+ south.add(okButton, c);
+ c.gridx = 1;
+ south.add(resetButton, c);
+ c.gridx = 2;
+ south.add(cancelButton, c);
+ c.gridx = 3;
+ south.add(helpButton, c);
+
+ add("South", south);
+ }
+
+ class ButtonListener implements ActionListener {
+ int activeButton;
+
+ // Constructor
+ public ButtonListener(int aButton)
+ {
+ activeButton = aButton;
+ }
+
+ // Select Active Button and call routine
+
+ public void actionPerformed(ActionEvent e)
+ {
+
+ switch (activeButton) {
+ case OK:
+ actionokButton();
+ break;
+ case RESET:
+ actionresetButton();
+ break;
+ case CANCEL:
+ actioncancelButton();
+ break;
+ case HELP:
+ actionhelpButton();
+ break;
+ }
+
+ }
+ }
+
+ public void pmScreendispose() {
+ frame.dispose();
+ }
+
+ // Action for buttons
+
+ public void actionokButton() {
+ Debug.message("CLNT:pmLoad:actionokButton()");
+ mytop.pmsetNS();
+ mytop.pmsetNSLabel();
+ mytop.pmsetPrinterList();
+ mytop.pmsetdefaultpLabel();
+ frame.setVisible(false);
+ frame.repaint();
+ frame.dispose();
+ }
+
+ public void actionresetButton() {
+ Debug.message("CLNT:pmLoad:actionresetButton()");
+ nameserviceCombo.setSelectedIndex(resetIndex);
+ frame.repaint();
+ }
+
+ public void actioncancelButton() {
+ Debug.message("CLNT:pmLoad:actioncancelButton()");
+ nameserviceCombo.setSelectedIndex(resetIndex);
+ frame.setVisible(false);
+ frame.repaint();
+ frame.dispose();
+ }
+
+ public void actionhelpButton() {
+ Debug.message("CLNT:pmLoad:actionhelpButton()");
+ mytop.showHelpItem("NameService");
+ }
+
+ public void Show() {
+ Debug.message("CLNT:pmLoad:Show()");
+
+ frame.getContentPane().add("North", this);
+ frame.pack();
+
+ // handle Esc as cancel
+ frame.getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ actioncancelButton();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ // default button is always OK, for now...
+ okButton.setAsDefaultButton();
+
+ frame.setDefaultComponent(nameserviceCombo);
+
+ nameserviceCombo.requestFocus();
+
+ frame.setVisible(true);
+ frame.repaint();
+
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLogDisplay.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLogDisplay.java
new file mode 100644
index 0000000000..fc23e6a8c0
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLogDisplay.java
@@ -0,0 +1,244 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright(c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmLogDisplay.java
+ * Command Log implementation
+ */
+
+package com.sun.admin.pm.client;
+
+import javax.swing.*;
+
+import java.awt.*;
+import java.util.*;
+import java.awt.event.*;
+
+import com.sun.admin.pm.server.*;
+
+public class pmLogDisplay extends pmFrame {
+
+ pmButton helpButton = null;
+ pmButton okButton = null;
+ pmButton clearButton = null;
+ pmTop theTop = null;
+ String helpTag = null;
+ JTextArea theList = null;
+ String theContents = null;
+
+ public pmLogDisplay() {
+ this(null, null);
+ }
+
+
+ public pmLogDisplay(pmTop t, String h) {
+ super(pmUtility.getResource("SPM:Command-Line.Console"));
+
+ theTop = t;
+ helpTag = h;
+
+ setLocation(150, 200); // relative to parent frame
+
+ // top panel
+ JPanel p = new JPanel();
+ p.setLayout(new BorderLayout());
+
+ theContents = new String();
+ theList = new JTextArea(12, 36);
+ theList.setLineWrap(false);
+ theList.setEditable(false);
+
+ theList.registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ copyPressed();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, Event.CTRL_MASK),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ theList.registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ copyPressed();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+
+ JScrollPane scroll = new JScrollPane();
+ scroll.getViewport().setView(theList);
+
+ p.add(scroll, "Center");
+
+ this.getContentPane().add(p, "Center");
+
+ p = new JPanel();
+
+ okButton = new pmButton(
+ pmUtility.getResource("Dismiss"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("Dismiss.mnemonic"));
+ p.add(okButton);
+
+ clearButton = new pmButton(
+ pmUtility.getResource("Clear"));
+ clearButton.setMnemonic(
+ pmUtility.getIntResource("Clear.mnemonic"));
+ p.add(clearButton);
+
+ if (theTop != null && helpTag != null) {
+ helpButton = new pmButton(
+ pmUtility.getResource("Help"));
+ helpButton.setMnemonic(
+ pmUtility.getIntResource("Help.mnemonic"));
+ p.add(helpButton);
+ helpButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ Debug.message("Help button event");
+ theTop.showHelpItem(helpTag);
+ }
+ });
+ }
+
+ this.getContentPane().add(p, "South");
+
+ this.pack();
+
+ this.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ returnValue = JOptionPane.CLOSED_OPTION;
+ pmLogDisplay.this.setVisible(false);
+ if (pmLogDisplay.this.theTop != null)
+ pmLogDisplay.this.theTop.setLogOption(false);
+ }
+ });
+
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ okPressed();
+ }
+ });
+
+ clearButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ pmLogDisplay.this.clear();
+ }
+ });
+
+ // handle Esc as dismiss in any case
+ getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ okPressed();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ // getRootPane().setDefaultButton(okButton);
+ okButton.setAsDefaultButton();
+
+ theList.requestFocus();
+
+ }
+
+ protected void copyPressed() {
+ theList.copy();
+ }
+
+
+ protected void okPressed() {
+ returnValue = JOptionPane.OK_OPTION;
+ pmLogDisplay.this.setVisible(false);
+ if (pmLogDisplay.this.theTop != null)
+ pmLogDisplay.this.theTop.setLogOption(false);
+ }
+
+ public int getValue() {
+ // Debug.message("getValue");
+ return returnValue;
+ }
+
+ // i.e. a solid line, or spaces, or...
+ public void addSeparator() {
+ theContents = theContents + "\n\r";
+ theList.setText(theContents);
+ }
+
+ // tricky: s may have embedded newlines...
+ public void addText(String s) {
+ theContents = theContents + s;
+
+ /*
+ * StringTokenizer st = new StringTokenizer(s, "\n\r", false);
+ * try {
+ * while(st.hasMoreTokens()) {
+ * String ss = st.nextToken();
+ * theContents.addElement(ss);
+ * }
+ * } catch(Exception x) {
+ * Debug.warning("CLNT: Log addText caught: " + x);
+ * }
+ */
+
+ /*
+ * Debug.message("Log contents len = " + theContents.size());
+ * for (int i = 0; i < theContents.size(); ++i)
+ * Debug.message("\t" + i + ": " + theContents.elementAt(i));
+ */
+
+ // conveniently, this forces the last line to be scrolled to.
+ theList.setText(theContents);
+
+ }
+
+ public void clear() {
+ theContents = null;
+ theContents = new String();
+ theList.setText(theContents);
+ }
+
+ public void disableText(boolean d) {
+ // theText.setEnabled(!d);
+ }
+
+ public static void main(String[] args) {
+ JFrame f = new JFrame("Test Dialog");
+ f.setSize(300, 100);
+
+ f.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ System.exit(0);
+ }
+ });
+
+ f.setVisible(true);
+
+ pmLogDisplay d = new pmLogDisplay();
+ d.addText("A\nB\nC\nD\nE\nF\nG\nH\nI\nJ");
+ d.setVisible(true);
+ }
+
+
+ protected int returnValue = JOptionPane.CLOSED_OPTION;
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLogin.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLogin.java
new file mode 100644
index 0000000000..97f3dca8b8
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLogin.java
@@ -0,0 +1,423 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmLogin.java
+ * Login dialog
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JPanel;
+import javax.swing.*;
+import com.sun.admin.pm.server.*;
+
+
+
+/*
+ * a panel dialog which captures a username and password.
+ */
+
+public class pmLogin extends pmDialog {
+ private pmTop theTop = null;
+ private String theTag = null;
+ private JFrame theFrame = null;
+
+ protected pmButton okButton = null;
+ protected pmButton cancelButton = null;
+ protected pmButton helpButton = null;
+
+ public pmLogin(JFrame f, String title, String msg) {
+ this(f, title, msg, null, null);
+ }
+
+ public pmLogin(JFrame f, String title, String msg, pmTop t, String h) {
+
+ super(f, title, true); // modal
+
+ theTop = t;
+ theTag = h;
+ theFrame = f;
+
+ JLabel l;
+ JPanel p;
+
+ // initialize constraints
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.insets = new Insets(10, 10, 10, 10);
+ c.anchor = GridBagConstraints.EAST;
+
+ // top panel contains the desired message
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ l = new JLabel(msg, SwingConstants.CENTER);
+ p.add(l, c);
+ this.getContentPane().add(p, "North");
+
+ // NIS middle panel
+ // contains username and password
+ if (t.ns.getNameService().equals("nis")) {
+
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ l = new JLabel(pmUtility.getResource("Hostname:"),
+ SwingConstants.RIGHT);
+ p.add(l, c);
+
+ l = new JLabel(pmUtility.getResource("Username:"),
+ SwingConstants.RIGHT);
+ p.add(l, c);
+
+ l = new JLabel(pmUtility.getResource("Password:"),
+ SwingConstants.RIGHT);
+ p.add(l, c);
+
+ passwordField = new JPasswordField(12);
+ passwordField.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ okPressed();
+ }
+ });
+ l.setLabelFor(passwordField);
+ // for consistency, don't implement this until all are...
+ // l.setDisplayedMnemonic(
+ // pmUtility.getIntResource("Password.mnemonic"));
+
+ c.gridx = 1;
+ c.weightx = 1.0;
+
+ String nisMaster;
+ try {
+ nisMaster = theTop.host.getNisMaster();
+ } catch (Exception e) {
+ nisMaster = new String("Unknown");
+ Debug.warning("pmLogin: getNisMaster() returns exception: " + e);
+ }
+
+ c.anchor = GridBagConstraints.WEST;
+
+ l = new JLabel(nisMaster, SwingConstants.LEFT);
+ p.add(l, c);
+
+ l = new JLabel(("root"), SwingConstants.LEFT);
+ p.add(l, c);
+
+
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridy = GridBagConstraints.RELATIVE;
+
+ p.add(passwordField, c);
+ passwordField.setEchoChar('*');
+
+ this.getContentPane().add(p, "Center");
+
+ } else if (t.ns.getNameService().equals("ldap")) {
+
+ // middle panel contains LDAP server name, distinguished name,
+ // and password
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ // LDAP Server Name
+ l = new JLabel(pmUtility.getResource("LDAP.Server:"),
+ SwingConstants.RIGHT);
+ p.add(l, c);
+
+ serverField = new pmTextField(25);
+ serverField.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ okPressed();
+ }
+ });
+
+ String ldapMaster;
+ try {
+ ldapMaster = theTop.host.getLDAPMaster();
+ } catch (Exception e) {
+ ldapMaster = new String("");
+ Debug.warning(
+ "pmLdap: getLDAPMaster() returns exception: " + e);
+ }
+
+ serverField.setText(ldapMaster);
+ c.gridx = 1;
+ p.add(serverField, c);
+
+
+ // Distinguished Name
+ c.gridx = 0;
+ l = new JLabel(pmUtility.getResource("Distinguished.Name:"),
+ SwingConstants.RIGHT);
+ p.add(l, c);
+
+ dnField = new pmTextField(25);
+ dnField.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ okPressed();
+ }
+ });
+
+ String defaultDN;
+ try {
+ defaultDN = theTop.host.getDefaultAdminDN();
+ } catch (Exception e) {
+ defaultDN = new String("");
+ Debug.warning(
+ "pmLdap: getDefaultAdminDN() returns exception: " + e);
+ }
+
+ dnField.setText(defaultDN);
+ c.gridx = 1;
+ p.add(dnField, c);
+
+ // Password
+ c.gridx = 0;
+ l = new JLabel(pmUtility.getResource("Password:"),
+ SwingConstants.RIGHT);
+ p.add(l, c);
+
+ passwordField = new JPasswordField(12);
+ passwordField.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ okPressed();
+ }
+ });
+ l.setLabelFor(passwordField);
+ // for consistency, don't implement this until all are...
+ // l.setDisplayedMnemonic(
+ // pmUtility.getIntResource("Password.mnemonic"));
+
+ c.gridx = 1;
+ c.weightx = 1.0;
+
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.gridy = GridBagConstraints.RELATIVE;
+
+ p.add(passwordField, c);
+ passwordField.setEchoChar('*');
+
+ this.getContentPane().add(p, "Center");
+
+ }
+
+
+ // bottom panel contains buttons
+ c.gridx = 0;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+
+ JPanel thePanel = new JPanel();
+
+ okButton = new pmButton(
+ pmUtility.getResource("OK"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("OK.mnemonic"));
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ okPressed();
+ }
+ });
+ thePanel.add(okButton, c);
+
+ cancelButton = new pmButton(
+ pmUtility.getResource("Cancel"));
+ cancelButton.setMnemonic(
+ pmUtility.getIntResource("Cancel.mnemonic"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ cancelPressed();
+ }
+ });
+ thePanel.add(cancelButton, c);
+
+ if (theTag != null && theTop != null) {
+
+ helpButton = new pmButton(
+ pmUtility.getResource("Help"));
+ helpButton.setMnemonic(
+ pmUtility.getIntResource("Help.mnemonic"));
+ p.add(helpButton);
+ helpButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ helpPressed();
+ }
+ });
+ thePanel.add(helpButton, c);
+ }
+
+ this.getContentPane().add(thePanel, "South");
+
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ returnValue = JOptionPane.CLOSED_OPTION;
+ pmLogin.this.setVisible(false);
+ }
+ });
+
+ // handle Esc as cancel in any case
+ this.getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ cancelPressed();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ // lay out the dialog
+ this.pack();
+
+ // set focus and defaults after packing...
+ // this.getRootPane().setDefaultButton(okButton);
+ okButton.setAsDefaultButton();
+
+ passwordField.requestFocus();
+ }
+
+ public int getValue() {
+ return returnValue;
+ }
+
+ public void getLDAPServer() throws pmIncompleteFormException {
+ // LDAP Server name is required
+ String LDAPserver = null;
+ LDAPserver = serverField.getText();
+ if (LDAPserver.equals("")) {
+ serverField.requestFocus();
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("LDAP.server.name.required."));
+ }
+ }
+
+ public void getLDAPDN() throws pmIncompleteFormException {
+ // LDAP Distinguished name is required
+ String LDAPdn = null;
+ LDAPdn = dnField.getText();
+ if (LDAPdn.equals("")) {
+ dnField.requestFocus();
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("LDAP.Distinguished.name.required."));
+ }
+ }
+
+ public void getLDAPPassword() throws pmIncompleteFormException {
+
+ // LDAP password is required
+
+ String tmpp = new String(passwordField.getPassword());
+ String LDAPpass = new String(tmpp.trim());
+
+ if (LDAPpass.equals("")) {
+ passwordField.requestFocus();
+ throw new pmIncompleteFormException(
+ pmUtility.getResource("LDAP.Password.required."));
+ }
+ }
+
+ public void okPressed() {
+
+ // For LDAP, Check Server, Distinguished Name and Password
+ boolean complete = true;
+
+ if (theTop.ns.getNameService().equals("ldap")) {
+ complete = false;
+ try {
+ getLDAPServer();
+ getLDAPDN();
+ getLDAPPassword();
+ complete = true;
+ } catch (pmIncompleteFormException fe) {
+ pmMessageDialog m = new pmMessageDialog(
+ theFrame,
+ pmUtility.getResource("Error"),
+ fe.getMessage()); // "FormError"
+ m.setVisible(true);
+ }
+ }
+
+ if (complete) {
+ returnValue = JOptionPane.OK_OPTION;
+ pmLogin.this.setVisible(false);
+ }
+ }
+
+
+
+ public void cancelPressed() {
+ returnValue = JOptionPane.CANCEL_OPTION;
+ pmLogin.this.setVisible(false);
+ }
+
+
+ public void clearPressed() {
+
+ passwordField.setText("");
+ }
+
+ public void helpPressed() {
+ theTop.showHelpItem(theTag);
+ }
+
+ public static void main(String[] args) {
+ JFrame f = new JFrame("Password test");
+
+ f.setSize(300, 100);
+ f.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ });
+ f.setVisible(true);
+
+ while (true) {
+ pmLogin d = new pmLogin(f, "Test Login",
+ "NIS/LDAP Authentication.");
+ d.setVisible(true);
+
+
+ }
+ // System.exit(0);
+ }
+
+ public JPasswordField passwordField = null;
+ public pmTextField serverField = null;
+ public pmTextField dnField = null;
+
+ protected int returnValue = JOptionPane.CLOSED_OPTION;
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLoginFailedException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLoginFailedException.java
new file mode 100644
index 0000000000..2c769eeb37
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmLoginFailedException.java
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmLoginFailedException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmLoginFailedException extends pmGuiException {
+ public pmLoginFailedException(String s) {
+ super(s);
+ }
+ public pmLoginFailedException() {
+ super();
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmMessageDialog.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmMessageDialog.java
new file mode 100644
index 0000000000..8f46a3f3e8
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmMessageDialog.java
@@ -0,0 +1,206 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmMessageDialog.java
+ * Common info message dialog
+ */
+
+package com.sun.admin.pm.client;
+
+import javax.swing.*;
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import com.sun.admin.pm.server.*;
+
+public class pmMessageDialog extends pmDialog {
+
+ pmButton helpButton = null;
+ pmButton okButton = null;
+ JList theText = null;
+ pmTop theTop = null;
+ String helpTag = null;
+
+
+ public pmMessageDialog(String title, String msg) {
+ this(null, title, msg, null, null);
+ }
+
+ public pmMessageDialog(Frame f, String title, String msg) {
+ this(f, title, msg, null, null);
+ }
+
+ public pmMessageDialog(Frame f,
+ String title,
+ String msg,
+ pmTop top,
+ String h) {
+
+ super(f, title, true); // modal
+
+ theTop = top;
+ helpTag = h;
+
+ // initialize constraints
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.insets = new Insets(10, 10, 10, 10);
+ c.anchor = GridBagConstraints.EAST;
+
+ // top panel
+ JPanel p = new JPanel();
+ p.setLayout(new GridBagLayout());
+ // p.setLayout(new BoxLayout(BoxLayout.X_AXIS));
+
+ // JLabel label = new JLabel(msg, SwingConstants.CENTER);
+ JList theText = new JList() {
+ public boolean isFocusable() {
+ return false;
+ }
+ };
+
+ Vector v = new Vector();
+
+ Debug.message("CLNT: MessageDialog: " + title + " , " + msg);
+
+ if (msg != null) {
+ StringTokenizer st = new StringTokenizer(msg, "\n", false);
+ try {
+ while (st.hasMoreTokens())
+ v.addElement(st.nextToken());
+ } catch (Exception x) {
+ Debug.warning("CLNT: pmMessageDialog caught " + x);
+ }
+ theText.setListData(v);
+ }
+
+ theText.setBackground(p.getBackground());
+
+ // p.add(theText, "Center");
+ p.add(theText, c);
+
+ this.getContentPane().add(p, "Center");
+
+ okButton = new pmButton(
+ pmUtility.getResource("Dismiss"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("Dismiss.mnemonic"));
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ actionOKButton();
+ }
+ });
+
+ // handle Esc as dismiss in any case
+ this.getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ actionOKButton();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ p = new JPanel();
+ p.add(okButton);
+
+ if (theTop != null && helpTag != null) {
+ helpButton = new pmButton(
+ pmUtility.getResource("Help"));
+ helpButton.setMnemonic(
+ pmUtility.getIntResource("Help.mnemonic"));
+ p.add(helpButton);
+ helpButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ theTop.showHelpItem(helpTag);
+ }
+ });
+ }
+
+ this.getContentPane().add(p, "South");
+ this.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ actionOKButton();
+ }
+ });
+
+ this.pack();
+
+ // this.getRootPane().setDefaultButton(okButton);
+ okButton.setAsDefaultButton();
+
+ // okButton.requestFocus();
+ okButton.grabFocus();
+
+ }
+
+
+ protected void actionOKButton() {
+ returnValue = JOptionPane.OK_OPTION;
+ pmMessageDialog.this.setVisible(false);
+ }
+
+
+ public int getValue() {
+ return returnValue;
+ }
+
+
+ public static void main(String[] args) {
+ JFrame f = new JFrame("Test Dialog");
+ f.setSize(300, 100);
+
+ f.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ System.exit(0);
+ }
+ });
+
+ f.setVisible(true);
+
+ while (true) {
+ System.out.println("creating a new dialog instance...");
+ pmMessageDialog d =
+ new pmMessageDialog(null,
+ "Dialog Test",
+ "Dumb test message.",
+ null,
+ null);
+ d.setVisible(true);
+ System.out.println("Dialog returns " + d.getValue());
+
+ d.dispose();
+
+ }
+
+ }
+
+
+ protected int returnValue = JOptionPane.CLOSED_OPTION;
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmModifyPrinterFailedException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmModifyPrinterFailedException.java
new file mode 100644
index 0000000000..007c10e77d
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmModifyPrinterFailedException.java
@@ -0,0 +1,40 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmModifyPrinterFailedException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmModifyPrinterFailedException extends pmGuiException {
+ public pmModifyPrinterFailedException(String s) {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmMustBeRemoteServerException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmMustBeRemoteServerException.java
new file mode 100644
index 0000000000..670e3df4b8
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmMustBeRemoteServerException.java
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmDeleteFailedException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmMustBeRemoteServerException extends pmGuiException {
+ public pmMustBeRemoteServerException(String s) {
+ super(s);
+ }
+ public pmMustBeRemoteServerException() {
+ super();
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmNeedPPDCacheException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmNeedPPDCacheException.java
new file mode 100644
index 0000000000..2f2265070a
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmNeedPPDCacheException.java
@@ -0,0 +1,44 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmInstallPrinter.java
+ * Install and Modify Printer implementation
+ *
+ * pmNeedPPDCache.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+public class pmNeedPPDCacheException extends pmGuiException {
+ public pmNeedPPDCacheException(String s) {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmNullSelectedPrinterException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmNullSelectedPrinterException.java
new file mode 100644
index 0000000000..943e5cdeb7
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmNullSelectedPrinterException.java
@@ -0,0 +1,39 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmNullSelectedPrinterException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmNullSelectedPrinterException extends pmGuiException {
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmOKCancelDialog.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmOKCancelDialog.java
new file mode 100644
index 0000000000..4bffb3733a
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmOKCancelDialog.java
@@ -0,0 +1,242 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmOKCancelDialog.java
+ * Common dialog
+ */
+
+package com.sun.admin.pm.client;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import com.sun.admin.pm.server.Debug;
+
+
+public class pmOKCancelDialog extends pmDialog {
+ private pmTop theTop;
+ private String theTag;
+ protected boolean defaultIsOK = true;
+
+ public pmOKCancelDialog(Frame f, String title, String msg) {
+ this(f, title, msg, null, null, true);
+ }
+
+ public pmOKCancelDialog(Frame f, String title, String msg, boolean ok) {
+ this(f, title, msg, null, null, ok);
+ }
+
+ public pmOKCancelDialog(Frame f, String title, String msg,
+ pmTop t, String h) {
+ this(f, title, msg, t, h, true);
+ }
+
+ public pmOKCancelDialog(Frame f, String title, String msg,
+ pmTop t, String h, boolean ok) {
+ super(f, title, true); // modal
+
+ theTop = t;
+ theTag = h;
+ defaultIsOK = ok;
+
+ // initialize constraints
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.insets = new Insets(10, 10, 10, 10);
+ c.anchor = GridBagConstraints.EAST;
+
+ // top panel
+ JPanel p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ JLabel label = new JLabel(msg, SwingConstants.CENTER);
+ p.add(label, c);
+
+ this.getContentPane().add(p, "Center");
+
+ this.getContentPane().add(
+ buttonPanel(defaultIsOK, theTop != null && theTag != null),
+ "South");
+
+ this.pack();
+
+ this.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ returnValue = JOptionPane.CLOSED_OPTION;
+ pmOKCancelDialog.this.setVisible(false);
+ }
+ });
+
+ if (defaultIsOK) {
+ // this.getRootPane().setDefaultButton(okButton);
+ okButton.setAsDefaultButton();
+ okButton.requestFocus();
+ } else {
+ // this.getRootPane().setDefaultButton(cancelButton);
+ cancelButton.setAsDefaultButton();
+ cancelButton.requestFocus();
+ }
+
+ // handle Esc as cancel in any case
+ this.getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ actionCancelButton();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+ }
+
+ public JPanel buttonPanel(boolean okDefault, boolean useHelp) {
+ JPanel panel = new JPanel();
+
+ panel.setLayout(new GridBagLayout());
+ GridBagConstraints c = new GridBagConstraints();
+
+ c.gridheight = 1;
+ c.gridwidth = 1;
+ c.weightx = c.weighty = 0.0;
+ c.anchor = GridBagConstraints.CENTER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.gridy = 0;
+
+
+ if (okDefault)
+ c.gridx = 0;
+ else
+ c.gridx = 1;
+
+ okButton = new pmButton(
+ pmUtility.getResource("OK"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("OK.mnemonic"));
+
+ if (okDefault)
+ c.gridx = 1;
+ else
+ c.gridx = 0;
+
+ cancelButton = new pmButton(
+ pmUtility.getResource("Cancel"));
+ cancelButton.setMnemonic(
+ pmUtility.getIntResource("Cancel.mnemonic"));
+
+ helpButton = null;
+
+ if (useHelp) {
+ c.gridx = 2;
+ helpButton = new pmButton(
+ pmUtility.getResource("Help"));
+ helpButton.setMnemonic(
+ pmUtility.getIntResource("Help.mnemonic"));
+ }
+
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ actionOKButton();
+ }
+ });
+
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ actionCancelButton();
+ }
+ });
+
+ if (helpButton != null) {
+ helpButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ theTop.showHelpItem(theTag);
+ }
+ });
+ }
+
+ c.insets = new Insets(15, 15, 15, 15);
+ c.gridx = 0;
+ panel.add(okButton, c);
+ c.gridx = 1;
+ panel.add(cancelButton, c);
+ c.gridx = 2;
+ if (helpButton != null)
+ panel.add(helpButton, c);
+
+ return panel;
+ }
+
+ protected void actionOKButton() {
+ returnValue = JOptionPane.OK_OPTION;
+ pmOKCancelDialog.this.setVisible(false);
+ }
+
+ protected void actionCancelButton() {
+ returnValue = JOptionPane.CANCEL_OPTION;
+ pmOKCancelDialog.this.setVisible(false);
+ }
+
+
+
+ public int getValue() {
+ return returnValue;
+ }
+
+
+ public static void main(String[] args) {
+ JFrame f = new JFrame("Test Dialog");
+ f.setSize(300, 100);
+
+ f.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ System.exit(0);
+ }
+ });
+
+ f.setVisible(true);
+
+ while (true) {
+ System.out.println("creating a new dialog instance...");
+ pmOKCancelDialog d =
+ new pmOKCancelDialog(
+ null, "Dialog Test", "Some message.", false);
+ d.setVisible(true);
+ System.out.println("Dialog returns " + d.getValue());
+
+ d.dispose();
+
+ }
+
+ }
+
+
+ pmButton helpButton = null;
+ pmButton okButton = null;
+ pmButton cancelButton = null;
+
+ protected int returnValue = JOptionPane.CLOSED_OPTION;
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmOther.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmOther.java
new file mode 100644
index 0000000000..230e398a04
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmOther.java
@@ -0,0 +1,232 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmOther.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.JPanel;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+/*
+ * panel dialog which captures "other"
+ */
+
+public class pmOther extends pmDialog {
+
+ private pmTop theTop;
+ private String theTag;
+ pmButton okButton = null;
+ pmButton cancelButton = null;
+ pmButton helpButton = null;
+
+ public pmOther(JFrame f, String title, String msg) {
+ this(f, title, msg, null, null);
+ }
+
+ public pmOther(JFrame f, String title, String msg, pmTop t, String h) {
+
+ super(f, title, true); // modal
+
+ theTop = t;
+ theTag = h;
+
+ JLabel l;
+ pmButton b;
+ JPanel p;
+
+ Debug.message("CLNT:pmOther()");
+
+ // initialize constraints
+ GridBagConstraints c = new GridBagConstraints();
+ c.gridx = 0;
+ c.gridy = GridBagConstraints.RELATIVE;
+ c.gridwidth = 1;
+ c.gridheight = 1;
+ c.insets = new Insets(10, 10, 5, 10);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.weightx = 1.0;
+
+ // top panel contains the message
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ l = new JLabel(msg, SwingConstants.LEFT);
+ p.add(l, c);
+ this.getContentPane().add(p, "North");
+
+ c.insets = new Insets(5, 10, 5, 10);
+
+ // middle panel contains "other" text field
+ p = new JPanel();
+ p.setLayout(new GridBagLayout());
+
+ deviceName.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ okPressed();
+ }
+ });
+
+ l.setLabelFor(deviceName);
+
+ c.gridx = 1;
+ c.gridy = 0;
+ c.weightx = 1.0;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+
+ p.add(deviceName, c);
+
+ c.gridy = GridBagConstraints.RELATIVE;
+
+ this.getContentPane().add(p, "Center");
+
+ // bottom panel contains buttons
+ c.gridx = 0;
+ c.weightx = 1.0;
+ c.weighty = 0.0;
+ c.gridwidth = GridBagConstraints.REMAINDER;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = new Insets(5, 10, 10, 10);
+
+ JPanel thePanel = new JPanel();
+ okButton = new pmButton(
+ pmUtility.getResource("OK"));
+ okButton.setMnemonic(
+ pmUtility.getIntResource("OK.mnemonic"));
+ thePanel.add(okButton, c);
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ okPressed();
+ }
+ });
+
+ cancelButton = new pmButton(
+ pmUtility.getResource("Cancel"));
+ cancelButton.setMnemonic(
+ pmUtility.getIntResource("Cancel.mnemonic"));
+ thePanel.add(cancelButton, c);
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ cancelPressed();
+ }
+ });
+
+ if (theTop != null && theTag != null) {
+ helpButton = new pmButton(
+ pmUtility.getResource("Help"));
+ helpButton.setMnemonic(
+ pmUtility.getIntResource("Help.mnemonic"));
+ thePanel.add(helpButton, c);
+ helpButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent evt) {
+ theTop.showHelpItem(theTag);
+ }
+ });
+ }
+
+
+ this.getContentPane().add(thePanel, "South");
+
+ // lay out the dialog
+ this.pack();
+
+ this.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent evt) {
+ returnValue = JOptionPane.CLOSED_OPTION;
+ pmOther.this.setVisible(false);
+ }
+ });
+
+ // this.getRootPane().setDefaultButton(okButton);
+ okButton.setAsDefaultButton();
+
+ // handle Esc as cancel in any case
+ this.getRootPane().registerKeyboardAction(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: default cancel action");
+ cancelPressed();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+ deviceName.requestFocus();
+
+ }
+
+ public int getValue() {
+ return returnValue;
+ }
+
+
+ public void okPressed() {
+ Debug.message("CLNT:pmOther: " + deviceName.getText());
+ returnValue = JOptionPane.OK_OPTION;
+ pmOther.this.setVisible(false);
+ }
+
+ public void cancelPressed() {
+ Debug.message("CLNT:pmOther: cancelPressed");
+ pmOther.this.dispose();
+ }
+
+
+ public static void main(String[] args) {
+ JFrame f = new JFrame("Other test");
+
+ f.setSize(300, 100);
+ f.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ });
+ f.setVisible(true);
+
+ while (true) {
+ pmOther d = new pmOther(f, "Test pmOther", "Enter Printer Port");
+ d.setVisible(true);
+
+ Debug.message("CLNT:pmOther: Dialog login returns " + d.getValue());
+
+ }
+ // System.exit(0);
+ }
+
+
+ public pmTextField deviceName = new pmTextField(30);
+ protected int returnValue = JOptionPane.CLOSED_OPTION;
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmPrinterExistsException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmPrinterExistsException.java
new file mode 100644
index 0000000000..1912ab5f52
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmPrinterExistsException.java
@@ -0,0 +1,39 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmPrinterExistsException.java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmPrinterExistsException extends pmGuiException {
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmResources.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmResources.java
new file mode 100644
index 0000000000..5a5a8ec932
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmResources.java
@@ -0,0 +1,614 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * pmResources.java
+ * Localizable resource strings
+ */
+
+package com.sun.admin.pm.client;
+
+import java.util.*;
+
+/*
+ * In accordance with the ResourceBundle pattern,
+ * each line in this file defines a tuple containing
+ * two strings:
+ * string 1 is the key used by the app -- DO NOT LOCALIZE
+ * string 2 is the string to be localized
+ *
+ * For example, in the tuple
+ * {"info_name", "Oracle Solaris Print Manager"}
+ *
+ * "info_name" is the resource key that must
+ * not be modified in any way
+ *
+ * "Oracle Solaris Print Manager" is the corresponding
+ * text to be localized
+ */
+
+public class pmResources extends ListResourceBundle {
+ static final Object[][] pmBundlecontents = {
+
+ /*
+ * Descriptive strings used in the 'About' dialog
+ */
+ {"info_name", "Oracle Solaris Print Manager"},
+ {"info_version", "Version 1.0"},
+ {"info_authors", "Authors: Wendy Phillips"},
+
+ // Note: the copyright notice is displayed on two lines.
+ {"info_copyright1", "Copyright \251 "},
+ /* JSTYLED */
+ {"info_copyright2", " (c) Oracle and/or its affiliates. All rights reserved."},
+
+ /*
+ * Main window title, the application name
+ */
+ {"Solaris.Print.Manager", "Oracle Solaris Print Manager"},
+
+
+ /*
+ * Main window column labels for printer list
+ */
+ {"Printer.Name", "Printer Name"},
+ {"Printer.Server", "Printer Server"},
+ {"Description", "Description"},
+
+
+ /*
+ * Main window menu titles and mnemonics
+ */
+ {"Print.Manager", "Print Manager"},
+ {"Print.Manager.mnemonic", "M"},
+
+ {"Printer", "Printer" },
+ {"Printer.mnemonic", "P"},
+
+ {"Tools", "Tools" },
+ {"Tools.mnemonic", "T"},
+
+ {"Help", "Help"},
+ {"Help.mnemonic", "H"},
+
+
+ /*
+ * Main window data labels
+ */
+ {"Default.Printer:", "Default Printer:"},
+ {"Domain:", "Domain:"},
+ {"Host:", "Host:"},
+
+
+ /*
+ * 'Printer Manager' menu item labels and mnemonics
+ */
+ {"Select.Naming.Service", "Select Naming Service..."},
+ {"Select.Naming.Service.mnemonic", "N"},
+
+ {"Show.Command-Line.Console", "Show Command-Line Console"},
+ {"Show.Command-Line.Console.mnemonic", "L"},
+
+ {"Confirm.All.Actions", "Confirm All Actions"},
+ {"Confirm.All.Actions.mnemonic", "C"},
+
+ {"Use.PPD.files", "Use PPD files"},
+ {"Use.PPD.files.mnemonic", "F"},
+
+ {"Use.localhost", "Use localhost for Printer Server"},
+ {"Use.localhost.mnemonic", "U"},
+
+ {"Exit", "Exit"},
+ {"Exit.mnemonic", "X"},
+
+ /*
+ * 'Printer' menu item labels and mnemonics
+ */
+ {"Add.Access.to.Printer...", "Add Access to Printer..."},
+ {"Add.Access.to.Printer.mnemonic", "A"},
+
+ {"New.Attached.Printer...", "New Attached Printer..."},
+ {"New.Attached.Printer.mnemonic", "T"},
+
+ {"New.Network.Printer...", "New Network Printer..."},
+ {"New.Network.Printer.mnemonic", "N"},
+
+ {"Modify.Printer.Properties...", "Modify Printer Properties..."},
+ {"Modify.Printer.Properties.mnemonic", "M"},
+
+ {"Delete.Printer...", "Delete Printer..."},
+ {"Delete.Printer.mnemonic", "D"},
+
+
+ /*
+ * 'Tools' menu item labels
+ */
+ {"Find.Printer", "Find Printer..."},
+ {"Find.Printer.mnemonic", "F"},
+
+
+ /*
+ * 'Help' menu item labels
+ */
+ {"Overview", "Overview"},
+ {"Overview.mnemonic", "O"},
+
+ {"On.Help", "On Help"},
+ {"On.Help.mnemonic", "H"},
+
+ {"About.Print.Manager", "About Print Manager..."},
+ {"About.Print.Manager.mnemonic", "A"},
+
+ {"Print.Manager.Settings", "Print Manager Settings"},
+ {"Print.Manager.Settings.mnemonic", "P"},
+
+
+ /*
+ * 'Select Naming Service' dialog title
+ */
+ {"SPM:Select.Naming.Service",
+ "Oracle Solaris Print Manager: Select Naming Service"},
+
+
+ /*
+ * 'Command-Line Console' dialog title
+ */
+ {"SPM:Command-Line.Console",
+ "Oracle Solaris Print Manager: Command-Line Console"},
+
+
+ /*
+ * 'Delete Printer' confirmation dialog title
+ */
+ {"SPM:Delete.Printer", "Oracle Solaris Print Manager: Delete Printer"},
+
+
+ /*
+ * 'Add Access to Printer' dialog title
+ */
+ {"SPM:Add.Access.To.Printer",
+ "Oracle Solaris Print Manager: Add Access to Printer"},
+
+
+ /*
+ * 'Add Attached Printer' dialog title
+ */
+ {"SPM:New.Attached.Printer",
+ "Oracle Solaris Print Manager: New Attached Printer"},
+
+
+ /*
+ * 'Add Network Printer' dialog title
+ */
+ {"SPM:New.Network.Printer",
+ "Oracle Solaris Print Manager: New Network Printer"},
+
+
+ /*
+ * 'Modify Printer Properties' dialog title
+ */
+ {"SPM:Modify.Printer.Properties",
+ "Oracle Solaris Print Manager: Modify Printer Properties"},
+
+
+ /*
+ * 'Find Printer' dialog title
+ */
+ {"SPM:Find.Printer", "Oracle Solaris Print Manager: Find Printer"},
+
+
+ /*
+ * 'Help' dialog title
+ */
+ {"SPM:Help", "Oracle Solaris Print Manager: Help"},
+
+
+ /*
+ * 'About Print Manager' dialog title
+ */
+ {"About.Solaris.Print.Manager", "About Oracle Solaris Print Manager"},
+
+
+ /*
+ * 'User Input of Printer Port' dialog title
+ */
+ {"SPM:Specify.Printer.Port",
+ "Oracle Solaris Print Manager: Specify Printer Port"},
+
+
+ /*
+ * 'User Input of Printer Type' dialog title
+ */
+ {"SPM:Specify.Printer.Type",
+ "Oracle Solaris Print Manager: Specify Printer Type"},
+
+
+ /*
+ * 'NIS Authentication' dialog title
+ */
+ {"NIS.Authentication", "NIS Authentication"},
+
+ /*
+ * 'LDAP Authentication' dialog title
+ */
+ {"LDAP.Authentication", "LDAP Authentication"},
+
+
+ /*
+ * 'Action Confirmation' dialog title
+ */
+ {"Action.Confirmation", "Action Confirmation"},
+
+
+ /*
+ * Button labels and mnemonics
+ */
+ {"Apply", "Apply"},
+ {"Apply.mnemonic", "P"},
+
+ {"Cancel", "Cancel"},
+ {"Cancel.mnemonic", "C"},
+
+ {"Clear", "Clear"},
+ {"Clear.mnemonic", "L"},
+
+ {"Dismiss", "Dismiss"},
+ {"Dismiss.mnemonic", "D"},
+
+ // {"Button Help", "Help"},
+ // {"Button.Help.mnemonic", "H"},
+
+ {"OK", "OK"},
+ {"OK.mnemonic", "O"},
+
+ {"Reset", "Reset"},
+ {"Reset.mnemonic", "R"},
+
+ {"Find", "Find"},
+ {"Find.mnemonic", "F"},
+
+ {"Show", "Show"},
+ {"Show.mnemonic", "S"},
+
+ {"Forward", "Forward"},
+ {"Forward.mnemonic", "W"},
+
+ {"Back", "Back"},
+ {"Back.mnemonic", "B"},
+
+ {"Add", "Add"},
+ {"Add.mnemonic", "A"},
+
+ {"Delete", "Delete"},
+ {"Delete.mnemonic", "D"},
+
+
+ /*
+ * Actions performed by the application
+ * as displayed in the Command-Line Console
+ */
+ {"New.Attached.Printer", "New Attached Printer"},
+ {"New.Network.Printer", "New Network Printer"},
+ {"Modify.Printer.Properties", "Modify Printer Properties"},
+ {"Delete.Printer", "Delete Printer"},
+ {"Add.Access.To.Printer", "Add Access To Printer"},
+
+
+ /*
+ * Prompts: messages to user describing required input.
+ */
+ {"Enter.name.of.printer.to.find",
+ "Enter the name of a printer to find:"},
+ {"Please.confirm.deletion.of.printer",
+ "Please confirm deletion of printer "},
+ {"Enter.printer.type:", "Enter printer type:"},
+ {"Enter.printer.port.or.file", "Enter printer port or file:"},
+
+
+ /*
+ * 'Help' dialog tabbed-pane tab selection labels
+ */
+ {"View", "View"},
+ {"Index", "Index"},
+ {"Search", "Search"},
+
+
+ /*
+ * 'Help' dialog prompts, labels, and mnemonics
+ */
+ {"Help.on:", "Help on:"},
+ {"See.also:", "See also:"},
+
+ {"Matching.entries:", "Matching entries:"},
+ {"Matching.entries:.mnemonic", "M"},
+
+ {"Search.help.index.for:", "Search help index for: "},
+ {"Search.help.index.for:.mnemonic", "S"},
+
+ {"Search.Results:", "Search Results:"},
+ {"Search.Results:.mnemonic", "R"},
+
+ {"Keywords:", "Keywords: "},
+ {"Keywords:.mnemonic", "K"},
+
+
+ /*
+ * 'Help' dialog descriptive messages to provide
+ * assistance in using the features.
+ */
+
+ /*
+ * The following two labels create one message, displayed on
+ * two adjacent lines.
+ */
+ {"To.search.the.index...",
+ "To search the index of help articles alphabetically,"},
+ {"type.your.query.below...",
+ "type your query below then select the desired article."},
+
+ /*
+ * The following two labels create one message, displayed on
+ * two adjacent lines.
+ */
+ {"To.find.help.articles...",
+ "To find help articles about a particular topic,"},
+ {"enter.keywords.below...",
+ "enter keywords below then press the Find button."},
+
+
+ /*
+ * Prompts/labels on 'Install Printer' and 'Modify Printer' dialogs
+ */
+ {"Printer.Name:", "Printer Name:"},
+ {"Printer.Server:", "Printer Server:"},
+ {"Description:", "Description:"},
+ {"Printer.Port:", "Printer Port:"},
+ {"Not.Selected", "Not Selected"},
+ {"Printer.Type:", "Printer Type:"},
+ {"Printer.Driver:", "Printer Driver:"},
+ {"No.PPD.Files.Found", "No PPD files found"},
+ {"Printer.Make:", "Printer Make:"},
+ {"Printer.Model:", "Printer Model:"},
+ {"No.Models.Found", "No Models Found"},
+ {"File.Contents:", "File Contents:"},
+ {"Fault.Notification:", "Fault Notification:"},
+ {"Destination:", "Destination:"},
+ {"Protocol:", "Protocol:"},
+ {"Options:", "Options:"},
+ {"Banner:", "Banner:"},
+ {"Options.mnemonic", "O"},
+ {"Option:", "Option:"},
+ {"User.Access.List:", "User Access List:"},
+
+
+ /*
+ * Combo item allowing custom 'Printer Port' selection
+ * See "Printer.Port:" above.
+ */
+ {"Other...", "Other..."},
+
+
+ /*
+ * Combo items specifying printer 'File Contents'
+ * See "File.Contents" above.
+ */
+ {"PostScript", "PostScript"},
+ {"ASCII", "ASCII"},
+ {"None", "None"},
+ {"Any", "Any"},
+ {"Both.PostScript.and.ASCII", "Both PostScript and ASCII"},
+
+
+ /*
+ * Combo items specifying 'Fault Notification' options.
+ * See "Fault.Notification" above.
+ */
+ {"Write.to.Superuser", "Write to Superuser"},
+ {"Mail.to.Superuser", "Mail to Superuser"},
+
+
+ /*
+ * Labels for checkboxes used in 'Install Printer' and
+ * 'Modify Printer' dialogs
+ */
+ {"Default.Printer", "Default Printer"},
+ {"Always.Print.Banner", "Always Print Banner"},
+ {"User.Selectable.Default.On", "User Selectable - Default=on"},
+ {"Never.Print.Banner", "Never Print Banner"},
+
+
+ /*
+ * Prompt for 'Select Naming Service' combo
+ */
+ {"Naming.Service:", "Naming Service:"},
+
+
+ /*
+ * Descriptive label for 'NIS Authentication' dialog
+ */
+ {"Enter.NIS.authentication.data.", "Enter NIS authentication data."},
+
+ /*
+ * Descriptive label for 'LDAP Authentication' dialog
+ */
+ {"Enter.LDAP.authentication.data.", "Enter LDAP authentication data."},
+
+
+ /*
+ * Prompts and mnemonics for 'NIS Authentication' dialog
+ */
+ {"Hostname:", "Hostname:"},
+ {"Hostname.mnemonic", "H"},
+
+ {"Username:", "Username:"},
+ {"Username.mnemonic", "U"},
+
+ {"Password:", "Password:"},
+ {"Password.mnemonic", "P"},
+
+ /*
+ * Prompts for 'LDAP Authentication' dialog
+ */
+ {"LDAP.Server:", "LDAP Server:"},
+ {"Distinguished.Name:", "Distinguished Name:"},
+ {"Password:", "Password:"},
+
+
+ /*
+ * Error dialog titles
+ */
+ {"Application.Error", "Application Error"},
+ {"Unknown.Application.Error", "Unknown Application Error"},
+ {"Command.Failed.Error", "Command Failed Error"},
+ {"Error", "Error"},
+ {"Warning", "Warning"},
+
+
+ /*
+ * Error messages displayed to user
+ */
+ {"Item.not.found:", "Item not found: "},
+ {"No.information.available.", "No information available."},
+ {"Unable.to.find.printer", "Unable to find printer "},
+ {"Printer.delete.operation.failed.",
+ "Printer delete operation failed."},
+ {"Invalid.printer.type.", "Invalid printer type."},
+ {"Device.missing.or.not.writeable.",
+ "Device missing or not writeable."},
+ {"Printer.name.required.", "Printer name required."},
+ {"Printer.Port.Selection.required", "Printer Port Selection required."},
+ {"Printer.Make.Selection.required", "Printer Make Selection required."},
+ {"Printer.name.invalid.", "Printer name invalid."},
+ {"Server.name.required.", "Server name required."},
+ {"Server.name.invalid.", "Server name invalid."},
+ {"User.Cancelled.Login", "User Cancelled Login"},
+ {"Destination.required.", "Destination required."},
+ {"User.Cancelled.Login", "User Cancelled Login"},
+ {"Destination.invalid.", "Destination invalid."},
+ {"Operation.Cancelled", "Operation Cancelled"},
+ {"Login.Failure", "Login Failure"},
+ {"Required.login.failed.", "Required login failed."},
+ {"Login.Authorization.Failed", "Login Authorization Failed"},
+ {"Cannot.modify.this.queue;ppdcache.file.missing.",
+ "Cannot modify this queue; ppdcache file missing."},
+ {"Cannot.modify.this.queue;PPD.file.not.in.ppdcache.",
+ "Cannot modify this queue; PPD file not in ppdcache."},
+ {"Request.cannot.be.completed.", "Request cannot be completed."},
+ {"Could.not.get.local.hostname", "Could not get local hostname"},
+ {"The.specified.printer.already.exists.",
+ "The specified printer already exists."},
+ {"The.server.must.be.a.remote.server.",
+ "The server must be a remote server."},
+ {"Required.login.failed.", "Required login failed."},
+ {"Invalid.printer.type.", "Invalid printer type."},
+ {"Invalid.username", "Invalid username"},
+ {"Device.missing.or.not.writeable.",
+ "Device missing or not writeable."},
+ {"User.cancelled.login.", "User cancelled login."},
+ {"Nothing.matched.", "Nothing matched."},
+ {"The.specified.printer.already.exists.",
+ "The specified printer already exists."},
+ {"The.selected.printer.does.not.exist.",
+ "The selected printer does not exist."},
+ {"User.not.authorized.to.modify.this.namespace.",
+ "User not authorized to modify this namespace."},
+ {"Cannot.get.list.of.printers.Exiting.",
+ "Cannot get list of printers. Exiting."},
+ {"LDAP.server.name.required.",
+ "LDAP Server Name required."},
+ {"LDAP.Distinguished.name.required.",
+ "LDAP Distinguished Name required."},
+ {"LDAP.Password.required.",
+ "LDAP Password required."},
+
+
+ /*
+ * Prompts for 'Confirm Action' dialogs
+ */
+ {"Continue.action.for.this.printer?",
+ "Continue action for this printer?"},
+ {"Continue.creating.access.for.this.printer?",
+ "Continue creating access for this printer?"},
+
+
+ /*
+ * The help subsystem builds a database of searchable
+ * keywords based in part on the title of each help
+ * article. In order to avoid excessive false hits, the
+ * following words are ignored when adding title words
+ * to the searchable keyword list.
+ *
+ * If this list is left empty, all the words in the title of
+ * each help article will be added to the keywords database.
+ */
+ {"help.ignore.words", "to an a of if the and or"},
+
+
+
+ /*
+ * Title for the authorization dialog which is invoked by
+ * the printmgr executable.
+ */
+ {"Authentication.required", "Authentication Required"},
+
+ /*
+ * Prompt for the printmgr authorization dialog.
+ * This is displayed with line breaks.
+ */
+ /* JSTYLED */
+ {"Root.access.is.required", "Root access is required for full functionality.\nYou may authenticate as root or continue\nwith limited functionality."},
+
+ /*
+ * Buttons for the authorization dialog.
+ */
+ {"Authenticate", "Authenticate"},
+ {"Authenticate.mnemonic", "A"},
+
+ {"Continue", "Continue"},
+ {"Continue.mnemonic", "N"},
+
+ /*
+ * Title for the root password request dialog invoked by printmgr.
+ */
+ {"Root.authentication", "Root Authentication"},
+
+ /*
+ * Prompt for the root password request dialog.
+ */
+ {"Enter.root.password", "Enter root password"},
+
+ /*
+ * Prompt for the root password request dialog.
+ */
+ {"Invalid.password", "Invalid password entered. Retry?"},
+
+ /*
+ * Just a placeholder, never used.
+ */
+ {"dummy", ""}
+ };
+
+ public Object[][] getContents() {
+ return pmBundlecontents;
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmTextField.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmTextField.java
new file mode 100644
index 0000000000..a02778c907
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmTextField.java
@@ -0,0 +1,86 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmTextField.java
+ * Extension of JTextField which accepts only 8-bit-ASCII.
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.text.*;
+
+public class pmTextField extends JTextField {
+ public pmTextField(int n) {
+ this(null, n);
+ }
+
+ public pmTextField(String s) {
+ this(s, 0);
+ }
+
+ public pmTextField(String s, int n) {
+ super(s, n);
+ }
+
+ protected Document createDefaultModel() {
+ return new pmFilterDoc();
+ }
+
+ /*
+ * This doc implementation will disallow insertion of a
+ * string containing any characters which are non-8-bit-ascii.
+ */
+ private class pmFilterDoc extends PlainDocument {
+ public void insertString(int offset, String str, AttributeSet a)
+ throws BadLocationException {
+ int i, c;
+ char[] buf = str.toCharArray();
+
+ for (i = 0; i < buf.length; i++) {
+ c = (new Character(buf[i])).charValue();
+ if (c > 0x00ff)
+ break;
+ }
+ if (i == buf.length)
+ super.insertString(offset, str, a);
+ else
+ Toolkit.getDefaultToolkit().beep();
+ }
+ }
+
+ public static void main(String args[]) {
+ JFrame f = new JFrame();
+ f.getContentPane().add(new pmTextField(20));
+ f.pack();
+ f.setVisible(true);
+ f.repaint();
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmTop.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmTop.java
new file mode 100644
index 0000000000..76fe55af95
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmTop.java
@@ -0,0 +1,1303 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmTop.java
+ * Top level
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.Vector;
+import java.lang.*;
+import javax.swing.JPanel;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.text.*;
+import javax.swing.border.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+/*
+ * Top window for printer manager
+ */
+
+public class pmTop extends JPanel {
+
+ static private pmTop myTop = null;
+ static private pmHelpFrame helpFrame = null;
+ static private pmAboutBox aboutBox = null;
+ static private pmLogDisplay commandLog = null;
+ static private pmFindFrame findFrame = null;
+
+ JLabel nameserviceLabel = new JLabel();
+ JLabel domainhostLabel;
+ JLabel defaultpLabel;
+ String defaultPrinter;
+ JScrollPane scrollPane;
+ JTable listTable;
+ Host host = new Host();
+ private JPanel north = new JPanel();
+ JPanel center;
+ listTableModel listModel;
+ ListSelectionModel listSM;
+
+ JMenuBar menuBar;
+ JFrame parentFrame;
+ JCheckBoxMenuItem logCheck;
+ JCheckBoxMenuItem confirmCheck;
+ JCheckBoxMenuItem usePPD;
+ JCheckBoxMenuItem useLocalhost;
+ JMenuItem modifyMenuItem = null;
+ JMenuItem deleteMenuItem = null;
+
+ JMenuItem access;
+ JMenuItem local;
+ JMenuItem network;
+
+ int actionindex = 0;
+ private String newNS;
+ NameService ns = null;
+ NameService nisns = null;
+ NameService systemns = null;
+ NameService ldapns = null;
+
+ pmAccess accessView = null;
+ pmInstallPrinter localinstallView = null;
+ pmInstallPrinter networkinstallView = null;
+ pmDelete deleteView = null;
+ pmInstallPrinter modifyView = null;
+ pmLoad loadView = null;
+
+ String clickedPrinter;
+ String selectedPrinter = null;
+ String selprinterServer = null;
+ int selectedRow = -1;
+
+ String cmdLog = null;
+ String errorLog = null;
+ String warningLog = null;
+
+ boolean runningAuth = false;
+ boolean isRoot = false;
+
+ pmFrame frame;
+
+
+ public pmTop(JFrame parent) {
+ parentFrame = parent;
+ setLayout(new BorderLayout());
+ pmTopInit();
+
+ }
+
+ public void pmTopInit() {
+
+ try {
+ systemns = new NameService("system");
+ } catch (Exception e) {
+ Debug.message("CLNT: system:Nameservice exception " + e);
+ }
+ try {
+ nisns = new NameService("nis");
+ } catch (Exception e) {
+ Debug.message("CLNT: nis:Nameservice exception " + e);
+ }
+ try {
+ ldapns = new NameService("ldap");
+ } catch (Exception e) {
+ Debug.message("CLNT: ldap:Nameservice exception " + e);
+ }
+
+ ns = systemns;
+ newNS = "files";
+
+ // determine root privileges
+ try {
+ ns.checkAuth();
+ } catch (Exception ax) {
+ Debug.message("CLNT: checkAuth threw " + ax);
+ }
+
+ if (ns.isAuth()) {
+ runningAuth = true;
+ isRoot = true;
+ Debug.message("CLNT: Running as root");
+ } else
+ Debug.message("CLNT: Not running as root");
+
+ northPanel();
+ centerPanel();
+ southPanel();
+
+ }
+
+ // Set values so that printer selection null
+ public void clearSelected() {
+ selectedPrinter = null;
+ selprinterServer = null;
+ selectedRow = -1;
+ enableEditMenuItems(false);
+ }
+
+
+ // Create north panel with GridBagLayout
+ public void northPanel() {
+
+ menuBar = new JMenuBar();
+ menuBar.setBorder(new EmptyBorder(5, 5, 5, 5));
+ menuBar.add(appMenu());
+ menuBar.add(objectMenu());
+ menuBar.add(toolsMenu());
+ menuBar.add(Box.createHorizontalGlue());
+ menuBar.add(helpMenu());
+
+ parentFrame.setJMenuBar(menuBar);
+ }
+
+ public class listTableModel extends AbstractTableModel {
+ int numColumns;
+
+ String[] columnNames = {
+ pmUtility.getResource("Printer.Name"),
+ pmUtility.getResource("Printer.Server"),
+ pmUtility.getResource("Description")
+
+ };
+
+ // Initialize for JTable calls from SWING classes
+ Vector data = new Vector(0, 0);
+
+ public listTableModel() {
+ numColumns = getColumnCount();
+ }
+
+ public void insertlistTable(String rowDataList[], int numcols) {
+ Vector rowData = new Vector(3, 1);
+ data = new Vector(100, 5);
+ int j = 0;
+
+ if ((rowDataList.length) <= 1) {
+ return;
+ }
+
+ for (int i = 0; i < rowDataList.length; i = i + 3) {
+ rowData = new Vector(3, 1);
+ for (j = 0; j < 3; j++) {
+ rowData.addElement(
+ rowDataList[i + j]);
+ }
+ data.addElement(rowData);
+ }
+ }
+
+ public void removeRow(int row) {
+ data.removeElementAt(row);
+ }
+
+ public int getRowCount() {
+ return data.size();
+ }
+
+ public int getColumnCount() {
+ return columnNames.length;
+ }
+
+ public String getColumnName(int col) {
+ return columnNames[col];
+ }
+
+ public Object getValueAt(int row, int col) {
+ Vector rowVector = (Vector)data.elementAt(row);
+ return rowVector.elementAt(col);
+ }
+
+ public void setValueAt(String value, int row, int col) {
+ Vector rowVector = (Vector)data.elementAt(row);
+ rowVector.setElementAt(value, col);
+ }
+
+ public void addRow(Vector row) {
+ data.addElement(row);
+ }
+
+ public int findValue(String value) {
+ for (int i = 0; i < data.size(); i++) {
+ if (getValueAt(i, 0).equals(value))
+ return i;
+ }
+ return -1;
+ }
+
+ };
+
+
+ // called on enter or double-click
+ void modifySelectedPrinter() {
+
+ ListSelectionModel m = listTable.getSelectionModel();
+
+ if (m.isSelectionEmpty()) {
+ Debug.message("CLNT: list selection is empty");
+ return;
+ }
+
+ int selectedRow = m.getMinSelectionIndex();
+
+ Debug.message("CLNT: list row selected is " + selectedRow);
+
+ selectedPrinter =
+ (String) listTable.getModel().getValueAt(selectedRow, 0);
+ selprinterServer =
+ (String)listTable.getModel().getValueAt(selectedRow, 1);
+
+ Debug.message("CLNT: selectedPrinter is " + selectedPrinter);
+
+ doModify();
+ }
+
+
+ // Create printer list in center panel
+ public void centerPanel() {
+
+ center = new JPanel();
+
+ listModel = new listTableModel();
+ listTable = new JTable(listModel);
+ listTable.setColumnSelectionAllowed(false);
+ listTable.setRowSelectionAllowed(true);
+ listTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ listTable.setShowGrid(false);
+ listTable.registerKeyboardAction(new ActionListener() {
+
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: enter action");
+ if (runningAuth)
+ modifySelectedPrinter();
+ else
+ Toolkit.getDefaultToolkit().beep();
+ }},
+ KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false),
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+
+ listTable.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ Point pt = e.getPoint();
+ int rowIndex = listTable.rowAtPoint(pt);
+ int colIndex = listTable.columnAtPoint(pt);
+ int clickCount = e.getClickCount();
+
+ Debug.message("CLNT: getClickCount() is " + clickCount);
+
+ if (clickCount == 2) {
+ if (rowIndex == -1) {
+ Debug.message("CLNT: clicked outside table");
+ } else {
+ if (runningAuth)
+ modifySelectedPrinter();
+ else
+ Toolkit.getDefaultToolkit().beep();
+ }
+ }
+ }
+ });
+
+ // Add selection listener
+ ListSelectionModel rowSelectModel = listTable.getSelectionModel();
+
+ rowSelectModel.addListSelectionListener(new ListSelectionListener() {
+
+ public void valueChanged(ListSelectionEvent e) {
+
+ listSM = (ListSelectionModel)e.getSource();
+ Debug.message("CLNT: listSM is " + listSM);
+
+ if (listSM.isSelectionEmpty()) {
+ Debug.message("CLNT: list selection is empty");
+ enableEditMenuItems(false);
+ } else {
+ selectedRow = listSM.getMinSelectionIndex();
+ Debug.message(
+ "CLNT: list element selected" + selectedRow);
+ selectedPrinter =
+ (String)listTable.getModel().getValueAt(selectedRow, 0);
+ selprinterServer =
+ (String)listTable.getModel().getValueAt(selectedRow, 1);
+ Debug.message(
+ "CLNT: selectedPrinter is " + selectedPrinter);
+ enableEditMenuItems(true);
+ }
+ }
+ });
+
+ GridBagConstraints c = new GridBagConstraints();
+ center.setLayout(new BorderLayout());
+
+ c.insets = new Insets(35, 50, 35, 50);
+
+ try {
+ listModel.insertlistTable(PrinterUtil.getPrinterList(ns),
+ listModel.getColumnCount());
+ } catch (Exception e) {
+ Debug.fatal("CLNT: pmTop:getPrinterList() caught " + e);
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "Cannot.get.list.of.printers.Exiting."),
+ myTop,
+ "getPrinterListFailed");
+ m.setVisible(true);
+ System.exit(-1);
+ }
+
+ scrollPane = new JScrollPane();
+ scrollPane.setViewportView(listTable);
+
+ listTable.setPreferredScrollableViewportSize(
+ new Dimension(500, 500));
+ scrollPane.getViewport().setView(listTable);
+ center.add(scrollPane);
+ add("Center", center);
+ }
+
+ // Create south panel with grid layout
+
+ public void southPanel() {
+ JPanel south = new JPanel();
+ GridBagConstraints c = new GridBagConstraints();
+ south.setLayout(new GridBagLayout());
+
+ // Constraints applied across all entries
+ c.fill = GridBagConstraints.BOTH;
+ c.insets = new Insets(6, 6, 6, 6);
+ c.gridheight = 1;
+ c.gridwidth = 1;
+ c.gridy = 1;
+
+ // Create the labels
+ c.gridx = 0;
+ c.weightx = c.weighty = 1.0;
+
+ try {
+ defaultpLabel =
+ new JLabel(pmUtility.getResource("Default.Printer:") +
+ " " + PrinterUtil.getDefaultPrinter(ns));
+
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmTop:getDefaultPrinter() caught " + e);
+ defaultpLabel = new JLabel(
+ pmUtility.getResource("Default.Printer:"));
+ }
+
+ south.add(defaultpLabel, c);
+
+
+ if (newNS.startsWith("files")) {
+ try {
+ domainhostLabel = new JLabel(pmUtility.getResource(
+ "Host:") + " " + host.getLocalHostName());
+
+ nameserviceLabel.setText(" ");
+
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmTop:getLocalHostName caught " + e);
+ }
+
+ } else {
+ try {
+ nameserviceLabel.setText(
+ pmUtility.getResource("Naming.Service:") + " " + newNS);
+ domainhostLabel = new JLabel(
+ pmUtility.getResource("Domain:") + " " +
+ host.getDomainName());
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmTop:getDomainName caught " + e);
+ }
+ }
+
+ c.weightx = c.weighty = 1.0;
+ c.gridx = 2;
+ south.add(nameserviceLabel, c);
+ c.gridx = 3;
+ south.add(domainhostLabel, c);
+ add("South", south);
+ }
+
+
+ public JMenu appMenu() {
+ // name service
+ // ---
+ // cmd line console
+ // confirm all actions
+ // use ppd file
+ // ---
+ // exit
+
+ JMenu appMenu = new JMenu(pmUtility.getResource("Print.Manager"));
+ appMenu.setMnemonic(
+ pmUtility.getIntResource("Print.Manager.mnemonic"));
+
+ appMenu.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ Debug.message("CLNT: appMenu MouseListener");
+ };
+ });
+
+ JMenuItem load = new JMenuItem(
+ pmUtility.getResource("Select.Naming.Service"),
+ pmUtility.getIntResource("Select.Naming.Service.mnemonic"));
+
+ load.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from load action");
+ if (loadView != null)
+ loadView.setVisible(true);
+ else
+ loadView = new pmLoad(myTop);
+ loadView.Show();
+
+ };
+ });
+ load.setEnabled(true);
+ appMenu.add(load);
+
+ appMenu.addSeparator();
+
+ logCheck = new JCheckBoxMenuItem(
+ pmUtility.getResource("Show.Command-Line.Console"));
+ logCheck.setMnemonic(
+ pmUtility.getIntResource("Show.Command-Line.Console.mnemonic"));
+
+ logCheck.addActionListener(new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from checkbox action");
+ JCheckBoxMenuItem c = (JCheckBoxMenuItem) e.getSource();
+ if (c.isSelected() == true) {
+ commandLog.setVisible(true);
+ } else {
+ commandLog.setVisible(false);
+ }
+ }
+ });
+
+ if (!runningAuth)
+ logCheck.setEnabled(false);
+
+ appMenu.add(logCheck);
+
+ confirmCheck = new JCheckBoxMenuItem(
+ pmUtility.getResource("Confirm.All.Actions"), false);
+ confirmCheck.setMnemonic(
+ pmUtility.getIntResource("Confirm.All.Actions.mnemonic"));
+ if (!runningAuth)
+ confirmCheck.setEnabled(false);
+
+ appMenu.add(confirmCheck);
+
+ usePPD = new JCheckBoxMenuItem(
+ pmUtility.getResource("Use.PPD.files"), true);
+ usePPD.setMnemonic(pmUtility.getIntResource("Use.PPD.files.mnemonic"));
+
+ useLocalhost = new JCheckBoxMenuItem(
+ pmUtility.getResource("Use.localhost"), false);
+ useLocalhost.setMnemonic(
+ pmUtility.getIntResource("Use.localhost.mnemonic"));
+
+
+ if (!runningAuth) {
+ usePPD.setEnabled(false);
+ useLocalhost.setEnabled(false);
+ }
+ appMenu.add(usePPD);
+ appMenu.add(useLocalhost);
+
+ appMenu.addSeparator();
+
+ JMenuItem exit = new JMenuItem(
+ pmUtility.getResource("Exit"),
+ pmUtility.getIntResource("Exit.mnemonic"));
+
+ exit.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from exit action");
+ System.exit(0);
+ };
+ });
+
+ exit.setEnabled(true);
+ appMenu.add(exit);
+
+ return appMenu;
+ }
+
+ // disable everything is not running as root
+ public JMenu objectMenu() {
+ // add access to printer...
+ // ---
+ // new local printer...
+ // new network printer...
+ // ---
+ // delete printer
+ // modify properties...
+
+ JMenu objectMenu = new JMenu(
+ pmUtility.getResource("Printer"));
+
+ objectMenu.setMnemonic(
+ pmUtility.getIntResource("Printer.mnemonic"));
+
+ access = new JMenuItem(
+ pmUtility.getResource("Add.Access.to.Printer..."),
+ pmUtility.getIntResource("Add.Access.to.Printer.mnemonic"));
+
+ access.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from access action");
+ if (accessView != null)
+ accessView.setVisible(true);
+ else
+ accessView = new pmAccess(myTop);
+ accessView.Show();
+ };
+ });
+
+ if (!runningAuth)
+ access.setEnabled(false);
+
+ objectMenu.add(access);
+ objectMenu.addSeparator();
+
+ local = new JMenuItem(
+ pmUtility.getResource("New.Attached.Printer..."),
+ pmUtility.getIntResource("New.Attached.Printer.mnemonic"));
+
+ local.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from localinstall action");
+ if (localinstallView != null)
+ localinstallView.setVisible(true);
+ else {
+ try {
+ localinstallView = new pmInstallPrinter(
+ myTop, Constants.ADDLOCAL);
+ } catch (Exception ex) {
+ Debug.message("CLNT:pmTop:caught exception" + ex);
+ }
+ }
+ localinstallView.Show();
+ };
+ });
+
+ if (!runningAuth)
+ local.setEnabled(false);
+
+ objectMenu.add(local);
+
+ network = new JMenuItem(
+ pmUtility.getResource("New.Network.Printer..."),
+ pmUtility.getIntResource("New.Network.Printer.mnemonic"));
+
+ network.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from networkinstall action");
+ if (networkinstallView != null)
+ networkinstallView.setVisible(true);
+ else {
+ try {
+ networkinstallView = new
+ pmInstallPrinter(myTop, Constants.ADDNETWORK);
+ } catch (Exception ex) {
+ Debug.message("CLNT:pmTop:caught exception" + ex);
+ }
+ }
+
+ networkinstallView.Show();
+ };
+ });
+
+ if (!runningAuth)
+ network.setEnabled(false);
+
+ objectMenu.add(network);
+ objectMenu.addSeparator();
+
+ modifyMenuItem = new JMenuItem(
+ pmUtility.getResource("Modify.Printer.Properties..."),
+ pmUtility.getIntResource("Modify.Printer.Properties.mnemonic"));
+
+ modifyMenuItem.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+
+ Debug.message("CLNT: Modify " + selectedPrinter);
+ Debug.message("CLNT: Modify " + selprinterServer);
+
+ doModify();
+ };
+ });
+
+ modifyMenuItem.setEnabled(false);
+ objectMenu.add(modifyMenuItem);
+
+ deleteMenuItem = new JMenuItem(
+ pmUtility.getResource("Delete.Printer..."),
+ pmUtility.getIntResource("Delete.Printer.mnemonic"));
+
+ deleteMenuItem.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from delete action");
+ if (selectedPrinter == null) {
+ Debug.warning("CLNT: selectedPrinter is null");
+ Debug.message("CLNT: cannot call pmDelete");
+ // show error window
+ } else {
+ deleteView = new pmDelete(myTop);
+ }
+ };
+ });
+ deleteMenuItem.setEnabled(false);
+ objectMenu.add(deleteMenuItem);
+ return objectMenu;
+ }
+
+ // returns true iff name was found in the printer list
+ public boolean findPrinterInList(String name) {
+
+ int row = -1;
+
+ try {
+ String p = name.trim();
+ row = listModel.findValue(p);
+ } catch (Exception ee) {
+ Debug.warning("CLNT: pmTop:find ActionList: caught " + ee);
+ }
+
+ if (row != -1) {
+ selectedRow = row;
+ listTable.clearSelection();
+ listTable.setRowSelectionInterval(row, row);
+ listTable.scrollRectToVisible(listTable.getCellRect(row, 0, true));
+ listTable.revalidate();
+ scrollPane.revalidate();
+ scrollPane.repaint();
+ }
+ return row != -1;
+ }
+
+ public JMenu toolsMenu() {
+
+ // find printer...
+ JMenu toolsMenu = new JMenu(
+ pmUtility.getResource("Tools"));
+ toolsMenu.setMnemonic(
+ pmUtility.getIntResource("Tools.mnemonic"));
+
+ JMenuItem find = new JMenuItem(
+ pmUtility.getResource("Find.Printer"),
+ pmUtility.getIntResource("Find.Printer.mnemonic"));
+ find.addActionListener(
+ new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from find action");
+ findFrame.setVisible(true);
+ }
+ });
+
+ toolsMenu.add(find);
+ return toolsMenu;
+ }
+
+ // Create help Menu
+
+ public JMenu helpMenu() {
+ JMenu helpMenu = new JMenu(pmUtility.getResource("Help"));
+ helpMenu.setMnemonic(pmUtility.getIntResource("Help.mnemonic"));
+
+ JMenuItem ov = new JMenuItem(
+ pmUtility.getResource("Overview"),
+ pmUtility.getIntResource("Overview.mnemonic"));
+ ov.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ myTop.showHelpItem("Overview");
+ };
+ });
+
+ helpMenu.add(ov);
+
+ JMenuItem on = new JMenuItem(
+ pmUtility.getResource("On.Help"),
+ pmUtility.getIntResource("On.Help.mnemonic"));
+ on.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ myTop.showHelpItem("HelpOnHelp");
+ };
+ });
+
+ helpMenu.add(on);
+ helpMenu.addSeparator();
+
+ JMenuItem about = new JMenuItem(
+ pmUtility.getResource("About.Print.Manager"),
+ pmUtility.getIntResource("About.Print.Manager.mnemonic"));
+ about.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: call from about help action");
+ aboutBox.setVisible(true);
+ };
+ });
+
+ helpMenu.add(about);
+ helpMenu.addSeparator();
+
+ JMenuItem settings = new JMenuItem(
+ pmUtility.getResource("Print.Manager.Settings"),
+ pmUtility.getIntResource("Print.Manager.Settings.mnemonic"));
+ settings.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Debug.message("CLNT: print manager settings help action");
+ myTop.showHelpItem("PrintManagerSettings");
+ };
+ });
+
+ helpMenu.add(settings);
+ return helpMenu;
+ }
+
+ public void actionPerformed(java.awt.event.ActionEvent e) {
+ }
+
+ public void doModify() {
+
+ if (modifyView != null)
+ modifyView.pmScreendispose();
+
+ try {
+
+ if (selectedPrinter == null || selprinterServer == null) {
+
+ } else {
+
+ if ((host.getLocalHostName()).equals(selprinterServer) ||
+ selprinterServer.equals("localhost")) {
+
+ if (isNetwork()) {
+
+ modifyView = new
+ pmInstallPrinter(
+ myTop, Constants.MODIFYNETWORK);
+
+ } else {
+ modifyView = new
+ pmInstallPrinter(
+ myTop, Constants.MODIFYATTACHED);
+ }
+
+ modifyView.Show();
+
+ } else {
+
+ try {
+ modifyView = new pmInstallPrinter(
+ myTop, Constants.MODIFYREMOTE);
+ } catch (Exception e) {
+ Debug.message(
+ "CLNT:pmTop:caught exception" + e);
+ }
+ modifyView.Show();
+ }
+ }
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmTop:getLocalHostName() caught " + e);
+ }
+ } // doModify()
+
+
+ public boolean isNetwork() {
+
+ Printer newpr = new Printer(myTop.ns);
+ newpr.setPrinterName(selectedPrinter);
+
+ try {
+ newpr.getPrinterDetails();
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmTop:getPrinterDetails() caught " + e);
+ }
+
+ pmCalls.debugShowPrinter(newpr);
+
+ if (newpr.getDestination() != null) {
+ Debug.message("CLNT: isNetwork:getDestination " +
+ newpr.getDestination());
+ return true;
+ } else {
+ Debug.message("CLNT: isNetwork:getDestination is null");
+ return false;
+ }
+ }
+
+ // Set the new namespace
+ public void pmsetNS() {
+
+ String serverNS;
+
+ // translate from gui to server
+ if (newNS.startsWith("files")) {
+ serverNS = new String("system");
+ useLocalhost.setState(true);
+ } else if (newNS.equals("NIS")) {
+ serverNS = new String("nis");
+ useLocalhost.setState(false);
+ } else if (newNS.equals("LDAP")) {
+ serverNS = new String("ldap");
+ useLocalhost.setState(false);
+ } else {
+ serverNS = new String("system");
+ useLocalhost.setState(true);
+ }
+
+ Debug.message("CLNT: newNS: " + newNS +
+ "\n serverNS: " + serverNS +
+ "\n ns.getNameService(): " + ns.getNameService());
+
+ if (!serverNS.equals(ns.getNameService())) {
+
+ if (newNS.startsWith("files")) {
+ useLocalhost.setState(true);
+ ns = systemns;
+ } else if (newNS.equals("NIS")) {
+ useLocalhost.setState(false);
+ ns = nisns;
+ } else if (newNS.equals("LDAP")) {
+ useLocalhost.setState(false);
+ ns = ldapns;
+ } else {
+ useLocalhost.setState(true);
+ ns = systemns;
+ }
+ }
+
+
+ // This tool is read-only unless the user is root on the
+ // print server. Thus, don't check for namespace authorization
+ // if user is not root.
+
+ if (isRoot) {
+ // Check if user is authorized with this nameservice
+ if (ns.isAuth()) {
+ runningAuth = true;
+ } else {
+ // nis/ldap is a special case
+ // need to login to nis/ldap server
+ if (ns.getNameService().equals("nis") == true ||
+ ns.getNameService().equals("ldap") == true) {
+
+ try {
+ if (!ns.isAuth()) {
+ pmUtility.doLogin(myTop, loadView.frame);
+ runningAuth = true;
+ }
+ } catch (pmUserCancelledException e) {
+ Debug.message(
+ "CLNT:pmTop:user cancelled login");
+ runningAuth = false;
+ } catch (pmGuiException e) {
+ Debug.message(
+ "CLNT:pmTop:login nis/ldap failed: " + e);
+ runningAuth = false;
+ pmMessageDialog m = new pmMessageDialog(
+ loadView.frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "Required.login.failed."),
+ myTop,
+ "LoginFailed");
+ m.setVisible(true);
+ } catch (Exception e) {
+ Debug.message(
+ "CLNT:pmTop:login nis/ldap failed: " + e);
+ runningAuth = false;
+ pmMessageDialog m = new pmMessageDialog(
+ loadView.frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "Required.login.failed."),
+ myTop,
+ "LoginFailed");
+ m.setVisible(true);
+ }
+ } else {
+ try {
+ ns.checkAuth();
+ runningAuth = true;
+ } catch (Exception ca) {
+ runningAuth = false;
+ pmMessageDialog m = new pmMessageDialog(
+ loadView.frame,
+ pmUtility.getResource("Error"),
+ pmUtility.getResource(
+ "User.not.authorized.to.modify.this.namespace."),
+ myTop,
+ "AuthorizationFailed");
+ m.setVisible(true);
+ }
+ }
+ }
+
+ if (!serverNS.equals(ns.getNameService())) {
+ deleteAllScreens();
+ }
+
+ // Change front panel as unauthorized to modify
+ if (!runningAuth) {
+ logCheck.setEnabled(false);
+ confirmCheck.setEnabled(false);
+ usePPD.setEnabled(false);
+ useLocalhost.setEnabled(false);
+ access.setEnabled(false);
+ local.setEnabled(false);
+ network.setEnabled(false);
+ modifyMenuItem.setEnabled(false);
+ deleteMenuItem.setEnabled(false);
+ } else {
+ logCheck.setEnabled(true);
+ confirmCheck.setEnabled(true);
+ access.setEnabled(true);
+ local.setEnabled(true);
+ network.setEnabled(true);
+ if (pmMisc.isppdCachefile())
+ usePPD.setEnabled(true);
+ else
+ usePPD.setEnabled(false);
+ if (ns.getNameService().equals("system") == true) {
+ useLocalhost.setEnabled(true);
+ useLocalhost.setVisible(true);
+ } else {
+ useLocalhost.setVisible(false);
+ }
+ }
+
+ } else {
+ runningAuth = false;
+ }
+
+
+ Debug.message("CLNT: NEW ns.getNameService(): " +
+ ns.getNameService());
+
+ }
+
+ class topnsListener implements ItemListener {
+ public topnsListener() {}
+
+ public void itemStateChanged(ItemEvent e) {
+ Debug.message("CLNT: hello from topnsListener" + e.getItem());
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ newNS = (String)e.getItem();
+ }
+ }
+ }
+
+ public void pmsetdefaultpLabel() {
+ try {
+ defaultpLabel.setText(
+ pmUtility.getResource("Default.Printer:") +
+ " " + PrinterUtil.getDefaultPrinter(ns));
+
+ Debug.message(
+ "CLNT: pmTop:pmsetdefaultpLabel(): default printer: " +
+ PrinterUtil.getDefaultPrinter(ns));
+
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmTop:getDefaultPrinter() caught " + e);
+ }
+ }
+
+ public boolean getLogOption() {
+ return logCheck.getState();
+ }
+
+ public void setLogOption(boolean val) {
+ logCheck.setState(val);
+ }
+
+ public boolean getConfirmOption() {
+ return confirmCheck.getState();
+ }
+
+ public boolean getUsePPD() {
+ return usePPD.getState();
+ }
+
+ public boolean getUseLocalhost() {
+ return useLocalhost.getState();
+ }
+
+ public void doFind(String printer) {
+ }
+
+ public void deleteAllScreens() {
+
+ if (accessView != null)
+ accessView.pmScreendispose();
+ accessView = null;
+
+ if (localinstallView != null)
+ localinstallView.pmScreendispose();
+ localinstallView = null;
+
+ if (networkinstallView != null)
+ networkinstallView.pmScreendispose();
+ networkinstallView = null;
+
+ if (modifyView != null)
+ modifyView.pmScreendispose();
+ modifyView = null;
+
+ if (loadView != null)
+ loadView.pmScreendispose();
+ loadView = null;
+ }
+
+
+ /*
+ * enable/disable modify and delete items
+ * this must be called when:
+ * . an existing printer is selected
+ * . the selection is disabled
+ */
+ void enableEditMenuItems(boolean state) {
+ if (!runningAuth)
+ return;
+ modifyMenuItem.setEnabled(state);
+ deleteMenuItem.setEnabled(state);
+ }
+
+ /*
+ * set the log/error state for the current operation
+ */
+ void setLogData(String cmd, String err, String warn) {
+ cmdLog = cmd;
+ errorLog = err;
+ warningLog = warn;
+ }
+
+ /*
+ * display current log state for the specified action
+ * if the cmdLog is empty nothing at all will be displayed!
+ */
+ void showLogData(String actionName) {
+
+ // Debug.info("CLNT: showLogData():actionName: " + actionName);
+ // Debug.info("CLNT: showLogData():cmdLog: " + cmdLog);
+
+ if (cmdLog == null)
+ return;
+
+ addToCommandLog(actionName + "\n");
+
+ // iterate over multiline cmds
+ StringTokenizer st = new StringTokenizer(
+ cmdLog, "\n\r", false);
+ while (st.hasMoreTokens()) {
+ addToCommandLog("% " + st.nextToken());
+ addToCommandLog("\n");
+ }
+
+ if (errorLog != null) {
+ st = new StringTokenizer(errorLog, "\n\r", false);
+ while (st.hasMoreTokens()) {
+ addToCommandLog(st.nextToken());
+ addToCommandLog("\n");
+ }
+ }
+
+ if (warningLog != null) {
+ st = new StringTokenizer(warningLog, "\n\r", false);
+ while (st.hasMoreTokens()) {
+ addToCommandLog(st.nextToken());
+ addToCommandLog("\n");
+ }
+ }
+
+ addToCommandLog("***\n");
+ }
+
+ private void addToCommandLog(String s) {
+ commandLog.addText(s);
+ }
+
+ public void showHelpItem(String tag) {
+ if (helpFrame != null)
+ helpFrame.showHelp(tag);
+ else
+ Toolkit.getDefaultToolkit().beep();
+ }
+
+ public void pmsetNSLabel() {
+
+ if (newNS.startsWith("files")) {
+
+ nameserviceLabel.setText(" ");
+ Debug.message("CLNT: pmsetNSLabel:nameserviceLabel is : " +
+ nameserviceLabel.getText());
+
+ try {
+ domainhostLabel.setText(
+ pmUtility.getResource("Host:") + " " +
+ host.getLocalHostName());
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT: pmTop:getLocalHostName caught " + e);
+ }
+
+ } else {
+ nameserviceLabel.setText(
+ pmUtility.getResource("Naming.Service:") + newNS);
+ Debug.message(
+ "CLNT: pmsetNSLabel:nameserviceLabel is : " +
+ nameserviceLabel.getText());
+
+ try {
+ domainhostLabel.setText(
+ pmUtility.getResource("Domain:") + " " +
+ host.getDomainName());
+ } catch (Exception e) {
+ Debug.warning(
+ "CLNT: pmTop:getDomainName caught " + e);
+ }
+ }
+ }
+
+ // Update the list of printers
+ // Printer list will change if nameservice changes and when user
+ // adds/deletes/changes printers
+
+ public void pmsetPrinterList() {
+
+ Debug.message("CLNT: pmsetPrinterList() ns is :" +
+ ns.getNameService());
+
+ try {
+ listModel.insertlistTable(PrinterUtil.getPrinterList(ns),
+ listModel.getColumnCount());
+ } catch (Exception e) {
+ Debug.warning("CLNT: pmTop:getPrinterList() caught " + e);
+ }
+
+ listTable.clearSelection();
+ scrollPane.getViewport().setView(listTable);
+ scrollPane.revalidate();
+ scrollPane.repaint();
+ }
+
+
+ // returns -1 if error, 0 otherwise
+ protected static int parseArgs(String[] args) {
+ int rv = 0;
+
+ for (int i = 0; i < args.length; ++i) {
+ if (args[i].compareTo("-debugall") == 0)
+ Debug.setDebugLevel(Debug.ALL);
+ else if (args[i].compareTo("-debugnone") == 0)
+ Debug.setDebugLevel(Debug.NONE);
+ else if (args[i].compareTo("-debugwarn") == 0)
+ Debug.setDebugLevel(Debug.WARNING);
+ else if (args[i].compareTo("-debugerr") == 0)
+ Debug.setDebugLevel(Debug.ERROR);
+ else if (args[i].compareTo("-debugfatal") == 0)
+ Debug.setDebugLevel(Debug.FATAL);
+ else if (args[i].compareTo("-debugmsg") == 0)
+ Debug.setDebugLevel(Debug.MESSAGE);
+ else if (args[i].compareTo("-debuginfo") == 0)
+ Debug.setDebugLevel(Debug.INFO);
+ }
+
+ return rv;
+ }
+
+ public static void main(String[] args) {
+
+ if (parseArgs(args) < 0)
+ System.exit(-1);
+
+ // use pmFrame to get app icon
+ pmFrame frame = new pmFrame(pmUtility.getResource("info_name"));
+
+ myTop = new pmTop(frame);
+
+ frame.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ });
+
+ frame.getContentPane().add("Center", myTop);
+ frame.pack();
+ frame.setVisible(true);
+ frame.repaint();
+
+ pmLoad firstload = new pmLoad(myTop);
+ myTop.loadView = firstload;
+ firstload.Show();
+
+ aboutBox = new pmAboutBox();
+ commandLog = new pmLogDisplay(myTop, "ShowCommandConsole");
+ findFrame = new pmFindFrame(myTop);
+
+ /*
+ * Make sure to open the help frame after the about box,
+ * command log, and find frame windows have been opened.
+ * Otherwise it might cause null pointer exceptions as it
+ * takes a long time for the help frame to load.
+ */
+ helpFrame = new pmHelpFrame();
+
+ }
+
+ // disable Enter action **for all JTextFields**
+ static {
+ JTextField f = new JTextField();
+ KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+ Keymap map = f.getKeymap();
+ map.removeKeyStrokeBinding(enter);
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmUserCancelledException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmUserCancelledException.java
new file mode 100644
index 0000000000..15ff9fb61c
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmUserCancelledException.java
@@ -0,0 +1,43 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmUserCancelledException .java
+ *
+ */
+
+package com.sun.admin.pm.client;
+
+import java.lang.*;
+
+class pmUserCancelledException extends pmGuiException {
+ public pmUserCancelledException(String s) {
+ super(s);
+ }
+ public pmUserCancelledException() {
+ super();
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmUtility.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmUtility.java
new file mode 100644
index 0000000000..dc10376dc5
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pmUtility.java
@@ -0,0 +1,216 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * pmUtility.java
+ * Resource loading and utility classes
+ */
+
+package com.sun.admin.pm.client;
+
+import java.awt.*;
+import java.applet.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+
+import com.sun.admin.pm.server.*;
+
+
+/*
+ * Utility class to provide common functions to the printing
+ * manager classes
+ */
+
+public class pmUtility {
+
+/*
+ * Gets the localized string from the named bundle
+ */
+
+ public static String getCopyrightResource(String key) {
+ String keyvalue = null;
+ ResourceBundle bundle = null;
+
+
+ try {
+ bundle = ResourceBundle.getBundle(
+ "com.sun.admin.pm.client.pmCopyright");
+ } catch (MissingResourceException e) {
+ Debug.fatal("Could not load pmCopyright file");
+ }
+
+ try {
+ keyvalue = bundle.getString(key);
+ } catch (MissingResourceException e) {
+ Debug.error("CLNT: getCopyrightResource: Missing: " + key);
+ keyvalue = new String("<<" + key + ">>");
+ }
+
+ return keyvalue;
+ }
+
+ public static String getResource(String key) {
+ String keyvalue = null;
+ ResourceBundle bundle = null;
+
+
+ try {
+ bundle = ResourceBundle.getBundle(
+ "com.sun.admin.pm.client.pmResources");
+ } catch (MissingResourceException e) {
+ Debug.fatal("Could not load pmResources file");
+ }
+
+ try {
+ keyvalue = bundle.getString(key);
+ } catch (MissingResourceException e) {
+ Debug.error("CLNT: getResource: Missing: " + key);
+ keyvalue = new String("<<" + key + ">>");
+ }
+
+ return keyvalue;
+ }
+
+ public static int getIntResource(String key) {
+ int keyvalue = 0;
+ String s = null;
+ ResourceBundle bundle = null;
+
+ try {
+ bundle = ResourceBundle.getBundle(
+ "com.sun.admin.pm.client.pmResources");
+ } catch (MissingResourceException e) {
+ Debug.fatal("Could not load pmResources file");
+ }
+
+ try {
+ s = bundle.getString(key);
+ } catch (MissingResourceException e) {
+ Debug.error("Missing: " + key);
+ }
+
+ Debug.message("Resource: " + key + " Value: " + s);
+
+ if (s != null) {
+ try {
+ keyvalue = s.charAt(0);
+ } catch (Exception x) {
+ Debug.error("Resource: " + key + " threw: " + x);
+ }
+ }
+
+ return keyvalue;
+ }
+
+ public static void doLogin(
+ pmTop mytop, JFrame frame) throws pmGuiException {
+
+ pmLogin l;
+
+ if (mytop.ns.getNameService().equals("nis") ||
+ mytop.ns.getNameService().equals("ldap")) {
+
+ if (mytop.ns.getNameService().equals("nis")) {
+
+ l = new pmLogin(
+ frame,
+ pmUtility.getResource("NIS.Authentication"),
+ pmUtility.getResource("Enter.NIS.authentication.data."),
+ mytop,
+ "NISAuthentication");
+
+ } else { // LDAP
+
+ l = new pmLogin(
+ frame,
+ pmUtility.getResource("LDAP.Authentication"),
+ pmUtility.getResource("Enter.LDAP.authentication.data."),
+ mytop,
+ "LDAPAuthentication");
+ }
+
+ l.setVisible(true);
+
+ if ((l.getValue() != JOptionPane.OK_OPTION) &&
+ (l.getValue() != JOptionPane.CANCEL_OPTION)) {
+
+ pmMessageDialog m = new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Login.Failure"),
+ pmUtility.getResource(
+ "Request.cannot.be.completed."));
+ m.setVisible(true);
+ throw new pmGuiException
+ ("pmAccess: Cannot create Login screen");
+ }
+
+
+ if (l.getValue() == JOptionPane.CANCEL_OPTION) {
+ throw new pmUserCancelledException("User.Cancelled.Login");
+ } else {
+
+ // Pass data to backend
+
+ // getPassword sends back untrimmed string that is invalid
+ // as a password as it's too long
+ String tmpp = new String(l.passwordField.getPassword());
+ mytop.ns.setPasswd(tmpp.trim());
+
+ if (mytop.ns.getNameService().equals("ldap")) {
+ // setUser for binddn
+ mytop.ns.setUser(l.dnField.getText());
+ // setNameServiceHost overloaded for LDAP server name
+ mytop.ns.setNameServiceHost(l.serverField.getText());
+ }
+
+ try {
+ mytop.ns.checkAuth();
+ Debug.message("doLogin():checkauth() OK");
+ } catch (Exception e) {
+ Debug.warning("doLogin:checkAuth()exception " + e);
+ throw new pmGuiException("Login.Authorization.Failed");
+ }
+ }
+
+
+ // User has not put in printer or server
+ } else {
+ pmMessageDialog m =
+ new pmMessageDialog(
+ frame,
+ pmUtility.getResource("Login.Failure"),
+ pmUtility.getResource("Request.cannot.be.completed."),
+ mytop, "LoginFailed");
+
+ m.setVisible(true);
+ throw new pmGuiException("pmAccess: Cannot create Login screen");
+ }
+
+ }
+
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pm_gen_copyright b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pm_gen_copyright
new file mode 100644
index 0000000000..0f8310dd38
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/pm_gen_copyright
@@ -0,0 +1,64 @@
+#!/usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# This script generates the pmCopyright.java file
+# which contains the copyright data needed by
+# the Solaris Print Manager. The pmCopyright.java
+# file is generated during a make in order to update
+# the copyright with the correct date info, eliminating
+# the need to update the copyright notice with every
+# release.
+
+PMFILE=pmCopyright.java
+DATE=`/usr/bin/date '+%Y'`
+
+/usr/bin/rm -f ${PMFILE}
+/usr/bin/cat > ${PMFILE} <<END
+/*
+ * GENERATED CODE
+ *
+ * Copyright ${DATE} Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+package com.sun.admin.pm.client;
+import java.util.*;
+
+public class pmCopyright extends ListResourceBundle {
+ static final Object[][] pmHelpBundlecontents = {
+
+ {"copyright_year", "1999-${DATE}"},
+ {"dummy", ""}
+ };
+
+ public Object[][] getContents() {
+ return pmHelpBundlecontents;
+ }
+}
+END
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddAccess.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddAccess.rawhlp
new file mode 100644
index 0000000000..9898ecfa8e
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddAccess.rawhlp
@@ -0,0 +1,97 @@
+<TITLE> Dialog: Add Access to Printer</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=AddAccess -->
+
+<CONTENT>
+
+<p>
+
+Use the Add Access to Printer dialog to make an installed printer
+accessible to print client computers. See the printers.conf(4) man
+page if you need more information about print client commands.
+
+<p>
+
+<b>Printer Name:</b> The name of the printer you wish to add access
+to. The printer name must be a text string composed of uppercase or
+lowercase alphabetical characters (a-z, A-Z), digits (0-9), hyphens, or
+underscores. A printer name can be a maximum of 14 characters long.
+<p>
+
+<b>Printer Server:</b> The name of the printer server the named printer is
+installed on. The printer may be physically connected to
+the server or it may be a network printer.
+
+<p>
+
+<b>NOTE:</b> Oracle Solaris Print Manager does not check for the validity of
+Printer Name or Printer Server.
+
+<p>
+
+<b>Description:</b> [Optional] A description of the printer, including,
+for example, the type and location of the printer.
+<p>
+
+<b>Option: Default Printer:</b> If checked and no naming service is
+being used, this printer is designated as the default printer for the
+computer on which you are running Oracle Solaris Print Manager. If checked
+and a naming service is being used, designates this as the default
+printer for the naming service.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+access "add access" description "default printer" "naming service"
+"printer name" "printer server" dialog: add printer
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToAddAccess
+ToModify
+ToDelete
+ToInstallLocal
+ToInstallNetwork
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddAccessFailed.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddAccessFailed.rawhlp
new file mode 100644
index 0000000000..b0153bb465
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddAccessFailed.rawhlp
@@ -0,0 +1,62 @@
+<TITLE> If Add Access Fails</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+--
+-- ident "%Z%%M% %I% %E% SMI"
+-->
+<!-- Tag=AddAccessFailed -->
+
+<CONTENT>
+
+<p>
+
+You must enter a printer name and a printer server name; the printer
+server must be a remote server (not the current server). See the man
+page for lpadmin(1M) for more information.
+
+<p>
+
+Display the Command-Line Console to help pinpoint where the error
+may have occurred. Choose Show Command-Line Console from the Print
+Manager menu to display the Command-Line Console.
+
+</CONTENT>
+
+<p>
+
+<KEYWORDS>
+add access fail failure fails
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+AddAccess
+ToAddAccess
+ToShowCommand
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddPrinterFailed.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddPrinterFailed.rawhlp
new file mode 100644
index 0000000000..948abce0f6
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/AddPrinterFailed.rawhlp
@@ -0,0 +1,68 @@
+<TITLE> If New Printer Action Fails</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+--
+-- ident "%Z%%M% %I% %E% SMI"
+-->
+<!-- Tag=AddPrinterFailed -->
+
+<CONTENT>
+
+<p>
+
+The printer name must be a text string composed of uppercase or
+lowercase alphabetical characters (a-z, A-Z), digits (0-9), hyphens,
+or underscores. A printer name can be a maximum of 14 characters long.
+
+<p>
+
+Display the Command-Line Console to help pinpoint where the error
+may have occurred. Choose Show Command-Line Console from the Print
+Manager menu to display the Command-Line Console. See the man
+page for lpadmin(1M) for more information.
+
+<p>
+
+</CONTENT>
+
+<p>
+
+<KEYWORDS>
+install fail failure "new attached" "new network" new printer action
+fails
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+InstallLocal
+InstallNetwork
+ToInstallLocal
+ToInstallNetwork
+ToShowCommand
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/DeletePrinterFailed.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/DeletePrinterFailed.rawhlp
new file mode 100644
index 0000000000..ea10c85462
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/DeletePrinterFailed.rawhlp
@@ -0,0 +1,56 @@
+<TITLE> If Delete Printer Fails</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+-- Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+--
+-- ident "%Z%%M% %I% %E% SMI"
+-->
+<!-- Tag=DeletePrinterFailed -->
+
+<CONTENT>
+
+<p>
+
+If the Delete printer process fails, follow the instructions in the
+error dialog. If the instructions are incomplete or unclear, display
+the Command-Line Console to help pinpoint where the error may have
+occurred. Choose Show Command-Line Console from the Print Manager menu
+to display the Command-Line Console. See the man page for lpadmin(1M)
+for more information.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+delete fail failure printer fails
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToDelete
+ToShowCommand
+Overview
+MainWindow
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/HelpOnHelp.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/HelpOnHelp.rawhlp
new file mode 100644
index 0000000000..d8286edfa8
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/HelpOnHelp.rawhlp
@@ -0,0 +1,127 @@
+<TITLE> Help on Help </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=HelpOnHelp -->
+
+<CONTENT>
+
+<p>
+
+Oracle Solaris Print Manager help is displayed if you choose one of the help
+items from the Help menu in the Print Manager main window or if you
+click on a Help button in any of the Print Manager windows or dialogs.
+
+<p>
+
+<b> Viewing a help article </b>
+
+<p>
+
+When you click on a Help button or choose a help item from the Help
+menu, help for the selected topic is displayed in the help viewer. See
+the headings labeled Navigation, Index, and Search below for
+instructions for viewing other help articles.
+
+<p>
+
+<b> Navigation </b>
+
+<p>
+
+To move around in an article, click on the scroll bar to the right of
+the article text. Note that you can expand or contract the help window
+by grabbing a corner with the mouse cursor and moving the mouse. See
+below for instructions for viewing other help articles.
+
+<p>
+
+Back button: Click to move to the last article viewed.
+<br>
+Forward button: Click to move to the article viewed prior to clicking
+the Back button.
+<br>
+See also pulldown menu: Select an item from the menu and click Show to display
+the selected article.
+<br>
+Show button: After selecting an item from the See also menu, click Show
+to display it.
+
+<p>
+
+<b> Index </b>
+
+<p>
+
+1. Click the Index tab at the top of the help window to display the index
+search tool.
+
+<p>
+
+By default the Search field is blank and all help articles are listed.
+To limit the index listing, enter the first letters of a help article;
+the articles that start with the entered letters will be displayed as
+you type. To see all the task descriptions, for instance, enter "to"
+and a blank.
+
+<p>
+
+2. To view an article, double-click on it or select it and click
+Show. The article is displayed in view mode.
+
+<p>
+
+<b> Search </b>
+
+<p>
+
+Click the Search tab at the top of the help window to display the
+search tool.
+
+<p>
+
+Enter a word or phrase in the Keywords field and click Search.
+
+<p>
+
+All articles with the entered keyword or phrase marked as a keyword
+will be displayed in the Search Results list.
+
+<p>
+
+To view an article, double-click on it or select it and click
+Show. The article is displayed in view mode.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+view index search show back forward "see also" help keywords
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+Overview
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallLocal.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallLocal.rawhlp
new file mode 100644
index 0000000000..ff8602be43
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallLocal.rawhlp
@@ -0,0 +1,171 @@
+<TITLE> Dialog: New Attached Printer </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=InstallLocal -->
+
+<CONTENT>
+
+<p>
+
+Once you have physically connected the printer to the printer server,
+use the New Attached Printer dialog to install the printer, which
+makes the printer available for printing from the computer on which
+you are running Oracle Solaris Print Manager.
+
+<p>
+
+<b> Printer Name:</b>
+ Specifies a unique name for the printer. The
+ printer name must be a text string composed of
+ uppercase or lowercase alphabetical characters
+ (a-z, A-Z), digits (0-9), hyphens, or
+ underscores. A printer name can be a maximum of
+ 14 characters long.
+<p>
+
+<b> Printer Server:</b> This is the computer you have selected to act
+as the server for print actions. You must be logged on to this
+computer and be running Oracle Solaris Print Manager on it. Oracle
+Solaris Print Manager sets up this system with the appropriate software to manage
+local and remote printers.
+
+<p>
+<b> Description:</b>
+ [Optional] Describes the printer, including the printer type and
+ location, possibly, or provides other information about the
+ printer.
+
+<p>
+
+<b> Printer Port:</b>
+
+Specifies the hardware port, such as /dev/term/a, that the printer is
+connected to.
+<p>
+
+<b> Printer Type:</b>
+ Specifies the generic name for a type of
+ printer. Supported printer types correspond to
+ items listed in the /usr/share/lib/terminfo
+ directories. Examples are PostScript, Daisy, and Diablo.
+
+<p>
+
+<b> File Contents:</b>
+ Specifies the format of files that can be
+ printed without any special filtering by the
+ print software. PostScript is the default and is
+ probably correct most of the time.
+<p>
+
+<b> Fault Notification:</b>
+ Specifies how the superuser will be notified in
+ case of a printer error.
+
+<p>
+
+<b> Options: Default Printer:</b> If checked, designates this printer
+as the default printer for printing jobs from the computer on which
+you are running Oracle Solaris Print Manager. If you are using a naming
+service, this printer will be the default printer for the naming
+service, also.
+
+<p>
+
+Note that this is the last place the print subsystem looks to
+determine where a particular print job will be printed; the
+destination option of the lp command is the first place looked, and
+other environment variables are checked before this one. See the man
+page for printers.conf(4) for a full explanation of the search order.
+
+<p>
+
+<b> Options: Banner:</b> Specifies whether a banner
+page will be printed between jobs.
+<br>
+<br>
+"Aways Print Banner" stipulates that a banner will always be printed
+and may not be turned off by the user.
+<br>
+"User Selectable - Default=on" stipulates that a banner will be printed
+unless the user selects
+to turn the banner off.
+<br>
+"Never Print Banner" stipulates that a banner will never be printed
+and may not be turned on by the user.
+
+<p>
+
+<b> User Access List:</b>
+Specifies the print clients that can
+ print to this printer. By default, all print
+ clients have access to this printer, as designated by the word
+"all" in the list.
+
+<p>
+
+If you want to restrict its use to individual users, enter a user name
+in the text field below the list and click Add. Other legal constructs
+are system-name!login-ID (user "login-ID" on system "system-name"),
+system-name!all (all users on system "system-name"), and all!login-ID
+(user "login-ID" on all systems). Use the lpadmin(1M) command to deny
+access to users.
+
+<p>
+
+To delete a user from the list, select the user in the list and click
+Delete.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+</CONTENT>
+
+<KEYWORDS>
+install "local printer" "printer name" server description port
+"printer type" "file contents" fault "fault notification" "default
+printer" banner "attached printer" new nobanner dialog: new attached
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToInstallLocal
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallLocalPPD.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallLocalPPD.rawhlp
new file mode 100644
index 0000000000..c344d43861
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallLocalPPD.rawhlp
@@ -0,0 +1,177 @@
+<TITLE> Dialog: New Attached Printer </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=InstallLocal -->
+
+<CONTENT>
+
+<p>
+
+Once you have physically connected the printer to the printer server,
+use the New Attached Printer dialog to install the printer, which
+makes the printer available for printing from the computer on which
+you are running Oracle Solaris Print Manager.
+
+<p>
+
+<b> Printer Name:</b>
+ Specifies a unique name for the printer. The
+ printer name must be a text string composed of
+ uppercase or lowercase alphabetical characters
+ (a-z, A-Z), digits (0-9), hyphens, or
+ underscores. A printer name can be a maximum of
+ 14 characters long.
+<p>
+
+<b> Printer Server:</b> This is the computer you have selected to act
+as the server for print actions. You must be logged on to this
+computer and be running Oracle Solaris Print Manager on it. Oracle
+Solaris Print Manager sets up this system with the appropriate software to manage
+local and remote printers.
+
+<p>
+<b> Description:</b>
+ [Optional] Describes the printer, including the printer type and
+ location, possibly, or provides other information about the
+ printer.
+
+<p>
+
+<b> Printer Port:</b>
+
+Specifies the hardware port, such as /dev/term/a, that the printer is
+connected to.
+<p>
+
+<b> Printer Make:</b>
+ Specifies the printer make, or manufacturer. This
+ information is on the printer and/or in the documentation
+ that is delivered with the printer.
+<p>
+
+<b> Printer Model:</b>
+ Specifies the printer model. This information
+ is found on the printer and/or in the documentation that is
+ delivered with the printer.
+<p>
+
+<b> Printer Driver:</b>
+ Specifies the printer driver to use with this printer. The label
+ name followed in parentheses by one of the following letters
+representing the repository in which the printer driver information resides:
+U (user supplied printer information), A (administrator supplied printer
+information), V (vendor supplied printer information), or S (system supplied
+printer information), precedes the name of the Printer Driver.
+<p>
+
+<b> Fault Notification:</b>
+ Specifies how the superuser will be notified in
+ case of a printer error.
+
+<p>
+
+<b> Options: Default Printer:</b> If checked, designates this printer
+as the default printer for printing jobs from the computer on which
+you are running Oracle Solaris Print Manager. If you are using a naming
+service, this printer will be the default printer for the naming
+service, also.
+
+<p>
+
+Note that this is the last place the print subsystem looks to
+determine where a particular print job will be printed; the
+destination option of the lp command is the first place looked, and
+other environment variables are checked before this one. See the man
+page for printers.conf(4) for a full explanation of the search order.
+
+<p>
+
+<b> Options: Banner:</b> Specifies whether a banner
+page will be printed between jobs.
+<br>
+<br>
+"Aways Print Banner" stipulates that a banner will always be printed
+and may not be turned off by the user.
+<br>
+"User Selectable - Default=on" stipulates that a banner will be printed
+unless the user selects
+to turn the banner off.
+<br>
+"Never Print Banner" stipulates that a banner will never be printed
+and may not be turned on by the user.
+
+<p>
+
+<b> User Access List:</b>
+Specifies the print clients that can
+ print to this printer. By default, all print
+ clients have access to this printer, as designated by the word
+"all" in the list.
+
+<p>
+
+If you want to restrict its use to individual users, enter a user name
+in the text field below the list and click Add. Other legal constructs
+are system-name!login-ID (user "login-ID" on system "system-name"),
+system-name!all (all users on system "system-name"), and all!login-ID
+(user "login-ID" on all systems). Use the lpadmin(1M) command to deny
+access to users.
+
+<p>
+
+To delete a user from the list, select the user in the list and click
+Delete.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+</CONTENT>
+
+<KEYWORDS>
+install "local printer" "printer name" server description port
+"printer make" "printer model" "printer driver" fault "fault notification" "default
+printer" banner "attached printer" new nobanner dialog: new attached
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToInstallLocal
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallNetwork.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallNetwork.rawhlp
new file mode 100644
index 0000000000..c6d372193e
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallNetwork.rawhlp
@@ -0,0 +1,176 @@
+<title> Dialog: New Network Printer </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=InstallNetwork -->
+
+<CONTENT>
+
+<p>
+
+Use the New Network Printer dialog to install a network printer,
+thus making the printer available for printing from the network.
+
+<p>
+
+<b> Printer Name:</b>
+ Specifies a unique name for the printer. The
+ printer name must be a text string composed of
+ uppercase or lowercase alphabetical characters
+ (a-z, A-Z), digits (0-9), hyphens, or
+ underscores. A printer name can be a maximum of
+ 14 characters long.
+<p>
+
+<b> Printer Server:</b> This is the computer you have selected to act
+as the server for print actions. You must be logged on to this
+computer and be running Oracle Solaris Print Manager on it. Oracle
+Solaris Print Manager sets up this system with the appropriate software to manage
+local and remote printers.
+
+<p>
+<b> Description:</b>
+ [Optional] Describes the printer, including the printer type and
+ location, possibly, or provides other information about the
+ printer.
+
+<p>
+
+<b> Printer Type:</b>
+ Specifies the generic name for a type of
+ printer. Supported printer types correspond to
+ entries in the /usr/share/lib/terminfo
+ directory. Examples are PostScript, Daisy, and Diablo.
+<p>
+
+<b> File Contents:</b>
+ Specifies the format of files that can be
+ printed without any special filtering by the
+ print software. PostScript is the default and is
+ probably correct most of the time.
+<p>
+
+<b> Fault Notification:</b>
+ Specifies how the superuser will be notified in
+ case of a printer error.
+
+<p>
+<b> Destination:</b>
+<br>
+For <b>BSD</b> Protocol, the network name of the printer followed by a colon
+and the printer-vendor-supplied queue name.
+<br>
+For <b>TCP</b> Protocol, the network name of the printer followed by a colon
+and the tcp port number to connect to.
+<br>
+For <b>URI</b> Protocol, a printer URI to be used in connecting to the remote
+printer. For example: "smb://user@printer-host/printer-name".
+<p>
+
+<b> Protocol:</b>
+The internet protocol for file transfer; choices are BSD, TCP, or URI.
+<p>
+
+<b> Options: Default Printer:</b> If checked, this printer is
+designated as the default printer for printing jobs sent to this
+server. If another printer had been designated as the default printer
+for the network, this printer will replace it as the default. If you
+are using a naming service, this printer will be the default printer
+for the naming service, also.
+
+<p> Note that this is the last place the print subsystem looks to
+determine where a particular print job will be printed; the
+destination option of the lp command is the first place looked, and
+other environment variables are checked before this one. See the man
+page for printers.conf(4) for a full explanation of the search order.
+
+<p>
+
+<b> Options: Banner:</b> Specifies whether a banner
+page will be printed between jobs.
+<br>
+<br>
+"Aways Print Banner" stipulates that a banner will always be printed
+and may not be turned off by the user.
+<br>
+"User Selectable - Default=on" stipulates that a banner will be printed
+unless the user selects
+to turn the banner off.
+<br>
+"Never Print Banner" stipulates that a banner will never be printed
+and may not be turned on by the user.
+
+<p>
+
+<b> User Access List:</b>
+Specifies the print clients that can
+ print to this printer. By default, all print
+ clients have access to this printer, as designated by the word
+"all" in the list.
+<p>
+
+To add a user to the list, type a user name in the blank text field
+below the list and click Add. Note that this user name replaces "all"
+or "none" if either "all" or "none" is in the user access list. If
+"all" or "none" is added as a user, "all" or "none" will replace the
+names in the list.
+
+<p>
+
+To delete a user from the list, select the user in the list and click
+Delete.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+
+install "network printer" "printer name" server description port
+"printer type" "file contents" fault "fault notification" "default
+printer" banner new dialog: network printer
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToInstallNetwork
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallNetworkPPD.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallNetworkPPD.rawhlp
new file mode 100644
index 0000000000..77c3217898
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/InstallNetworkPPD.rawhlp
@@ -0,0 +1,187 @@
+<TITLE> Dialog: New Network Printer </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=InstallNetwork -->
+
+<CONTENT>
+
+<p>
+
+Use the New Network Printer dialog to install a network printer,
+thus making the printer available for printing from the network.
+
+<p>
+
+<b> Printer Name:</b>
+ Specifies a unique name for the printer. The
+ printer name must be a text string composed of
+ uppercase or lowercase alphabetical characters
+ (a-z, A-Z), digits (0-9), hyphens, or
+ underscores. A printer name can be a maximum of
+ 14 characters long.
+<p>
+
+<b> Printer Server:</b> This is the computer you have selected to act
+as the server for print actions. You must be logged on to this
+computer and be running Oracle Solaris Print Manager on it. Oracle
+Solaris Print Manager sets up this system with the appropriate software to manage
+local and remote printers.
+
+<p>
+<b> Description:</b>
+ [Optional] Describes the printer, including the printer type and
+ location, possibly, or provides other information about the
+ printer.
+
+<p>
+
+<b> Printer Make:</b>
+ Specifies the printer make, or manufacturer. This
+ information is on the printer and/or in the documentation
+ that is delivered with the printer.
+<p>
+
+<b> Printer Model:</b>
+ Specifies the printer model. This information
+ is found on the printer and/or in the documentation that is
+ delivered with the printer.
+
+<p>
+
+<b> Printer Driver:</b>
+ Specifies the printer driver to use with this printer. The label
+ name followed in parentheses by one of the following letters
+representing the repository in which the printer driver information resides:
+U (user supplied printer information), A (administrator supplied printer
+information), V (vendor supplied printer information), or S (system supplied
+printer information), precedes the name of the Printer Driver.
+<p>
+
+
+<b> Fault Notification:</b>
+ Specifies how the superuser will be notified in
+ case of a printer error.
+
+<p>
+<b> Destination:</b>
+<br>
+For <b>BSD</b> Protocol, the network name of the printer followed by a colon
+and the printer-vendor-supplied queue name.
+<br>
+For <b>TCP</b> Protocol, the network name of the printer followed by a colon
+and the tcp port number to connect to.
+<br>
+For <b>URI</b> Protocol, a printer URI to be used in connecting to the remote
+printer. For example: "smb://user@printer-host/printer-name".
+<p>
+
+<b> Protocol:</b>
+The internet protocol for file transfer; choices are BSD, TCP, or URI.
+<p>
+
+<b> Options: Default Printer:</b> If checked, this printer is
+designated as the default printer for printing jobs sent to this
+server. If another printer had been designated as the default printer
+for the network, this printer will replace it as the default. If you
+are using a naming service, this printer will be the default printer
+for the naming service, also.
+
+<p> Note that this is the last place the print subsystem looks to
+determine where a particular print job will be printed; the
+destination option of the lp command is the first place looked, and
+other environment variables are checked before this one. See the man
+page for printers.conf(4) for a full explanation of the search order.
+
+<p>
+
+<b> Options: Banner:</b> Specifies whether a banner
+page will be printed between jobs.
+<br>
+<br>
+"Aways Print Banner" stipulates that a banner will always be printed
+and may not be turned off by the user.
+<br>
+"User Selectable - Default=on" stipulates that a banner will be printed
+unless the user selects
+to turn the banner off.
+<br>
+"Never Print Banner" stipulates that a banner will never be printed
+and may not be turned on by the user.
+
+<p>
+
+<p>
+
+<b> User Access List:</b>
+Specifies the print clients that can
+ print to this printer. By default, all print
+ clients have access to this printer, as designated by the word
+"all" in the list.
+<p>
+
+To add a user to the list, type a user name in the blank text field
+below the list and click Add. Note that this user name replaces "all"
+or "none" if either "all" or "none" is in the user access list. If
+"all" or "none" is added as a user, "all" or "none" will replace the
+names in the list.
+
+<p>
+
+To delete a user from the list, select the user in the list and click
+Delete.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+
+install "network printer" "printer name" server description port
+"printer make" "printer model" "printer driver" fault "fault notification" "default
+printer" banner new dialog: network printer
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToInstallNetwork
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp
new file mode 100644
index 0000000000..2e6070dc66
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LDAPAuthentication.rawhlp
@@ -0,0 +1,132 @@
+<TITLE> LDAP Authentication</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=LDAPAuthentication -->
+
+<CONTENT>
+
+<p>
+
+If you are using the LDAP naming service, you will need the distinguished
+name and password for a user who has update privileges to make any changes.
+Before making changes to the LDAP directory the user should be fully aware of
+the items in the <b>notes</b> below.
+The LDAP Authentication dialog is displayed when you select LDAP as the
+naming service.
+
+<p>
+
+1. Check the LDAP server name for correctness. You may select a
+different server name if appropriate.
+
+<p>
+
+2. Check the Distinguished Name (DN) for correctness. You may enter a
+different distinguished name of another user if appropriate. This may be the DN
+of any directory user who has permissions (directory update privileges) to
+update printer entries in the LDAP directory for the current ldapclient (1M)
+naming service (NS) domain.
+
+<p>
+
+3. Enter the password for the user's Distinguished Name.
+
+<p>
+
+4. Click OK.
+
+<p>
+
+The entries you have made will be validated against the LDAP directory and then
+saved, the LDAP Authentication dialog will be dismissed.
+
+<p>
+
+Click Cancel if you don't know the password for the Distinguished Name.
+
+<p>
+
+<b>Note:</b> Keep the following in mind if you are using Oracle Solaris Print
+Manager to update printer information in the LDAP naming service:
+
+<p>
+
+If the LDAP server is the Netscape Directory Server (NSDS) then
+the default distinguished name is "cn=Directory Manager".
+If the LDAP server is Sun Directory Server then an example
+of the distinguished name is "cn=admin, dc=XYZ, dc=COM".
+
+The Oracle Solaris Print Manager uses ldapclient(1M) to determine
+the default LDAP server name. If there is more than one
+server specified then the first one will be used.
+
+<p>
+
+The Print Manager always displays printer entries from the current
+ldapclient (1M) server. If this is not the domain Master LDAP server then
+the list of printers displayed may <b>not</b> be the current list of printers,
+this is because the ldapclient replica server may not have been updated by the
+master server and so be out of sync with the master. Replica servers can have
+various update replication agreements, for example; updated immediately there
+is a change on the master, or updated once a day from the master.
+
+<p>
+
+If the selected LDAP server is a replica LDAP server, any <b>updates</b> will be
+referred to the master server and done there. This again means the printer list
+could be out of sync with the master. For example, a deleted printer may still
+appear in the displayed printer list until the replica is updated from
+the master.
+
+<p>
+
+Users can use the ldap command line utilities (ldapadd (1) & ldapmodify (1))
+to update printer entries in the directory, but this is not recommended. If
+these utilities are used then the user <b>must ensure</b> that the printer-name
+attribute value is unique within the ou=printers container. If it is not unique
+the result of modifies done by the print manager (or lpset (1M)) may not be
+predictable.
+
+<p>
+
+</CONTENT>
+
+<p>
+
+<KEYWORDS>
+
+LDAP ldap "LDAP server" authentication login password naming "naming
+service" files "replica server" replica replication referral ldapclient
+"distinguished name" DN
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+NameService
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LoginFailed.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LoginFailed.rawhlp
new file mode 100644
index 0000000000..8844f2323b
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/LoginFailed.rawhlp
@@ -0,0 +1,59 @@
+<TITLE> If Login Fails</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+-->
+<!-- Tag=LoginFailed -->
+
+<CONTENT>
+
+<p>
+
+If the NIS naming service is being used, you will need to know the
+password for the naming service master. If LDAP is being used then
+a fully distinguished name with update privilege and password will
+be required. Note that default values may need to be overridden.
+See the man page for lpadmin(1M) and the help articles, "About
+Naming Services" and "NIS Authentication," for further information.
+
+<p>
+
+</CONTENT>
+
+<p>
+
+<KEYWORDS>
+"login failed" login fail failure fails
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToStart
+ToShowCommand
+NISAuthentication
+NameService
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/MainWindow.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/MainWindow.rawhlp
new file mode 100644
index 0000000000..8a7f535d7a
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/MainWindow.rawhlp
@@ -0,0 +1,116 @@
+<TITLE> Oracle Solaris Print Manager Main Window </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+-->
+<!-- Tag=MainWindow -->
+
+<CONTENT>
+
+<p>
+
+The main window is the starting point for any Oracle Solaris Print Manager
+activities.
+
+<p>
+<b> Print Manager Menu: </b> Select Naming Service, Show
+Command-Line Console, Confirm All Actions, Exit
+
+<p>
+<b> Printer Menu: </b> Add Access to Printer, New Attached
+Printer, New Network Printer, Modify Printer Properties,
+Delete Printer
+
+<p>
+<b> Tools Menu: </b> Find Printer
+
+<p>
+<b> Help Menu: </b> Overview, On Help, About Print Manager
+<p>
+
+<b> List of Printers: </b> This is the list of printers installed on
+the computer on which you are running Oracle Solaris Print Manager, or, if a
+naming service is being used, all printers in the naming service.
+
+<p>
+There are three columns in the list:
+<p>
+
+<b> Printer Name:</b> The name of the printer as specified during printer
+installation.
+<p>
+
+<b> Printer Server:</b> The name of the printer server for the printer
+specified in the Printer Name column.
+<p>
+
+<b> Description:</b> A description of the printer as specified during
+printer installation (New Attached Printer or New Network
+Printer) or modification (Modify Printer Properties). The
+description might include the location of the printer and its printer
+type.
+
+<p>
+
+The footer panel at the bottom of the window has two or three entries:
+
+<p>
+
+<b> Default Printer: </b> If no naming service is being used, the
+default printer for the computer on which you are running Oracle Solaris
+Print Manager. If a naming service is being used, the default printer
+for the naming service.
+
+<p>
+
+<b> Naming Service: </b> The naming service -- NIS or LDAP --
+that is being used for printing. This is not displayed if no naming
+service is being used.
+
+<p>
+
+<b> Domain or Host: </b> The network domain you are working in or the
+current host (if no naming service is being used). If you are
+using a naming service, the list of printers includes all printers in
+this domain.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+"Print Manager menu" "Printer menu" "Tools menu" "Help menu" "list
+of printers" printers "printer name" "printer server" description
+"default printer" "naming service" domain Oracle solaris print manager main
+window
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+Overview
+ToAddAccess
+ToInstallLocal
+ToInstallNetwork
+ToModify
+ToDelete
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/Modify.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/Modify.rawhlp
new file mode 100644
index 0000000000..019f379c43
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/Modify.rawhlp
@@ -0,0 +1,167 @@
+<TITLE> Dialog: Modify Printer Properties </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=Modify -->
+
+<CONTENT>
+
+<p>
+
+Use the Modify Printer Properties dialog to modify an installed
+printer. Note that you can modify the Description field only if this
+is not an attached printer. You can also check or uncheck the Default
+Printer box.
+
+<p>
+
+<b> Printer Name:</b> Cannot be modified.
+
+<p>
+
+<b> Printer Server:</b> Cannot be modified.
+This is the computer you have selected to act
+as the server for print actions. You must be logged on to this
+computer and be running Oracle Solaris Print Manager on it.
+
+<p>
+
+<b> Description:</b>
+ [Optional] Describes the printer, including the printer type and
+ location, possibly, or provides other information about the
+ printer.
+
+<p>
+
+<b> Printer Port:</b> Cannot be modified.
+Specifies the hardware port, such as /dev/term/a, that the printer is
+connected to.
+
+<p>
+
+<b> Printer Type:</b>
+ Specifies the generic name for a type of
+ printer. Supported printer types correspond to
+ items listed in the /usr/share/lib/terminfo
+ directories. Examples are PostScript, Daisy, and Diablo.
+
+<p>
+
+<b> File Contents:</b>
+ Specifies the format of files that can be
+ printed without any special filtering by the
+ print software. PostScript is the default and is
+ probably correct most of the time.
+<p>
+
+<b> Fault Notification:</b>
+ Specifies how the superuser will be notified in
+ case of a printer error.
+
+<p>
+
+<b> Options: Default Printer:</b> If checked, designates this printer
+as the default printer for printing jobs from the computer on which
+you are running Oracle Solaris Print Manager. If you are using a naming
+service, this printer will be the default printer for the naming
+service, also.
+
+<p>
+
+Note that this is the last place the print subsystem looks to
+determine where a particular print job will be printed; the
+destination option of the lp command is the first place looked, and
+other environment variables are checked before this one. See the man
+page for printers.conf(4) for a full explanation of the search order.
+
+<p>
+
+<b> Options: Banner:</b> Specifies whether a banner
+page will be printed between jobs.
+<br>
+<br>
+"Aways Print Banner" stipulates that a banner will always be printed
+and may not be turned off by the user.
+<br>
+"User Selectable - Default=on" stipulates that a banner will be printed
+unless the user selects
+to turn the banner off.
+<br>
+"Never Print Banner" stipulates that a banner will never be printed
+and may not be turned on by the user.
+
+<p>
+
+<b> User Access List:</b>
+Specifies the print clients that can
+ print to this printer. By default, all print
+ clients have access to this printer, as designated by the word
+"all" in the list.
+
+<p>
+
+If you want to restrict its use to individual users, enter a user name
+in the text field below the list and click Add. Other legal constructs
+are system-name!login-ID (user "login-ID" on system "system-name"),
+system-name!all (all users on system "system-name"), and all!login-ID
+(user "login-ID" on all systems). Use the lpadmin(1M) command to deny
+access to users.
+
+<p>
+
+To delete a user from the list, select the user in the list and click
+Delete.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+</CONTENT>
+
+<KEYWORDS> modify properties "printer properties" "attached printer"
+"printer name" server description port "printer type" "file contents"
+fault "fault notification" "default printer" banner "attached printer"
+new nobanner dialog: printer
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToModify
+ModifyFailed
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ModifyFailed.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ModifyFailed.rawhlp
new file mode 100644
index 0000000000..97a59c6a46
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ModifyFailed.rawhlp
@@ -0,0 +1,62 @@
+<TITLE> If Modify Printer Fails</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+--
+-- ident "%Z%%M% %I% %E% SMI"
+-->
+<!-- Tag=ModifyFailed -->
+
+<CONTENT>
+
+<p>
+
+An attempt to modify printer properties failed. It is possible that
+someone has deleted the printer before this modify operation completed.
+
+<p>
+
+Display the Command-Line Console to help pinpoint where the error
+may have occurred. Choose Show Command-Line Console from the Print
+Manager menu to display the Command-Line Console. See the man page for
+lpadmin(1M) for further information.
+
+</CONTENT>
+
+<p>
+
+<KEYWORDS>
+modify "modify printer" fail failure printer fails
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToModify
+Modify
+ToShowCommand
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ModifyPPD.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ModifyPPD.rawhlp
new file mode 100644
index 0000000000..6399b8ac94
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ModifyPPD.rawhlp
@@ -0,0 +1,176 @@
+<TITLE> Dialog: Modify Printer Properties </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ModifyPPD -->
+
+<CONTENT>
+
+<p>
+
+Use the Modify Printer Properties dialog to modify an installed
+printer. Note that you can modify the Description field only if this
+is not an attached printer. You can also check or uncheck the Default
+Printer box.
+
+<p>
+
+<b> Printer Name:</b> Cannot be modified.
+
+<p>
+
+<b> Printer Server:</b> Cannot be modified.
+This is the computer you have selected to act
+as the server for print actions. You must be logged on to this
+computer and be running Oracle Solaris Print Manager on it.
+
+<p>
+
+<b> Description:</b>
+ [Optional] Describes the printer, including the printer type and
+ location, possibly, or provides other information about the
+ printer.
+
+<p>
+
+<b> Printer Port:</b> Cannot be modified.
+Specifies the hardware port, such as /dev/term/a, that the printer is
+connected to.
+
+<p>
+
+<b> Printer Make:</b>
+ Specifies the printer make, or manufacturer. This
+ information is on the printer and/or in the documentation
+ that is delivered with the printer.
+
+<p>
+
+<b> Printer Model:</b>
+ Specifies the printer model. This information
+ is found on the printer and/or in the documentation that is
+ delivered with the printer.
+<p>
+
+<b> Printer Driver:</b>
+ Specifies the printer driver to use with this printer. The label
+ name followed in parentheses by one of the following letters
+representing the repository in which the printer driver information resides:
+U (user supplied printer information), A (administrator supplied printer
+information), V (vendor supplied printer information), or S (system supplied
+printer information), precedes the name of the Printer Driver.
+<p>
+
+
+<b> Fault Notification:</b>
+ Specifies how the superuser will be notified in
+ case of a printer error.
+
+<p>
+
+<b> Options: Default Printer:</b> If checked, designates this printer
+as the default printer for printing jobs from the computer on which
+you are running Oracle Solaris Print Manager. If you are using a naming
+service, this printer will be the default printer for the naming
+service, also.
+
+<p>
+
+Note that this is the last place the print subsystem looks to
+determine where a particular print job will be printed; the
+destination option of the lp command is the first place looked, and
+other environment variables are checked before this one. See the man
+page for printers.conf(4) for a full explanation of the search order.
+
+<p>
+
+<b> Options: Banner:</b> Specifies whether a banner
+page will be printed between jobs.
+<br>
+<br>
+"Aways Print Banner" stipulates that a banner will always be printed
+and may not be turned off by the user.
+<br>
+"User Selectable - Default=on" stipulates that a banner will be printed
+unless the user selects
+to turn the banner off.
+<br>
+"Never Print Banner" stipulates that a banner will never be printed
+and may not be turned on by the user.
+
+<p>
+
+<b> User Access List:</b>
+Specifies the print clients that can
+ print to this printer. By default, all print
+ clients have access to this printer, as designated by the word
+"all" in the list.
+
+<p>
+
+If you want to restrict its use to individual users, enter a user name
+in the text field below the list and click Add. Other legal constructs
+are system-name!login-ID (user "login-ID" on system "system-name"),
+system-name!all (all users on system "system-name"), and all!login-ID
+(user "login-ID" on all systems). Use the lpadmin(1M) command to deny
+access to users.
+
+<p>
+
+To delete a user from the list, select the user in the list and click
+Delete.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+</CONTENT>
+
+<KEYWORDS> modify properties "printer properties" "attached printer"
+"printer name" server description port "printer make" "printer model"
+"printer driver" fault "fault notification" "default printer" banner
+"attached printer"
+new nobanner dialog: printer
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToModify
+ModifyFailed
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/NISAuthentication.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/NISAuthentication.rawhlp
new file mode 100644
index 0000000000..6294176d9b
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/NISAuthentication.rawhlp
@@ -0,0 +1,97 @@
+<TITLE> NIS Authentication</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=NISAuthentication -->
+
+<CONTENT>
+
+<p>
+
+If you are using the NIS naming service, you will need the root
+password for the NIS master computer to make any changes. The NIS
+Authentication dialog is displayed when you select NIS as the
+naming service.
+
+<p>
+
+1. Enter the password for the NIS master.
+
+<p>
+
+2. Click OK.
+
+<p>
+
+The entries you have made will be saved and the NIS Authentication
+dialog will be dismissed.
+
+<p>
+
+Click Cancel if you don't know the password for the NIS master.
+
+<p>
+
+<b>Note:</b> Keep the following in mind if you are using Oracle Solaris Print
+Manager to update printer information in the NIS name service:
+
+<p>
+
+- If your network is set up with NIS master and slave servers,
+the NIS slaves may not see the updated printer information
+until the NIS slaves are updated. See ypmake(1M) for more
+information.
+
+<p>
+
+- If your NIS servers are running Oracle Solaris 2.5 and compatible
+versions, you must have explicit permissions on the NIS master
+server to update the maps. This means an entry for your system
+name must reside in root's .rhosts file on the NIS master server.
+
+<p>
+
+- If you have modified the yp makefile to use something other
+than /etc/printers.conf as the source for the NIS map,
+printers.conf.byname, do not use Oracle Solaris Print Manager to modify NIS.
+
+</CONTENT>
+
+<p>
+
+<KEYWORDS>
+
+NIS "NIS master" master authentication login password naming "naming
+service" files .rhosts
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+NameService
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/NameService.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/NameService.rawhlp
new file mode 100644
index 0000000000..885356086f
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/NameService.rawhlp
@@ -0,0 +1,155 @@
+<TITLE> About Naming Services </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+-->
+<!-- Tag=NameService -->
+
+<CONTENT>
+
+<p>
+
+You can select "files" or a naming service (NIS or LDAP) when you
+start up Oracle Solaris Print Manager or when you choose Select Naming
+Service from the Print Manager menu. See the descriptions of each
+of the choices below.
+
+<p>
+
+Once you select a naming service, Print Manager will retrieve and update
+printer information in the database for the specified naming service
+when you add, modify, or delete a printer. Note that in addition to
+the naming service map, when updating attached or network printers
+the file /etc/printers.conf is also updated when a naming service
+is being used.
+
+<p>
+
+When you make a remote printer accessible by choosing Add Access to
+Printer from the Printer menu, either the naming service map is
+updated or /etc/printers.conf is updated (if "files" is selected and
+no naming service is being used).
+
+<p>
+
+<b>files</b>: Retrieve or update printer information from
+the file /etc/printers.conf.
+
+<p>
+
+<b>NIS</b>: Use the printers.conf.byname map stored in the Network
+Information Service for retrieving or updating printer information.
+See the ypserv(1M) man page for more information.
+
+<p>
+
+<b>Note: </b>When a site is set up with a NIS master and slaves, if the
+host binds to a slave, a user may not see NIS updates made through
+Print Manager until the slave computers are updated. See the ypmake(1M)
+man page for more information.
+
+<p>
+
+<b>LDAP</b>: Use the printers map stored in the LDAP
+naming service for retrieving or updating printer information.
+See the ldap(1) man page for more information.
+
+<p>
+
+To used the LDAP naming service the host computer must be configured as a
+LDAP client, see ldapclient(1M).
+
+<p>
+
+<b>Note:</b>If the host binds to a replica LDAP server, a user may not see
+updates made through Print Manager until the replica is updated from the master
+LDAP server.
+
+<p>
+
+The following privileges are needed for each naming service:
+
+<p>
+
+<b>For files:</b>
+
+<p>
+
+The tool must be started as root.
+
+<p>
+
+<b>For NIS:</b>
+
+<p>
+
+1) The tool must be started as root.
+
+<p>
+
+2) The password for the NIS master will be required when you select
+this naming service.
+
+<p>
+
+3) For NIS servers running pre-2.6 Oracle Solaris, you need to set up an
+rhosts entry on the NIS server allowing root on the print server root
+access on the NIS server. You must have explicit permissions on the
+NIS master server to update the maps. This means an entry for your
+host name must reside in root's .rhosts file on the NIS master server.
+See the hosts.equiv(4) man page for more information.
+
+<p>
+
+<b>For LDAP:</b>
+
+<p>
+
+1) The tool must be started as root.
+
+<p>
+
+2) A fully distinguished name (DN) with update privilege and password will
+ be required when you select this naming service.
+
+<p>
+
+</CONTENT>
+
+<p>
+
+<KEYWORDS>
+
+"name service" "naming service" name naming nis none ldap
+keylogin printers.conf service files
+hosts.equiv nisgrpadm about services
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToStart
+ToSelectName
+Overview
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/Overview.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/Overview.rawhlp
new file mode 100644
index 0000000000..361c3580e5
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/Overview.rawhlp
@@ -0,0 +1,122 @@
+<TITLE> Overview </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=Overview -->
+
+<CONTENT>
+
+<p>
+
+Use Oracle Solaris Print Manager to select a naming service, to install attached
+or network printers, and to add, modify, or remove access to installed
+printers. Five windows or dialogs and 11 tasks -- listed below -- are described
+in the help volume. To view one of the help articles, select it
+in the See also pulldown menu and click the Show button.
+
+<p>
+
+If you need more information about printing, see the "Oracle Solaris Print
+Manager Administration Guide" AnswerBook or the "Setting Up Printers"
+chapter in the Oracle Solaris System Administrator AnswerBook.
+
+<p>
+
+<b> Windows and Dialogs </b>
+<p>
+Main Window
+<br>
+Add Access to Printer
+<br>
+New Attached Printer
+<br>
+New Network Printer
+<br>
+Modify Printer Properties
+
+<p>
+<b>Tasks</b>
+<p>
+To Start Oracle Solaris Print Manager
+<br>
+To Add Access to an Installed Printer
+<br>
+To Install an Attached Printer
+<br>
+To Install a Network Printer
+<br>
+To Modify Printer Properties
+<br>
+To Delete a Printer
+<br>
+To Select a Naming Service
+<br>
+To Exit Oracle Solaris Print Manager
+<br>
+To Find a Printer
+<br>
+To Show the Command-Line Console
+<br>
+To Confirm All Actions
+<p>
+
+<b>More About Printing and Oracle Solaris Print Manager </b>
+
+<p>
+
+If you need more information about printing or about Oracle Solaris Print
+Manager, including a description of mouseless navigation, see the
+"Oracle Solaris Print Manager Administration Guide" AnswerBook or the
+"Setting Up Printers" chapter in the Oracle Solaris System Administrator
+AnswerBook.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+overview contents task dialog
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+MainWindow
+AddAccess
+InstallLocal
+InstallNetwork
+Modify
+ToAddAccess
+ToStart
+ToInstallLocal
+ToInstallNetwork
+ToModify
+ToDelete
+ToSelectName
+ToExit
+ToFindPrinter
+ToShowCommand
+ToConfirmActions
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrintManagerSettings.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrintManagerSettings.rawhlp
new file mode 100644
index 0000000000..de175c0b7d
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrintManagerSettings.rawhlp
@@ -0,0 +1,111 @@
+<TITLE> Print Manager Settings </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=Overview -->
+
+<CONTENT>
+
+<p>
+
+The Oracle Solaris Print Manager has tool-wide settings that may be selected.
+Each of these choices applies to all further tasks utilized within the
+Oracle Solaris Print Manager. For example, once Show Command-Line Console has been
+selected, or checked, the Console will be visible for all tasks until
+this selection is turned off, or unchecked.
+
+
+<p>
+
+<b> Show Command-Line Console: </b>
+The Command-Line Console displays the command-line version of add, modify,
+delete actions. Errors and warnings may also be displayed after the
+command.
+
+<p>
+The default is off.
+
+<p>
+
+<b> Confirm All Actions: </b>
+When Confirm All Actions is selected, all subsequent Oracle Solaris Print
+Manager actions will require confirmation before being performed.
+
+<p>
+The default is off.
+
+<p>
+<b> Use PPD files: </b>
+When configuring local printers, PPD files may be used to describe the
+printer. If selected, the New Attached Printer and New Network Printer
+screens offer the selection of printer Make, Model, and Printer Driver
+from matching PPD files. Duplicate entries may be displayed from
+PPD files in different labels within different PPD file repositories
+that represent suppliers of the PPD files. Thus, the label name
+associated with the PPD file, and one of the following letters,
+within parentheses, representing the repository in which the printer
+driver information resides: U (user supplied printer information),
+A (administrator supplied printer information), V (vendor supplied
+printer information), or S (system supplied printer information),
+precedes the name of the Printer Driver.
+
+<p>
+The default is on.
+
+<p>
+<b> Use localhost for Print Server Name: </b>
+
+The print server name utilized by the Oracle Solaris Print System may be
+either the hostname or "localhost". This applies to the tasks for adding
+new local printers in the "files" Name Service: New Attached Printer
+and New Network Printer. The use of "localhost" is recommended.
+
+<p>
+The default is on.
+<p>
+
+Documentation about Printing Services is found in the System Administration
+Guide: Advanced Administration.
+
+</CONTENT>
+
+<KEYWORDS>
+confirm action all actions "command-line" log console show "local printer"
+"printer model" "printer driver" "printer make" localhost hostname
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+Overview
+MainWindow
+ShowCommandConsole
+ToConfirmActions
+ToShowCommand
+InstallLocalPPD
+InstallNetworkPPD
+ToExit
+HelpOnHelp
+
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrinterPort.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrinterPort.rawhlp
new file mode 100644
index 0000000000..23d11c054f
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrinterPort.rawhlp
@@ -0,0 +1,67 @@
+<TITLE> Specify Printer Port </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+--
+-- ident "%Z%%M% %I% %E% SMI"
+-->
+<!-- Tag=PrinterPort -->
+
+<CONTENT>
+
+<p>
+
+The printer port is the device name (typically, /dev/term/a,
+/dev/term/b, or /dev/bpp0) corresponding to the port to which a
+locally attached printer is physically connected. You usually connect
+printer cables to a serial port (/dev/term/a or /dev/term/b, for
+example) but in some cases you can use a parallel port (/dev/bpp0, for
+example). See the printer vendor's documentation and your system's
+installation documentation for information about switch settings and
+cabling requirements.
+
+<p>
+
+Note that the device name must exist and have write permissions
+set.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+port "printer port" other specify printer
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+InstallLocal
+ToInstallLocal
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
+
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrinterType.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrinterType.rawhlp
new file mode 100644
index 0000000000..5ef9a49fce
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/PrinterType.rawhlp
@@ -0,0 +1,64 @@
+<TITLE> Specify Printer Type </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+--
+-- ident "%Z%%M% %I% %E% SMI"
+-->
+<!-- Tag=PrinterType -->
+
+<CONTENT>
+
+<p>
+
+When you configure a printer, you must identify the manufacturer
+and model of the printer in a way that the LP print service
+understands the printer type. Examples are PostScript, Daisy, and Diablo.
+
+<p>
+
+If you have a PostScript printer, for example, select PostScript as
+the Printer Type. To install a printer type that is not listed select
+Other. The printer type you enter must correspond to an entry in the
+/usr/share/lib/terminfo directories. See the terminfo(4) man page for
+more information.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+"printer type" type specify printer
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+InstallLocal
+InstallNetwork
+ToInstallLocal
+ToInstallNetwork
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/RemoteServer.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/RemoteServer.rawhlp
new file mode 100644
index 0000000000..2188adb1c1
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/RemoteServer.rawhlp
@@ -0,0 +1,53 @@
+<TITLE> Specify Remote Server </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License, Version 1.0 only
+ (the "License"). You may not use this file except in compliance
+ with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+-- Use is subject to license terms.
+--
+-- ident "%Z%%M% %I% %E% SMI"
+-->
+<!-- Tag=RemoteServer -->
+
+<CONTENT>
+
+<p>
+
+A printer server must be specified; the printer server is the computer
+on which the software for the remote printer is installed.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+remote "remote printer" server "printer server" fail failure specify
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+AddAccess
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ShowCommandConsole.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ShowCommandConsole.rawhlp
new file mode 100644
index 0000000000..26b00dc463
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ShowCommandConsole.rawhlp
@@ -0,0 +1,84 @@
+<TITLE> Command-Line Console</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ShowCommandConsole -->
+
+<CONTENT>
+
+<p>
+
+The Command-Line Console displays the command-line version of add,
+modify, and delete actions. Errors and warnings may also be
+displayed after the command.
+
+<p>
+
+For example, if you choose Add Access to Printer from the Print
+Manager menu and enter Printer Name = MyPrinter, Printer Server =
+PrintServer2, Description = Local Printer, the Command-line Console
+will display:
+
+<p>
+
+Add Access to printer
+<br>
+% /usr/sbin/lpadmin -p MyPrinter -s PrintServer2 -D "Local Printer"
+
+<p>
+
+The Command-line Console is displayed if the Show Command-Line Console box
+is checked in the Print Manager menu.
+
+<p>
+
+<b>Note: </b>When updating the NIS naming service, there are some
+cases where there is no command line equivalent for what Oracle Solaris Print
+Manager is doing. In these cases what gets reported to the
+Command-Line console is: "rsh [nis_master] ..." or
+"rexec([nis_master]) ..."
+
+<p>
+
+<b>Note: </b>When updating the LDAP naming service, the Oracle Solaris Print
+Manager uses native (or compiled) code to process updates. This
+is done to enhance security related to the LDAP password. The command-line
+used to update the LDAP database is not displayed for security reasons, but
+the log will include the entry "ldap ..." to indicate that the LDAP database
+has been updated.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+"command-line" log command console show
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+Overview
+MainWindow
+ToShowCommand
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToAddAccess.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToAddAccess.rawhlp
new file mode 100644
index 0000000000..d1c994ae88
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToAddAccess.rawhlp
@@ -0,0 +1,141 @@
+<TITLE>To Add Access to an Installed Printer</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToAddAccess -->
+
+<CONTENT>
+
+<p>
+
+Do the following to make an installed printer accessible to print
+client computers. See the printers.conf(4) man page for more
+information about print client commands.
+
+<p>
+
+<b>Note:</b> If you are using a naming service, use this procedure to
+add access to a private printer (one that is not listed in the naming
+service) or to make the printer usable even if the naming service
+server is down. This adds access for all users in the naming service
+domain; see the man page for domainname(1M) for more information about
+domains.
+
+<p>
+
+If a naming service is not being used for printing, use this procedure
+to add access to a remote printer.
+
+<p>
+
+1. Choose Add Access to Printer from the Printer menu.
+
+<p>
+
+ The Add Access To Printer dialog is displayed.
+
+<p>
+
+2. Enter a printer name, printer server name, and description (optional).
+
+<p>
+
+Note that Oracle Solaris Print Manager does not check for the validity of
+Printer Name or Printer Server.
+
+<p>
+
+3. Click Default Printer if you want this printer to be the default
+printer.
+
+<p>
+
+If a naming service is being used, this printer will be designated as
+the default printer for all users in the domain.
+
+<p>
+
+If no naming service is being used, this printer will be designated as
+the default printer for the computer on which you are running Oracle Solaris
+Print Manager.
+
+<p>
+
+Note that this is the last place the print commands will look to
+determine the printer for a specific print command; see the
+man page for printers.conf(4) for more information about resolving
+printer conflicts.
+
+<p>
+
+4. Click OK or Apply to add access for the specified printer.
+
+<p>
+
+<b> Note:</b> If you are using the NIS naming service, you have to know the
+root password for the NIS master. If you are using the LDAP naming service,
+you must know a fully distinguished name which has update privilege and
+the corresponding password. Default values may need to be overridden. You
+will be prompted for the password when you click Apply or OK. Enter the
+password and click OK.
+
+<p>
+ The list of printers displayed in the Oracle Solaris Print Manager main window
+ is updated to include the new printer.
+<p>
+ The Add Access dialog will remain displayed if you click Apply,
+allowing you to add access to additional printers.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+access "add access" description "default printer" "naming service"
+"printer name" "printer server" add installed printer
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+AddAccess
+ToModify
+ToDelete
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
+
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToConfirmActions.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToConfirmActions.rawhlp
new file mode 100644
index 0000000000..af9d31a9ac
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToConfirmActions.rawhlp
@@ -0,0 +1,66 @@
+<TITLE> To Confirm All Actions </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToConfirmActions -->
+
+<CONTENT>
+
+<p>
+
+Do the following to require that all Oracle Solaris Print Manager actions be
+confirmed before being executed, or to turn off this option.
+
+<p>
+
+1. Choose Confirm All Actions from the Print Manager menu.
+
+<p>
+
+If the Confirm All Actions box was not checked, it will be checked
+and all subsequent Oracle Solaris Print Manager actions will require
+confirmation before being performed.
+
+<p>
+
+If the Confirm All Actions box was checked, it will no longer be checked
+and subsequent Oracle Solaris Print Manager actions will NOT require
+confirmation before being performed. Note that some actions, such as
+Delete Printer, require confirmation regardless of the setting of the
+Confirm All Actions box.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+confirm action all actions
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToDelete.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToDelete.rawhlp
new file mode 100644
index 0000000000..0842d3046b
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToDelete.rawhlp
@@ -0,0 +1,81 @@
+<TITLE> To Delete a Printer </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToDelete -->
+
+<CONTENT>
+
+<p>
+
+Do the following to delete a printer from the printer list.
+
+<p> 1. Select the printer in the list of printers in the Oracle Solaris
+Print Manager main window.
+
+<p>
+
+2. Choose Delete Printer from the Printer menu.
+
+<p>
+
+A dialog is displayed,
+asking if you really want to delete the selected printer.
+
+<p> <b>Note:</b> If the printer is a local printer (one installed on
+the current server), the printer will be uninstalled; if a naming
+service has been selected, the entry for this printer will also be
+removed from the naming service.
+
+<p>
+3. Click OK to delete the printer.
+<p>
+ A window is displayed asking you to confirm the
+ deletion.
+<p>
+4. Click Delete.
+<p>
+The selected printer is deleted from the Oracle Solaris Print Manager main
+window.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+delete uninstall "local printer" "network printer" "attached printer"
+printer
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToAddAccess
+AddAccess
+MainWindow
+Overview
+HelpOnHelp
+</SEEALSO>
+
+
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToExit.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToExit.rawhlp
new file mode 100644
index 0000000000..2f8ed987fc
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToExit.rawhlp
@@ -0,0 +1,53 @@
+<TITLE> To Exit Oracle Solaris Print Manager </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToExit -->
+
+<CONTENT>
+
+<p>
+
+1. Choose Exit from the Print Manager menu.
+
+<p>
+
+The Oracle Solaris Print Manager main window and any other open Print Manager
+dialogs are closed.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+exit close Oracle solaris print manager
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToStart
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToFindPrinter.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToFindPrinter.rawhlp
new file mode 100644
index 0000000000..1f8f54b42d
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToFindPrinter.rawhlp
@@ -0,0 +1,68 @@
+<TITLE> To Find a Printer </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToFindPrinter -->
+
+<CONTENT>
+
+<p>
+
+Do the following to find a printer in the Oracle Solaris Print Manager list
+of printers.
+
+<p>
+
+1. Choose Find Printer from the Tools menu.
+
+<p>
+
+A dialog will be displayed, asking you to enter the name of a printer to find.
+
+<p>
+
+2. Type a printer name in the text field and click Find.
+
+<p>
+
+If the exact printer name is found in the list, it will be selected;
+the list will scroll, if necessary. If the printer is not found, a
+message will be displayed, indicating that the named printer was not
+found in the current list.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+find "printer name" tool printer
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToInstallLocal.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToInstallLocal.rawhlp
new file mode 100644
index 0000000000..ce6cc22764
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToInstallLocal.rawhlp
@@ -0,0 +1,176 @@
+<TITLE> To Install an Attached Printer </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToInstallLocal -->
+
+<CONTENT>
+
+<p>
+
+Once you have physically connected the printer to the printer server,
+do the following to install the printer, which makes the printer
+available for printing from the computer on which you are running
+Oracle Solaris Print Manager.
+
+<p>
+
+<b> Note:</b> The computer on which you are running Oracle Solaris Print
+Manager becomes the printer server for the printer being installed.
+
+<p>
+
+1. Choose New Attached Printer from the Printer menu.
+
+<p>
+
+The New Attached Printer dialog will be displayed.
+
+<p>
+
+2. Enter a name in Printer Name.
+<p>
+
+3. [Optional] Enter a description of the printer.
+
+<p>
+This might include the location and the type of printer.
+
+<p>
+4. Select a port from the Printer Port pulldown menu.
+
+<p>
+This is the hardware port where the printer is plugged into the
+server. If you choose Other, a dialog will pop up asking you to
+specify a port. Enter a port and click OK.
+
+<p>
+5. Select a printer type from the Printer Type pulldown menu.
+
+<p>
+
+Scroll the list if necessary. If the printer type is not in the list,
+select Other; you will be asked to specify a printer type. Enter a
+printer type and click OK.
+
+<p>
+6. Select an item in the File Contents pulldown menu.
+
+<p>
+Choices include PostScript and ASCII; the default is PostScript, which
+will work in most cases.
+
+<p>
+7. Select an item in the Fault Notification pulldown menu.
+
+<p>
+
+The default is Write to Superuser.
+
+<p>
+8. [Optional] Click Default Printer if you want this printer to be the default
+printer for this server.
+
+<p>
+
+9. [Optional] Select option to define whether a banner
+page is to be printed between jobs. "Always Print Banner"
+specifies that a banner will be printed and the user may not specify
+otherwise. "User Selectable - Default=on" specifies that the user may
+specify to turn off the banner in the print command; if the user does
+not specify, the banner will be printed. "Never Print Banner" specifies
+that a banner will not be printed and the user may not specify
+otherwise. The default action is to always print the banner.
+
+<p>
+
+10. Modify the User Access List, if necessary.
+
+<p>
+
+The default value is "all," meaning that anyone can use this printer.
+If you want to restrict its use to individual users, enter a user name
+in the text field below the list and click Add. Other legal constructs
+are system-name!login-ID (user "login-ID" on system "system-name"),
+system-name!all (all users on system "system-name"), and all!login-ID
+(user "login-ID" on all systems). Use the lpadmin(1M) command to deny
+access to users.
+
+<p>
+
+To remove a name from the list, select it and click Delete.
+
+<p>
+
+<b> Note:</b> If you enter "all" or "none" in the text field and click
+Add, all individual user names will be deleted from the list and
+replaced by "all" or "none."
+
+<p>
+11. Click OK or Apply to install the printer.
+
+<p>
+The window will remain if you click Apply, allowing you to install
+additional printers.
+
+<p>
+
+<b> Note:</b> If you are using the NIS naming service, you have to know
+the root password for the NIS master. If you are using the LDAP naming
+service you must know a fully distinguished name which has update
+privilege and the corresponding password. Default values may need to be
+overridden. You will be prompted for the password when you click Apply or OK.
+Enter the password and click OK.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+install "local printer" "printer name" server description port
+"printer type" "file contents" fault "fault notification" "default
+printer" banner nobanner "attached printer" new attached printer
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+InstallLocal
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToInstallNetwork.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToInstallNetwork.rawhlp
new file mode 100644
index 0000000000..60c41b168d
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToInstallNetwork.rawhlp
@@ -0,0 +1,181 @@
+<TITLE> To Install a Network Printer </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToInstallNetwork -->
+
+<CONTENT>
+
+<p>
+
+Once you have physically connected the printer to the network,
+do the following to install the printer, which makes the printer
+available for printing from the network.
+
+<p>
+
+<b> Note:</b> The computer on which you are running Oracle Solaris Print
+Manager becomes the printer server for the printer being installed.
+
+<p>
+
+1. Choose New Network Printer from the Printer menu.
+
+<p>
+
+The New Attached Printer dialog will be displayed.
+
+<p>
+
+2. Enter a name in Printer Name.
+
+<p>
+
+3. [Optional] Enter a description of the printer.
+
+<p>
+This might include the location and the type of printer.
+
+<p>
+4. Select a printer type from the Printer Type pulldown menu.
+
+<p>
+
+Scroll the list if necessary. If the printer type is not in the list,
+select Other; you will be asked to specify a printer type. Enter a
+printer type and click OK.
+
+<p>
+5. Select an item in the File Contents pulldown menu.
+
+<p>
+Choices include PostScript and ASCII; the default is PostScript, which
+will work in most cases.
+
+<p>
+6. Select an item in the Fault Notification pulldown menu.
+
+<p>
+
+The default is Write to Superuser.
+
+<p>
+7a. If the printer uses BSD protocol, enter the network name of the printer
+in the Destination field, followed by a colon and the printer-vendor-supplied
+queue name.
+<p>
+7b. If the printer uses TCP protocol, enter the network name of the printer
+in the Destination field, followed by a colon and port number to be used in the
+tcp connection to the printer.
+<p>
+7c. If the printer uses a printer URI, enter the the URI for the printer
+in the Destination field (for example:
+"smb://printer-host/printer-name").
+
+<p>
+8. Select either BSD, TCP, or URI from the Protocol pulldown menu.
+
+<p>
+9. [Optional] Click Default Printer if you want this printer to be the default
+printer for this server.
+
+<p>
+
+10. [Optional] Select option to define whether a banner
+page is to be printed between jobs. "Always Print Banner"
+specifies that a banner will be printed and the user may not specify
+otherwise. "User Selectable - Default=on" specifies that the user may
+specify to turn off the banner in the print command; if the user does
+not specify, the banner will be printed. "Never Print Banner" specifies
+that a banner will not be printed and the user may not specify
+otherwise. The default action is to always print the banner.
+
+<p>
+11. Modify the User Access List, if necessary.
+
+<p>
+
+
+The default value is "all," meaning that anyone can use this printer.
+If you want to restrict its use to individual users, enter a user name
+in the text field below the list and click Add. Other legal constructs
+are system-name!login-ID (user "login-ID" on system "system-name"),
+system-name!all (all users on system "system-name"), and all!login-ID
+(user "login-ID" on all systems). Use the lpadmin(1M) command to deny
+access to users.
+
+<p>
+
+<b> Note:</b> If you enter "all" or "none" in the text field and click
+Add, all individual user names will be deleted from the list and
+replaced by "all" or "none."
+
+<p>
+12. Click OK or Apply to install the printer.
+
+<p>
+The window will remain if you click Apply, allowing you to install
+additional printers.
+
+<p>
+
+<b> Note:</b> If you are using the NIS naming service, you have to know
+the root password for the NIS master. If you are using the LDAP naming
+service, you must know a fully distinguished name which has update privilege
+and the corresponding password. Default values may need to be overridden.
+You will be prompted for the password when you click Apply or OK.
+Enter the password and click OK.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+
+install network "network printer" "printer name" server description
+port "printer type" "file contents" fault "fault notification"
+"default printer" banner destination protocol new bsd tcp printer
+
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+InstallNetwork
+ToAddAccess
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToModify.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToModify.rawhlp
new file mode 100644
index 0000000000..567520e439
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToModify.rawhlp
@@ -0,0 +1,119 @@
+<TITLE> To Modify Printer Properties </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToModify -->
+
+<CONTENT>
+
+<p>
+
+Do the following to modify the properties of an installed printer.
+
+<p>
+
+1. Double-click the printer in the Oracle Solaris Print Manager main window
+<p>
+ OR
+<p>
+ Select the printer in the Oracle Solaris Print Manager main window and choose
+ Modify Printer Properties from the Printer menu.
+<p>
+ The Modify Printer Properties dialog is displayed.
+
+<p>
+2. Modify the printer configuration, as needed.
+<p>
+
+If this is an attached printer (one installed on the computer on which
+you are running Oracle Solaris Print Manager) you can modify the Description,
+Printer Port, Printer Type, File Contents, Fault Notification,
+Options, and User Access List.
+
+<p>
+
+If this is not an attached printer, only the Description field can be
+modified. You can also check or uncheck the Default Printer box.
+
+<p>
+3. Click OK.
+<p>
+
+The changes you made are saved and the Modify Printer Properties
+dialog is dismissed.
+
+<p>
+
+ If you modified the Description field, the new description is
+displayed in the Oracle Solaris Print Manager main window.
+
+<p>
+
+<b> Note:</b> If you are using the NIS naming service, you have to know
+the root password for the NIS master. If you are using the LDAP naming service,
+you must know a fully distinguished name which has update privilege and
+the corresponding password. Default values may need to be overridden.
+You will be prompted for the password when you select the NIS or
+LDAP naming service. Enter the password and click OK.
+
+<p>
+
+<b> Note:</b> To modify the Printer Name or Printer Server field,
+delete the printer and add it with a new printer and/or server name.
+
+<p>
+
+<b>OK:</b> Apply changes and dismiss the window.
+<br>
+<b>Apply:</b> Apply the changes and leave the window displayed.
+<br>
+<b>Reset:</b> Reset all fields to last Apply
+<br>
+<b>Cancel:</b> Dismiss the window.
+<br>
+<b>Help:</b> Display help for the current window or dialog.
+
+<p>
+</CONTENT>
+
+<KEYWORDS>
+modify "Printer menu" "local printer" nis "nis master" "naming service"
+ldap LDAP attached "network printer" local network printer properties
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+Modify
+ModifyFailed
+InstallLocal
+InstallNetwork
+ToInstallLocal
+ToInstallNetwork
+ToAddAccess
+ToDelete
+AddAccess
+MainWindow
+Overview
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToSelectName.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToSelectName.rawhlp
new file mode 100644
index 0000000000..80eebff891
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToSelectName.rawhlp
@@ -0,0 +1,83 @@
+<TITLE> To Select a Naming Service </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToSelectName -->
+
+<CONTENT>
+
+<p>
+
+Do the following to select a naming service for Oracle Solaris Print Manager or
+to change from using a naming service to using no naming service.
+
+<p>
+
+When you select a naming service you are specifying where Oracle Solaris
+Print Manager will retrieve printer information from, and where
+changes made in Print Manager will be made. If a naming service is
+selected, additions and deletions will be made in the printing
+configuration database for the selected naming service. If you choose
+"files," the /etc/printers.conf file will be used to determine which
+printers are available, and changes will be made there.
+
+<p>
+
+1. Choose Select Naming Service from the Print Manager menu.
+
+<p>
+
+A dialog is displayed, asking you to choose a naming service.
+
+<p>
+
+2. Choose a naming service (or "files," if no naming service is to be
+used) and click OK.
+
+<p>
+
+The Oracle Solaris Print Manager main window is displayed, listing all the
+accessible printers, which includes all printers in the selected
+naming service's printer configuration database.
+
+
+<p>
+
+See the man page for printers.conf(4) for more information.
+
+</CONTENT>
+
+<KEYWORDS>
+select "name service" "naming service" name naming service
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+NameService
+ToStart
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToShowCommand.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToShowCommand.rawhlp
new file mode 100644
index 0000000000..ad5324a322
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToShowCommand.rawhlp
@@ -0,0 +1,75 @@
+<TITLE> To Show Command-Line Console</TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToShowCommand -->
+
+<CONTENT>
+
+<p>
+
+Do the following to cause the command-line version of add, modify, and
+delete actions to be displayed in the Oracle Solaris Print Manager
+Command-Line Console -- or to turn off this option if it was
+previously turned on. Errors and warnings may also be
+displayed after the command.
+
+<p>
+
+1. Choose Show Command-Line Console from the Print Manager menu.
+
+<p>
+
+If the Show Command-line Console box was not checked when you chose
+it, it will be checked and the Show Command-line Console will be
+displayed; Oracle Solaris Print Manager actions will be displayed in the
+Console.
+
+<p>
+
+Note that errors and warnings may also appear in the Console, after
+the commands used to complete the action.
+
+<p>
+
+If the Show Command-line Console box was checked when you chose it,
+it will no longer be checked and the Show Command-line Console will be
+closed.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+"command-line" log command show console
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ShowCommandConsole
+Overview
+MainWindow
+HelpOnHelp
+</SEEALSO>
+
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToStart.rawhlp b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToStart.rawhlp
new file mode 100644
index 0000000000..10b238a49f
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/client/raw-help/ToStart.rawhlp
@@ -0,0 +1,81 @@
+<TITLE> To Start Oracle Solaris Print Manager </TITLE>
+<!--
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+-- Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+--
+-->
+<!-- Tag=ToStart -->
+
+<CONTENT>
+
+<p>
+
+If you have installed SUNWppm package, do the following to start
+Oracle Solaris Print Manager. Note that you must be root to run Print
+Manager; if you attempt to launch it from Solaris Management Console
+you will be prompted for the root password.
+
+<p>
+
+1. Double-click the Oracle Solaris Print Manager icon in Solaris Management
+Console
+
+<p>
+
+ OR
+
+<p>
+
+cd to the directory /usr/sadm/admin/bin and as root type ./printmgr
+
+<p>
+
+A dialog is displayed, asking you to choose a naming service.
+
+<p>
+
+2. Choose a naming service (or files, if no naming service is to be
+used) and click OK.
+
+<p>
+
+The Oracle Solaris Print Manager main window is displayed, listing all the
+printers accessible from the computer on which you are running Oracle Solaris
+Print Manager.
+
+<p>
+
+</CONTENT>
+
+<KEYWORDS>
+start startup load "name service" "naming service" SUNWppm "Solaris Management Console"
+"the Console" Oracle solaris print manager
+</KEYWORDS>
+
+<p>
+
+<SEEALSO>
+ToSelectName
+ToExit
+Mainwindow
+Overview
+HelpOnHelp
+</SEEALSO>
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Debug.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Debug.java
new file mode 100644
index 0000000000..dc0147b093
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Debug.java
@@ -0,0 +1,314 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Debug class
+ */
+
+package com.sun.admin.pm.server;
+
+import java.util.*;
+
+/**
+ * A simple configurable debug logging class.
+ * <p>
+ *
+ * Calling member classes <b>message()</b>, <b>warning()</b>,
+ * <b>error()</b>, and <b>fatal()</b> causes a log entry to be
+ * generated if the current verbosity level is greater than or equal
+ * to the specified severity.
+ * <p>
+ *
+ * Calling <b>setDebugLevel()</b> sets the verbosity level, which is a
+ * threshold of severity below which messages will not be logged. The
+ * verbosity level can be set at any time.
+ * <p>
+ *
+ * For example, setting the verbosity level to <b>Debug.ERROR</b>
+ * means that only <b>error()</b> and <b>fatal()</b> calls will
+ * generate log entries, while setting the level to <b>WARNING</b>
+ * will log <b>warning()</b> calls as well as <b>error()</b> and
+ * <b>fatal()</b> while ignoring <b>message()</b>.
+ * <p>
+ *
+ * Setting the verbosity level to <b>ALL</b> is equivalent to setting
+ * it to <b>MESSAGE</b>; all calls are logged. The constant
+ * <b>NONE</b> suppresses logging of all calls.
+ * <p>
+ *
+ * The verbosity level can be set globally or on a class-by-class
+ * basis. Use the form of <b>setDebugLevel()</b> which takes an
+ * argument of type Object to set the level for all instances of the
+ * specified class.
+ * <p>
+ *
+ * Using the forms of <b>message()</b>, <b>warning()</b>,
+ * <b>error()</b>, and <b>fatal()</b> which accept an argument of type
+ * Object will use the verbosity value associated with the specified
+ * class. If no value has been explicitly set for the class, the
+ * global default will be used.
+ * <p>
+ *
+ * At present log messages are written only to stdout.
+ * An enhancement would be to implement an interface to the syslog facility.
+ */
+
+
+public class Debug {
+
+ /**
+ * Log a highest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void fatal(String s) {
+ printIf(s, FATAL);
+ }
+
+ /**
+ * Log a high-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void error(String s) {
+ printIf(s, ERROR);
+ }
+
+ /**
+ * Log a medium-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void warning(String s) {
+ printIf(s, WARNING);
+ }
+
+ /**
+ * Log a low-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void message(String s) {
+ printIf(s, MESSAGE);
+ }
+
+
+ /**
+ * Log a lowest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void info(String s) {
+ printIf(s, INFO);
+ }
+
+
+ /**
+ * Log a highest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void fatal(Object o, String s) {
+ printIf(o, s, FATAL);
+ }
+
+ /**
+ * Log a high-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void error(Object o, String s) {
+ printIf(o, s, ERROR);
+ }
+
+ /**
+ * Log a medium-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void warning(Object o, String s) {
+ printIf(o, s, WARNING);
+ }
+
+ /**
+ * Log a low-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void message(Object o, String s) {
+ printIf(o, s, MESSAGE);
+ }
+
+ /**
+ * Log a lowest-priority message.
+ * @param String s The message to be logged.
+ */
+ static public void info(Object o, String s) {
+ printIf(o, s, INFO);
+ }
+
+ /**
+ * Set the verbosity level to the specified severity.
+ * @param String s The message to be logged.
+ */
+ static public void setDebugLevel(int lvl) {
+ if (lvl < ALL || lvl > NONE)
+ return;
+
+ globalDebugLevel = lvl;
+ }
+
+ /**
+ * Set the verbosity level to the specified severity.
+ * @param String s The message to be logged.
+ */
+ static public void setDebugLevel(Object o, int lvl) {
+ if (lvl < ALL || lvl > NONE)
+ return;
+
+ classDB.put(o.getClass(), new Integer(lvl));
+
+ /*
+ * System.out.println("Debug: class " + o.getClass().getName() +
+ * " level = " + classDB.get(o.getClass()));
+ */
+ }
+
+ static public void setDebugLevel(String classname, int lvl) {
+ if (lvl < ALL || lvl > NONE)
+ return;
+
+ try {
+ classDB.put(Class.forName(classname), new Integer(lvl));
+ } catch (Exception x) {
+ System.out.println("setDebugLevel: " + x);
+ }
+ }
+
+
+ private static void printIf(String s, int lvl) {
+ if (lvl < globalDebugLevel)
+ return;
+ debugPrint(s);
+ }
+
+ private static void printIf(Object o, String s, int lvl) {
+ if (lvl < getLevelForClass(o))
+ return;
+ debugPrint(s);
+ }
+
+
+ /*
+ * get debug level for o's class, if already there
+ * otherwise create an entry for o and set it to the global level
+ */
+ private synchronized static int getLevelForClass(Object o) {
+ int lvl = globalDebugLevel;
+ Object g;
+ if ((g = classDB.get(o.getClass())) != null)
+ lvl = ((Integer) g).intValue();
+ else
+ classDB.put(o.getClass(), new Integer(lvl));
+
+ /*
+ * System.out.println("Debug: getLevelForClass " +
+ * o.getClass().getName() +
+ * " = " + lvl);
+ */
+
+ return lvl;
+ }
+
+ // here is where we could hide syslog or file destination...
+ private static void debugPrint(String s) {
+ System.out.println(s); // for now
+ }
+
+ Object theInstance = null;
+
+ public Debug(Object o) {
+ theInstance = o;
+ }
+
+ public void SetDebugLevel(int lvl) {
+ if (lvl < ALL || lvl > NONE)
+ return;
+ setDebugLevel(theInstance, lvl);
+ }
+
+ public void Fatal(String s) {
+ fatal(theInstance, s);
+ }
+
+ public void Warning(String s) {
+ warning(theInstance, s);
+ }
+
+ public void Error(String s) {
+ error(theInstance, s);
+ }
+
+ public void Message(String s) {
+ message(theInstance, s);
+ }
+
+ public void Info(String s) {
+ info(theInstance, s);
+ }
+
+ /*
+ * Verbosity level to suppress all messages.
+ */
+ static public final int NONE = 6;
+
+ /*
+ * Verbosity level to log only highest-priority messages.
+ */
+ static public final int FATAL = 5;
+
+ /*
+ * Verbosity level to log high- and highest-priority messages.
+ */
+ static public final int ERROR = 4;
+
+ /*
+ * Verbosity level to log medium-, high-, and highest-priority messages.
+ */
+ static public final int WARNING = 3;
+
+ /*
+ * Verbosity level to log low-, medium-, high-, and
+ * highest-priority messages.
+ */
+ static public final int MESSAGE = 2;
+
+ /*
+ * Verbosity level to log lowest-, low-, medium-, high-, and
+ * highest-priority messages.
+ */
+ static public final int INFO = 1;
+
+
+ /*
+ * Verbosity level to log all messages.
+ */
+ static public final int ALL = 0;
+
+ private static int globalDebugLevel = FATAL;
+ private static Hashtable classDB = new Hashtable();
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterAdd.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterAdd.java
new file mode 100644
index 0000000000..287b0a328b
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterAdd.java
@@ -0,0 +1,552 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * DoPrinterAdd class
+ * Worker class for adding local and remote printers.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+import java.util.*;
+
+public class DoPrinterAdd {
+
+ public static void main(String[] args) {
+ //
+ // Set attributes for testing
+ //
+ NameService ns = new NameService();
+
+ String file_contents[] = new String[1];
+ file_contents[0] = "any";
+ String user_allow_list[] = new String[1];
+ user_allow_list[0] = "allow1";
+ String user_deny_list[] = new String[1];
+ user_deny_list[0] = "deny1";
+
+ Printer p = new Printer(ns);
+ p.setPrinterName("javatest");
+ p.setPrinterType("PS");
+ p.setPrintServer("zelkova");
+ p.setComment("This is a comment");
+ p.setDevice("/var/tmp/test");
+ p.setNotify("none");
+ p.setProtocol("bsd");
+ p.setDestination(null);
+ p.setFileContents(file_contents);
+ p.setUserAllowList(user_allow_list);
+ p.setIsDefaultPrinter(false);
+ p.setBanner("never");
+ p.setEnable(true);
+ p.setAccept(true);
+ p.setLocale(null);
+
+ try {
+ add(p, ns);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ System.out.println("Commands:\n" + p.getCmdLog());
+ System.out.println("Errors:\n" + p.getErrorLog());
+ System.out.println("Warnings:\n" + p.getWarnLog());
+ System.exit(0);
+ }
+
+ //
+ // Interface to Printer object.
+ //
+ public static void add(
+ Printer p,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterAdd.add()");
+
+ String device = p.getDevice();
+ if (device == null) {
+ addRemote(p, ns);
+ } else {
+ addLocal(p, ns);
+ }
+ return;
+ }
+
+ //
+ // Do the work of adding a local printer.
+ //
+ private static void addLocal(
+ Printer p,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterAdd.addLocal()");
+
+ int exitvalue = 0;
+ String err = null;
+ String cmd = null;
+ SysCommand syscmd = null;
+
+ // Since it's local set extensions.
+ // Eventually the gui should do this.
+ p.setExtensions("Solaris");
+
+ String printername = p.getPrinterName();
+ String printertype = p.getPrinterType();
+ String printserver = p.getPrintServer();
+ String comment = p.getComment();
+ String device = p.getDevice();
+ String make = p.getMake();
+ String model = p.getModel();
+ String ppd = p.getPPD();
+ String notify = p.getNotify();
+ String protocol = p.getProtocol();
+ String destination = p.getDestination();
+ String[] file_contents = p.getFileContents();
+ String[] user_allow_list = p.getUserAllowList();
+ String[] user_deny_list = p.getUserDenyList();
+ boolean default_printer = p.getIsDefaultPrinter();
+ String banner = p.getBanner();
+ boolean enable = p.getEnable();
+ boolean accept = p.getAccept();
+
+ String nameservice = ns.getNameService();
+ String ppdfile = null;
+
+ //
+ // "uri" is a pseudo protocol and means that the device is
+ // specified in the destination.
+ //
+ if ((protocol != null) && (protocol.equals("uri"))) {
+ device = destination;
+ destination = null;
+ protocol = null;
+ }
+
+ if (ppd != null) {
+ ppdfile = new String(
+ DoPrinterUtil.getPPDFile(make, model, ppd));
+ }
+
+ cmd = "/usr/sbin/lpadmin -p " + printername;
+ if (printserver != null)
+ cmd = cmd.concat(" -s " + printserver);
+ if (device != null) {
+ cmd = cmd.concat(" -v " + device);
+
+ if (device.indexOf("://") != -1)
+ cmd = cmd.concat(" -m uri");
+ else {
+ if (destination != null)
+ cmd = cmd.concat(" -m netstandard");
+ else
+ cmd = cmd.concat(" -m standard");
+ if (ppd != null)
+ cmd = cmd.concat("_foomatic");
+ }
+ }
+ if (printertype != null)
+ cmd = cmd.concat(" -T " + printertype);
+ if (notify != null)
+ cmd = cmd.concat(" -A " + notify);
+ if (ppdfile != null) {
+ cmd = cmd.concat(" -n " + ppdfile);
+ }
+
+
+ if (destination != null)
+ cmd = cmd.concat(" -o dest=" + destination);
+ if (protocol != null)
+ cmd = cmd.concat(" -o protocol=" + protocol);
+ if (banner != null)
+ cmd = cmd.concat(" -o banner=" + banner);
+
+ if ((file_contents != null) && (file_contents.length != 0)) {
+ String tmpstr = file_contents[0];
+ for (int i = 1; i < file_contents.length; i++) {
+ tmpstr = tmpstr.concat("," + file_contents[i]);
+ }
+ cmd = cmd.concat(" -I " + tmpstr);
+ } else {
+ cmd = cmd.concat(" -I postscript");
+ }
+ if ((user_allow_list != null) && (user_allow_list.length != 0)) {
+ String tmpstr = user_allow_list[0];
+ for (int i = 1; i < user_allow_list.length; i++) {
+ tmpstr = tmpstr.concat("," + user_allow_list[i]);
+ }
+ cmd = cmd.concat(" -u allow:" + tmpstr);
+ }
+
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ syscmd = null;
+ p.setErrorLog(err);
+ throw new pmCmdFailedException(err);
+ } else {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+
+ //
+ // lpadmin won't take allow and deny lists together
+ // so do the deny seperately.
+ //
+ if ((user_deny_list != null) && (user_deny_list.length != 0)) {
+ String tmpstr = user_deny_list[0];
+ for (int i = 1; i < user_deny_list.length; i++) {
+ tmpstr = tmpstr.concat("," + user_deny_list[i]);
+ }
+ cmd = "/usr/sbin/lpadmin -p " + printername +
+ " -u deny:" + tmpstr;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ if ((comment != null) && (!comment.equals(""))) {
+ //
+ // Have to use a command array here since
+ // exec(String) doesn't parse quoted strings.
+ //
+ String cmd_array[] =
+ { "/usr/sbin/lpadmin", "-p", printername,
+ "-D", comment };
+ cmd = "/usr/sbin/lpadmin -p " + printername + " -D " +
+ "\"" + comment + "\"";
+ p.setCmdLog(cmd);
+
+ syscmd = new SysCommand();
+ syscmd.exec(cmd_array);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ // If this is the default printer set it.
+ // If it fails warn user.
+ if (default_printer) {
+ cmd = "/usr/sbin/lpadmin -d " + printername;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ // Check to see if we should enable it.
+ // If it fails warn user.
+ if (enable) {
+ cmd = "/usr/bin/enable " + printername;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ // Check to see if we should accept it.
+ // If it fails warn user.
+ if (accept) {
+ cmd = "/usr/sbin/accept " + printername;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ doFilters(p);
+
+ //
+ // Take care of name service now.
+ //
+ if (!nameservice.equals("system")) {
+ try {
+ DoPrinterNS.set("add", p, ns);
+ }
+ catch (Exception e) {
+ p.clearLogs();
+ NameService localns = new NameService();
+ //
+ // Back out the local printer.
+ //
+ try {
+ DoPrinterDelete.delete(p, localns);
+ }
+ catch (Exception e2) {
+ Debug.message("SVR:" + e2.getMessage());
+ }
+ p.clearLogs();
+ throw (e);
+ }
+ }
+ return;
+ }
+
+ //
+ // Do the work of adding a remote printer.
+ //
+ private static void addRemote(
+ Printer p,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterAdd.addRemote()");
+
+ int exitvalue = 0;
+ String err = null;
+ String cmd = "";
+ String cmd_array[] = new String[7];
+ SysCommand syscmd = null;
+
+ String printername = p.getPrinterName();
+ String printserver = p.getPrintServer();
+ String comment = p.getComment();
+ boolean default_printer = p.getIsDefaultPrinter();
+ String nameservice = ns.getNameService();
+
+ boolean isnismaster = false;
+ if (nameservice.equals("nis")) {
+ //
+ // Find out if we are the nis master
+ //
+ String nshost = ns.getNameServiceHost();
+ Host h = new Host();
+ String lh = h.getLocalHostName();
+ if (lh.equals(nshost))
+ isnismaster = true;
+ h = null;
+ }
+
+ //
+ // If the name service is not system and we are
+ // not the nis master then do the name service
+ // update and return.
+ //
+ if ((!nameservice.equals("system")) && (!isnismaster)) {
+ DoPrinterNS.set("add", p, ns);
+ return;
+ }
+
+ cmd_array[0] = "/usr/sbin/lpadmin";
+ cmd_array[1] = "-p";
+ cmd_array[2] = printername;
+ cmd_array[3] = "-s";
+ cmd_array[4] = printserver;
+
+ if ((comment != null) && (!comment.equals(""))) {
+ cmd_array[5] = "-D";
+ cmd_array[6] = comment;
+ }
+
+ //
+ // Fix up cmd so we can log it.
+ //
+ for (int i = 0; i < cmd_array.length; i++) {
+ if (cmd_array[i] == null)
+ continue;
+ if (i == 6) {
+ cmd = cmd.concat("\"" + comment + "\"");
+ continue;
+ }
+ cmd = cmd.concat(cmd_array[i] + " ");
+ }
+
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd_array);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ }
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+
+ // If this is the default printer set it.
+ // If it fails warn user.
+ if (default_printer) {
+ cmd = "/usr/sbin/lpadmin -d " + printername;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ //
+ // If it's nis and we are here then we are the nis
+ // master. This call will do the make for us.
+ //
+ if (nameservice.equals("nis")) {
+ try {
+ DoPrinterNS.set("add", p, ns);
+ }
+ catch (Exception e) {
+ p.clearLogs();
+ try {
+ //
+ // Back out the local printer.
+ //
+ DoPrinterDelete.delete(p, ns);
+ }
+ catch (Exception e2)
+ {
+ Debug.message("SVR:" + e2.getMessage());
+ }
+ p.clearLogs();
+ throw e;
+ }
+ }
+ return;
+ }
+
+
+ //
+ // Configure filters
+ // Look in /etc/lp/fd and configure each filter if it hasn't
+ // already been configured. We'll add warning messages if
+ // there are problems but don't consider anything here fatal.
+ //
+ private static void doFilters(Printer p) throws Exception
+ {
+ Debug.message("SVR: DoPrinterAdd.doFilters()");
+
+ int i = 0;
+ int j = 0;
+ String o = null;
+ String err = null;
+ String cmd = null;
+ String psfilters[] = null;
+ SysCommand syscmd = null;
+
+ //
+ // Get list of potential filters
+ //
+ cmd = "/usr/bin/ls /etc/lp/fd";
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ syscmd = null;
+ return;
+ }
+ o = syscmd.getOutput();
+ syscmd = null;
+ if (o == null) {
+ return;
+ }
+
+ StringTokenizer st = new StringTokenizer(o);
+ if (st.countTokens() == 0) {
+ return;
+ }
+ psfilters = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ psfilters[i] = st.nextToken();
+ }
+ //
+ // Remove .fd suffix and empty slots that aren't filters.
+ //
+ for (i = 0; i < psfilters.length; i++) {
+ if (psfilters[i].endsWith(".fd")) {
+ j = psfilters[i].indexOf(".fd");
+ psfilters[i] = psfilters[i].substring(0, j);
+ } else {
+ psfilters[i] = "";
+ }
+ }
+
+ // Get list of currently configured filters
+ cmd = "/usr/sbin/lpfilter -l -f all";
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+
+ o = null;
+ if (syscmd.getExitValue() != 0) {
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ return;
+ } else {
+ o = syscmd.getOutput();
+ }
+
+ for (i = 0; i < psfilters.length; i++) {
+ if (psfilters[i].equals(""))
+ continue;
+
+ // If we have filters see if this one is
+ // already configured.
+ if (o != null) {
+ if (o.indexOf("\"" + psfilters[i] + "\"") > -1)
+ continue;
+ }
+
+ // Add the filter
+ cmd = "/usr/sbin/lpfilter -f " + psfilters[i] +
+ " -F /etc/lp/fd/" + psfilters[i] + ".fd";
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+
+ if (syscmd.getExitValue() != 0) {
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ }
+ syscmd = null;
+ }
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterDelete.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterDelete.java
new file mode 100644
index 0000000000..ceeb721d84
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterDelete.java
@@ -0,0 +1,197 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * DoPrinterDelete class
+ * Worker class for deleting a printer.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+
+public class DoPrinterDelete {
+
+ //
+ // main for testing
+ //
+ public static void main(String[] args) {
+
+ Printer p = null;
+ try {
+ NameService ns = new NameService();
+
+ p = new Printer(ns);
+ p.setPrinterName("javatest");
+
+ delete(p, ns);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ System.out.println("Commands:\n" + p.getCmdLog());
+ System.out.println("Errors:\n" + p.getErrorLog());
+ System.out.println("Warnings:\n" + p.getWarnLog());
+ System.exit(0);
+ }
+
+ //
+ // Interface to Printer object.
+ //
+ public static void delete(
+ Printer p,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterDelete.delete()");
+
+ boolean success = true;
+ String err = null;
+ String cmd = null;
+ SysCommand syscmd = null;
+
+ String printername = p.getPrinterName();
+ String nameservice = ns.getNameService();
+
+ boolean islocal = DoPrinterUtil.isLocal(printername);
+
+ // Take care of locally installed case first.
+ if (islocal) {
+ // See if printer is already rejected.
+ // Don't disable so queue can drain.
+ Printer curr = new Printer();
+ curr.setPrinterName(printername);
+ try {
+ DoPrinterView.view(curr, ns);
+ }
+ catch (Exception e) {
+ Debug.message("SVR:" + e.getMessage());
+ curr.setAccept(false);
+ }
+
+ if (curr.getAccept()) {
+ cmd = "/usr/sbin/reject " + printername;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ curr = null;
+ try {
+ deleteLocal(p);
+ }
+ catch (Exception e) {
+ Debug.message("SVR:" + e.getMessage());
+ success = false;
+ }
+ }
+
+ //
+ // Check if we already removed it from /etc/printers.conf
+ //
+ boolean exists;
+ exists = DoPrinterUtil.exists(printername, "system");
+ if (nameservice.equals("system")) {
+ if (exists) {
+ try {
+ deleteLocal(p);
+ }
+ catch (Exception e) {
+ Debug.message("SVR:" + e.getMessage());
+ success = false;
+ }
+ }
+ } else {
+ if ((nameservice.equals("nis")) && exists) {
+ //
+ // Special case if we are nis master
+ //
+ Host h = new Host();
+ String nshost = ns.getNameServiceHost();
+ String lh = h.getLocalHostName();
+ if (lh.equals(nshost)) {
+ try {
+ deleteLocal(p);
+ }
+ catch (Exception e) {
+ Debug.message("SVR:" + e.getMessage());
+ success = false;
+ }
+ }
+ h = null;
+ }
+ DoPrinterNS.set("delete", p, ns);
+ }
+ if (!success) {
+ throw new pmException();
+ }
+ return;
+ }
+
+ private static void deleteLocal(Printer p) throws Exception
+ {
+ Debug.message("SVR: DoPrinterDelete.deleteLocal()");
+
+ String cmd = null;
+ String err = null;
+ SysCommand syscmd = null;
+ String printername = null;
+
+ printername = p.getPrinterName();
+
+ // Workaround for lpadmin bug not removing default
+ String def = DoPrinterUtil.getDefault("system");
+ if ((def != null) && (def.equals(printername))) {
+ cmd = "/usr/sbin/lpadmin -x _default";
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ cmd = "/usr/sbin/lpadmin -x " + printername;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ if (syscmd.getExitValue() != 0) {
+ syscmd = null;
+ throw new pmException(err);
+ }
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterMod.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterMod.java
new file mode 100644
index 0000000000..b7cadaa1cb
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterMod.java
@@ -0,0 +1,841 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * DoPrinterMod class
+ * Worker class for modifying a printer.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+
+public class DoPrinterMod {
+
+ //
+ // main for testing
+ //
+ public static void main(String[] args) {
+ NameService ns = new NameService();
+
+ String[] arr;
+ arr = new String[1];
+
+ Printer p = new Printer();
+
+ p.setPrinterName("javatest");
+ p.setPrinterType("hplaser");
+ p.setPrintServer("zelkova");
+ p.setComment("This is a new comment");
+ p.setDevice("/var/tmp/test");
+ p.setNotify("none");
+ p.setProtocol("bsd");
+ p.setDestination("");
+ p.setIsDefaultPrinter(true);
+ p.setBanner("never");
+ p.setEnable(true);
+ p.setAccept(false);
+
+ arr[0] = "any";
+ p.setFileContents(arr);
+ arr[0] = "one";
+ p.setUserAllowList(arr);
+ arr[0] = "two";
+ p.setUserDenyList(arr);
+
+ p.setLocale(null);
+
+ try {
+ modify(p, ns);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ System.out.println("Commands:\n" + p.getCmdLog());
+ System.out.println("Errors:\n" + p.getErrorLog());
+ System.out.println("Warnings:\n" + p.getWarnLog());
+ System.exit(0);
+
+ }
+
+ //
+ // Interface to Printer object.
+ //
+ public static void modify(
+ Printer p,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterMod.modify()");
+
+ Printer curr = new Printer(ns);
+ curr.setPrinterName(p.getPrinterName());
+ try {
+ DoPrinterView.view(curr, ns);
+ }
+ catch (Exception e) {
+ String err = curr.getErrorLog();
+ p.setErrorLog(err);
+ throw new pmCmdFailedException(err);
+ }
+
+ boolean islocal = DoPrinterUtil.isLocal(p.getPrinterName());
+ if (islocal) {
+ modifyLocal(p, curr, ns);
+ } else {
+ modifyRemote(p, curr, ns);
+ }
+ return;
+ }
+
+ //
+ // Do the work of modifying a local printer.
+ //
+ private static void modifyLocal(
+ Printer p,
+ Printer curr,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterMod.modifyLocal()");
+
+ String err = null;
+ String cmd = null;
+ SysCommand syscmd = null;
+
+ // Since it's local set extensions
+ // Eventually the gui should do this.
+ p.setExtensions("Solaris");
+
+ String nameservice = ns.getNameService();
+
+ String printername = p.getPrinterName();
+ String printertype = null;
+ String printserver = null;
+ String comment = null;
+ String device = null;
+ String notify = null;
+ String make = null;
+ String model = null;
+ String ppd = null;
+ String protocol = null;
+ String destination = null;
+ String[] file_contents = null;
+ String[] user_allow_list = null;
+ String[] user_deny_list = null;
+ boolean default_printer = false;
+ String banner = null;
+ boolean enable = false;
+ boolean accept = false;
+ boolean isURI = false;
+
+ boolean allow_changed = false;
+ boolean default_printer_changed = false;
+ boolean banner_req_changed = false;
+ boolean enable_changed = false;
+ boolean accept_changed = false;
+
+ String ppdfile = null;
+
+
+ //
+ // Set the things that have changed.
+ //
+ if (!strings_equal(curr.getPrinterType(), p.getPrinterType()))
+ printertype = p.getPrinterType();
+ if (!strings_equal(curr.getComment(), p.getComment())) {
+ comment = p.getComment();
+ if (comment == null) {
+ // Comment changed to empty.
+ p.setComment("");
+ comment = "";
+ }
+ }
+ if (!strings_equal(curr.getDevice(), p.getDevice()))
+ device = p.getDevice();
+
+ if (!strings_equal(curr.getNotify(), p.getNotify()))
+ notify = p.getNotify();
+
+ if (!strings_equal(curr.getProtocol(), p.getProtocol())) {
+ protocol = p.getProtocol();
+ }
+
+ // Need to know if the new protocol is uri or if the
+ // protocol did not change and the current one is uri
+ if (((protocol == null) && (curr.getProtocol() == "uri")) ||
+ ((protocol != null) && (protocol.equals("uri")))) {
+ isURI = true;
+ }
+ Debug.message("SVR:DoPrinterMod:isURI: " + isURI);
+ Debug.message("SVR:DoPrinterMod:protocol: " + protocol);
+ Debug.message(
+ "SVR:DoPrinterMod:curr.getProtocol(): " + curr.getProtocol());
+ Debug.message("SVR:DoPrinterMod:p.getProtocol(): " + p.getProtocol());
+
+ if (!strings_equal(curr.getDestination(), p.getDestination()))
+ destination = p.getDestination();
+
+ if ((!strings_equal(curr.getMake(), p.getMake())) ||
+ (!strings_equal(curr.getModel(), p.getModel())) ||
+ (!strings_equal(curr.getPPD(), p.getPPD()))) {
+
+ model = p.getModel();
+ make = p.getMake();
+ ppd = p.getPPD();
+ }
+
+
+ if (curr.getIsDefaultPrinter() != p.getIsDefaultPrinter()) {
+ default_printer = p.getIsDefaultPrinter();
+ default_printer_changed = true;
+ }
+ if (curr.getEnable() != p.getEnable()) {
+ enable = p.getEnable();
+ enable_changed = true;
+ }
+
+ if (curr.getIsDefaultPrinter() != p.getIsDefaultPrinter()) {
+ default_printer = p.getIsDefaultPrinter();
+ default_printer_changed = true;
+ }
+ if (curr.getEnable() != p.getEnable()) {
+ enable = p.getEnable();
+ enable_changed = true;
+ }
+
+ if (curr.getIsDefaultPrinter() != p.getIsDefaultPrinter()) {
+ default_printer = p.getIsDefaultPrinter();
+ default_printer_changed = true;
+ }
+ if (curr.getEnable() != p.getEnable()) {
+ enable = p.getEnable();
+ enable_changed = true;
+ }
+ if (curr.getAccept() != p.getAccept()) {
+ accept = p.getAccept();
+ accept_changed = true;
+ }
+ if (!strings_equal(curr.getBanner(), p.getBanner())) {
+ banner = p.getBanner();
+ banner_req_changed = true;
+ }
+
+ if (!arrays_equal(curr.getFileContents(), p.getFileContents()))
+ file_contents = p.getFileContents();
+
+ if (!arrays_equal(curr.getUserAllowList(), p.getUserAllowList())) {
+ allow_changed = true;
+ // If the current value is "none" and the new
+ // value is null nothing is changing.
+ String[] arr = curr.getUserAllowList();
+ if ((arr != null) && (arr.length != 0)) {
+ if (arr[0].equals("none")) {
+ if (p.getUserAllowList() == null) {
+ allow_changed = false;
+ }
+ }
+ }
+ }
+ if (!arrays_equal(curr.getUserDenyList(), p.getUserDenyList())) {
+ allow_changed = true;
+ }
+ if (allow_changed) {
+ user_allow_list = p.getUserAllowList();
+ user_deny_list = p.getUserDenyList();
+ }
+
+ //
+ // Return if nothing changed.
+ //
+ if ((printertype == null) &&
+ (comment == null) &&
+ (device == null) &&
+ (notify == null) &&
+ (protocol == null) &&
+ (destination == null) &&
+ (make == null) &&
+ (model == null) &&
+ (ppd == null) &&
+ (file_contents == null) &&
+ (!allow_changed) &&
+ (!default_printer_changed) &&
+ (!enable_changed) &&
+ (!accept_changed) &&
+ (!banner_req_changed)) {
+ return;
+ }
+
+ // If this is the default printer set it.
+ if (default_printer_changed) {
+ if (default_printer) {
+ cmd = "/usr/sbin/lpadmin -d " + printername;
+ } else {
+ cmd = "/usr/sbin/lpadmin -x _default";
+ }
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ //
+ // If this is only a default printer change then possibly
+ // update the name service and return.
+ if ((printertype == null) &&
+ (comment == null) &&
+ (device == null) &&
+ (notify == null) &&
+ (protocol == null) &&
+ (destination == null) &&
+ (make == null) &&
+ (model == null) &&
+ (ppd == null) &&
+ (file_contents == null) &&
+ (!allow_changed) &&
+ (!enable_changed) &&
+ (!accept_changed) &&
+ (!banner_req_changed)) {
+ if (nameservice.equals("system")) {
+ return;
+ }
+ p.modhints = "defaultonly";
+
+ DoPrinterNS.set("modify", p, ns);
+ p.modhints = "";
+ return;
+ }
+
+ //
+ // Do enable/accept
+ //
+ if (enable_changed) {
+ if (p.getEnable() == true) {
+ cmd = "/usr/bin/enable " + printername;
+ } else {
+ cmd = "/usr/bin/disable " + printername;
+ }
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ if (accept_changed) {
+ if (p.getAccept() == true) {
+ cmd = "/usr/sbin/accept " + printername;
+ } else {
+ cmd = "/usr/sbin/reject " + printername;
+ }
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+
+ //
+ // Do some slight of hand to deal with overloading of destination
+ // with device for uri protocol
+ // Done at the last moment to prevent modifying logic for old/new
+ // properties of the queue
+
+ if (isURI) {
+ if (destination != null)
+ device = destination;
+ else
+ device = curr.getDestination();
+ destination = null;
+ protocol = null;
+ } else {
+ if (protocol != null) {
+ device = "/dev/null";
+ }
+ }
+
+
+
+ //
+ // Build the modify command
+ //
+
+ cmd = "/usr/sbin/lpadmin -p " + printername;
+
+ if (printername != null)
+ if (DoPrinterUtil.isLocalhost(printername)) {
+ cmd = cmd.concat(" -s localhost");
+ Debug.message("SVR:DoModifyPrinter:isLocalhost:true");
+ }
+
+ if (device != null) {
+ cmd = cmd.concat(" -v " + device);
+ }
+
+ // Network printer
+ if (isURI) {
+ cmd = cmd.concat(" -m uri");
+
+ } else if (protocol != null) {
+
+ if (curr.getPPD() != null)
+ cmd = cmd.concat(" -m netstandard_foomatic");
+ else
+ cmd = cmd.concat(" -m netstandard");
+ }
+
+ if (printertype != null)
+ cmd = cmd.concat(" -T " + printertype);
+
+ if (ppd != null) {
+ ppdfile = new String(DoPrinterUtil.getPPDFile(make,
+ model, ppd));
+
+ Debug.message("SVR:modifyLocal:ppdfile: " + ppdfile);
+
+ cmd = cmd.concat(" -n " + ppdfile);
+ }
+
+ if (notify != null)
+ cmd = cmd.concat(" -A " + notify);
+
+ // destination is overloaded to hold uri device for network printers
+ // if the protocol is uri, don't set either destination or protocol
+ // the device has been set to the destination above
+
+ if (isURI) {
+ cmd = cmd.concat(" -o dest=");
+ cmd = cmd.concat(" -o protocol=");
+ } else {
+ if (destination != null)
+ cmd = cmd.concat(" -o dest=" + destination);
+ if (protocol != null)
+ cmd = cmd.concat(" -o protocol=" + protocol);
+ }
+
+ if ((file_contents != null) && (file_contents.length != 0)) {
+ String tmpstr = file_contents[0];
+ for (int i = 1; i < file_contents.length; i++) {
+ tmpstr = tmpstr.concat("," + file_contents[i]);
+ }
+ cmd = cmd.concat(" -I " + tmpstr);
+ }
+
+ if (banner_req_changed) {
+ if (banner != null) {
+ cmd = cmd.concat(" -o banner=" + banner);
+ }
+ }
+
+ //
+ // Has any of the above changed.
+ //
+ if (!cmd.equals("/usr/sbin/lpadmin -p " + printername)) {
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ //
+ // If the user allow list changed delete all then re-add
+ //
+ if (allow_changed) {
+ cmd = "/usr/sbin/lpadmin -p " + printername +
+ " -u allow:none";
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+
+ if ((user_deny_list != null) &&
+ (user_deny_list.length != 0)) {
+ String tmpstr = user_deny_list[0];
+ for (int i = 1; i < user_deny_list.length; i++) {
+ tmpstr = tmpstr.concat(","
+ + user_deny_list[i]);
+ }
+ cmd = "/usr/sbin/lpadmin -p " + printername +
+ " -u deny:" + tmpstr;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ if ((user_allow_list != null) &&
+ (user_allow_list.length != 0) &&
+ (!user_allow_list[0].equals("none"))) {
+ String tmpstr = user_allow_list[0];
+ for (int i = 1; i < user_allow_list.length; i++) {
+ tmpstr = tmpstr.concat(","
+ + user_allow_list[i]);
+ }
+ cmd = "/usr/sbin/lpadmin -p " + printername +
+ " -u allow:" + tmpstr;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ }
+
+ if (comment != null) {
+ //
+ // Have to use a command array here since
+ // exec(String) doesn't parse quoted strings.
+ // Use lpadmin so the comment in /etc/printers.conf
+ // and /etc/lp/printers/comment stay in sync.
+ //
+ String cmd_array[] =
+ { "/usr/sbin/lpadmin", "-D",
+ comment, "-p", printername };
+ cmd = "/usr/sbin/lpadmin -D " +
+ "\"" + comment + "\"" + " -p " + printername;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd_array);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ if (comment.equals("")) {
+ //
+ // LPADMIN BUG. Comment not cleared in printers.conf
+ // so force it with lpset.
+ //
+ cmd = "/usr/bin/lpset -a description= " + printername;
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ err = syscmd.getError();
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ }
+
+ //
+ // Return if we don't need to touch the name service.
+ //
+ if (nameservice.equals("system")) {
+ return;
+ }
+ if ((comment == null) && (!default_printer_changed)) {
+ return;
+ }
+
+ DoPrinterNS.set("modify", p, ns);
+ return;
+ }
+
+ //
+ // Do the work of modifying a remote printer.
+ //
+ private static void modifyRemote(
+ Printer p,
+ Printer curr,
+ NameService ns) throws Exception
+ {
+ int exitvalue = 0;
+ String err = null;
+ String cmd = null;
+ String cmd_array[] = new String[4];
+ SysCommand syscmd = null;
+
+ String printername = null;
+ String printserver = null;
+ String comment = null;
+ String extensions = null;
+ boolean default_printer = false;
+ boolean default_printer_changed = false;
+
+ String nameservice = ns.getNameService();
+
+ printername = p.getPrinterName();
+ if (!strings_equal(curr.getPrintServer(), p.getPrintServer()))
+ printserver = p.getPrintServer();
+
+ if (!strings_equal(curr.getComment(), p.getComment())) {
+ comment = p.getComment();
+ if (comment == null) {
+ // The comment changed to empty.
+ p.setComment("");
+ comment = "";
+ }
+ }
+//
+// Don't support extensions in the gui yet.
+// If they exist leave them alone.
+// EXTENSIONS
+ p.setExtensions(curr.getExtensions());
+ if (!strings_equal(curr.getExtensions(), p.getExtensions()))
+ extensions = p.getExtensions();
+ if (curr.getIsDefaultPrinter() != p.getIsDefaultPrinter()) {
+ default_printer = p.getIsDefaultPrinter();
+ default_printer_changed = true;
+ }
+
+ //
+ // Return if nothing changed.
+ //
+ if ((printserver == null) &&
+ (extensions == null) &&
+ (comment == null) &&
+ (!default_printer_changed)) {
+ return;
+ }
+
+ //
+ // If this is only a default printer change then set modhints
+ //
+ if ((printserver == null) &&
+ (extensions == null) &&
+ (comment == null)) {
+ p.modhints = "defaultonly";
+ }
+
+
+ //
+ // Find out if we are the nis master
+ //
+ boolean isnismaster = false;
+ if (nameservice.equals("nis")) {
+ String nshost = ns.getNameServiceHost();
+ Host h = new Host();
+ String lh = h.getLocalHostName();
+ if (lh.equals(nshost))
+ isnismaster = true;
+ h = null;
+ }
+
+ //
+ // If we are not updating system and we are not the nis
+ // master then update the name service and return.
+ //
+ if ((!nameservice.equals("system")) && (!isnismaster)) {
+ DoPrinterNS.set("modify", p, ns);
+ p.modhints = "";
+ return;
+ }
+ p.modhints = "";
+
+ //
+ // Take care of the bsdaddr attribute
+ //
+ // EXTENSIONS
+ // The gui doesn't support extensions yet so the goal
+ // here is to prepare for it but don't actually
+ // modify them.
+ //
+ if ((printserver != null) || (extensions != null)) {
+ // If printserver is null we are changing
+ // extensions. Set printserver to its current
+ // value.
+ if (printserver == null) {
+ printserver = curr.getPrintServer();
+ }
+ String bsdaddr = "bsdaddr=" + printserver + ","
+ + printername;
+ //
+ // Leave the extensions alone
+ // EXTENSIONS
+ //
+ extensions = curr.getExtensions();
+ if (extensions != null) {
+ bsdaddr = bsdaddr.concat("," + extensions);
+ }
+ cmd = "/usr/bin/lpset -a " + bsdaddr + " " + printername;
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ }
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ if (comment != null) {
+ cmd = "/usr/bin/lpset" + " -a description=" +
+ "\"" + comment + "\"" +
+ " " + printername;
+ cmd_array[0] = "/usr/bin/lpset";
+ cmd_array[1] = "-a";
+ cmd_array[2] = "description=" + comment;
+ cmd_array[3] = printername;
+
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd_array);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ }
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ // If this is the default printer set it.
+ if (default_printer_changed) {
+ if (default_printer) {
+ cmd = "/usr/sbin/lpadmin -d " + printername;
+ } else {
+ cmd = "/usr/sbin/lpadmin -x _default";
+ }
+ p.setCmdLog(cmd);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ }
+ if (err != null) {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+
+ //
+ // If it's nis and we are here then we are the nis
+ // master. This call will do the make for us.
+ //
+ if (nameservice.equals("nis")) {
+ DoPrinterNS.set("modify", p, ns);
+ }
+ return;
+ }
+
+ private static boolean arrays_equal(String[] arr1, String[] arr2)
+ {
+ if ((arr1 == null) && (arr2 == null)) {
+ return (true);
+ }
+ if ((arr1 == null) || (arr2 == null)) {
+ return (false);
+ }
+ if (arr1.length != arr2.length) {
+ return (false);
+ }
+
+ int i, j;
+ String str;
+ boolean found;
+ for (i = 0; i < arr1.length; i++) {
+ found = false;
+ str = arr1[i];
+ for (j = 0; j < arr2.length; j++) {
+ if (str.equals(arr2[j])) {
+ found = true;
+ }
+ }
+ if (found == false) {
+ return (false);
+ }
+ }
+ return (true);
+ }
+
+ private static boolean strings_equal(String str1, String str2)
+ {
+ if ((str1 == null) && (str2 == null)) {
+ return (true);
+ }
+ if ((str1 == null) || (str2 == null)) {
+ return (false);
+ }
+
+ return (str1.equals(str2));
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterNS.c b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterNS.c
new file mode 100644
index 0000000000..2cd059860d
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterNS.c
@@ -0,0 +1,276 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* LINTLIBRARY */
+
+#include <stdio.h>
+#include <strings.h>
+#include <libintl.h>
+#include "com_sun_admin_pm_server_DoPrinterNS.h"
+
+jstring glob_jstdout = NULL;
+jstring glob_jstderr = NULL;
+
+extern char glob_stdout[];
+extern char glob_stderr[];
+
+void set_stderr(JNIEnv *env);
+void set_stdout(JNIEnv *env);
+extern int _dorexec(
+ const char *host,
+ const char *user,
+ const char *passwd,
+ const char *cmd,
+ const char *locale);
+
+extern int _updateoldyp(
+ const char *action,
+ const char *printername,
+ const char *printserver,
+ const char *extensions,
+ const char *comment,
+ const char *isdefault);
+
+extern int _updateldap(
+ const char *action,
+ const char *host,
+ const char *user,
+ const char *passwd,
+ const char *printername,
+ const char *printserver,
+ const char *extensions,
+ const char *comment,
+ const char *isdefault);
+
+JNIEXPORT jint JNICALL
+Java_com_sun_admin_pm_server_DoPrinterNS_dorexec(
+ JNIEnv *env,
+ jclass class,
+ jstring jhost,
+ jstring juser,
+ jstring jpasswd,
+ jstring jcmd,
+ jstring jlocale)
+{
+ const char *host;
+ const char *user;
+ const char *passwd;
+ const char *cmd;
+ const char *locale;
+
+ int ret = 0;
+ jstring empty = (*env)->NewStringUTF(env, "");
+ glob_jstdout = (*env)->NewGlobalRef(env, empty);
+ glob_jstderr = (*env)->NewGlobalRef(env, empty);
+
+ host = (*env)->GetStringUTFChars(env, jhost, 0);
+ user = (*env)->GetStringUTFChars(env, juser, 0);
+ passwd = (*env)->GetStringUTFChars(env, jpasswd, 0);
+ cmd = (*env)->GetStringUTFChars(env, jcmd, 0);
+ locale = (*env)->GetStringUTFChars(env, jlocale, 0);
+
+ ret = _dorexec(host, user, passwd, cmd, locale);
+
+ if (ret != 0) {
+ (void) set_stderr(env);
+ return (ret);
+ }
+ (void) set_stderr(env);
+ (void) set_stdout(env);
+ return (ret);
+}
+
+JNIEXPORT jstring JNICALL
+Java_com_sun_admin_pm_server_DoPrinterNS_getstderr(JNIEnv *env, jclass class)
+{
+ return (glob_jstderr);
+}
+
+JNIEXPORT jstring JNICALL
+Java_com_sun_admin_pm_server_DoPrinterNS_getstdout(JNIEnv *env, jclass class)
+{
+ return (glob_jstdout);
+}
+
+void
+set_stderr(JNIEnv *env)
+{
+ static jstring jerrstr;
+ static char errbuf[BUFSIZ];
+
+ if (*glob_stderr == '\0') {
+ (void) strcpy(errbuf, "");
+ } else {
+ (void) strcpy(errbuf, glob_stderr);
+ }
+
+ jerrstr = (*env)->NewStringUTF(env, "");
+ if (glob_jstderr != NULL) {
+ (*env)->DeleteGlobalRef(env, glob_jstderr);
+ }
+
+ jerrstr = (*env)->NewStringUTF(env, errbuf);
+ glob_jstderr = (*env)->NewGlobalRef(env, jerrstr);
+}
+
+void
+set_stdout(JNIEnv *env)
+{
+ static jstring joutstr;
+ static char outbuf[BUFSIZ];
+
+ if (*glob_stdout == '\0') {
+ (void) strcpy(outbuf, "");
+ } else {
+ (void) strcpy(outbuf, glob_stdout);
+ }
+
+ joutstr = (*env)->NewStringUTF(env, "");
+ if (glob_jstdout != NULL) {
+ (*env)->DeleteGlobalRef(env, glob_jstdout);
+ }
+
+ joutstr = (*env)->NewStringUTF(env, outbuf);
+ glob_jstdout = (*env)->NewGlobalRef(env, joutstr);
+}
+
+JNIEXPORT jint JNICALL
+Java_com_sun_admin_pm_server_DoPrinterNS_updateoldyp(
+ JNIEnv *env,
+ jclass class,
+ jstring jaction,
+ jstring jprintername,
+ jstring jprintserver,
+ jstring jextensions,
+ jstring jcomment,
+ jstring jisdefault)
+{
+ const char *action = NULL;
+ const char *printername = NULL;
+ const char *printserver = NULL;
+ const char *extensions = NULL;
+ const char *comment = NULL;
+ const char *isdefault = NULL;
+
+ int ret = 0;
+ jstring empty = (*env)->NewStringUTF(env, "");
+ glob_jstdout = (*env)->NewGlobalRef(env, empty);
+ glob_jstderr = (*env)->NewGlobalRef(env, empty);
+
+ action = (*env)->GetStringUTFChars(env, jaction, 0);
+ printername = (*env)->GetStringUTFChars(env, jprintername, 0);
+ if (jprintserver != NULL) {
+ printserver =
+ (*env)->GetStringUTFChars(env, jprintserver, 0);
+ }
+ if (jextensions != NULL) {
+ extensions =
+ (*env)->GetStringUTFChars(env, jextensions, 0);
+ }
+ if (jcomment != NULL) {
+ comment =
+ (*env)->GetStringUTFChars(env, jcomment, 0);
+ }
+ isdefault = (*env)->GetStringUTFChars(env, jisdefault, 0);
+
+ ret = _updateoldyp(action, printername, printserver,
+ extensions, comment, isdefault);
+
+ if (ret != 0) {
+ (void) set_stderr(env);
+ return (ret);
+ }
+ (void) set_stderr(env);
+ (void) set_stdout(env);
+ return (ret);
+}
+
+JNIEXPORT jint JNICALL
+Java_com_sun_admin_pm_server_DoPrinterNS_updateldap(
+ JNIEnv *env,
+ jclass class,
+ jstring jaction,
+ jstring jhost,
+ jstring jbinddn,
+ jstring jpasswd,
+ jstring jprintername,
+ jstring jprintserver,
+ jstring jextensions,
+ jstring jcomment,
+ jstring jisdefault)
+{
+ const char *action = NULL;
+ const char *host = NULL;
+ const char *binddn = NULL;
+ const char *passwd = NULL;
+ const char *printername = NULL;
+ const char *printserver = NULL;
+ const char *extensions = NULL;
+ const char *comment = NULL;
+ const char *isdefault = NULL;
+
+ int ret = 0;
+ jstring empty = (*env)->NewStringUTF(env, "");
+ glob_jstdout = (*env)->NewGlobalRef(env, empty);
+ glob_jstderr = (*env)->NewGlobalRef(env, empty);
+
+ action = (*env)->GetStringUTFChars(env, jaction, 0);
+ printername = (*env)->GetStringUTFChars(env, jprintername, 0);
+ if (jhost != NULL) {
+ host = (*env)->GetStringUTFChars(env, jhost, 0);
+ }
+ if (jbinddn != NULL) {
+ binddn = (*env)->GetStringUTFChars(env, jbinddn, 0);
+ }
+ if (jpasswd != NULL) {
+ passwd = (*env)->GetStringUTFChars(env, jpasswd, 0);
+ }
+ if (jprintserver != NULL) {
+ printserver =
+ (*env)->GetStringUTFChars(env, jprintserver, 0);
+ }
+ if (jextensions != NULL) {
+ extensions =
+ (*env)->GetStringUTFChars(env, jextensions, 0);
+ }
+ if (jcomment != NULL) {
+ comment =
+ (*env)->GetStringUTFChars(env, jcomment, 0);
+ }
+ isdefault = (*env)->GetStringUTFChars(env, jisdefault, 0);
+
+ ret = _updateldap(action, host, binddn, passwd, printername,
+ printserver, extensions, comment, isdefault);
+
+ if (ret != 0) {
+ (void) set_stderr(env);
+ return (ret);
+ }
+ (void) set_stderr(env);
+ (void) set_stdout(env);
+ return (ret);
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterNS.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterNS.java
new file mode 100644
index 0000000000..3fdb9753ee
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterNS.java
@@ -0,0 +1,626 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * DoPrinterNS class
+ * Worker class for updating name services.
+ * Interfaces to JNI code.
+ */
+
+package com.sun.admin.pm.server;
+
+public class DoPrinterNS
+{
+ //
+ // JNI member functions
+ //
+ private synchronized static native int dorexec(String nshost,
+ String user, String passwd, String cmd, String locale);
+ private synchronized static native int updateoldyp(String action,
+ String printername, String printserver, String extensions,
+ String comment, String isdefault);
+ private synchronized static native int updateldap(String action,
+ String host, String binddn, String passwd,
+ String printername, String printserver, String extensions,
+ String comment, String isdefault);
+ private synchronized static native String getstderr();
+ private synchronized static native String getstdout();
+
+ //
+ // Load JNI.
+ //
+ static
+ {
+ System.loadLibrary("pmgr");
+ }
+
+ //
+ // main for testing
+ //
+ public static void main(String[] args) {
+ //
+ // Set attributes for testing.
+ //
+ NameService ns = null;
+ try {
+ ns = new NameService("nis");
+ }
+ catch (Exception e) {
+ System.out.println(e);
+ System.exit(1);
+ }
+ ns.setPasswd("");
+
+ Printer p = new Printer(ns);
+ p.setPrinterName("javatest");
+ p.setPrintServer("zelkova");
+ p.setComment("This is a comment");
+ p.setIsDefaultPrinter(false);
+ p.setLocale(null);
+
+ String action = "add";
+ if (args.length >= 1)
+ action = args[0];
+ try {
+ set(action, p, ns);
+ }
+ catch (Exception e) {
+ System.out.println(e);
+ }
+ System.out.println("Commands:\n" + p.getCmdLog());
+ System.out.println("Errors:\n" + p.getErrorLog());
+ System.out.println("Warnings:\n" + p.getWarnLog());
+ System.exit(0);
+ }
+
+ //
+ // Interface to DoPrinter[add|mod|delete]
+ //
+ public static void set(
+ String action,
+ Printer p,
+ NameService ns) throws Exception
+ {
+ String nameservice = ns.getNameService();
+
+ if (nameservice.equals("system")) {
+ return;
+ } else if (nameservice.equals("nis")) {
+ setNIS(action, p, ns);
+ return;
+ }
+ setNS(action, p, ns);
+ return;
+ }
+
+ private static void setNIS(
+ String action,
+ Printer p,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterNS.setNIS(): " + action);
+
+ String printername = p.getPrinterName();
+ String printserver = p.getPrintServer();
+ String comment = p.getComment();
+ String extensions = p.getExtensions();
+ boolean default_printer = p.getIsDefaultPrinter();
+ String locale = p.getLocale();
+ if (locale == null)
+ locale = "C";
+
+ String nameservice = ns.getNameService();
+ String nshost = ns.getNameServiceHost();
+ String user = ns.getUser();
+ String passwd = ns.getPasswd();
+
+ String cmd = null;
+ String err = null;
+ int ret = 0;
+ int exitvalue = 0;
+
+ //
+ // If this is the nis master we only need to do the make
+ // locally.
+ //
+ Host h = new Host();
+ String lh = h.getLocalHostName();
+ if (lh.equals(nshost)) {
+ cmd = "/usr/ccs/bin/make -f /var/yp/Makefile";
+ cmd = cmd.concat(" -f /usr/lib/print/Makefile.yp ");
+ cmd = cmd.concat("printers.conf");
+
+ p.setCmdLog(cmd);
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else {
+ // ignore touch warning
+ // p.setWarnLog(err);
+ }
+ syscmd = null;
+ return;
+ }
+
+ String cmdprefix = "rexec(" + nshost + "): ";
+
+ cmd = "/usr/bin/echo";
+ Debug.message("SVR: " + cmdprefix + cmd);
+ ret = dorexec(nshost, user, passwd, cmd, locale);
+ if (ret != 0) {
+ throw new pmAuthException(getstderr());
+ }
+ //
+ // Do we have lpset
+ //
+ cmd = "/usr/bin/ls /usr/bin/lpset";
+ Debug.message("SVR: " + cmdprefix + cmd);
+ ret = dorexec(nshost, user, passwd, cmd, locale);
+ if (ret != 0) {
+ throw new pmCmdFailedException(getstderr());
+ }
+ String tmpstr = getstdout();
+ tmpstr = tmpstr.trim();
+ if (!tmpstr.equals("/usr/bin/lpset")) {
+ Debug.message("SVR: No lpset found. Checking rhosts.");
+
+ // Are we set up in rhosts?
+ cmd = "rsh ";
+ cmd = cmd.concat(nshost);
+ cmd = cmd.concat(" echo");
+
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ syscmd = null;
+ throw new pmAuthRhostException(err);
+ }
+ syscmd = null;
+ //
+ // We don't have lpset. Must be pre-2.6 master.
+ // We are set up in rhosts so use libprint
+ // to update it.
+ //
+ p.setCmdLog("rsh " + nshost + "...");
+ String def = "false";
+ if (default_printer)
+ def = "true";
+
+ Debug.message("SVR: updateoldyp(): ");
+ Debug.message("SVR: action=" + action);
+ Debug.message("SVR: printername=" + printername);
+ Debug.message("SVR: printserver=" + printserver);
+ Debug.message("SVR: extensions=" + extensions);
+ Debug.message("SVR: comment=" + comment);
+ Debug.message("SVR: default=" + def);
+
+ ret = updateoldyp(action, printername,
+ printserver, extensions, comment, def);
+ if (ret != 0) {
+ throw new pmCmdFailedException("libprint");
+ }
+ return;
+ }
+
+ //
+ // Add and modify are the same
+ //
+ boolean domake = false;
+ if (!action.equals("delete")) {
+ //
+ // If we are here from a modify and only need
+ // to change the default printer ...
+ //
+ if (!p.modhints.equals("defaultonly")) {
+ String bsdaddr = "bsdaddr=" + printserver + "," +
+ printername;
+ if (extensions != null) {
+ bsdaddr = bsdaddr.concat("," + extensions);
+ }
+ cmd = "/usr/bin/lpset -a " + bsdaddr;
+ if (comment != null) {
+ cmd = cmd.concat(" -a " + "description=" +
+ "\"" + comment + "\"");
+ }
+ cmd = cmd.concat(" " + printername);
+
+ Debug.message("SVR: " + cmdprefix + cmd);
+ p.setCmdLog(cmdprefix + cmd);
+ ret = dorexec(nshost, user, passwd, cmd, locale);
+ err = getstderr();
+ if (ret != 0) {
+ p.setErrorLog(err);
+ throw new pmCmdFailedException(err);
+ }
+ if (!err.equals("")) {
+ p.setWarnLog(err);
+ }
+ domake = true;
+ }
+
+ cmd = null;
+ String def = DoPrinterUtil.getDefault("nis");
+ if (default_printer) {
+ if (!printername.equals(def)) {
+ cmd = "/usr/bin/lpset -a " + "use=" +
+ printername + " _default";
+ }
+ } else {
+ if ((def != null) && (def.equals(printername))) {
+ //
+ // It was the default but not any more.
+ //
+ cmd = "/usr/bin/lpset -x _default";
+ }
+ }
+ if (cmd != null) {
+ Debug.message("SVR: " + cmdprefix + cmd);
+ p.setCmdLog(cmdprefix + cmd);
+ ret = dorexec(nshost, user, passwd, cmd, locale);
+ err = getstderr();
+ if (ret != 0) {
+ p.setErrorLog(err);
+ throw new pmCmdFailedException(err);
+ }
+ if (!err.equals("")) {
+ p.setWarnLog(err);
+ }
+ domake = true;
+ }
+ } else {
+ if (DoPrinterUtil.exists(printername, "nis")) {
+ // delete
+ cmd = "/usr/bin/lpset -x " + printername;
+ Debug.message("SVR: " + cmdprefix + cmd);
+ p.setCmdLog(cmdprefix + cmd);
+ ret = dorexec(nshost, user, passwd, cmd, locale);
+ err = getstderr();
+ if (ret != 0) {
+ p.setErrorLog(err);
+ throw new pmCmdFailedException(err);
+ }
+ if (!err.equals("")) {
+ p.setWarnLog(err);
+ }
+ domake = true;
+ }
+ String def = DoPrinterUtil.getDefault("nis");
+ if ((def != null) && (def.equals(printername))) {
+ cmd = "/usr/bin/lpset -x _default";
+ Debug.message("SVR: " + cmdprefix + cmd);
+ p.setCmdLog(cmdprefix + cmd);
+ ret = dorexec(nshost, user, passwd, cmd, locale);
+ err = getstderr();
+ if (ret != 0) {
+ p.setErrorLog(err);
+ throw new pmCmdFailedException(err);
+ }
+ if (!err.equals("")) {
+ p.setWarnLog(err);
+ }
+ domake = true;
+ }
+ }
+ if (!domake) {
+ return;
+ }
+
+ cmd = "cd /var/yp; /usr/ccs/bin/make -f /var/yp/Makefile";
+ cmd = cmd.concat(" -f /usr/lib/print/Makefile.yp printers.conf");
+ Debug.message("SVR: " + cmdprefix + cmd);
+ p.setCmdLog(cmdprefix + cmd);
+ ret = dorexec(nshost, user, passwd, cmd, locale);
+ err = getstderr();
+ if (ret != 0) {
+ p.setErrorLog(err);
+ throw new pmCmdFailedException(err);
+ }
+ if (!err.equals("")) {
+ p.setWarnLog(err);
+ }
+ return;
+ }
+
+ private static void setNS(
+ String action,
+ Printer p,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterNS.setNS(): " + action);
+
+ String printername = p.getPrinterName();
+ String printserver = p.getPrintServer();
+ String extensions = p.getExtensions();
+ String comment = p.getComment();
+ boolean default_printer = p.getIsDefaultPrinter();
+
+ String nameservice = ns.getNameService();
+
+ String nshost = ns.getNameServiceHost();
+ String user = ns.getUser();
+ String passwd = ns.getPasswd();
+
+ int exitvalue;
+ SysCommand syscmd = null;
+ String err;
+ String cmd = null;
+ String cmd_log = null;
+ String cmd_array[] = new String[14];
+
+ int index = 0;
+ String base_cmd = "/usr/bin/lpset -n " + nameservice;
+ String base_cmd_log = "/usr/bin/lpset -n " + nameservice;
+
+ cmd_array[index++] = "/usr/bin/lpset";
+ cmd_array[index++] = "-n";
+ cmd_array[index++] = nameservice;
+
+ /*
+ * Use jni to update ldap since the passwd is sensitive.
+ */
+ if (nameservice.equals("ldap")) {
+
+ if ((nshost == null) || (nshost.equals(""))) {
+ throw new pmInternalErrorException(
+ "Missing LDAP host for ldap operation");
+ }
+ if ((user == null) && (user.equals(""))) {
+ throw new pmInternalErrorException(
+ "Missing Binddn for ldap operation");
+ }
+ if ((passwd == null) && (passwd.equals(""))) {
+ throw new pmInternalErrorException(
+ "Missing passwd for ldap operation");
+ }
+
+ p.setCmdLog("ldap ...");
+
+ String def = "false";
+ if (default_printer)
+ def = "true";
+
+ Debug.message("SVR: updateldap(): ");
+ Debug.message("SVR: action=" + action);
+ Debug.message("SVR: host=" + nshost);
+ Debug.message("SVR: binddn=" + user);
+ Debug.message("SVR: passwd=****");
+ Debug.message("SVR: printername=" + printername);
+ Debug.message("SVR: printserver=" + printserver);
+ Debug.message("SVR: extensions=" + extensions);
+ Debug.message("SVR: comment=" + comment);
+ Debug.message("SVR: default=" + def);
+
+ exitvalue = updateldap(action, nshost, user, passwd,
+ printername, printserver, extensions, comment,
+ def);
+
+ if (exitvalue != 0) {
+ throw new pmCmdFailedException("libprint");
+ }
+ return;
+ }
+
+ //
+ // Add and modify are the same
+ //
+ if (!action.equals("delete")) {
+ //
+ // If we are here for a modify and we're only setting
+ // the default printer ...
+ //
+ if (!p.modhints.equals("defaultonly")) {
+ String bsdaddr = "bsdaddr=" + printserver + "," +
+ printername;
+ if (extensions != null) {
+ bsdaddr = bsdaddr.concat("," + extensions);
+ }
+ cmd_array[index++] = "-a";
+ cmd_array[index++] = bsdaddr;
+ cmd_log = base_cmd_log + " -a " + bsdaddr;
+ if (comment != null) {
+ cmd_array[index++] = "-a";
+ cmd_array[index++] = "description=" + comment;
+ cmd_log = cmd_log.concat(" -a " +
+ "description=" + "\"" + comment + "\"");
+ }
+ cmd_array[index++] = printername;
+ cmd_log = cmd_log.concat(" " + printername);
+
+ p.setCmdLog(cmd_log);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd_array);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ cmd = null;
+ cmd_log = null;
+ String args = null;
+ String def = DoPrinterUtil.getDefault(nameservice);
+ if (default_printer) {
+ if (!printername.equals(def)) {
+ args = " -a " + "use=" + printername +
+ " _default";
+ cmd = base_cmd + args;
+ cmd_log = base_cmd_log + args;
+ }
+ } else {
+ if ((def != null) && (def.equals(printername))) {
+ //
+ // It was the default but not any more.
+ //
+ args = " -x _default";
+ cmd = base_cmd + args;
+ cmd_log = base_cmd_log + args;
+ }
+ }
+ if (cmd != null) {
+ p.setCmdLog(cmd_log);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ } else {
+ if (DoPrinterUtil.exists(printername, nameservice)) {
+ // delete
+ cmd = base_cmd + " -x " + printername;
+ cmd_log = base_cmd_log + " -x " + printername;
+ p.setCmdLog(cmd_log);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+
+ }
+ String def = DoPrinterUtil.getDefault(nameservice);
+ if ((def != null) && (def.equals(printername))) {
+ cmd = base_cmd + " -x _default";
+ cmd_log = base_cmd_log + " -x _default";
+ p.setCmdLog(cmd_log);
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ err = syscmd.getError();
+ if (syscmd.getExitValue() != 0) {
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ } else {
+ p.setWarnLog(err);
+ }
+ syscmd = null;
+ }
+ }
+ return;
+ }
+
+ public static boolean doAuth(NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterNS.checkAuth()");
+
+ String nsname = ns.getNameService();
+ String host = ns.getNameServiceHost();
+ String user = ns.getUser();
+ String passwd = ns.getPasswd();
+
+ if (nsname.equals("system")) {
+ if (!isRoot()) {
+ Debug.error(
+ "SVR: User does not have root priveleges.");
+ throw new pmAuthException();
+ }
+ } else if (nsname.equals("nis")) {
+ Host h = new Host();
+ String lh = h.getLocalHostName();
+ String nm = h.getNisHost("master");
+ if (lh.equals(nm)) {
+ // Since we are on the NIS master the
+ // check is the same as for "system".
+ Debug.message("SVR: Host is NIS master.");
+ if (!isRoot()) {
+ Debug.error(
+ "SVR: User does not have root access.");
+ throw new pmAuthException();
+ }
+ }
+ int ret = dorexec(host, user, passwd, "/usr/bin/echo", "C");
+ if (ret != 0) {
+ Debug.error(
+ "SVR: User does not have NIS update access.");
+ throw new pmAuthException(getstderr());
+ }
+ } else if (nsname.equals("ldap")) {
+ int ret = updateldap("add", host, user, passwd,
+ "_pmTestAuthToken", null, null, null, "false");
+
+ if (ret != 0) {
+ Debug.error(
+ "SVR: User does not have LDAP update priveleges.");
+ throw new pmAuthException();
+ }
+ ret = updateldap("delete", host, user, passwd,
+ "_pmTestAuthToken", null, null, null, "false");
+
+ } else {
+ throw new pmInternalErrorException(
+ "doAuth(): Invalid name service: " + nsname);
+ }
+ return (true);
+ }
+
+ public static void doCheckRootPasswd(String p)
+ throws Exception
+ {
+ Host h = new Host();
+ String lh = h.getLocalHostName();
+
+ int ret = dorexec(lh, "root", p, "/usr/bin/echo", "C");
+ if (ret != 0) {
+ throw new pmAuthException(getstderr());
+ }
+ return;
+ }
+
+ public static boolean isRoot()
+ throws Exception
+ {
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/id", "LC_ALL=C");
+
+ String o = syscmd.getOutput();
+
+ if (o == null) {
+ throw new pmCmdFailedException(syscmd.getError());
+ }
+ if (o.indexOf("uid=0(") == -1) {
+ return (false);
+ }
+ return (true);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterUtil.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterUtil.java
new file mode 100644
index 0000000000..6d8790a55c
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterUtil.java
@@ -0,0 +1,557 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * DoPrinterUtil class
+ * Worker utility class.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+import java.util.*;
+
+public class DoPrinterUtil {
+
+ public static String getDefault(String ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterUtil.getDefault()");
+ Debug.message("SVR: name service equals " + ns);
+
+ String o = null;
+ String cmd = "/usr/bin/lpget -n " + ns + " _default";
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ o = syscmd.getOutput();
+ syscmd = null;
+
+ if (o == null) {
+ return (null);
+ }
+ int i = o.indexOf("use=");
+ if (i == -1) {
+ return (null);
+ }
+ o = o.substring(i);
+ String dflt = DoPrinterView.getToken(o + "\n", "use=");
+
+ Debug.message("SVR: default is " + dflt);
+ return (new String(dflt));
+ }
+
+ public static String[] getDevices() throws Exception
+ {
+ Debug.message("SVR: DoPrinterUtil.getDevices()");
+
+ int i = 0;
+ String dev = "";
+ String devices = "";
+
+ String serial_possibilities[] = {"a", "b", "c", "d",
+ "e", "f", "g", "h", "i", "j", "k", "l", "m",
+ "n", "o", "p", "q", "r", "s", "t", "u", "v",
+ "w", "x", "y", "z"};
+
+ String cmd = "/usr/bin/find /dev -print";
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ String errstr = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(errstr);
+ }
+
+ String o = syscmd.getOutput();
+ syscmd = null;
+
+ if (o == null) {
+ return (null);
+ }
+ o = o.concat("\n");
+
+ for (i = 0; i < serial_possibilities.length; i++) {
+ dev = "/dev/term/" + serial_possibilities[i] + "\n";
+ if (o.indexOf(dev) != -1) {
+ devices = devices.concat(" " + dev + " ");
+ }
+ }
+ // sparc bpp parallel ports
+ for (i = 0; i < 100; i++) {
+ dev = "/dev/bpp" + i + "\n";
+ if (o.indexOf(dev) != -1) {
+ devices = devices.concat(" " + dev + " ");
+ }
+ }
+ // sparc ecpp parallel ports
+ for (i = 0; i < 100; i++) {
+ dev = "/dev/ecpp" + i + "\n";
+ if (o.indexOf(dev) != -1) {
+ devices = devices.concat(" " + dev + " ");
+ }
+ }
+ // intel parallel ports
+ for (i = 0; i < 100; i++) {
+ dev = "/dev/lp" + i + "\n";
+ if (o.indexOf(dev) != -1) {
+ devices = devices.concat(" " + dev + " ");
+ }
+ }
+
+ // USB
+ for (i = 0; i < 100; i++) {
+ dev = "/dev/printers/" + i + "\n";
+ if (o.indexOf(dev) != -1) {
+ devices = devices.concat(" " + dev + " ");
+ }
+ }
+
+ // SunPics
+ dev = "/dev/lpvi\n";
+ if (o.indexOf(dev) != -1) {
+ devices = devices.concat(" " + dev + " ");
+ }
+
+ o = null;
+
+ if (devices.equals("")) {
+ return (null);
+ }
+
+ String ret[];
+ StringTokenizer st = new StringTokenizer(devices);
+ if (st.countTokens() == 0) {
+ return (null);
+ } else {
+ ret = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ ret[i] = st.nextToken();
+ }
+ }
+ return (ret);
+ }
+
+ public static String[] getMakes() throws Exception
+ {
+ int i;
+
+ Debug.message("SVR: DoPrinterUtil.getMakes()");
+
+ String cmd = "/usr/lib/lp/bin/getmakes";
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ String errstr = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(errstr);
+ }
+ String makes = syscmd.getOutput();
+
+ String ret[];
+ StringTokenizer st = new StringTokenizer(makes);
+ if (st.countTokens() == 0) {
+ return (null);
+ } else {
+ ret = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ ret[i] = st.nextToken();
+
+ }
+ }
+ return (ret);
+
+ }
+ public static String[] getModels(String make) throws Exception
+ {
+ int i;
+ String ret[];
+
+ Debug.message("SVR:getModels()");
+
+ if (make == null) {
+ Debug.message("SVR:getModels: make is null");
+ return (null);
+ }
+ // Make call for models for this make
+ String cmd = "/usr/lib/lp/bin/getmodels " + make;
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ String errstr = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(errstr);
+ }
+ String models = syscmd.getOutput();
+
+ if (models != null) {
+ StringTokenizer st = new StringTokenizer(models, "\n");
+ if (st.countTokens() == 0) {
+ Debug.message("SVR:String tokenizer count is zero");
+ return (null);
+ } else {
+ ret = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ ret[i] = st.nextToken();
+
+ }
+ }
+ return (ret);
+ } else
+ return (null);
+ }
+
+ public static String[] getPPDs(String make, String model) throws Exception
+ {
+ int i;
+ String ret[];
+ ret = new String[2];
+ if ((make == null) || (model == null)) {
+ return null;
+ }
+ // get ppd files for this make/model
+ String cmd = "/usr/lib/lp/bin/getppds " + make + " " + model;
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ String errstr = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(errstr);
+ }
+ String ppds = syscmd.getOutput();
+ StringTokenizer st = new StringTokenizer(ppds, "\n");
+ if (st.countTokens() == 0) {
+ return (null);
+ } else {
+ ret = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ ret[i] = st.nextToken();
+
+ }
+ }
+ return (ret);
+ }
+
+ public static String[] getMakeModelNick(String ppdfilename) throws Exception
+ {
+ int i;
+ String ret[] = null;
+ if (ppdfilename == null) {
+ return (null);
+ }
+ // get ppd files for this make/model
+ String cmd = "/usr/lib/lp/bin/ppdfilename2mmp " + ppdfilename;
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ String errstr = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(errstr);
+ }
+ String mmp = syscmd.getOutput();
+
+ if (mmp != null) {
+ ret = new String[2];
+
+ StringTokenizer st = new StringTokenizer(mmp, "\n");
+ if (st.countTokens() == 0) {
+ return (null);
+ } else {
+ ret = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ ret[i] = st.nextToken();
+
+ }
+ }
+ }
+ return (ret);
+ }
+
+ public static String getPPDFile(
+ String make, String model, String ppd) throws Exception
+ {
+ int i;
+ String ret[];
+ ret = new String[2];
+ if (ppd == null) {
+ return (null);
+ }
+ // get ppd path/filename for this ppd
+ String cmd = "/usr/lib/lp/bin/getppdfile " +
+ make + ":" + " " + model + ":" + " " + ppd + ":";
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ String errstr = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(errstr);
+ }
+ String ppdfile = syscmd.getOutput();
+
+ return (ppdfile);
+ }
+
+
+ public static String[] getProbe(String device)
+ {
+ int i;
+ String pmake = null;
+ String pmodel = null;
+ String tokens[] = null;
+ String ret[];
+ ret = new String[2];
+
+ if (device == null)
+ return (null);
+
+ Debug.message("SVR: DoPrinterUtil.getProbe()");
+
+ // Get Manufacturer and Model for printer in this port
+ String cmd = "/usr/lib/lp/bin/printer-info -M -m " + device;
+ SysCommand syscmd = new SysCommand();
+ try {
+ syscmd.exec(cmd);
+ } catch (Exception e) {
+ System.out.println(e);
+ }
+ if (syscmd.getExitValue() != 0) {
+ String errstr = syscmd.getError();
+ syscmd = null;
+ return (null);
+ }
+
+ String mm = syscmd.getOutput();
+ if (mm != null) {
+ int numtokens;
+ StringTokenizer st = new StringTokenizer(mm, ":" + "\n");
+ if (st.countTokens() == 0) {
+ return (null);
+ } else {
+ numtokens = st.countTokens();
+ tokens = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ tokens[i] = st.nextToken();
+ }
+ }
+ for (i = 0; i < numtokens; i++) {
+ if ((tokens[i].trim()).equals("Manufacturer")) {
+ pmake = new String(tokens[i + 1].trim());
+ } else { if ((tokens[i].trim()).equals("Model"))
+ pmodel = new String(tokens[i + 1].trim());
+ }
+ }
+
+ if (pmake != null)
+ ret[0] = pmake;
+ if (pmodel != null)
+ ret[1] = pmodel;
+
+ return (ret);
+ }
+ return (null);
+
+ }
+
+ public static boolean isMakeModel(
+ String make,
+ String model)
+ {
+ int exitvalue;
+
+ Debug.message("SVR: DoPrinterUtil.isMakeModel() " + make + " " + model);
+
+ SysCommand syscmd = new SysCommand();
+ // syscmd.exec("/usr/bin/lpget -n " + ns + " " + name);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+ if (exitvalue == 0) {
+ return (true);
+ }
+ return (false);
+ }
+
+
+ public static String[] getList(String nsarg)
+ throws Exception
+ {
+ Debug.message("SVR: DoPrinterUtil.getList()");
+
+ int i = 0;
+ int j = 0;
+ int listi = 0;
+
+ String cmd = null;
+ String printername = "";
+ String printserver = "";
+ String comment = "";
+ String nameservice;
+ String list[];
+
+ String o = null;
+ cmd = "/usr/bin/lpget -n " + nsarg + " list";
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ String errstr = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(errstr);
+ }
+ o = syscmd.getOutput();
+ syscmd = null;
+
+ if (o == null) {
+ return (null);
+ }
+
+ // Count entries
+ int index = 0;
+ while ((index = o.indexOf("bsdaddr=", index)) != -1) {
+ index = index + 8;
+ i++;
+ }
+ if (i <= 0)
+ return (null);
+
+ list = new String [i*3];
+
+ int colon = 0;
+ int nextcolon = 0;
+ while ((colon = o.indexOf(":\n", colon + 1)) != -1) {
+ nextcolon = o.indexOf(":\n", colon + 1);
+ if (nextcolon == -1)
+ nextcolon = o.length();
+ // Extract printername
+ i = colon;
+ while ((o.charAt(i) != '\n') && (i != 0)) {
+ i--;
+ }
+ if (i == 0)
+ printername = o.substring(i, colon);
+ else
+ printername = o.substring(i + 1, colon);
+
+ // Skip _all and _default keywords
+ if (printername.equals("_all")) {
+ continue;
+ }
+ if (printername.equals("_default")) {
+ continue;
+ }
+
+ // Extract servername
+ i = o.indexOf("bsdaddr=", colon);
+ if ((i != -1) && (i < nextcolon)) {
+ j = o.indexOf(",", i);
+ if (j != -1)
+ printserver = o.substring(i + 8, j);
+ }
+ // Skip entries without a server.
+ if (printserver.equals("")) {
+ Debug.warning(
+ "SVR: printer does not have a server: "
+ + printername);
+ continue;
+ }
+
+ // Extract description
+ i = o.indexOf("description=", colon);
+ if ((i != -1) && (i < nextcolon)) {
+ j = i;
+ while (j < o.length()) {
+ if (o.charAt(j) == '\n')
+ break;
+ j++;
+ }
+ comment = o.substring(i + 12, j);
+ }
+
+ list[listi++] = printername;
+ list[listi++] = printserver;
+ list[listi++] = comment;
+ printername = "";
+ printserver = "";
+ comment = "";
+ }
+ return (list);
+ }
+
+ public static boolean exists(
+ String name,
+ String ns) throws Exception
+ {
+ int exitvalue;
+
+ Debug.message("SVR: DoPrinterUtil.exists() " + ns);
+
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/lpget -n " + ns + " " + name);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+ if (exitvalue == 0) {
+ return (true);
+ }
+ return (false);
+ }
+
+ public static boolean isLocal(
+ String pn) throws Exception
+ {
+ int exitvalue;
+
+ Debug.message("SVR: DoPrinterUtil.isLocal()");
+
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/test -d /etc/lp/printers/" + pn);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+ if (exitvalue != 0) {
+ return (false);
+ }
+ return (true);
+ }
+
+ public static boolean isLocalhost(
+ String queue) throws Exception
+ {
+ int exitvalue;
+ String o = null;
+
+ Debug.message("SVR: DoPrinterUtil.isLocalhost():queue " + queue);
+
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/grep " + queue + " /etc/printers.conf");
+ exitvalue = syscmd.getExitValue();
+ if (exitvalue != 0) {
+ Debug.message(
+ "SVR:DoPrinterUtil:isLocalhost:failed:queue: " + queue);
+ return (false);
+ }
+ o = syscmd.getOutput();
+ syscmd = null;
+ Debug.message("SVR:DoPrinterUtil.java:isLocalhost: output: " + o);
+ if (o.indexOf("localhost") != -1)
+ return (true);
+ else
+ return (false);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterView.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterView.java
new file mode 100644
index 0000000000..d3446bb6bd
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/DoPrinterView.java
@@ -0,0 +1,485 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * DoPrinterView class
+ * Worker class for gathering printer information.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+import java.util.*;
+
+import com.sun.admin.pm.client.pmNeedPPDCacheException;
+import com.sun.admin.pm.client.pmCacheMissingPPDException;
+// import com.sun.admin.pm.client.pmGuiException;
+
+public class DoPrinterView {
+
+ public static void main(String[] args) {
+ Debug.setDebugLevel(Debug.ALL);
+
+ Printer p = new Printer();
+ p.setPrinterName("petite");
+ NameService ns = new NameService();
+
+ try {
+ view(p, ns);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ PrinterDebug.printObj(p);
+
+ System.out.println("Commands:\n" + p.getCmdLog());
+ System.out.println("Errors:\n" + p.getErrorLog());
+ System.out.println("Warnings:\n" + p.getWarnLog());
+ System.exit(0);
+ }
+
+ //
+ // Interface to Printer object.
+ //
+ public static void view(
+ Printer p,
+ NameService ns) throws Exception
+ {
+ boolean islocal =
+ DoPrinterUtil.isLocal(p.getPrinterName());
+ if (islocal) {
+ viewLocal(p, ns);
+ } else {
+ viewRemote(p, ns);
+ }
+
+ return;
+ }
+
+ //
+ // Do the work getting Remote printer attributes.
+ //
+ private static void viewRemote(
+ Printer p,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterView.viewRemote()");
+
+ int exitvalue = 0;
+ int i, j;
+ String o = null;
+ String printername = p.getPrinterName();
+ String printserver = null;
+ String comment = null;
+ String extensions = null;
+ boolean default_printer = false;
+
+ String nsarg = ns.getNameService();
+
+ String err = null;
+
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/lpget -n " + nsarg + " " +
+ printername, "LC_ALL=C");
+
+ if (syscmd.getExitValue() != 0) {
+ err = syscmd.getError();
+ p.setErrorLog(err);
+ // Add stdout since thats where lpget sends errors.
+ err = syscmd.getOutput();
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ }
+ o = syscmd.getOutput();
+ syscmd = null;
+
+ if (o == null) {
+ throw new pmCmdFailedException(err);
+ }
+ // For easier parsing.
+ o = o.concat("\n");
+
+ i = o.indexOf("bsdaddr=");
+ if (i == -1) {
+ Debug.message("SVR: Can't parse bsdaddr for " + printername);
+ throw new pmException();
+ }
+ i = i + 8;
+ j = o.indexOf(",", i);
+ if (j == -1) {
+ Debug.message("SVR: Can't parse bsdaddr for " + printername);
+ throw new pmException();
+ }
+ printserver = o.substring(i, j);
+
+ i = o.indexOf(",Solaris");
+ if (i != -1) {
+ extensions = "Solaris";
+ }
+
+ i = o.indexOf("description=");
+ if (i != -1) {
+ i = i + 12;
+ j = o.indexOf("\n", i);
+ if (j != -1) {
+ comment = o.substring(i, j);
+ }
+ }
+
+ String def = DoPrinterUtil.getDefault(nsarg);
+ if ((def != null) && (def.equals(printername))) {
+ default_printer = true;
+ }
+ p.setPrintServer(printserver);
+ p.setExtensions(extensions);
+ p.setComment(comment);
+ p.setIsDefaultPrinter(default_printer);
+ return;
+ }
+
+ //
+ // Do the work getting printer attributes.
+ //
+ private static void viewLocal(
+ Printer p, NameService ns) throws Exception
+ {
+ Debug.message("SVR: DoPrinterView.viewLocal()");
+
+ int i = -1;
+ int exitvalue = 0;
+ String str = null;
+ String o = null;
+
+ String printername = p.getPrinterName();
+ String printertype = null;
+ String printserver = null;
+ String comment = null;
+ String device = null;
+ String make = null;
+ String model = null;
+ String ppd = null;
+ String notify = null;
+ String protocol = null;
+ String destination = null;
+ String extensions = "Solaris";
+ String[] file_contents = null;
+ String[] user_allow_list = null;
+ String[] user_deny_list = null;
+ boolean default_printer = false;
+ String banner = null;
+ boolean enable = false;
+ boolean accept = false;
+
+ String ppdfile = null;
+
+ String def = DoPrinterUtil.getDefault("system");
+ if ((def != null) && (def.equals(printername))) {
+ default_printer = true;
+ }
+
+ //
+ // Parse lpstat output
+ //
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/lpstat -L -l -a " +
+ printername + " -p " + printername, "LC_ALL=C");
+
+ if (syscmd.getExitValue() != 0) {
+ String err = syscmd.getError();
+ p.setErrorLog(err);
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ }
+
+ o = syscmd.getOutput();
+ syscmd = null;
+
+ // Append a newline to make parsing easier.
+ o = o.concat("\n");
+
+ comment = getToken(o, "\tDescription:");
+ if (comment == null || comment.equals("")) {
+ comment = null;
+ }
+
+ // Get the PPD path/filename from lpstat
+ // Get the make/model/ppd nickname using ppd-filename
+ ppdfile = getToken(o, "\tPPD:");
+ if ((ppdfile == null) || (ppdfile.equals("none")) ||
+ (ppdfile.equals(""))) {
+ ppdfile = null;
+ } else {
+ // Set the make/model/ppd
+
+ if (!pmMisc.isppdCachefile()) {
+ throw new pmNeedPPDCacheException("ppdcache missing");
+ }
+ String ret[];
+ ret = new String[3];
+ ret = DoPrinterUtil.getMakeModelNick(ppdfile);
+
+ if ((ret != null) && (!ret.equals(""))) {
+ make = ret[0];
+ model = ret[1];
+ ppd = ret[2];
+ } else {
+ throw new pmCacheMissingPPDException(
+ "PPD file not in cache");
+ }
+ }
+
+ int j = -1;
+ printserver = p.getPrintServer();
+
+ printertype = getToken(o, "Printer types:");
+ i = o.indexOf("enabled since");
+ if (i != -1) {
+ enable = true;
+ }
+ i = o.indexOf("not accepting requests");
+ if (i == -1) {
+ accept = true;
+ }
+
+ i = o.indexOf("Banner not required");
+ if (i != -1) {
+ banner = "optional";
+ }
+ i = o.indexOf("Banner required");
+ if (i != -1) {
+ banner = "always";
+ }
+ i = o.indexOf("Banner page never printed");
+ if (i != -1) {
+ banner = "never";
+ }
+
+
+
+ // If we have Options then look for destination and protocol.
+ protocol = "bsd";
+ str = "Options:";
+ i = o.indexOf(str);
+ if (i != -1) {
+ // Set str to the substring containing only the options line.
+ j = o.indexOf("\n", i);
+ str = o.substring(i, j);
+
+ // Append a comma to make parsing easier.
+ str = str.concat(",");
+ i = str.indexOf("dest=");
+ if (i != -1) {
+ i += 5;
+ j = str.indexOf(",", i);
+ destination = str.substring(i, j);
+ destination = destination.trim();
+ }
+ i = str.indexOf("protocol=");
+ if (i != -1) {
+ i += 9;
+ j = str.indexOf(",", i);
+ protocol = str.substring(i, j);
+ protocol = protocol.trim();
+ }
+ }
+
+ StringTokenizer st;
+
+ // Build array of content types.
+ str = getToken(o, "Content types:");
+ if (str != null) {
+ str = str.replace(',', ' ');
+ st = new StringTokenizer(str);
+ if (st.countTokens() != 0) {
+ file_contents = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ file_contents[i] = st.nextToken();
+ }
+ }
+ }
+
+ //
+ // User allow list.
+ //
+ str = "Users allowed:\n";
+ i = o.indexOf(str);
+ if (i != -1) {
+ i += str.length();
+ // Grab the substring containing only users.
+ j = o.indexOf("\tForms");
+ if (j != -1) {
+ str = o.substring(i, j);
+ st = new StringTokenizer(str);
+ if (st.countTokens() != 0) {
+ user_allow_list = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ user_allow_list[i] = st.nextToken();
+ }
+ }
+ }
+ }
+ if (user_allow_list == null) {
+ } else if (user_allow_list[0].equals("(all)")) {
+ user_allow_list[0] = "all";
+ } else if (user_allow_list[0].equals("(none)")) {
+ user_allow_list[0] = "none";
+ }
+ //
+ // User deny list
+ //
+ syscmd = new SysCommand();
+ String cmd = "/bin/cat /etc/lp/printers/" + printername + "/users.deny";
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() == 0) {
+ str = syscmd.getOutput();
+ if ((str != null) && (str.length() != 0)) {
+ st = new StringTokenizer(str);
+ if (st.countTokens() != 0) {
+ user_deny_list = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ user_deny_list[i] = st.nextToken();
+ }
+ }
+ }
+ }
+ syscmd = null;
+
+ //
+ // Get fault action
+ //
+ str = getToken(o, "On fault:");
+ if (str != null) {
+ if (!str.equals("")) {
+ if (str.indexOf("write") != -1) {
+ notify = "write";
+ } else if (str.indexOf("mail") != -1) {
+ notify = "mail";
+ } else if (str.indexOf("no alert") != -1) {
+ notify = "none";
+ } else if (str.indexOf("alert with") != -1) {
+ i = str.indexOf("\"");
+ if (i != -1) {
+ j = str.lastIndexOf("\"");
+ if (j > i) {
+ notify = str.substring(++i, j);
+ }
+ }
+ } else if (str.indexOf(" quiet ") != -1) {
+ notify = "quiet";
+ } else {
+ notify = "unknown";
+ }
+ }
+ }
+ syscmd = null;
+ //
+ // Get the printers device
+ //
+ syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/lpstat -L -v " + printername,
+ "LC_ALL=C");
+
+ o = syscmd.getOutput();
+ if (o != null) {
+ o = o.concat("\n");
+ device = getToken(o, ":");
+ }
+
+ Debug.message("SVR: DEVICE (" + device + ")");
+ //
+ // If the device is in URI form (scheme:// ...), set the protocol
+ // for the "network attached" modify screen.
+ //
+ if (device != null && device.indexOf("://") != -1) {
+ protocol = "uri";
+ destination = device;
+ device = null;
+ }
+
+ syscmd = null;
+
+ p.setPrinterType(printertype);
+ p.setPrintServer(printserver);
+ p.setFileContents(file_contents);
+ p.setComment(comment);
+ p.setDevice(device);
+ p.setMake(make);
+ p.setModel(model);
+ p.setPPD(ppd);
+ p.setPPDFile(ppdfile);
+ p.setNotify(notify);
+ p.setProtocol(protocol);
+ p.setDestination(destination);
+ p.setExtensions(extensions);
+ p.setIsDefaultPrinter(default_printer);
+ p.setBanner(banner);
+ p.setEnable(enable);
+ p.setAccept(accept);
+ p.setUserAllowList(user_allow_list);
+ p.setUserDenyList(user_deny_list);
+
+ if (ns.getNameService().equals("system"))
+ return;
+ Debug.message(
+ "SVR: Overlaying name service attributes on local printer");
+ try {
+ viewRemote(p, ns);
+ }
+ catch (Exception e)
+ {
+ Debug.warning(
+ "SVR: Overlay of name service attributes failed.");
+ Debug.warning("SVR: " + e.getMessage());
+ }
+ return;
+ }
+
+ //
+ // Return substring starting at sub + 1 and ending with
+ // a newline.
+ //
+ public static String getToken(String str, String sub)
+ {
+ int i = -1;
+ int j = -1;
+ String result = null;
+
+ i = str.indexOf(sub);
+ if (i != -1) {
+ if (str.charAt(i + sub.length()) == '\n') {
+ return (null);
+ }
+ i = i + sub.length();
+ j = str.indexOf("\n", i);
+ if (j != -1) {
+ result = str.substring(i, j);
+ result = result.trim();
+ }
+ }
+ return (result);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Host.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Host.java
new file mode 100644
index 0000000000..330d990b7b
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Host.java
@@ -0,0 +1,351 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Host class
+ * Methods associated with a host.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+
+public class Host
+{
+ public static void main(String[] args)
+ {
+ try {
+ System.out.println(getLocalHostName());
+ System.out.println(getDomainName());
+ System.out.println(getNisHost("master"));
+ }
+ catch (Exception e) {
+ System.out.println(e);
+ }
+ System.exit(0);
+ }
+
+ //
+ // Get the local hostname
+ // Return an empty string if we don't find one.
+ //
+ public synchronized static String getLocalHostName()
+ throws Exception
+ {
+ Debug.message("SVR: Host.getLocalHostName()");
+
+ String cmd = "/usr/bin/hostname";
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+
+ if (syscmd.getExitValue() != 0) {
+ String err = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ }
+ String o = syscmd.getOutput();
+ syscmd = null;
+
+ if (o == null)
+ return (new String(""));
+ return (new String(o));
+ }
+
+ //
+ // Get the domainname
+ // Return an empty string if we don't find one.
+ //
+ public synchronized static String getDomainName()
+ throws Exception
+ {
+ Debug.message("SVR: Host.getDomainName()");
+
+ String cmd = "/usr/bin/domainname";
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ String err = syscmd.getError();
+ syscmd = null;
+ throw new pmCmdFailedException(err);
+ }
+
+ String o = syscmd.getOutput();
+ syscmd = null;
+
+ if (o == null)
+ return (new String(""));
+ return (new String(o));
+ }
+
+ public synchronized static void pingHost(String host)
+ throws Exception
+ {
+ int exitvalue;
+
+ Debug.message("SVR: Host.pingHost()");
+
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/sbin/ping " + host);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+
+ if (exitvalue != 0) {
+ String err = syscmd.getError();
+ throw new pmHostNotPingableException(err);
+ }
+ }
+
+ public synchronized static String getNisMaster()
+ throws Exception
+ {
+ return (getNisHost("master"));
+ }
+
+ //
+ // Look for the nis server.
+ // If we are looking for the master server first try
+ // the printers.conf.byname map. If that fails
+ // look for passwd.
+ //
+ public synchronized static String getNisHost(String type)
+ throws Exception
+ {
+ Debug.message("SVR: Host.getNisHost() " + type);
+
+ SysCommand syscmd = null;
+ String cmd = null;
+ int exitvalue = 0;
+
+ if (type.equals("master")) {
+ cmd = "/usr/bin/ypwhich -m printers.conf.byname";
+ } else {
+ cmd = "/usr/bin/ypwhich";
+ }
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ exitvalue = syscmd.getExitValue();
+ if ((exitvalue != 0) && (type.equals("master"))) {
+ Debug.message("SVR: printers.conf NIS host not found.");
+ Debug.message("SVR: Looking for NIS passwd host.");
+ cmd = "/usr/bin/ypwhich -m passwd";
+
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ exitvalue = syscmd.getExitValue();
+ }
+ if (exitvalue != 0) {
+ Debug.error("SVR: NIS server could not be found");
+ String err = syscmd.getError();
+ syscmd = null;
+ throw new pmNSNotConfiguredException(err);
+ }
+
+ String o = syscmd.getOutput();
+ syscmd = null;
+
+ if (o == null) {
+ throw new pmCmdFailedException(syscmd.getError());
+ }
+ o = o.trim();
+ return (new String(o));
+ }
+
+ /*
+ * Return the name of the first server listed by ldapclient
+ */
+ public synchronized static String getLDAPMaster()
+ throws Exception
+ {
+ SysCommand syscmd = null;
+ String cmd = null;
+ int exitvalue = 0;
+
+ /* ldapclient will hang if we are not root. */
+ if (!DoPrinterNS.isRoot()) {
+ Debug.error("SVR: Not root. Can't determine LDAP master.");
+ return null;
+ }
+
+ cmd = "/usr/sbin/ldapclient list";
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ exitvalue = syscmd.getExitValue();
+
+ if (exitvalue != 0) {
+ Debug.error("SVR: ldapclient failed.");
+ Debug.error("SVR: " + syscmd.getError());
+ syscmd = null;
+ return null;
+ }
+ String o = syscmd.getOutput();
+ syscmd = null;
+
+ String master = DoPrinterView.getToken(o + "\n", "NS_LDAP_SERVERS=");
+ if (master == null) {
+ Debug.error("SVR: ldapclient did not return NS_LDAP_SERVERS.");
+ syscmd = null;
+ return null;
+ }
+
+ /* Extract the first address from the NS_LDAP_SERVERS list */
+
+ for (int i = 0; i < master.length(); i++) {
+ if ((master.charAt(i) == ',') ||
+ (master.charAt(i) == ' ') ||
+ (master.charAt(i) == '\t')) {
+ master = master.substring(0, i);
+ break;
+ }
+ }
+ master = master.trim();
+
+ return (new String(master));
+ }
+
+ /*
+ * Get a default admin DN.
+ */
+ public synchronized static String getDefaultAdminDN()
+ throws Exception
+ {
+ SysCommand syscmd = null;
+ String cmd = null;
+ int exitvalue = 0;
+
+ try {
+ String master = getLDAPMaster();
+ cmd = "/usr/bin/ldapsearch -h " + master +
+ " -b o=NetScapeRoot o=NetscapeRoot";
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ exitvalue = syscmd.getExitValue();
+ if (exitvalue == 0) {
+ String on = syscmd.getOutput();
+ syscmd = null;
+ if (on != null) {
+ if (on.indexOf("NetscapeRoot") != -1) {
+ return ("cn=Directory Manager");
+ }
+ }
+ }
+ syscmd = null;
+ }
+ catch (Exception e) {
+ Debug.message("SVR: ldapsearch for NSDS failed. Continuing");
+ }
+
+ cmd = "/usr/bin/ldaplist -d printers";
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ exitvalue = syscmd.getExitValue();
+
+ if (exitvalue != 0) {
+ Debug.error("SVR: ldaplist printers failed.");
+ Debug.error("SVR: " + syscmd.getError());
+ syscmd = null;
+ return null;
+ }
+ String o = syscmd.getOutput();
+ syscmd = null;
+
+ if (o == null) {
+ return null;
+ }
+
+ String dn = DoPrinterView.getToken(o + "\n", "ou=printers,");
+ if (dn == null) {
+ return null;
+ }
+ dn = "cn=admin," + dn;
+ dn = dn.trim();
+
+ return (new String(dn));
+ }
+
+ //
+ // Check to see if a name service is configured
+ //
+ public synchronized static void isNSConfigured(String ns)
+ throws Exception
+ {
+ Debug.message("SVR: Host.isNSConfigured() " + ns);
+
+ int exitvalue;
+ String cmd = null;
+ String err = null;
+ SysCommand syscmd = null;
+
+ if (ns.equals("system")) {
+ return;
+ } else if (ns.equals("nis")) {
+ cmd = "/usr/bin/ypwhich";
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ exitvalue = syscmd.getExitValue();
+ err = syscmd.getError();
+ syscmd = null;
+
+ if (exitvalue != 0) {
+ throw new pmNSNotConfiguredException(err);
+ }
+
+ cmd = "/usr/bin/ypcat cred";
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+ if (exitvalue == 0) {
+ Debug.warning(
+ "SVR: Unable to update this configuration.");
+ throw new pmNSNotConfiguredException();
+ }
+ } else if (ns.equals("ldap")) {
+ /*
+ * Check if the ldap-client is configured by first checking
+ * if the config file exists and then invoking ldaplist
+ * Note: we need to check if the config file exists before
+ * invoking ldaplist so that we don't get its error message
+ */
+
+ File ldapConfig = new File("/var/ldap/ldap_client_file");
+ if (ldapConfig.isFile()) {
+ // Config file exists
+
+ cmd = "/usr/bin/ldaplist -d printers";
+ syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+
+ if (exitvalue != 0) {
+ throw new pmNSNotConfiguredException();
+ }
+ } else {
+ throw new pmNSNotConfiguredException();
+ }
+ } else {
+ throw new pmInternalErrorException(
+ "Unkown name service " + ns);
+ }
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Makefile b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Makefile
new file mode 100644
index 0000000000..690b18ccfa
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Makefile
@@ -0,0 +1,126 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Makefile for Java Print Manager server
+#
+
+LIBRARY = libpmgr.a
+VERS = .1
+
+JNIHDR_FILES = com_sun_admin_pm_server_DoPrinterNS.h
+
+OBJECTS = DoPrinterNS.o NS.o
+
+CLASSFILES = Printer.class \
+ Host.class \
+ SysCommand.class \
+ NameService.class \
+ PrinterUtil.class \
+ DoPrinterView.class \
+ DoPrinterAdd.class \
+ DoPrinterDelete.class \
+ DoPrinterUtil.class \
+ DoPrinterMod.class \
+ DoPrinterNS.class \
+ Valid.class \
+ Test.class \
+ Debug.class \
+ PrinterDebug.class \
+ pmException.class \
+ pmAuthException.class \
+ pmAuthRhostException.class \
+ pmCmdFailedException.class \
+ pmInternalErrorException.class \
+ pmHostNotPingableException.class \
+ pmNSNotConfiguredException.class \
+ pmMisc.class
+
+JNICLASSFILES = DoPrinterNS.class
+
+include $(SRC)/lib/Makefile.lib
+
+SRCDIR = .
+
+# There should be a mapfile here
+MAPFILES =
+
+CLASSPATH= $(SRC)/cmd/print/printmgr
+
+JAVAFILES = $(CLASSFILES:.class=.java)
+
+ROOTDIRS = $(ROOT)/usr/sadm/admin \
+ $(ROOT)/usr/sadm/admin/printmgr \
+ $(ROOT)/usr/sadm/admin/printmgr/lib
+
+# override ROOTLIBDIR and ROOTLINKS
+ROOTLIBDIR = $(ROOT)/usr/sadm/admin/printmgr/lib
+ROOTLIBS= $(LIBS:%=$(ROOTLIBDIR)/%)
+
+
+# Following variables define where to find header files
+CPPFLAGS += -I$(JAVA_ROOT)/include -I$(JAVA_ROOT)/include/solaris -I.
+
+CERRWARN += -_gcc=-Wno-unused-variable
+CERRWARN += -_gcc=-Wno-uninitialized
+
+LDLIBS += -lprint -lnsl -lsocket -lc
+
+CLEANFILES= *.class $(LINTLIB) $(LINTOUT)
+CLOBBERFILES= $(JNIHDR_FILES) $(LIBLINKS)
+
+all: $(CLASSFILES) $(JNIHDR_FILES) $(DYNLIB)
+
+install: all $(ROOTDIRS) $(ROOTLINKS)
+
+#
+# Build jni header file
+# Use $@ instead of the "unreliable" $*
+#
+$(JNIHDR_FILES): $(JNICLASSFILES)
+ $(JAVAH) -jni -classpath $(CLASSPATH) \
+ `echo $@ | sed 's/.h$$//' | tr _ .`
+
+#
+# Build standalone programs for testing
+#
+NS: NS.c
+ $(CC) NS.c -g $(ILDOFF) -o NS -DMAIN=1 $(ENVLDLIBS1) $(ENVLIBS2) \
+ -lprint -lnsl -lsocket
+
+lint: $(JNIHDR_FILES) lintcheck
+
+cstyle:
+ cstyle $(SRCS)
+
+jstyle:
+ jstyle $(JAVAFILES)
+
+_msg:
+
+$(ROOTDIRS):
+ $(INS.dir)
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/NS.c b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/NS.c
new file mode 100644
index 0000000000..eeeefdd31c
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/NS.c
@@ -0,0 +1,821 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <rpcsvc/ypclnt.h>
+
+char glob_stdout[BUFSIZ];
+char glob_stderr[BUFSIZ];
+
+void f_cleanup(FILE *fp, char *tmpf);
+void fd_cleanup(int fd1, int fd2);
+static void _freeList(char ***list);
+
+extern void **list_append(void **list, void *item);
+
+#ifdef MAIN
+
+#define THOSTNAME "cherwell"
+#define TPRINTERNAME "c"
+
+int
+main() {
+ char *host = THOSTNAME;
+ const char *user = "cn=Directory Manager";
+ const char *passwd = "directorymanager";
+ int result = 0;
+
+ result = _updateldap("add", host, user, passwd,
+ "_pmTestAuthToken", NULL, NULL, "new comment", "false");
+ if (result != 0) {
+ printf("Add 1 failed, err code = %d\n");
+ }
+
+ result = _updateldap("delete", host, user, passwd,
+ "_pmTestAuthToken", NULL, NULL, NULL, "false");
+ if (result != 0) {
+ printf("Delete 1 failed, err code = %d\n");
+ }
+
+ result = _updateldap("delete", host, user, passwd, TPRINTERNAME,
+ THOSTNAME, "", "new comment", "true");
+ if (result != 0) {
+ printf("delete failed, err code = %d\n");
+ }
+
+ result = _updateldap("delete", host, user, passwd, "_default",
+ THOSTNAME, "", "new comment", "true");
+ if (result != 0) {
+ printf("delete failed, err code = %d\n");
+ }
+
+ result = _updateldap("add", host, user, passwd, TPRINTERNAME,
+ THOSTNAME, "Solaris", "new comment", "true");
+ if (result != 0) {
+ printf("add failed, err code = %d\n");
+ }
+
+ result = _updateldap("modify", host, user, passwd, TPRINTERNAME,
+ THOSTNAME, "", "modified comment", "true");
+ if (result != 0) {
+ printf("modify failed, err code = %d\n");
+ }
+
+ result = _updateldap("modify", host, user, passwd, TPRINTERNAME,
+ THOSTNAME, "", NULL, "false");
+ if (result != 0) {
+ printf("modify failed, err code = %d\n");
+ }
+
+
+ exit(0);
+}
+#endif
+
+
+int
+_dorexec(
+ const char *host,
+ const char *user,
+ const char *passwd,
+ const char *cmd,
+ const char *locale) {
+
+ int ret = 0;
+ int fd = 0;
+ int fd2 = 1;
+
+ FILE *fderr;
+ char *ferr;
+
+ (void) memset(glob_stdout, 0, BUFSIZ);
+ (void) memset(glob_stderr, 0, BUFSIZ);
+
+ /*
+ * Re-direct stderr to a file
+ */
+ ferr = tempnam(NULL, NULL);
+ if (ferr != NULL) {
+ fderr = freopen(ferr, "w+", stderr);
+ }
+
+ fd = rexec((char **)&host, htons(512), user,
+ passwd, cmd, &fd2);
+
+ if (fd > -1) {
+ /*
+ * rexec worked. Clean up stderr file.
+ */
+ f_cleanup(fderr, ferr);
+
+ ret = read(fd, glob_stdout, BUFSIZ - 1);
+ if (ret < 0) {
+ (void) strncpy(glob_stderr, strerror(errno),
+ (BUFSIZ - 1));
+ fd_cleanup(fd, fd2);
+ return (errno);
+ }
+
+ ret = read(fd2, glob_stderr, BUFSIZ - 1);
+ if (ret < 0) {
+ (void) strncpy(glob_stderr, strerror(errno),
+ (BUFSIZ - 1));
+ fd_cleanup(fd, fd2);
+ return (errno);
+ }
+ } else {
+ /*
+ * rexec failed. Read from the stderr file.
+ */
+ if (fderr != NULL) {
+ char tmpbuf[BUFSIZ];
+
+ (void) rewind(fderr);
+ strcpy(glob_stderr, "");
+ while (fgets(tmpbuf, BUFSIZ - 1,
+ fderr) != NULL) {
+ if ((strlen(glob_stderr) +
+ strlen(tmpbuf)) > BUFSIZ - 1) {
+ break;
+ } else {
+ (void) strcat(glob_stderr, tmpbuf);
+ }
+ }
+ }
+ f_cleanup(fderr, ferr);
+ fd_cleanup(fd, fd2);
+ return (1);
+ }
+ fd_cleanup(fd, fd2);
+ return (0);
+}
+
+void
+fd_cleanup(int fd, int fd2)
+{
+ if (fd > 0) {
+ (void) close(fd);
+ }
+ if (fd2 > 0) {
+ (void) close(fd2);
+ }
+}
+
+void
+f_cleanup(FILE *fp, char *tmpf)
+{
+ if (fp != NULL) {
+ (void) fclose(fp);
+ }
+ if (tmpf != NULL) {
+ (void) unlink(tmpf);
+ (void) free(tmpf);
+ }
+}
+
+struct ns_bsd_addr {
+ char *server; /* server name */
+ char *printer; /* printer name or NULL */
+ char *extension; /* RFC-1179 conformance */
+ char *pname; /* Local printer name */
+};
+typedef struct ns_bsd_addr ns_bsd_addr_t;
+
+/* Key/Value pair structure */
+struct ns_kvp {
+ char *key; /* key */
+ void *value; /* value converted */
+};
+typedef struct ns_kvp ns_kvp_t;
+
+/*
+ * Information needed to update a name service.
+ * Currently only used for ldap. (see lib/print/ns.h)
+ */
+
+/* LDAP bind password security type */
+
+typedef enum NS_PASSWD_TYPE {
+ NS_PW_INSECURE = 0,
+ NS_PW_SECURE = 1
+} NS_PASSWD_TYPE;
+
+
+struct ns_cred {
+ char *binddn;
+ char *passwd;
+ char *host;
+ int port; /* LDAP port, 0 = default */
+ NS_PASSWD_TYPE passwdType; /* password security type */
+ uchar_t *domainDN; /* NS domain DN */
+};
+typedef struct ns_cred ns_cred_t;
+
+/* LDAP specific NS Data */
+
+typedef struct NS_LDAPDATA {
+ char **attrList; /* list of user defined Key Value Pairs */
+} NS_LDAPDATA;
+
+/* Printer Object structure */
+struct ns_printer {
+ char *name; /* primary name of printer */
+ char **aliases; /* aliases for printer */
+ char *source; /* name service derived from */
+ ns_kvp_t **attributes; /* key/value pairs. */
+ ns_cred_t *cred; /* info to update name service */
+ void *nsdata; /* name service specific data */
+};
+typedef struct ns_printer ns_printer_t;
+
+extern ns_printer_t *ns_printer_get_name(const char *, const char *);
+extern int ns_printer_put(const ns_printer_t *);
+extern char *ns_get_value_string(const char *, const ns_printer_t *);
+extern int ns_set_value(const char *, const void *, ns_printer_t *);
+extern int ns_set_value_from_string(const char *, const char *,
+ ns_printer_t *);
+extern ns_bsd_addr_t *bsd_addr_create(const char *, const char *,
+ const char *);
+extern char *bsd_addr_to_string(const ns_bsd_addr_t *);
+extern void ns_printer_destroy(ns_printer_t *);
+
+int
+_updateoldyp(
+ const char *action,
+ const char *printername,
+ const char *printserver,
+ const char *extensions,
+ const char *comment,
+ const char *isdefault) {
+
+ ns_printer_t *printer;
+ ns_bsd_addr_t *addr;
+ int status = 0;
+
+ char mkcmd[BUFSIZ];
+ char *domain = NULL;
+ char *host = NULL;
+
+ /*
+ * libprint returns before we know that the printers.conf
+ * map is made. So we'll make it again.
+ */
+ (void) yp_get_default_domain(&domain);
+
+ if ((yp_master(domain, "printers.conf.byname", &host) != 0) &&
+ (yp_master(domain, "passwd.byname", &host) != 0)) {
+ strcpy(mkcmd, "/usr/bin/sleep 1");
+ } else {
+ sprintf(mkcmd, "/usr/bin/rsh -n %s 'cd /var/yp; "
+ "/usr/ccs/bin/make -f /var/yp/Makefile "
+ "-f /var/yp/Makefile.print printers.conf "
+ "> /dev/null'", host);
+ }
+
+ if (strcmp(action, "delete") == 0) {
+ if ((printer = (ns_printer_t *)
+ ns_printer_get_name(printername, "nis")) == NULL) {
+ return (0);
+ }
+
+ printer->attributes = NULL;
+ status = ns_printer_put(printer);
+ if (status != 0) {
+ (void) free(printer);
+ return (status);
+ }
+
+ if ((printer = (ns_printer_t *)
+ ns_printer_get_name("_default", "nis")) != NULL) {
+ char *dflt = (char *)
+ ns_get_value_string("use", printer);
+ if ((dflt != NULL) &&
+ (strcmp(dflt, printername) == 0)) {
+ printer->attributes = NULL;
+ status = ns_printer_put(printer);
+ if (status != 0) {
+ (void) free(printer);
+ return (status);
+ }
+ }
+ }
+ (void) free(printer);
+ (void) system(mkcmd);
+ return (0);
+
+ } else if (strcmp(action, "add") == 0) {
+ printer = (ns_printer_t *)malloc(sizeof (*printer));
+ memset(printer, 0, sizeof (*printer));
+ printer->name = (char *)printername;
+ printer->source = "nis";
+
+ addr = (ns_bsd_addr_t *)malloc(sizeof (*addr));
+ memset(addr, 0, sizeof (*addr));
+ addr->printer = (char *)printername;
+ addr->server = (char *)printserver;
+ if ((extensions != NULL) &&
+ (strlen(extensions) > 0)) {
+ addr->extension = (char *)extensions;
+ }
+ ns_set_value("bsdaddr", addr, printer);
+
+ if ((comment != NULL) && (strlen(comment) > 0)) {
+ ns_set_value_from_string("description",
+ comment, printer);
+ }
+ status = ns_printer_put(printer);
+ if (status != 0) {
+ (void) free(addr);
+ (void) free(printer);
+ return (status);
+ }
+
+ if (strcmp(isdefault, "true") == 0) {
+ printer->name = "_default";
+ printer->attributes = NULL;
+ ns_set_value_from_string("use", printername, printer);
+ status = ns_printer_put(printer);
+ if (status != 0) {
+ (void) free(addr);
+ (void) free(printer);
+ return (status);
+ }
+ }
+ (void) free(addr);
+ (void) free(printer);
+ (void) system(mkcmd);
+ return (0);
+ }
+
+ /*
+ * Modify
+ */
+ if ((printer = (ns_printer_t *)
+ ns_printer_get_name(printername, "nis")) == NULL) {
+ return (1);
+ }
+ if ((comment != NULL) && (strlen(comment) > 0)) {
+ ns_set_value_from_string("description", comment, printer);
+ } else {
+ ns_set_value_from_string("description",
+ NULL, printer);
+ }
+ status = ns_printer_put(printer);
+ if (status != 0) {
+ (void) free(printer);
+ return (status);
+ }
+
+ if ((printer = (ns_printer_t *)
+ ns_printer_get_name("_default", "nis")) != NULL) {
+ char *dflt = (char *)ns_get_value_string("use", printer);
+ if (strcmp(printername, dflt) == 0) {
+ if (strcmp(isdefault, "false") == 0) {
+ /*
+ * We were the default printer but not
+ * any more.
+ */
+ printer->attributes = NULL;
+ status = ns_printer_put(printer);
+ if (status != 0) {
+ (void) free(printer);
+ return (status);
+ }
+ }
+ } else {
+ if (strcmp(isdefault, "true") == 0) {
+ ns_set_value_from_string("use",
+ printername, printer);
+ status = ns_printer_put(printer);
+ if (status != 0) {
+ (void) free(printer);
+ return (status);
+ }
+ }
+ }
+ } else {
+ printer = (ns_printer_t *)malloc(sizeof (*printer));
+ memset(printer, 0, sizeof (*printer));
+ printer->name = "_default";
+ printer->source = "nis";
+ ns_set_value_from_string("use", printername, printer);
+ status = ns_printer_put(printer);
+ if (status != 0) {
+ (void) free(printer);
+ return (status);
+ }
+ }
+ (void) system(mkcmd);
+ return (0);
+}
+
+int
+_updateldap(
+ const char *action,
+ const char *host,
+ const char *binddn,
+ const char *passwd,
+ const char *printername,
+ const char *printserver,
+ const char *extensions,
+ const char *comment,
+ const char *isdefault)
+
+{
+ ns_printer_t *printer;
+ ns_bsd_addr_t *addr;
+ ns_cred_t *cred;
+
+ char *item = NULL;
+ char **attrList = NULL;
+
+ int status;
+
+ if (printserver == NULL) {
+ /* printserver not given so use host */
+ printserver = host;
+ }
+
+ cred = (ns_cred_t *)malloc(sizeof (*cred));
+ (void) memset(cred, '\0', sizeof (*cred));
+ cred->passwd = strdup((char *)passwd);
+ cred->binddn = strdup((char *)binddn);
+ cred->host = strdup((char *)host);
+
+ cred->passwdType = NS_PW_INSECURE; /* use default */
+ cred->port = 0; /* use default */
+ cred->domainDN = NULL; /* use default */
+
+ if (strcmp(action, "delete") == 0) {
+ /*
+ * Delete printer object from LDAP directory DIT
+ */
+
+ if ((printer = (ns_printer_t *)
+ ns_printer_get_name(printername, "ldap")) == NULL) {
+ return (0);
+ }
+
+ printer->attributes = NULL;
+ printer->nsdata = malloc(sizeof (NS_LDAPDATA));
+ if (printer->nsdata == NULL) {
+ return (1);
+ }
+ ((NS_LDAPDATA *)(printer->nsdata))->attrList = NULL;
+ printer->cred = cred;
+ printer->source = strdup("ldap");
+ status = ns_printer_put(printer);
+ free(printer->nsdata);
+ (void) ns_printer_destroy(printer);
+
+ if (status != 0) {
+ return (status);
+ }
+
+ if ((printer = (ns_printer_t *)
+ ns_printer_get_name("_default", "ldap")) != NULL) {
+ char *dflt = (char *)
+ ns_get_value_string("use", printer);
+ if ((dflt != NULL) &&
+ (strcmp(dflt, printername) == 0)) {
+ printer->attributes = NULL;
+ printer->nsdata = malloc(sizeof (NS_LDAPDATA));
+ if (printer->nsdata == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ ((NS_LDAPDATA *)(printer->nsdata))->attrList = NULL;
+ printer->cred = cred;
+ printer->source = strdup("ldap");
+ status = ns_printer_put(printer);
+ free(printer->nsdata);
+ if (status != 0) {
+ (void) ns_printer_destroy(printer);
+ return (status);
+ }
+ }
+
+ (void) ns_printer_destroy(printer);
+ }
+ return (0);
+
+ } else if (strcmp(action, "add") == 0) {
+ /*
+ * Add new printer object into LDAP directory DIT
+ */
+
+ printer = (ns_printer_t *)malloc(sizeof (*printer));
+ if (printer == NULL) {
+ return (1);
+ }
+ (void) memset(printer, 0, sizeof (*printer));
+ printer->name = strdup((char *)printername);
+ printer->source = strdup("ldap");
+
+ printer->cred = cred;
+
+ /* set BSD address in attribute list */
+
+ if (extensions == NULL) {
+ item = (char *)malloc(strlen("bsdaddr") +
+ strlen(printserver) +
+ strlen(printername) +
+ strlen("Solaris") + 6);
+ } else {
+ item = (char *)malloc(strlen("bsdaddr") +
+ strlen(printserver) +
+ strlen(printername) +
+ strlen(extensions) + 6);
+ }
+ if (item == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+
+ if (extensions == NULL) {
+ sprintf(item, "%s=%s,%s,%s", "bsdaddr",
+ printserver, printername, "Solaris");
+ } else {
+ sprintf(item, "%s=%s,%s,%s", "bsdaddr",
+ printserver, printername, extensions);
+ }
+
+ attrList = (char **)list_append((void**)attrList,
+ (void *)item);
+ if ((comment != NULL) && (strlen(comment) > 0)) {
+ item = (char *)malloc(strlen("description") +
+ strlen(comment) + 4);
+ if (item == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ sprintf(item, "%s=%s", "description", comment);
+ attrList = (char **)list_append((void**)attrList,
+ (void *)item);
+ }
+
+ printer->attributes = NULL;
+ printer->nsdata = malloc(sizeof (NS_LDAPDATA) + 2);
+ if (printer->nsdata == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
+
+ status = ns_printer_put(printer);
+ _freeList(&attrList);
+ if (status != 0) {
+ free(printer->nsdata);
+ (void) ns_printer_destroy(printer);
+ return (status);
+ }
+
+ if (strcmp(isdefault, "true") == 0) {
+ (void) free(printer->name);
+
+ printer->name = strdup("_default");
+ printer->attributes = NULL;
+
+ attrList = NULL;
+ item = (char *)malloc(strlen("use") +
+ strlen(printername) + 4);
+ if (item == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ sprintf(item, "%s=%s", "use", printername);
+ attrList = (char **)list_append((void**)attrList,
+ (void *)item);
+
+ ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
+
+ status = ns_printer_put(printer);
+ _freeList(&attrList);
+ free(printer->nsdata);
+ if (status != 0) {
+ (void) ns_printer_destroy(printer);
+ return (status);
+ }
+ }
+ (void) ns_printer_destroy(printer);
+ return (0);
+ }
+
+ /*
+ * Modify printer object in the LDAP directory DIT
+ */
+
+ if ((printer = (ns_printer_t *)
+ ns_printer_get_name(printername, "ldap")) == NULL) {
+ return (1);
+ }
+ printer->cred = cred;
+ printer->source = strdup("ldap");
+
+ if ((comment != NULL) && (strlen(comment) > 0)) {
+ item = (char *)malloc(strlen("description") +
+ strlen(comment) + 4);
+ if (item == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ sprintf(item, "%s=%s", "description", comment);
+ attrList = (char **)list_append((void**)attrList, (void *)item);
+ } else {
+ item = (char *)malloc(strlen("description") + 4);
+ if (item == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ sprintf(item, "%s=", "description");
+ attrList = (char **)list_append((void**)attrList, (void *)item);
+ }
+
+ printer->attributes = NULL;
+ printer->nsdata = malloc(sizeof (NS_LDAPDATA));
+ if (printer->nsdata == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
+
+ status = ns_printer_put(printer);
+ _freeList(&attrList);
+ free(printer->nsdata);
+ if (status != 0) {
+ (void) ns_printer_destroy(printer);
+ return (status);
+ }
+
+ /*
+ * Handle the default printer.
+ */
+ if ((printer = (ns_printer_t *)
+ ns_printer_get_name("_default", "ldap")) != NULL) {
+ char *dflt = (char *)ns_get_value_string("use", printer);
+
+ printer->source = strdup("ldap");
+ printer->cred = cred;
+ if (strcmp(printername, dflt) == 0) {
+ if (strcmp(isdefault, "false") == 0) {
+ /*
+ * We were the default printer but not
+ * any more. So delete the default entry
+ */
+ printer->attributes = NULL;
+ printer->nsdata = malloc(sizeof (NS_LDAPDATA));
+ if (printer->nsdata == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ ((NS_LDAPDATA *)(printer->nsdata))->attrList = NULL;
+ status = ns_printer_put(printer);
+ free(printer->nsdata);
+ if (status != 0) {
+ (void) ns_printer_destroy(printer);
+ return (status);
+ }
+ }
+ } else if (strcmp(isdefault, "true") == 0) {
+ /*
+ * Modify this default entry to use us.
+ */
+ printer->attributes = NULL;
+ printer->nsdata = malloc(sizeof (NS_LDAPDATA));
+ if (printer->nsdata == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ attrList = NULL;
+ item = (char *)malloc(strlen("use") +
+ strlen(printername) + 4);
+ if (item == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ sprintf(item, "%s=%s", "use", printername);
+ attrList = (char **)list_append((void**)attrList,
+ (void *)item);
+
+ ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
+
+ status = ns_printer_put(printer);
+ _freeList(&attrList);
+ free(printer->nsdata);
+
+ if (status != 0) {
+ (void) ns_printer_destroy(printer);
+ return (status);
+ }
+ }
+ } else if (strcmp(isdefault, "true") == 0) {
+ /*
+ * No default entry existed and we need one.
+ */
+ printer = (ns_printer_t *)malloc(sizeof (*printer));
+ (void) memset(printer, 0, sizeof (*printer));
+ printer->name = strdup("_default");
+ printer->source = strdup("ldap");
+ printer->cred = cred;
+
+ printer->nsdata = malloc(sizeof (NS_LDAPDATA));
+ if (printer->nsdata == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+
+ attrList = NULL;
+ item = (char *)malloc(strlen("use") + strlen(printername) + 4);
+ if (item == NULL) {
+ (void) ns_printer_destroy(printer);
+ return (1);
+ }
+ sprintf(item, "%s=%s", "use", printername);
+ attrList = (char **)list_append((void**)attrList, (void *)item);
+
+ ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
+
+ status = ns_printer_put(printer);
+ _freeList(&attrList);
+ free(printer->nsdata);
+
+ if (status != 0) {
+ (void) ns_printer_destroy(printer);
+ return (status);
+ }
+ }
+
+ (void) ns_printer_destroy(printer);
+ return (0);
+}
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _freeList()
+ *
+ * Description: Free the list created by list_append() where the items in
+ * the list have been strdup'ed.
+ *
+ * Parameters:
+ * Input: char ***list - returned set of kvp values
+ *
+ * Result: void
+ *
+ * *****************************************************************************
+ */
+
+static void
+_freeList(char ***list)
+
+{
+ int i = 0;
+
+ /* ------ */
+
+ if (list != NULL) {
+ if (*list != NULL) {
+ for (i = 0; (*list)[i] != NULL; i++) {
+ free((*list)[i]);
+ }
+ free(*list);
+ }
+
+ *list = NULL;
+ }
+} /* _freeList */
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/NameService.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/NameService.java
new file mode 100644
index 0000000000..8b3e874161
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/NameService.java
@@ -0,0 +1,140 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * NameService class
+ * Methods and state associated with a name service.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+
+public class NameService
+{
+ private String nameservice = null;
+ private String nshost = null;
+ private String user = null;
+ private String passwd = null;
+ private boolean boundtonisslave = false;
+ private boolean isauth = false;
+
+ //
+ // Constructors
+ //
+ // This constructor is used internally in the server package.
+ public NameService()
+ {
+ nameservice = "system";
+ isauth = true;
+ }
+ // This constructor should always be used by the client.
+ public NameService(String nsname) throws Exception
+ {
+ if ((nsname.equals("system")) ||
+ (nsname.equals("nis")) ||
+ (nsname.equals("ldap"))) {
+ nameservice = nsname;
+ } else {
+ throw new pmInternalErrorException(
+ "Unknown name service: " + nsname);
+ }
+
+ Host h = new Host();
+ h.isNSConfigured(nameservice);
+
+ if (nsname.equals("nis")) {
+ String nm = h.getNisHost("master");
+ String nb = h.getNisHost("bound");
+ if (!nm.equals(nb)) {
+ boundtonisslave = true;
+ }
+ setUser("root");
+ setNameServiceHost(nm);
+ setPasswd("");
+ } else if (nsname.equals("ldap")) {
+ String master = h.getLDAPMaster();
+ if (master == null) {
+ setNameServiceHost("");
+ } else {
+ setNameServiceHost(master);
+ }
+
+ String admin = h.getDefaultAdminDN();
+ if (admin == null) {
+ setUser("");
+ } else {
+ setUser(admin);
+ }
+
+ setPasswd("");
+ }
+
+ }
+
+ public void setNameServiceHost(String arg)
+ {
+ nshost = arg;
+ }
+ public void setUser(String arg)
+ {
+ user = arg;
+ }
+ public void setPasswd(String arg)
+ {
+ passwd = arg;
+ }
+
+ public String getNameService()
+ {
+ return (nameservice);
+ }
+ public String getNameServiceHost()
+ {
+ return (nshost);
+ }
+ public String getUser()
+ {
+ return (user);
+ }
+ public String getPasswd()
+ {
+ return (passwd);
+ }
+ public boolean getBoundToNisSlave()
+ {
+ return (boundtonisslave);
+ }
+ public boolean isAuth()
+ {
+ return (isauth);
+ }
+
+ public void checkAuth() throws Exception
+ {
+ Debug.message("SVR: NameService.checkAuth()");
+
+ DoPrinterNS.doAuth(this);
+ isauth = true;
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Printer.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Printer.java
new file mode 100644
index 0000000000..1f75989a3c
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Printer.java
@@ -0,0 +1,497 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Printer class
+ * Printer object containing attributes and methods for
+ * updating printers.
+ */
+
+package com.sun.admin.pm.server;
+
+public class Printer
+{
+ //
+ // Printer object attributes
+ //
+ private String printername = null;
+ private String printertype = null;
+ private String printserver = null;
+ private String comment = null;
+ private String device = null;
+ private String make = null;
+ private String model = null;
+ private String ppd = null;
+ private String ppdfile = null;
+ private String notify = null;
+ private String protocol = null;
+ private String destination = null;
+ private String extensions = null;
+ private String[] file_contents = null;
+ private String[] user_allow_list = null;
+ private String[] user_deny_list = null;
+ private boolean use_ppd_file = true;
+ private boolean default_printer = false;
+ private String banner = null;
+ private boolean enable = true;
+ private boolean accept = true;
+
+ private String locale = null; // Possible future use
+
+ private NameService nscontext;
+
+ //
+ // Logs
+ //
+ private String warnlog = null;
+ private String errlog = null;
+ private String cmdlog = null;
+
+ //
+ // Constructors
+ //
+ public Printer()
+ {
+ Debug.message("SVR: Printer constructor called empty.");
+ nscontext = new NameService();
+ PrinterDebug.printObj(nscontext);
+ }
+ public Printer(NameService ns)
+ {
+ Debug.message("SVR: Printer constructor called with NS.");
+ nscontext = ns;
+ PrinterDebug.printObj(ns);
+ }
+
+ //
+ // Is a printer local to this machine
+ //
+ public synchronized boolean isPrinterLocal(String printername)
+ throws Exception
+ {
+ Debug.message("SVR: Printer.isPrinterLocal()");
+ return (DoPrinterUtil.isLocal(printername));
+ }
+
+ //
+ // Get details of a printer.
+ //
+ public synchronized void getPrinterDetails()
+ throws Exception
+ {
+ Debug.message("SVR: Printer.getPrinterDetails()");
+
+ if (printername == null) {
+ throw new pmInternalErrorException(
+ "Printer.getPrinterDetails(): printername must be set");
+ }
+ DoPrinterView.view(this, nscontext);
+ }
+
+ //
+ // Add a local printer
+ //
+ public synchronized void addLocalPrinter()
+ throws Exception
+ {
+ Debug.message("SVR: Printer.addLocalPrinter()");
+
+ if (printername == null) {
+ throw new pmInternalErrorException(
+ "Printer.addLocalPrinter(): printername must be set");
+ }
+ if (printserver == null) {
+ Host h = new Host();
+ printserver = h.getLocalHostName();
+ h = null;
+ }
+ if (device == null) {
+ throw new pmInternalErrorException(
+ "Printer.addLocalPrinter(): device must be set");
+ }
+ if ((pmMisc.isppdCachefile()) && use_ppd_file) {
+ if (make == null) {
+ throw new pmInternalErrorException(
+ "Printer.addLocalPrinter(): make must be set");
+ }
+ if (model == null) {
+ throw new pmInternalErrorException(
+ "Printer.addLocalPrinter(): model must be set");
+ }
+ if (ppd == null) {
+ throw new pmInternalErrorException(
+ "Printer.addLocalPrinter(): ppd file must be selected");
+ }
+ }
+
+
+ PrinterDebug.printObj(this);
+
+ clearLogs();
+ DoPrinterAdd.add(this, nscontext);
+ }
+
+ //
+ // Add access to a remote printer
+ //
+ public synchronized void addRemotePrinter()
+ throws Exception
+ {
+ Debug.message("SVR: Printer.addRemotePrinter()");
+
+ if (printername == null) {
+ throw new pmInternalErrorException(
+ "Printer.addRemotePrinter(): printername must be set");
+ }
+ if (printserver == null) {
+ throw new pmInternalErrorException(
+ "Printer.addRemotePrinter(): printserver must be set");
+ }
+ PrinterDebug.printObj(this);
+
+ clearLogs();
+ DoPrinterAdd.add(this, nscontext);
+ }
+
+ //
+ // Delete a printer
+ //
+ public synchronized void deletePrinter()
+ throws Exception
+ {
+ Debug.message("SVR: Printer.deletePrinter()");
+
+ if (printername == null) {
+ throw new pmInternalErrorException(
+ "Printer.deletePrinter(): printername must be set");
+ }
+ PrinterDebug.printObj(this);
+
+ clearLogs();
+ DoPrinterDelete.delete(this, nscontext);
+ }
+
+ //
+ // Modify a printer
+ //
+ public synchronized void modifyPrinter()
+ throws Exception
+ {
+ Debug.message("SVR: Printer.modifyPrinter()");
+
+ if (printername == null) {
+ throw new pmInternalErrorException(
+ "Printer.modifyPrinter(): printername must be set");
+ }
+ PrinterDebug.printObj(this);
+
+ clearLogs();
+ DoPrinterMod.modify(this, nscontext);
+ }
+
+ //
+ // Set list of commands executed
+ //
+ public synchronized void setCmdLog(String newcmds)
+ {
+ if (newcmds == null) {
+ return;
+ }
+ if (!newcmds.endsWith("\n")) {
+ newcmds = newcmds.concat("\n");
+ }
+ if (cmdlog == null) {
+ cmdlog = new String(newcmds);
+ return;
+ }
+ cmdlog = cmdlog.concat(newcmds);
+ }
+
+ //
+ // Set an error message.
+ //
+ public synchronized void setErrorLog(String errs)
+ {
+ if (errs == null) {
+ return;
+ }
+ if (!errs.endsWith("\n")) {
+ errs = errs.concat("\n");
+ }
+ if (errlog == null) {
+ errlog = new String(errs);
+ return;
+ } else {
+ errlog = errlog.concat(errs);
+ }
+ }
+
+ //
+ // Set an warning message.
+ //
+ public synchronized void setWarnLog(String warning)
+ {
+ if (warning == null) {
+ return;
+ }
+ if (!warning.endsWith("\n")) {
+ warning = warning.concat("\n");
+ }
+ if (warnlog == null) {
+ warnlog = new String(warning);
+ return;
+ } else {
+ warnlog = warnlog.concat(warning);
+ }
+ }
+
+ //
+ // Get commands executed.
+ //
+ public String getCmdLog()
+ {
+ if (cmdlog == null) {
+ return (null);
+ }
+ return (new String(cmdlog.trim()));
+ }
+
+ //
+ // Get error messages
+ //
+ public String getErrorLog()
+ {
+ if (errlog == null) {
+ return (null);
+ }
+ return (new String(errlog.trim()));
+ }
+
+ //
+ // Get warning messages
+ //
+ public String getWarnLog()
+ {
+ if (warnlog == null) {
+ return (null);
+ }
+ return (new String(warnlog.trim()));
+ }
+
+ //
+ // Set printer attributes
+ //
+ public synchronized void setPrinterName(String arg)
+ {
+ printername = arg;
+ }
+ public synchronized void setPrinterType(String arg)
+ {
+ printertype = arg;
+ }
+ public synchronized void setPrintServer(String arg)
+ {
+ printserver = arg;
+ }
+ public synchronized void setComment(String arg)
+ {
+ comment = arg;
+ }
+ public synchronized void setMake(String arg)
+ {
+ make = arg;
+ }
+ public synchronized void setModel(String arg)
+ {
+ model = arg;
+ }
+ public synchronized void setPPD(String arg)
+ {
+ ppd = arg;
+ }
+ public synchronized void setPPDFile(String arg)
+ {
+ ppdfile = arg;
+ }
+ public synchronized void setDevice(String arg)
+ {
+ device = arg;
+ }
+ public synchronized void setUsePPD(boolean arg)
+ {
+ use_ppd_file = arg;
+ }
+ public synchronized void setNotify(String arg)
+ {
+ notify = arg;
+ }
+ public synchronized void setProtocol(String arg)
+ {
+ protocol = arg;
+ }
+ public synchronized void setDestination(String arg)
+ {
+ destination = arg;
+ }
+ public synchronized void setExtensions(String arg)
+ {
+ extensions = arg;
+ }
+ public synchronized void setFileContents(String[] arg)
+ {
+ file_contents = arg;
+ }
+ public synchronized void setUserAllowList(String[] arg)
+ {
+ user_allow_list = arg;
+ }
+ public synchronized void setUserDenyList(String[] arg)
+ {
+ user_deny_list = arg;
+ }
+ public synchronized void setIsDefaultPrinter(boolean arg)
+ {
+ default_printer = arg;
+ }
+ public synchronized void setBanner(String arg)
+ {
+ banner = arg;
+ }
+ public synchronized void setEnable(boolean arg)
+ {
+ enable = arg;
+ }
+ public synchronized void setAccept(boolean arg)
+ {
+ accept = arg;
+ }
+ public synchronized void setLocale(String arg)
+ {
+ locale = arg;
+ }
+
+ //
+ // Get printer attributes.
+ //
+ public String getPrinterName()
+ {
+ return (printername);
+ }
+ public String getPrinterType()
+ {
+ return (printertype);
+ }
+ public String getPrintServer()
+ {
+ return (printserver);
+ }
+ public String getComment()
+ {
+ return (comment);
+ }
+ public String getDevice()
+ {
+ return (device);
+ }
+ public boolean getUsePPD()
+ {
+ return (use_ppd_file);
+ }
+ public String getMake()
+ {
+ return (make);
+ }
+ public String getModel()
+ {
+ return (model);
+ }
+ public String getPPD()
+ {
+ return (ppd);
+ }
+ public String getPPDFile()
+ {
+ return (ppdfile);
+ }
+ public String getNotify()
+ {
+ return (notify);
+ }
+ public String getProtocol()
+ {
+ return (protocol);
+ }
+ public String getDestination()
+ {
+ return (destination);
+ }
+ public String getExtensions()
+ {
+ return (extensions);
+ }
+ public String[] getFileContents()
+ {
+ return (file_contents);
+ }
+ public String[] getUserAllowList()
+ {
+ return (user_allow_list);
+ }
+ public String[] getUserDenyList()
+ {
+ return (user_deny_list);
+ }
+ public boolean getIsDefaultPrinter()
+ {
+ return (default_printer);
+ }
+ public String getBanner()
+ {
+ return (banner);
+ }
+ public boolean getEnable()
+ {
+ return (enable);
+ }
+ public boolean getAccept()
+ {
+ return (accept);
+ }
+ public String getLocale()
+ {
+ return (locale);
+ }
+
+ protected void clearLogs()
+ {
+ warnlog = null;
+ errlog = null;
+ cmdlog = null;
+ }
+
+ // Hints for optimizing printer modifications
+ protected String modhints = "";
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/PrinterDebug.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/PrinterDebug.java
new file mode 100644
index 0000000000..1997111b1c
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/PrinterDebug.java
@@ -0,0 +1,126 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * PrinterDebug class
+ * Helper class to print attributes in objects.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+import java.util.*;
+
+public class PrinterDebug {
+
+ public static void printObj(Printer p)
+ {
+ String arr[];
+ int i;
+
+ Debug.message("SVR: PrinterDebug.print_obj(Printer)");
+
+ Debug.message("SVR: \tName:\t\t" + p.getPrinterName());
+ Debug.message("SVR: \tType:\t\t" + p.getPrinterType());
+ Debug.message("SVR: \tServer:\t\t" + p.getPrintServer());
+ Debug.message("SVR: \tComment:\t" + p.getComment());
+ Debug.message("SVR: \tDevice:\t\t" + p.getDevice());
+ Debug.message("SVR: \tMake:\t\t" + p.getMake());
+ Debug.message("SVR: \tModel:\t\t" + p.getModel());
+ Debug.message("SVR: \tPPD:\t\t" + p.getPPD());
+ Debug.message("SVR: \tNotify:\t\t" + p.getNotify());
+ Debug.message("SVR: \tProtocol:\t" + p.getProtocol());
+ Debug.message("SVR: \tDest:\t\t" + p.getDestination());
+ Debug.message("SVR: \tExtensions:\t" + p.getExtensions());
+ Debug.message("SVR: \tDefault:\t" + p.getIsDefaultPrinter());
+ Debug.message("SVR: \tBanner:\t\t" + p.getBanner());
+ Debug.message("SVR: \tEnable:\t\t" + p.getEnable());
+ Debug.message("SVR: \tAccept:\t\t" + p.getAccept());
+
+ arr = p.getFileContents();
+ if (arr == null) {
+ Debug.message("SVR: \tContents:\tNULL");
+ } else {
+ Debug.message("SVR: \tContents:");
+ for (i = 0; i < arr.length; i++) {
+ Debug.message("SVR: \t\t\t" + arr[i]);
+ }
+ }
+ arr = p.getUserAllowList();
+ if (arr == null) {
+ Debug.message("SVR: \tUser allow:\tNULL");
+ } else {
+ Debug.message("SVR: \tUser allow:");
+ for (i = 0; i < arr.length; i++) {
+ Debug.message("SVR: \t\t\t" + arr[i]);
+ }
+ }
+ arr = p.getUserDenyList();
+ if (arr == null) {
+ Debug.message("SVR: \tUser deny:\tNULL");
+ } else {
+ Debug.message("SVR: \tUser deny:");
+ for (i = 0; i < arr.length; i++) {
+ Debug.message("SVR: \t\t\t" + arr[i]);
+ }
+ }
+ }
+
+ public static void printObj(NameService ns)
+ {
+ Debug.message("SVR: PrinterDebug.printObj(NameService)");
+
+ // Keep passwd secret.
+ String passwd = ns.getPasswd();
+ if (passwd != null) {
+ passwd = "*****";
+ }
+ Debug.message("SVR: \tnameservice:\t" + ns.getNameService());
+ Debug.message("SVR: \tnshost:\t\t" + ns.getNameServiceHost());
+ Debug.message("SVR: \tuser:\t\t" + ns.getUser());
+ Debug.message("SVR: \tpasswd:\t\t" + passwd);
+ Debug.message("SVR: \tboundtonisslave:" + ns.getBoundToNisSlave());
+ Debug.message("SVR: \tisAuth:\t\t" + ns.isAuth());
+ }
+
+ public static String arr_to_str(String[] arr)
+ {
+ if (arr == null) {
+ return (new String("NULL"));
+ }
+ if (arr.length == 0) {
+ return (new String("0 length array"));
+ }
+ String str = "";
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] == null) {
+ break;
+ }
+ str = str.concat(arr[i] + " ");
+ }
+ return (str);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/PrinterUtil.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/PrinterUtil.java
new file mode 100644
index 0000000000..ff5e947dcf
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/PrinterUtil.java
@@ -0,0 +1,206 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * PrinterUtil class
+ * Methods not associated with a printer instance.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+import java.util.*;
+
+public class PrinterUtil {
+
+ //
+ // main for testing
+ //
+ public static void main(String[] args) {
+ String dp = null;
+ String devs[] = null;
+ String printers[] = null;
+
+ try {
+ NameService ns = new NameService("ldap");
+// checkRootPasswd("xxx");
+ dp = getDefaultPrinter(ns);
+ devs = getDeviceList();
+ printers = getPrinterList(ns);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ System.out.println("Default printer is: " + dp);
+ for (int i = 0; i < devs.length; i++) {
+ System.out.println(devs[i]);
+ }
+ for (int i = 0; i < printers.length; i += 3) {
+ System.out.println("printername: " + printers[i]);
+ System.out.println("servername: " + printers[i+1]);
+ System.out.println("comment: " + printers[i+2]);
+ }
+ System.exit(0);
+ }
+
+ //
+ // Get the default printer for a specified name space
+ //
+ public synchronized static String getDefaultPrinter(
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: PrinterUtil.getDefaultPrinter()");
+
+ String nsarg = ns.getNameService();
+ String ret = DoPrinterUtil.getDefault(nsarg);
+ if (ret == null) {
+ return (new String(""));
+ }
+ return (new String(ret));
+ }
+
+ //
+ // Get a list of possible printer devices for this machine.
+ //
+ public synchronized static String[] getDeviceList() throws Exception
+ {
+ Debug.message("SVR: PrinterUtil.getDeviceList()");
+
+ String emptylist[] = new String[1];
+ emptylist[0] = "";
+
+ String ret[] = DoPrinterUtil.getDevices();
+ if (ret == null) {
+ return (emptylist);
+ }
+ return (ret);
+ }
+
+ //
+ // Get the list of supported Printer Makes (Manufacturers)
+ // If supported, a PPD file exists for this Make
+ //
+ public synchronized static String[] getMakesList() throws Exception
+ {
+ Debug.message("SVR: PrinterUtil.getMakesList()");
+
+ String emptylist[] = new String[1];
+ emptylist[0] = "";
+
+ String ret[] = DoPrinterUtil.getMakes();
+ if (ret == null) {
+ return (emptylist);
+ }
+ return (ret);
+ }
+
+ public synchronized static String[] getModelsList(
+ String make) throws Exception
+
+ {
+ Debug.message("SVR: PrinterUtil.getModelsList()");
+
+ String emptylist[] = new String[1];
+ emptylist[0] = "";
+
+ String ret[] = DoPrinterUtil.getModels(make);
+ return (ret);
+ }
+
+ public synchronized static String[] getPPDList(
+ String make, String model) throws Exception
+
+ {
+ Debug.message("SVR: PrinterUtil.getPPDList()");
+
+ String emptylist[] = new String[1];
+ emptylist[0] = "";
+
+ String ret[] = DoPrinterUtil.getPPDs(make, model);
+ if (ret == null) {
+ return (emptylist);
+ }
+ return (ret);
+ }
+
+ public synchronized static String[] getProbePrinter(String device)
+ {
+ Debug.message("SVR: PrinterUtil.getProbePrinter()");
+
+ String ret[] = DoPrinterUtil.getProbe(device);
+ return (ret);
+ }
+
+
+ //
+ // Get a list of printers in the specified name service.
+ //
+ public synchronized static String[] getPrinterList(
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: PrinterUtil.getPrinterList()");
+
+ String emptylist[] = new String[1];
+ emptylist[0] = "";
+
+ String nsarg = ns.getNameService();
+ String[] ret = DoPrinterUtil.getList(nsarg);
+ if (ret == null) {
+ return (emptylist);
+ }
+ return (ret);
+ }
+
+ //
+ // Does this printer already exist in the specified
+ // name service
+ //
+ public synchronized static boolean exists(
+ String name,
+ NameService ns) throws Exception
+ {
+ Debug.message("SVR: PrinterUtil.exists()");
+
+ String nsname = ns.getNameService();
+ return (DoPrinterUtil.exists(name, nsname));
+ }
+
+ public synchronized static boolean isLocal(
+ String printername) throws Exception
+ {
+ Debug.message("SVR: PrinterUtil.isLocal()");
+
+ return (DoPrinterUtil.isLocal(printername));
+ }
+
+ public synchronized static void checkRootPasswd(
+ String passwd) throws Exception
+ {
+ DoPrinterNS.doCheckRootPasswd(passwd);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/SysCommand.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/SysCommand.java
new file mode 100644
index 0000000000..cd8afb1364
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/SysCommand.java
@@ -0,0 +1,245 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * SysCommand
+ * Execute a command and capture stdout/stderr.
+ *
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+
+public class SysCommand
+{
+
+ private Process p = null;
+ private String out = null;
+ private String err = null;
+ private int status = 0;
+
+ public static void main(String[] args) {
+ SysCommand syscmd = new SysCommand();
+ String cmd = "ypcat hosts";
+ String o = "";
+ try {
+ syscmd.exec(cmd);
+ }
+ catch (Exception e) {
+ System.out.println(e);
+ }
+ o = syscmd.getOutput();
+ System.out.println(o);
+ }
+
+ /*
+ * Execute a system command.
+ * @param String cmd The command to be executed.
+ */
+ public void exec(String cmd) throws Exception
+ {
+ if (cmd == null) {
+ throw new pmInternalErrorException(
+ "SysCommand.exec(): null command");
+ }
+
+ debug_log(cmd);
+
+ p = Runtime.getRuntime().exec(cmd);
+ if (p == null) {
+ throw new pmInternalErrorException(
+ "SysCommand.exec(): null process");
+ }
+ out = readOut();
+ err = readErr();
+ p.waitFor();
+ status = getStatus();
+ dispose();
+ }
+
+ public void exec(String[] cmd) throws Exception
+ {
+ if (cmd == null) {
+ throw new pmInternalErrorException(
+ "SysCommand.exec(): null command");
+ }
+
+ // Trim command arrays with nulls at the end.
+ int i;
+ for (i = 0; i < cmd.length; i++) {
+ if (cmd[i] == null) {
+ break;
+ }
+ }
+ if (i != cmd.length) {
+ String[] newcmd = new String[i];
+
+ for (i = 0; i < newcmd.length; i++) {
+ newcmd[i] = cmd[i];
+ }
+ debug_log(PrinterDebug.arr_to_str(newcmd));
+ p = Runtime.getRuntime().exec(newcmd);
+ } else {
+ debug_log(PrinterDebug.arr_to_str(cmd));
+ p = Runtime.getRuntime().exec(cmd);
+ }
+ if (p == null) {
+ throw new pmInternalErrorException(
+ "SysCommand.exec(): null process");
+ }
+ out = readOut();
+ err = readErr();
+ p.waitFor();
+ status = getStatus();
+ dispose();
+ }
+
+
+ public void exec(String cmd, String locale) throws Exception
+ {
+ if (cmd == null) {
+ throw new pmInternalErrorException(
+ "SysCommand.exec(): null command");
+ }
+
+ debug_log(locale + "; " + cmd);
+
+ String [] envp = new String[1];
+ envp[0] = locale;
+ p = Runtime.getRuntime().exec(cmd, envp);
+ if (p == null) {
+ throw new pmInternalErrorException(
+ "SysCommand.exec(): null process");
+ }
+ out = readOut();
+ err = readErr();
+ p.waitFor();
+ status = getStatus();
+ dispose();
+ }
+
+ public String getOutput() {
+ if (out == null)
+ return (null);
+ return (new String(out));
+ }
+ public String getError() {
+ if (err == null)
+ return (null);
+ return (new String(err));
+ }
+ public int getExitValue() {
+ return (status);
+ }
+
+
+ private String readOut() throws Exception
+ {
+ String result = null;
+ String line = null;
+ BufferedReader out = null;
+
+ out = new BufferedReader(
+ new InputStreamReader(p.getInputStream()));
+ while ((line = out.readLine()) != null) {
+ if (result == null)
+ result = line;
+ else
+ result = result.concat("\n" + line);
+ }
+ return (result);
+ }
+
+ private String readErr() throws Exception
+ {
+ String errstr = null;
+ String line = null;
+ BufferedReader err = null;
+
+ err = new BufferedReader(
+ new InputStreamReader(p.getErrorStream()));
+ while ((line = err.readLine()) != null) {
+ if (errstr == null) {
+ errstr = line;
+ } else {
+ errstr = errstr.concat("\n" + line);
+ }
+ }
+ return (errstr);
+ }
+
+ private int getStatus() throws Exception
+ {
+ return (p.exitValue());
+ }
+
+ /*
+ * Clean up opened file descriptors.
+ */
+ private void dispose() {
+
+ try {
+ p.getInputStream().close();
+ p.getOutputStream().close();
+ p.getErrorStream().close();
+ p.destroy();
+ }
+ catch (Exception e) {
+ Debug.message("SVR:" + e.getMessage());
+ }
+ }
+
+ /*
+ * Log all commands as is except lpset with a password.
+ */
+ private void debug_log(String cmd)
+ {
+ if ((cmd.indexOf("lpset") != -1) &&
+ (cmd.indexOf(" -w ") != -1)) {
+ String clean = "";
+ int i = cmd.indexOf(" -w ");
+ int j = 0;
+
+ try {
+ i += 4;
+ clean = cmd.substring(0, i);
+ clean = clean.concat("**** ");
+ while (cmd.charAt(i) != ' ') {
+ i++;
+ }
+ } catch (Exception e) {
+ Debug.message("SVR: lpset command with a passwd.");
+ return;
+ }
+
+ clean = clean.concat(cmd.substring(i, cmd.length()));
+ Debug.message("SVR: " + clean);
+
+ } else {
+ Debug.message("SVR: " + cmd);
+ }
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Test.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Test.java
new file mode 100644
index 0000000000..31e9339f10
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Test.java
@@ -0,0 +1,369 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Test
+ * Command line front end to Printer class
+ *
+ * Takes one argument - the name of a test file
+ * The format of the file is:
+ * Required:
+ * action=[add,delete,modify,view,list]
+ *
+ * Optional:
+ * printername=
+ * printertype=
+ * printserver=
+ * comment=
+ * device=
+ * notify=
+ * protocol=
+ * destination=
+ * extensions=
+ * default_printer=[true,false]
+ * banner=
+ * enable=[true,false]
+ * accept=[true,false]
+ * file_contents=[space seperated list]
+ * user_allow_list=[space seperated list]
+ * user_deny_list=[space seperated list]
+ * nameservice=[system,nis]
+ * nshost=
+ * user=
+ * passwd=
+ * locale=
+ *
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+import java.util.*;
+
+public class Test {
+ public static void main(String[] args) {
+ String tmpstr;
+ int i;
+ String testfile = "";
+ if (args.length == 1) {
+ testfile = args[0];
+ } else {
+ System.out.println("Usage: Test testfile");
+ System.exit(1);
+ }
+
+ String cmd = "/usr/bin/cat " + testfile;
+ String o = null;
+ try {
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec(cmd);
+ if (syscmd.getExitValue() != 0) {
+ System.out.println("Problem opening test file");
+ System.exit(1);
+ }
+ o = syscmd.getOutput();
+ syscmd = null;
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ o = o.concat("\n");
+
+ String action = getToken(o, "action=");
+ String printername = getToken(o, "printername=");
+ String printertype = getToken(o, "printertype=");
+ String printserver = getToken(o, "printserver=");
+ String comment = getToken(o, "comment=");
+ String device = getToken(o, "device=");
+ String notify = getToken(o, "notify=");
+ String banner = getToken(o, "banner=");
+ String protocol = getToken(o, "protocol=");
+ String destination = getToken(o, "destination=");
+ String extensions = getToken(o, "extensions=");
+
+ String[] file_contents = null;
+ String[] user_allow_list = null;
+ String[] user_deny_list = null;
+
+ StringTokenizer st;
+ tmpstr = getToken(o, "file_contents=");
+ if (tmpstr != null) {
+ st = new StringTokenizer(tmpstr);
+ if (st.countTokens() != 0) {
+ file_contents = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ file_contents[i] = st.nextToken();
+ }
+ }
+ }
+ tmpstr = getToken(o, "user_allow_list=");
+ if (tmpstr != null) {
+ st = new StringTokenizer(tmpstr);
+ if (st.countTokens() != 0) {
+ user_allow_list = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ user_allow_list[i] = st.nextToken();
+ }
+ }
+ }
+ tmpstr = getToken(o, "user_deny_list=");
+ if (tmpstr != null) {
+ st = new StringTokenizer(tmpstr);
+ if (st.countTokens() != 0) {
+ user_deny_list = new String[st.countTokens()];
+ for (i = 0; st.hasMoreTokens(); i++) {
+ user_deny_list[i] = st.nextToken();
+ }
+ }
+ }
+
+ boolean default_printer = false;
+ boolean enable = false;
+ boolean accept = false;
+
+ tmpstr = getToken(o, "default_printer=");
+ if (tmpstr != null) {
+ if (tmpstr.equals("true")) {
+ default_printer = true;
+ }
+ }
+ tmpstr = getToken(o, "enable=");
+ if (tmpstr != null) {
+ if (tmpstr.equals("true")) {
+ enable = true;
+ }
+ }
+ tmpstr = getToken(o, "accept=");
+ if (tmpstr != null) {
+ if (tmpstr.equals("true")) {
+ accept = true;
+ }
+ }
+
+ String nameservice = getToken(o, "nameservice=");
+ String nshost = getToken(o, "nshost=");
+ String user = getToken(o, "user=");
+ String passwd = getToken(o, "passwd=");
+ String locale = getToken(o, "locale=");
+
+ //
+ // Done parsing. Let's do the work.
+ //
+ Debug.setDebugLevel(Debug.ALL);
+
+ NameService ns = null;
+ try {
+ ns = new NameService(nameservice);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ if (nameservice.equals("nis") || nameservice.equals("ldap")) {
+ if (nshost != null)
+ ns.setNameServiceHost(nshost);
+ if (user != null)
+ ns.setUser(user);
+ if (passwd != null)
+ ns.setPasswd(passwd);
+ }
+ try {
+ ns.checkAuth();
+ }
+ catch (Exception e) {
+ System.out.println(e);
+ }
+
+ Printer p = new Printer(ns);
+
+ p.setPrinterName(printername);
+ p.setPrinterType(printertype);
+ p.setPrintServer(printserver);
+ p.setFileContents(file_contents);
+ p.setComment(comment);
+ p.setDevice(device);
+ p.setNotify(notify);
+ p.setProtocol(protocol);
+ p.setDestination(destination);
+ p.setIsDefaultPrinter(default_printer);
+ p.setBanner(banner);
+ p.setEnable(enable);
+ p.setAccept(accept);
+ p.setUserAllowList(user_allow_list);
+ p.setUserDenyList(user_deny_list);
+ p.setLocale(locale);
+
+ if (action.equals("list")) {
+ String[] plist = null;
+ try {
+ plist = PrinterUtil.getPrinterList(ns);
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ if (plist == null) {
+ System.out.println("No printers");
+ } else {
+ printPList(plist);
+ }
+ } else if (action.equals("view")) {
+ try {
+ p.getPrinterDetails();
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ printView(p);
+ } else if (action.equals("add")) {
+ try {
+ if (device == null) {
+ p.addRemotePrinter();
+ } else {
+ p.addLocalPrinter();
+ }
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ } else if (action.equals("modify")) {
+ try {
+ p.modifyPrinter();
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ } else if (action.equals("delete")) {
+ try {
+ p.deletePrinter();
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ }
+ } else {
+ System.out.println("unknown action");
+ System.exit(1);
+ }
+ System.out.println("============================");
+ System.out.println("Commands:\n" + p.getCmdLog());
+ System.out.println("Errors:\n" + p.getErrorLog());
+ System.out.println("Warnings:\n" + p.getWarnLog());
+ System.exit(0);
+ }
+
+ private static String getToken(String str, String sub)
+ {
+ int i = -1;
+ int j = -1;
+ String result = null;
+
+ i = str.indexOf(sub);
+ if (i != -1) {
+ i = i + sub.length();
+ j = str.indexOf("\n", i);
+ if (j != -1) {
+ result = str.substring(i, j);
+ result = result.trim();
+ if (result.equals(""))
+ result = null;
+ }
+ }
+ return (result);
+ }
+
+ private static void printPList(String[] list)
+ {
+ if (list == null)
+ return;
+ if (list[0].equals("")) {
+ System.out.println("No printers found");
+ return;
+ }
+
+ for (int i = 0; i < list.length; ) {
+ System.out.println("name: " + list[i++]);
+ System.out.println("server: " + list[i++]);
+ System.out.println("comment: " + list[i++]);
+ }
+ }
+
+ private static void printView(Printer p)
+ {
+ String arr[];
+ int i;
+
+ System.out.println("Name: " + p.getPrinterName());
+ System.out.println("Type: " + p.getPrinterType());
+ System.out.println("Server: " + p.getPrintServer());
+ System.out.println("Comment: " + p.getComment());
+ System.out.println("Device: " + p.getDevice());
+ System.out.println("Notify: " + p.getNotify());
+ System.out.println("Protocol: " + p.getProtocol());
+ System.out.println("Dest: " + p.getDestination());
+ System.out.println("Extensions: " + p.getExtensions());
+ System.out.println("Default: " + p.getIsDefaultPrinter());
+ System.out.println("Banner: " + p.getBanner());
+ System.out.println("Enable: " + p.getEnable());
+ System.out.println("Accept: " + p.getAccept());
+
+ arr = p.getFileContents();
+ if (arr == null) {
+ System.out.println("Contents: NULL");
+ } else {
+ System.out.println("Contents:");
+ for (i = 0; i < arr.length; i++) {
+ System.out.println("\t\t" + arr[i]);
+ }
+ }
+ arr = p.getUserAllowList();
+ if (arr == null) {
+ System.out.println("Users allow: NULL");
+ } else {
+ System.out.println("Users allow:");
+ for (i = 0; i < arr.length; i++) {
+ System.out.println("\t\t" + arr[i]);
+ }
+ }
+ arr = p.getUserDenyList();
+ if (arr == null) {
+ System.out.println("Users deny: NULL");
+ } else {
+ System.out.println("Users deny:");
+ for (i = 0; i < arr.length; i++) {
+ System.out.println("\t\t" + arr[i]);
+ }
+ }
+
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Valid.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Valid.java
new file mode 100644
index 0000000000..a457be1e58
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/Valid.java
@@ -0,0 +1,395 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Valid
+ * Check user input. We are mostly concerned with characters
+ * we know will cause problems for the sub-system.
+ * multi-byte characters will be screened out by the gui.
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+import java.util.*;
+
+public class Valid {
+
+ static String spaces = "\t ";
+ /* JSTYLED */
+ static String badmetas = "\"\\$^&*(){}`'|;:?<>";
+ /* JSTYLED */
+ static String baddestmetas = "\"\\$^&*(){}`'|;?<>";
+
+ // lpadmin used to only take 14.
+ static int validlocalprinternamelength = 1024;
+ // MAXHOSTNAMELEN + MAXPATHLEN seems reasonable.
+ static int validremoteprinternamelength = 1280;
+
+ static int validdestinationlength = 1023; // BUFSIZ-1 seems generous
+ static int validcommentlength = 256; // From admintool
+ static int validservernamelength = 256; // MAXHOSTNAMELEN = 256
+ static int validusernamelength = 128; // LOGNAME_MAX = 8 but since
+ // it's not enforced ...
+ static int validmakelength = 256; // MAXNAMELEN = 256
+
+ //
+ // main for testing
+ //
+ public static void main(String[] args) {
+ String[] users_arr = { "one", "two", "th`ee" };
+ try {
+ System.out.println(localPrinterName("foo/bar"));
+ System.out.println(comment("abad:comment"));
+ System.out.println(device("/dev/term/a"));
+ System.out.println(printerType(" "));
+ System.out.println(serverName(",bad"));
+ System.out.println(users(users_arr));
+ }
+ catch (Exception e)
+ {
+ System.out.println(e);
+ System.exit(1);
+ }
+ System.exit(0);
+ }
+
+ //
+ // Valid comment
+ //
+ public static boolean comment(String cstr)
+ {
+ Debug.message("SVR: Valid.comment()");
+ Debug.message("SVR: comment=" + cstr);
+
+ if (cstr == null)
+ return (false);
+ if (cstr.length() > validcommentlength)
+ return (false);
+
+ String c = cstr.substring(0, 1);
+ // Causes problems in lpadmin
+ if (c.equals(",")) {
+ return (false);
+ }
+ if (c.equals("-")) {
+ return (false);
+ }
+
+ return (validString(cstr, badmetas + "="));
+ }
+
+ //
+ // Valid local printer name
+ //
+ public static boolean localPrinterName(String pn)
+ {
+ Debug.message("SVR: Valid.localPrinterName()");
+ Debug.message("SVR: printerName=" + pn);
+
+ if (pn == null)
+ return (false);
+ if (pn.length() == 0)
+ return (false);
+ if (pn.length() > validlocalprinternamelength)
+ return (false);
+
+ String c = pn.substring(0, 1);
+ if (c.equals(".")) {
+ return (false);
+ }
+ if (c.equals("!")) {
+ return (false);
+ }
+ if (c.equals("=")) {
+ return (false);
+ }
+
+ // Keywords for the sub-system
+ if (pn.equals("_default"))
+ return (false);
+ if (pn.equals("_all"))
+ return (false);
+
+ return (validString(pn, badmetas + spaces + "/#:,"));
+ }
+
+ //
+ // Valid remote printer name
+ //
+ public static boolean remotePrinterName(String pn)
+ {
+ Debug.message("SVR: Valid.remotePrinterName()");
+ Debug.message("SVR: printerName=" + pn);
+
+ if (pn == null)
+ return (false);
+ if (pn.length() == 0)
+ return (false);
+ if (pn.length() > validremoteprinternamelength)
+ return (false);
+
+ // Keywords for the sub-system
+ if (pn.equals("_default"))
+ return (false);
+ if (pn.equals("_all"))
+ return (false);
+
+ String c = pn.substring(0, 1);
+ if (c.equals(".")) {
+ return (false);
+ }
+ if (c.equals("!")) {
+ return (false);
+ }
+ if (c.equals("=")) {
+ return (false);
+ }
+
+ return (validString(pn, badmetas + spaces + "/#:,"));
+ }
+
+ //
+ // Valid device
+ // Does it exist and is it writable.
+ //
+ public static boolean device(String dev)
+ throws Exception
+ {
+ int exitvalue;
+
+ Debug.message("SVR: Valid.device()");
+ Debug.message("SVR: device=" + dev);
+
+ if (dev == null)
+ return (false);
+ if (dev.length() == 0)
+ return (false);
+ if (dev.indexOf("://") != 0) // don't test if it's a URI
+ return (true);
+
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/test -w " + dev);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+
+ if (exitvalue != 0)
+ return (false);
+ return (true);
+ }
+
+ //
+ // Valid Printer Make
+ // Does a directory of that name exist, and is it readable.
+ //
+
+ public static boolean make(String dir)
+ throws Exception
+ {
+ int exitvalue;
+
+ Debug.message("SVR: Valid.make()");
+ Debug.message("SVR: dir=" + dir);
+
+ if (dir == null)
+ return (false);
+ if ((dir.length() == 0) || (dir.length() > validmakelength))
+ return (false);
+
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/test -d -r " + dir);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+
+ if (exitvalue != 0)
+ return (false);
+ return (true);
+ }
+
+ //
+ // Valid printer type
+ //
+ public static boolean printerType(String pt)
+ throws Exception
+ {
+ int exitvalue;
+
+ Debug.message("SVR: Valid.printerType()");
+ Debug.message("SVR: printerType=" + pt);
+
+ if (pt == null)
+ return (false);
+ if (pt.length() == 0)
+ return (false);
+
+ if (pt.equals("/"))
+ return (false);
+
+ if (pt.indexOf(" ") != -1) {
+ return (false);
+ }
+ if (pt.indexOf("\t") != -1) {
+ return (false);
+ }
+
+ String c = pt.substring(0, 1);
+ String path = "/usr/share/lib/terminfo/" + c + "/" + pt;
+ SysCommand syscmd = new SysCommand();
+ syscmd.exec("/usr/bin/test -r " + path);
+ exitvalue = syscmd.getExitValue();
+ syscmd = null;
+
+ if (exitvalue != 0)
+ return (false);
+ return (true);
+ }
+
+ //
+ // Valid destination
+ //
+ public static boolean destination(String d)
+ {
+ Debug.message("SVR: Valid.destination()");
+ Debug.message("SVR: destination=" + d);
+
+ if (d == null)
+ return (false);
+ if (d.length() == 0)
+ return (false);
+ if (d.length() > validdestinationlength)
+ return (false);
+
+ return (validString(d, baddestmetas + spaces));
+ }
+
+ //
+ // Valid Server name
+ //
+ public static boolean serverName(String s)
+ {
+ Debug.message("SVR: Valid.serverName()");
+ Debug.message("SVR: serverName=" + s);
+
+ if (s == null)
+ return (false);
+ if (s.length() == 0)
+ return (false);
+ if (s.length() > validservernamelength)
+ return (false);
+
+ String c = s.substring(0, 1);
+ if (c.equals("!")) {
+ return (false);
+ }
+ if (c.equals("=")) {
+ return (false);
+ }
+
+ return (validString(s, badmetas + spaces + "#,:"));
+ }
+
+ //
+ // Users
+ //
+ public static boolean users(String[] u)
+ {
+ Debug.message("SVR: Valid.users()");
+ Debug.message("SVR: users = " + PrinterDebug.arr_to_str(u));
+
+ if (u == null) {
+ return (false);
+ }
+ if (u.length == 0) {
+ return (false);
+ }
+
+ for (int i = 0; i < u.length; i++) {
+ if (u[i] == null) {
+ return (false);
+ }
+ if (u[i].length() == 0) {
+ return (false);
+ }
+ if (u[i].length() > validusernamelength) {
+ return (false);
+ }
+ if (!validString(u[i], badmetas + spaces)) {
+ return (false);
+ }
+ }
+ return (true);
+ }
+
+ //
+ // User
+ //
+ public static boolean user(String u)
+ {
+ Debug.message("SVR: Valid.users()");
+ Debug.message("SVR: users = " + u);
+
+ if (u == null) {
+ return (false);
+ }
+ if (u.length() == 0) {
+ return (false);
+ }
+
+ if (u == null) {
+ return (false);
+ }
+ if (u.length() == 0) {
+ return (false);
+ }
+ if (u.length() > validusernamelength) {
+ return (false);
+ }
+ if (!validString(u, badmetas + spaces)) {
+ return (false);
+ }
+ return (true);
+ }
+
+
+ //
+ // Check to see if a string contains an invalid character
+ //
+ private static boolean validString(String str, String badchars)
+ {
+ // Can't start with a hyphen
+ String start = str.substring(0, 1);
+ if (start.equals("-"))
+ return (false);
+
+ char[] badchars_arr = badchars.toCharArray();
+
+ for (int i = 0; i < badchars_arr.length; i++) {
+ if (str.indexOf(badchars_arr[i]) != -1) {
+ return (false);
+ }
+ }
+ return (true);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmAuthException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmAuthException.java
new file mode 100644
index 0000000000..3c24fa53d2
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmAuthException.java
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmAuthException class
+ * User is not authorized to perform an operation.
+ */
+
+package com.sun.admin.pm.server;
+
+public class pmAuthException extends pmException
+{
+ public pmAuthException()
+ {
+ super();
+ }
+
+ public pmAuthException(String s)
+ {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmAuthRhostException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmAuthRhostException.java
new file mode 100644
index 0000000000..2f6b41e5f3
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmAuthRhostException.java
@@ -0,0 +1,47 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmAuthRhostException class
+ * A .rhosts entry has not been set up allowing updates of
+ * pre-2.6 nis servers.
+ *
+ */
+
+package com.sun.admin.pm.server;
+
+public class pmAuthRhostException extends pmAuthException
+{
+ public pmAuthRhostException()
+ {
+ super();
+ }
+
+ public pmAuthRhostException(String s)
+ {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmCmdFailedException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmCmdFailedException.java
new file mode 100644
index 0000000000..26925a1d97
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmCmdFailedException.java
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmCmdFailedException class
+ * A command unexpectedly failed.
+ */
+
+package com.sun.admin.pm.server;
+
+public class pmCmdFailedException extends pmException
+{
+ public pmCmdFailedException()
+ {
+ super();
+ }
+
+ public pmCmdFailedException(String s)
+ {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmException.java
new file mode 100644
index 0000000000..081c27e79e
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmException.java
@@ -0,0 +1,44 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmException class
+ * General print manager exceptions
+ */
+
+package com.sun.admin.pm.server;
+
+public class pmException extends Exception
+{
+ public pmException()
+ {
+ super();
+ }
+
+ public pmException(String s)
+ {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmHostNotPingableException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmHostNotPingableException.java
new file mode 100644
index 0000000000..cc8464a17b
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmHostNotPingableException.java
@@ -0,0 +1,45 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmHostNotPingableException class
+ * A host is not accessible using ping.
+ */
+
+package com.sun.admin.pm.server;
+
+public class pmHostNotPingableException extends pmException
+{
+ public pmHostNotPingableException()
+ {
+ super();
+ }
+
+ public pmHostNotPingableException(String s)
+ {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmInternalErrorException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmInternalErrorException.java
new file mode 100644
index 0000000000..08f50dbc8f
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmInternalErrorException.java
@@ -0,0 +1,47 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmInternalErrorException class
+ * An internal error has occuured. This is often associated
+ * with the server not getting enough information to perform
+ * an action.
+ */
+
+package com.sun.admin.pm.server;
+
+public class pmInternalErrorException extends pmException
+{
+ public pmInternalErrorException()
+ {
+ super();
+ }
+
+ public pmInternalErrorException(String s)
+ {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmMisc.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmMisc.java
new file mode 100644
index 0000000000..21202c0eba
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmMisc.java
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Miscellaneous functions which don't apply to printer object
+ */
+
+package com.sun.admin.pm.server;
+
+import java.io.*;
+
+/*
+ * Class is miscellaneous routines
+ */
+
+public class pmMisc {
+
+ public static boolean isppdCachefile()
+ {
+ File ppdcache = new File("/var/lp/ppd/ppdcache");
+ return (ppdcache.isFile());
+ }
+
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmNSNotConfiguredException.java b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmNSNotConfiguredException.java
new file mode 100644
index 0000000000..1ffd8ccd50
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmNSNotConfiguredException.java
@@ -0,0 +1,46 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * ident "%Z%%M% %I% %E% SMI"
+ *
+ * Copyright (c) 1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * pmNSNotConfiguredException class
+ * The selected name service does not appear to be configured
+ * on the host.
+ */
+
+package com.sun.admin.pm.server;
+
+public class pmNSNotConfiguredException extends pmException
+{
+ public pmNSNotConfiguredException()
+ {
+ super();
+ }
+
+ public pmNSNotConfiguredException(String s)
+ {
+ super(s);
+ }
+}
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmtest b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmtest
new file mode 100644
index 0000000000..70a7770530
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/pmtest
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 1999 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+/usr/bin/java com.sun.admin.pm.server.Test $1
diff --git a/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/tests/template b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/tests/template
new file mode 100644
index 0000000000..4096d9bae5
--- /dev/null
+++ b/usr/src/cmd/print/printmgr/com/sun/admin/pm/server/tests/template
@@ -0,0 +1,27 @@
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+action=
+printername=
+printertype=
+printserver=
+file_contents=
+comment=
+device=
+notify=
+protocol=
+destination=
+default_printer=
+banner=
+enable=
+accept=
+user_allow_list=
+user_deny_list=
+nameservice=
+nshost=
+user=
+passwd=
+locale=
diff --git a/usr/src/cmd/print/scripts/Makefile b/usr/src/cmd/print/scripts/Makefile
new file mode 100644
index 0000000000..7dfa94546e
--- /dev/null
+++ b/usr/src/cmd/print/scripts/Makefile
@@ -0,0 +1,149 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.sp
+
+ROOTPRINTLIB = $(ROOTLIB)/print
+ROOTLIBLPBIN = $(ROOTLIBLP)/bin
+ROOTVARLP = $(ROOTVAR)/lp
+ROOTVARLPPPD = $(ROOTVARLP)/ppd
+
+$(ROOTVARLP) := DIRMODE=0775
+
+FILEMODE = 0755
+
+MSGFILES = lpadmin ppdmgr
+POFILE = scripts.po
+
+PROG = conv_lp conv_lpd Makefile.yp
+ROOTLIBPRINTPROG= $(PROG:%=$(ROOTPRINTLIB)/%)
+$(ROOTLIBPRINTPROG) := FILEMODE=0555
+$(ROOTPRINTLIB)/Makefile.yp := FILEMODE=0444
+
+USRSBINPROG= lpsystem ppdmgr
+ROOTUSRSBINPROG= $(USRSBINPROG:%=$(ROOTUSRSBIN)/%)
+$(ROOTUSRSBINPROG) := FILEMODE=555
+
+PCONF= printers.conf
+ROOTPCONF= $(PCONF:%=$(ROOTETC)/%)
+$(ROOTPCONF) := FILEMODE=644
+
+MANUFALIASES= manufaliases
+ROOTMANUFALIASES= $(MANUFALIASES:%=$(ROOTVARLPPPD)/%)
+$(ROOTMANUFALIASES) := FILEMODE=444
+
+LIBLPPROGS= getmakes getmodels getppdfile getppds ppdfilename2mmp \
+ lpadmin \
+ desktop-print-management \
+ desktop-print-management-applet \
+ desktop-print-management-prefs
+
+ROOTLIBLPPROGS= $(LIBLPPROGS:%=$(ROOTLIBLPBIN)/%)
+$(ROOTLIBLPPROGS) := FILEMODE=555
+
+LIBLINKS= $(ROOTLIB)/lpadmin $(ROOTLIB)/lpsystem
+
+APPFILES = desktop-print-management.desktop
+APPFILES += desktop-print-management-prefs.desktop
+AUTOFILES = desktop-print-management-applet.desktop
+
+ROOTAPPDIR = $(ROOT)/usr/share/applications
+ROOTAUTODIR = $(ROOT)/usr/share/gnome/autostart
+ROOTAPPFILES = $(APPFILES:%=$(ROOTAPPDIR)/%)
+ROOTAUTOFILES = $(AUTOFILES:%=$(ROOTAUTODIR)/%)
+
+$(ROOTAPPFILES) := FILEMODE = 444
+$(ROOTAUTOFILES) := FILEMODE = 444
+
+
+.KEEP_STATE:
+
+all : $(PROG)
+
+$(ROOTLIB)/print/%: %
+ $(INS.file)
+
+$(ROOTLIBLPBIN)/%: %
+ $(INS.file)
+
+$(ROOTVARLPPPD)/%: %
+ $(INS.file)
+
+$(ROOTAPPDIR)/%: %
+ $(INS.file)
+
+$(ROOTAUTODIR)/%: %
+ $(INS.file)
+
+$(ROOTUSRSBIN) $(ROOTVARSPOOLPRINT) $(ROOTVARLP) $(ROOTVARLPPPD):
+ $(INS.dir)
+
+$(ROOTLIB)/lpadmin:
+ $(RM) $@; $(SYMLINK) ../sbin/lpadmin $@
+
+$(ROOTLIB)/lpsystem:
+ $(RM) $@; $(SYMLINK) ../sbin/lpsystem $@
+
+$(ROOTLNKPROGS) : $(ROOTSTARTPROG)
+ $(RM) $@; $(LN) $(ROOTSTARTPROG) $@
+
+_msg: $(POFILE)
+
+$(POFILE): $(MSGFILES)
+ grep gettext $(MSGFILES) | tr '`' ' ' | sed -e "s/gettext \"/gettext \(\"/" | sed -e "s/$$/);/" > $(POFILE).i
+ $(XGETTEXT) -s $(POFILE).i
+ $(RM) $@ $(POFILE).i
+ mv messages.po $(POFILE)
+
+#
+# Create a message file to test with
+#
+_msg_test:
+ grep gettext $(MSGFILES) | tr '`' ' ' | sed -e "s/gettext \"/gettext \(\"/" | sed -e "s/$$/);/" > $(POFILE).i
+ $(XGETTEXT) -s -m "xxx" $(POFILE).i
+ $(RM) $@ $(POFILE).i
+ mv messages.po $(POFILE)
+
+install: $(ROOTLNKPROGS) \
+ $(ROOTLIBPRINTPROG) $(ROOTSTARTPROG) \
+ $(ROOTUSRSBIN) $(ROOTUSRSBINPROG) \
+ $(ROOTVARSPOOLPRINT) $(ROOTPCONF) \
+ $(ROOTLIBLPPROGS) $(LIBLINKS) \
+ $(ROOTVARLP) $(ROOTVARLPPPD) \
+ $(ROOTMANUFALIASES) \
+ $(ROOTAPPFILES) $(ROOTAUTOFILES)
+
+$(SYMLINKS1):
+ $(RM) $@; $(SYMLINK) ../sbin/$(SBINPROG1) $@
+
+$(SYMLINKS2):
+ $(RM) $@; $(SYMLINK) ../sbin/$(SBINPROG2) $@
+
+clean:
+ $(RM) $(POFILE)
+
+clobber: clean
+
+strip lint:
diff --git a/usr/src/cmd/print/scripts/Makefile.yp b/usr/src/cmd/print/scripts/Makefile.yp
new file mode 100644
index 0000000000..2e5647f4f1
--- /dev/null
+++ b/usr/src/cmd/print/scripts/Makefile.yp
@@ -0,0 +1,58 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyrights (c) 1996 by Sun Microsystems, Inc.
+# All Rights Reserved
+#
+# Example pieces of NIS Makefile.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Printers conf Rules
+#
+DIR=/etc
+#
+$(DOM)/printers.conf.time: $(DIR)/printers.conf
+ -@if [ -f $(DIR)/printers.conf ]; then \
+ (sed -e '/^#/d' -e s/#.*$$// -e 's/[ ][ ]*$$//' \
+ -e '/\\$$/s/\\$$/ /' $(DIR)/printers.conf $(CHKPIPE))\
+ |( awk '/ $$/ {printf "%s", $$0} !/ $$/ {print}' $(CHKPIPE))\
+ |( sed -e 's/[ ][ ]*/ /g' -e 's/:[ ]*:/:/' \
+ $(CHKPIPE))\
+ | awk -F: '{n=split($$1, nm, "|"); for (i=1; i<=n; i++) \
+ print nm[i], $$0}' \
+ | $(MAKEDBM) - $(YPDBDIR)/$(DOM)/printers.conf.byname ; \
+ touch $(DOM)/printers.conf.time; \
+ echo "updated printers.conf"; \
+ if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) printers.conf.byname; \
+ fi ; \
+ if [ ! $(NOPUSH) ]; then echo "pushed printers.conf"; fi ; \
+ else \
+ echo "couldn't find $(DIR)/printers.conf"; \
+ fi
+
+#
+# Dependency
+#
+printers.conf: $(DOM)/printers.conf.time
diff --git a/usr/src/cmd/print/scripts/conv_lp b/usr/src/cmd/print/scripts/conv_lp
new file mode 100644
index 0000000000..286ba6f682
--- /dev/null
+++ b/usr/src/cmd/print/scripts/conv_lp
@@ -0,0 +1,102 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1994, 1995, 1996 by Sun Microsystems, Inc.
+# All Rights Reserved
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# This script will automatically generate a "printcap" file
+# from the currently configured LP printer configuration.
+#
+PATH=/bin:/usr/bin:/usr/sbin
+
+TEXTDOMAIN="SUNW_OST_OSCMD"
+export TEXTDOMAIN
+
+export PATH
+umask 022
+
+set -- `getopt d:f: $*`
+if [ $? != 0 ] ; then
+ echo "Usage: $0 [-d dir] [-f file]"
+ exit 1
+fi
+
+for OPTION in $*
+do
+ case $OPTION in
+ -f) SYSTEM_FILE=$2; shift 2;;
+ -d) BASE_DIR=$2; shift 2;;
+ --) shift; break;;
+ esac
+done
+
+SYSTEM_FILE=${SYSTEM_FILE:-"${BASE_DIR}/etc/printers.conf"}
+
+if [ ! -d ${BASE_DIR}/etc/lp/printers ] ; then
+ gettext "Exit $0: There is no directory ${BASE_DIR}/etc/lp/printers\n\tfrom which to create /etc/printers.conf."
+ exit 0
+fi
+
+if [ -f ${BASE_DIR}/etc/lp/default ] ; then
+ DEFAULT_PRINTER=`cat ${BASE_DIR}/etc/lp/default`
+ lpset -n system -a "use=${DEFAULT_PRINTER}" _default
+ mv ${BASE_DIR}/etc/lp/default ${BASE_DIR}/etc/default.orig
+fi
+
+cd ${BASE_DIR}/etc/lp/printers # get the list of locally configured printers
+PRINTERS=`echo *`
+
+for PRINTER in ${PRINTERS} # for each printer get config info
+do
+ if [ "${PRINTER}" = "*" ] ; then
+ continue
+ fi
+
+ RNAME=${PRINTER}
+ DESC=""
+ RHOST=""
+
+ if [ -f ${PRINTER}/comment ] ; then
+ DESC=`cat ${PRINTER}/comment`
+ fi
+
+ REMOTE=`grep Remote: ${PRINTER}/configuration 2>/dev/null | sed -e "s/^Remote: //"`
+ DEVICE=`grep Device: ${PRINTER}/configuration 2>/dev/null | sed -e "s/^Device: //"`
+
+ if [ -n "${DEVICE}" ] ; then
+ RHOST=`uname -n`
+ elif [ `echo ${REMOTE} | grep -c \!` -ne 0 ] ; then
+ RHOST=`echo $REMOTE | cut -d \! -f 1`
+ RNAME=`echo $REMOTE | cut -d \! -f 2`
+ else
+ RHOST=${REMOTE}
+ fi
+
+ lpset -n system -a "bsdaddr=${RHOST},${RNAME}" -a "description=${DESC}" \
+ ${PRINTER}
+
+done
+
+exit 0
diff --git a/usr/src/cmd/print/scripts/conv_lpd b/usr/src/cmd/print/scripts/conv_lpd
new file mode 100644
index 0000000000..e75d411ba8
--- /dev/null
+++ b/usr/src/cmd/print/scripts/conv_lpd
@@ -0,0 +1,213 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1994, 1995, 1996 by Sun Microsystems, Inc.
+# All Rights Reserved
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# Printcap <-> Printers.conf conversion utility...
+#
+# Usage: conv_lpd [ -c (printers|printcap) ] [ -n ] (file)
+#
+
+TEXTDOMAIN="SUNW_OST_OSCMD"
+export TEXTDOMAIN
+
+USAGE=`gettext "Usage: conv_lpd [ -c (printers|printcap) ] [ -n ] (file)\n"`
+
+PATH=/usr/bin:/bin:/usr/sbin export PATH
+conversion="printers"
+namelist=0
+
+umask 022
+
+for i in $*
+do
+ case $1 in
+ -c*)
+ conversion=$2;
+ shift ; shift ;
+ ;;
+ -n*)
+ namelist=1;
+ shift ;
+ ;;
+ *)
+ break ;
+ ;;
+ esac
+done
+
+TMPF1=/tmp/tinput1.$$
+TMPF2=/tmp/tinput2.$$
+FILE=/tmp/input.$$
+
+# Any remaining arg is the "file" specification. It is a required arg.
+if [ -z "$1" ]; then
+ echo $USAGE
+ exit 1
+else
+ cp $1 $TMPF1
+fi
+
+echo >>$TMPF1
+echo "_done" >>$TMPF1
+
+#
+# First, strip all continuation characters, leaving one, single line
+# for each printer entry.
+#
+ CONV_FIX=/usr/lib/print/conv_fix
+
+ if [ -f $CONV_FIX ]; then
+ $CONV_FIX -f $TMPF1 -o $TMPF2
+ if [ $? != 0 ]; then
+ echo "$0:"
+ gettext "Fatal Error: $CONV_FIX failed.\n"
+ gettext "Please contact your Sun support representative.\n"
+ exit 1
+ fi
+ else
+ gettext "$0: Fatal: Cannot locate $CONV_FIX binary.\n"
+ gettext "Please contact your Sun support representative.\n"
+ exit 1
+ fi
+
+#
+# Continuation characters are now stripped. Continue processing.
+#
+ /bin/sed -e "s/:[ ]*:/:/g" $TMPF2 > $FILE
+
+#
+# Empty colons ":[ <TAB>]*:" are now stripped. Continue processing.
+#
+
+nawk '
+BEGIN {
+ "uname -n" | getline ;
+ host = $0 ;
+ found = 0 ;
+ local_pr = 0;
+}
+
+{
+ FS=":"; OFS=":" ;
+ if ($0 !~ /^#/)
+ {
+ if ($0 ~ /^[_a-zA-Z0-9_]/) { # New entry
+ if ( found != 0 ) {
+ if ( "'$namelist'" == 1 )
+ printer = names ;
+ else
+ printer = name[1] ;
+
+ if ( "'$conversion'" == "printers" ) {
+ printf "\n%s:", names ;
+ for (key in values) {
+ if ((key != "rp") &&
+ (key != "rm")) {
+ printf "\\\n\t:%s=%s:",
+ key, values[key] ;
+ delete values[key];
+ }
+ }
+ if (values["rm"] != "") {
+ printf "\\\n\t:bsdaddr=%s,%s:", \
+ values["rm"], \
+ values["rp"] ;
+ if (values["rm"] == host) local_pr++;
+ } else {
+ printf "\\\n\t:bsdaddr=%s,%s:", \
+ host, printer ;
+ local_pr++;
+ }
+ delete values["rp"];
+ delete values["rm"];
+ } else {
+ printf "\n%s:", names ;
+ for (key in values) {
+ if (key == "bsdaddr") {
+ split(values[key],
+ pair, ",");
+ printf "\\\n\t:%s=%s:", \
+ "rm", pair[1] ;
+ if (pair[2] == "")
+ pair[2] = printer;
+ printf "\\\n\t:%s=%s:", \
+ "rp", pair[2] ;
+
+ } else if ((key == "br") || \
+ (key == "fc") || \
+ (key == "fs") || \
+ (key == "mc") || \
+ (key == "mx") || \
+ (key == "pc") || \
+ (key == "pl") || \
+ (key == "pw") || \
+ (key == "px") || \
+ (key == "py") || \
+ (key == "xc") || \
+ (key == "xs"))
+ printf "\\\n\t:%s#%s:", \
+ key, \
+ values[key] ;
+ else if (values[key] == "true")
+ printf "\\\n\t:%s:", \
+ key ;
+ else if (values[key] != "false")
+ printf "\\\n\t:%s=%s:", \
+ key, \
+ values[key] ;
+ delete values[key];
+ }
+ }
+ }
+ split( $1, name, "|");
+ names = $1 ;
+ found++;
+ }
+
+ for ( i = 1 ; i <= NF ; i++ ) {
+ if (($i == names) || ($i == "") || \
+ ($i == "\t"))
+ continue ;
+ if ((split( $i, pair, "=" ) != 2) && \
+ (split( $i, pair, "\#") != 2))
+ pair[2] = "true";
+
+ if (pair[1] != "" && pair[1] != " ")
+ values[pair[1]] = pair[2] ;
+ }
+ }
+}
+END {
+ printf "\n" ;
+ if (local_pr != 0)
+ printf "One or more printers are local, you may want to run lpadmin to configure LP server side operation\n" | "cat 1>&2" ;
+
+}' ${FILE}
+
+/bin/rm -f ${TMPF1} ${TMP2} ${FILE}
+
+exit 0
diff --git a/usr/src/cmd/print/scripts/desktop-print-management b/usr/src/cmd/print/scripts/desktop-print-management
new file mode 100644
index 0000000000..2cc915be36
--- /dev/null
+++ b/usr/src/cmd/print/scripts/desktop-print-management
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# This interface launches an available print management tool capable of
+# configuration management of the LP print service.
+#
+exec /usr/bin/ospm-pm
+exec /bin/gksu /usr/sbin/printmgr
+/bin/zenity --error --test "unable to locate a desktop print management tool"
+exit 0
diff --git a/usr/src/cmd/print/scripts/desktop-print-management-applet b/usr/src/cmd/print/scripts/desktop-print-management-applet
new file mode 100644
index 0000000000..6a4932c8cf
--- /dev/null
+++ b/usr/src/cmd/print/scripts/desktop-print-management-applet
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# This interface launches any background desktop session service associated
+# with the configuration management app for the LP service.
+#
+exec /usr/lib/ospm/ospm-applet
+exit 0
diff --git a/usr/src/cmd/print/scripts/desktop-print-management-applet.desktop b/usr/src/cmd/print/scripts/desktop-print-management-applet.desktop
new file mode 100644
index 0000000000..e227313fb2
--- /dev/null
+++ b/usr/src/cmd/print/scripts/desktop-print-management-applet.desktop
@@ -0,0 +1,37 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+[Desktop Entry]
+Encoding=UTF-8
+Name=Desktop Printing Monitoring applet
+Comment=Show balloon dialog for printers
+Icon=print-manager
+Exec=env DESKTOP_LAUNCHED=true /usr/bin/desktop-print-management-applet
+Terminal=false
+Type=Application
+Categories=
+OnlyShowIn=GNOME;
+X-GNOME-Autostart-enabled=true
diff --git a/usr/src/cmd/print/scripts/desktop-print-management-prefs b/usr/src/cmd/print/scripts/desktop-print-management-prefs
new file mode 100644
index 0000000000..a0de4d1172
--- /dev/null
+++ b/usr/src/cmd/print/scripts/desktop-print-management-prefs
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+# This interface launches an available print management tool capable of
+# configuration management of the LP print service.
+#
+exec /usr/bin/ospm-preferences
+/bin/zenity --error --test "preferences are unavailable for the desktop print management tool"
+exit 0
diff --git a/usr/src/cmd/print/scripts/desktop-print-management-prefs.desktop b/usr/src/cmd/print/scripts/desktop-print-management-prefs.desktop
new file mode 100644
index 0000000000..970861d7e9
--- /dev/null
+++ b/usr/src/cmd/print/scripts/desktop-print-management-prefs.desktop
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+[Desktop Entry]
+Name=Printers
+Name[de]=Drucker
+Name[es]=Impresoras
+Name[fr]=Imprimantes
+Name[it]=Stampanti
+Name[ja]=プリンタ
+Name[ko]=프린터
+Name[pt_BR]=Impressoras
+Name[zh_CN]=打印机
+Name[zh_HK]=印表機
+Name[zh_TW]=印表機
+Comment=Set printer detection and connection behavior
+Comment[de]=Verhalten für Druckererkennung und -verbindung festlegen
+Comment[es]=Definir la detección de impresoras y el comportamiento de conexión
+Comment[fr]=Définir la détection des imprimantes et le comportement des connexions
+Comment[it]=Impostare la rilevazione della stampante e il comportamento della connessione
+Comment[ja]=プリンタの検出および接続の動作を設定します
+Comment[ko]=프린터 감지 및 연결 동작 설정
+Comment[pt_BR]=Definir comportamento de conexão e detecção da impressora
+Comment[zh_CN]=设置打印机检测和连接行为
+Comment[zh_HK]=設定印表機偵測和連線的運作方式
+Comment[zh_TW]=設定印表機偵測和連線的運作方式
+Exec=env DESKTOP_LAUNCHED=true /usr/bin/desktop-print-management-prefs
+Icon=print-manager
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=GNOME;GTK;Settings;
+OnlyShowIn=GNOME;
diff --git a/usr/src/cmd/print/scripts/desktop-print-management.desktop b/usr/src/cmd/print/scripts/desktop-print-management.desktop
new file mode 100644
index 0000000000..168ebc75ee
--- /dev/null
+++ b/usr/src/cmd/print/scripts/desktop-print-management.desktop
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+[Desktop Entry]
+Name=Print Manager
+Comment=Manage your printer queues and jobs
+Comment[cs]=Správa tiskových front a procesů
+Comment[de]=Druckerwarteschlangen und Druckaufträge verwalten
+Comment[es]=Administre las tareas y colas de la impresora
+Comment[fr]=Gérer les files d'attente et travaux de l'imprimante
+Comment[it]=Gestisci le code e i processi della stampante
+Comment[ja]=プリンタのキューおよびジョブを管理する
+Comment[ko]=프린터 대기열 및 작업 관리
+Comment[pt_BR]=Gerenciar filas e trabalhos da impressora
+Comment[zh_CN]=管理打印机队列和作业
+Comment[zh_HK]=管理印表機佇列和工作
+Comment[zh_TW]=管理印表機佇列和工作
+Exec=env DESKTOP_LAUNCHED=true /usr/bin/desktop-print-management
+Icon=print-manager
+Terminal=false
+Type=Application
+StartupNotify=true
+Categories=GNOME;Application;System;Settings
+OnlyShowIn=GNOME;
diff --git a/usr/src/cmd/print/scripts/getmakes b/usr/src/cmd/print/scripts/getmakes
new file mode 100644
index 0000000000..437d268324
--- /dev/null
+++ b/usr/src/cmd/print/scripts/getmakes
@@ -0,0 +1,37 @@
+#!/usr/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# get a list of the Manufacturers from the ppdcache
+#
+
+[[ -f /var/lp/ppd/ppdcache ]] || exit 1
+/bin/cat /var/lp/ppd/ppdcache |
+ nawk '{FS=":"; print $1}' |
+ nawk '{print $1}' |
+ /bin/sort -u
+exit 0
diff --git a/usr/src/cmd/print/scripts/getmodels b/usr/src/cmd/print/scripts/getmodels
new file mode 100644
index 0000000000..eeb4309ce2
--- /dev/null
+++ b/usr/src/cmd/print/scripts/getmodels
@@ -0,0 +1,45 @@
+#!/usr/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# get a list of the Models for this Model from the ppdcache
+#
+# Input:
+# Manufacturer (Note: printmgr passes only the first word
+# Lexmark of the manufacturer name)
+# Output:
+# Manufacturer Model
+# Lexmark Optra Color 1200
+
+if [[ $# -lt 1 ]]; then
+ exit 1
+fi
+
+cachefile=/var/lp/ppd/ppdcache
+[[ -f $cachefile ]] || exit 1
+/bin/grep "^$1" $cachefile | nawk '{FS=":"; print $2}' | uniq
+exit 0
diff --git a/usr/src/cmd/print/scripts/getppdfile b/usr/src/cmd/print/scripts/getppdfile
new file mode 100644
index 0000000000..bba0590b1b
--- /dev/null
+++ b/usr/src/cmd/print/scripts/getppdfile
@@ -0,0 +1,88 @@
+#!/usr/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Get the path/ppdfilename for this ppd NickName
+# Input:
+# make: model: ppdlabel: ppd:
+# PrintersRus: ABC Model 1234: SUNWfoomatic(S): Foomatic/Postscript (recommended):
+#
+
+#
+# Returns the full path to the repository associated with
+# the repository letter found between parenthesis in the
+# extended PPD label.
+#
+# $1 - Extended PPD label
+#
+rep_path()
+{
+ case "$(expr \"$1\" : ".*(\(.*\)).*")" in
+ "S")
+ echo "/usr/share/ppd"
+ ;;
+ "V")
+ echo "/opt/share/ppd"
+ ;;
+ "A")
+ echo "/usr/local/share/ppd"
+ ;;
+ "U")
+ echo "/var/lp/ppd"
+ ;;
+ esac
+}
+
+if [[ $# -lt 4 ]]; then
+ exit 1
+fi
+
+[[ -f /var/lp/ppd/ppdcache ]] || exit 1
+make=$(echo $* | /usr/bin/nawk '{FS=":"; print $1}')
+# strip leading blanks
+model=$(echo $* | /usr/bin/nawk '{FS=":"; print $2}' |
+ /bin/sed -e 's/^[ ]*//')
+extppdlabel=$(echo $* | /usr/bin/nawk '{FS=":"; print $3}' |
+ /bin/sed -e 's/^[ ]*//')
+ppd=$(echo $* | /usr/bin/nawk '{FS=":"; print $4}' |
+ /bin/sed -e 's/^[ ]*//')
+
+#
+# Do not use ":" with $make. printmgr collapses manufacturer name
+# to first word, ie PrintersRus and PrintersRus International become
+# PrintersRus. The full path to the PPD file will be the 6th
+# colon separated entry in the ppdcache entry. If the format
+# of a ppdcache entry changes, then this will need to be modified
+# also.
+#
+/bin/grep "${make}" /var/lp/ppd/ppdcache |
+ /bin/grep "${model}:" |
+ /bin/grep "${ppd}:" |
+ /bin/grep "$(rep_path ${extppdlabel})/${extppdlabel%\(*}" |
+ /usr/bin/nawk '{FS=":"; print $6}'
+
+exit 0
diff --git a/usr/src/cmd/print/scripts/getppds b/usr/src/cmd/print/scripts/getppds
new file mode 100644
index 0000000000..de91dadef4
--- /dev/null
+++ b/usr/src/cmd/print/scripts/getppds
@@ -0,0 +1,104 @@
+#!/usr/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# get a list of the Models for this Model from the ppdcache
+#
+
+# Input:
+# make model
+# HP OfficeJet 4200
+# Output:
+# <label>(<repository letter>): <driver>
+# userlabel(U): Foomatic/hpijs (recommended)
+# SUNWhpijs(S): Foomatic/hpijs (recommended)
+
+SaveIFS="$IFS"
+NoSpaceTabIFS='
+'
+SEP=": "
+
+#
+# Return cache entries matching the specified make
+# and model from the specified cache file.
+#
+# $1 - Make
+# $2 - Model
+# $3 - cachefile
+ppd_make_entries()
+{
+ for hit in $(/bin/grep "${1}" "${3}" | /bin/grep ":${2}:")
+ do
+ echo "${hit#*:*:}"
+ done
+}
+
+if [[ $# -lt 2 ]]; then
+ exit 1
+fi
+
+cachefile=/var/lp/ppd/ppdcache
+[[ -f $cachefile ]] || exit 1
+make=$1
+shift
+model="$*"
+system=
+vendor=
+admin=
+user=
+
+#
+# Ensure each ppdcache entry is processed as a single string
+# otherwise it would be split up by spaces.
+#
+IFS="$NoSpaceTabIFS"
+for pentry in $(ppd_make_entries "${make}" "${model}" "${cachefile}")
+do
+ IFS="$SaveIFS"
+ ppdpath="${pentry##*:}"
+ ppdlpath="${ppdpath%/*/*}"
+ ppdlabel="${ppdlpath##*/}"
+ driver="${pentry%%:*}"
+
+ case "${ppdpath}" in
+ "/usr/share/ppd/"*)
+ system="${system}${ppdlabel}(S)${SEP}${driver}\n"
+ ;;
+ "/opt/share/ppd/"*)
+ vendor="${vendor}${ppdlabel}(V)${SEP}${driver}\n"
+ ;;
+ "/usr/local/share/ppd/"*)
+ admin="${admin}${ppdlabel}(A)${SEP}${driver}\n"
+ ;;
+ "/var/lp/ppd/"*)
+ user="${user}${ppdlabel}(U)${SEP}${driver}\n"
+ ;;
+ esac
+ IFS="$NoSpaceTabIFS"
+done
+
+IFS="$SaveIFS"
+echo "${user}${admin}${vendor}${system}"
+exit 0
diff --git a/usr/src/cmd/print/scripts/lpadmin b/usr/src/cmd/print/scripts/lpadmin
new file mode 100644
index 0000000000..04c144a21f
--- /dev/null
+++ b/usr/src/cmd/print/scripts/lpadmin
@@ -0,0 +1,403 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+PATH=/bin:/usr/bin:/usr/sbin export PATH
+
+TEXTDOMAIN="SUNW_OST_OSCMD"
+export TEXTDOMAIN
+
+PFEXEC=/usr/bin/pfexec
+LPSET=/usr/bin/lpset
+LPGET=/usr/bin/lpget
+LPSTAT=/usr/bin/lpstat
+LPADMIN=/usr/lib/lp/local/lpadmin
+LPFILTER=/usr/sbin/lpfilter
+COMM=/usr/bin/comm
+PPDMGR=/usr/sbin/ppdmgr
+MKTEMP="/usr/bin/mktemp -t"
+
+HOST=$(/bin/uname -n)
+exit_code=0
+
+usage() {
+ gettext "Usage:\n" 1>&2
+ gettext " lpadmin -p (printer) (options)\n" 1>&2
+ gettext " lpadmin -x (dest)\n" 1>&2
+ gettext " lpadmin -d (dest)\n" 1>&2
+ gettext " lpadmin -S print-wheel -A alert-type [ -W minutes ]\n" 1>&2
+ gettext " [ -Q requests ]\n" 1>&2
+ gettext " lpadmin -M -f form-name [ -a [ -o filebreak ]\n" 1>&2
+ gettext " [ -t tray-number ]]\n" 1>&2
+ exit 1
+}
+
+# create a filter table for LP service
+lp_config_filters() {
+ if [[ ! -f /etc/lp/filter.table ]] ; then
+ cd /etc/lp/fd ; for filter in *.fd ; do
+ ${PFEXEC} ${LPFILTER} \
+ -f $(/usr/bin/basename $filter .fd) \
+ -F $filter
+ done
+ fi
+}
+
+# enable/disable LP related service(s)
+lp_config_service() { # (enable | disable)
+ svcadm ${1} -s svc:/application/print/server:default
+ # svcadm ${1} -s svc:/application/print/rfc1179:default
+ # svcadm ${1} -s svc:/application/print/ipp-listener:default
+}
+
+# synchronize printers.conf with LP configuration changes
+lp_config_sync_pconf() { # (pre) (post)
+ ADDED=$(${COMM} -13 ${1} ${2})
+ REMOVED=$(${COMM} -23 ${1} ${2})
+
+ lp_server=${server:-${HOST}}
+ for DEST in ${ADDED} ; do
+ lp_uri="ipp://${lp_server}/printers/${DEST}"
+ lp_bsdaddr="${lp_server},${DEST},Solaris"
+ ${LPSET} -n system \
+ -a "printer-uri-supported=${lp_uri}" \
+ -a "bsdaddr=${lp_bsdaddr}" \
+ ${DEST} 2>/dev/null
+ done
+
+ for DEST in ${REMOVED} ; do
+ ${LPSET} -n system -x ${DEST} 2>/dev/null
+ done
+}
+
+# Delete all destinations in printers.conf
+delete_all() {
+ for DEST in $(lpget -n system list | egrep -e '.+:$' | sed -e 's/://')
+ do
+ ${LPSET} -n system -x ${DEST}
+ status=$?
+ done
+}
+
+# Call the ppdmgr utility to add a new PPD file to the system.
+#
+# $1 - path to PPD file
+# $2 - label name (optional)
+add_new_ppd_file() {
+ # Add new ppd file and echo full path it was actually saved to
+ ppdmgrcmd="${PFEXEC} ${PPDMGR} -a ${1} -w"
+
+ ppderrfile=$(${MKTEMP} lpadminerror.XXXXXX)
+ if [[ -z "${ppderrfile}" ]] ; then
+ gettext "lpadmin: System error; cannot create temporary file\n" 1>&2
+ exit 2
+ fi
+ ppd_file=$(${ppdmgrcmd} 2>${ppderrfile})
+ ppdmgrrc=$?
+ if [[ -s "${ppderrfile}" ]] ; then
+ print -n "lpadmin: " 1>&2
+ cat ${ppderrfile} 1>&2
+ rm -f ${ppderrfile} >/dev/null 2>&1
+ if [[ ${ppdmgrrc} -ne 0 ]] ; then
+ exit 1
+ fi
+ fi
+ rm -f ${ppderrfile} >/dev/null 2>&1
+}
+
+#
+# Execution begins here
+#
+
+# be sure that we can run lpset and lpget
+if [[ ! -x ${LPSET} || ! -x ${LPGET} ]] ; then
+ gettext "lpadmin: System error; cannot set default printer\n" 1>&2
+ exit 2
+fi
+
+if [[ $# -lt 1 ]] ; then
+ usage
+ exit 1
+fi
+
+# Deal with the -d option independently since getopts does not handle
+# options that may or may not have arguments
+#
+if [[ ${1} = "-d" ]] ; then
+ if [[ $# -eq 1 ]] ; then # remove the "default"
+ ${LPGET} -n system _default >/dev/null 2>&1
+ exit_code=$?
+
+ if [[ ${exit_code} -eq 0 ]] ; then
+ ${LPSET} -n system -x _default
+ exit_code=$?
+ else # no default, nothing to do
+ exit_code=0
+ fi
+ elif [[ $# -eq 2 ]] ; then # add/change the "default"
+ ${LPGET} -k bsdaddr ${2} >/dev/null 2>&1
+ exit_code=$?
+
+ if [[ $exit_code -eq 0 ]] ; then
+ ${LPSET} -n system -a "use=${2}" _default
+ exit_code=$?
+ else # can't set default to an unconfigured printer
+ gettext "${2}: undefined printer\n" 1>&1
+ fi
+ else # invalid usage
+ usage
+ exit 1
+ fi
+
+ exit ${exit_code}
+fi
+
+# Strip off legal options
+while getopts "A:ac:D:e:f:F:H:hi:I:lm:Mn:o:p:Q:r:S:s:T:u:U:v:W:x:t:P:" arg
+do
+ case $arg in
+ D)
+ description="${OPTARG}"
+ ;;
+ n)
+ ppd_file="${OPTARG}"
+ ;;
+ p)
+ if [[ -n "${delete}" ]] ; then
+ usage
+ fi
+ printer=${OPTARG}
+ ;;
+ s)
+ server=${OPTARG}
+ ;;
+ v|U)
+ device=${OPTARG}
+ if [[ ! -n "${server}" ]] ; then
+ server=${HOST}
+ fi
+ local="true"
+ ;;
+ x)
+ if [[ -n "${printer}" || -n "${server}" || \
+ -n "${device}" || -n "${description}" ]] ; then
+ usage
+ fi
+ delete=${OPTARG}
+ printer=${OPTARG}
+ if [[ ${printer} = "all" ]] ; then
+ local="true"
+ fi
+ ;;
+ S|M|A)
+ local="true"
+ ;;
+ c)
+ class=${OPTARG}
+ local="true"
+ if [[ ! -f ${LPGET} ]] ; then
+ gettext "lpadmin: System error; cannot set class\n " 1>&2
+ exit 2
+ fi
+
+ ${LPGET} "${class}" > /dev/null 2>&1
+ lpget_class=$?
+ if [[ ${lpget_class} -eq 0 && ! -r /etc/lp/classes/"${class}" ]] ; then
+ gettext "lpadmin: ERROR: Can't create class ${class}.\n" 1>&2
+ gettext " TO FIX: This is an existing printer name;\n" 1>&2
+ gettext " choose another name.\n" 1>&2
+ exit 1
+ fi
+ ;;
+ r)
+ local="true"
+ ;;
+ esac
+done
+
+#
+# We don't have anything to do; let user know and bail
+#
+if [[ ! -n "${printer}" && ! -n "${delete}" && ! -n "${local}" ]] ; then
+ gettext "lpadmin: ERROR: Nothing to do.\n" 1>&2
+ gettext " TO FIX: You must give one of these options:\n" 1>&2
+ gettext " -p, -d, -x -S\n" 1>&2
+ exit 1
+fi
+
+#
+# Printer does not exist
+# To be consistent with 2.5, assume adding local printer
+#
+if [[ ! -n "${device}" && ! -n "${server}" && ! -n "${delete}" && \
+ ! -n "${local}" ]] ; then
+ ${LPGET} "${printer}" > /dev/null 2>&1
+ lpget_stat=$?
+ if [[ ${lpget_stat} -ne 0 ]] ; then
+ gettext "lpadmin: ERROR: Missing -U or -v option.\n" 1>&2
+ gettext " TO FIX: Local printers must have\n" 1>&2
+ gettext " a port defined (-v option) or\n" 1>&2
+ gettext " have dial-out instructions (-U option).\n" 1>&2
+ exit 1
+ fi
+fi
+
+# process the "server" value
+# It can be a hostname, UUCP form (server!queue), RCMD form(queue@server),
+# or in URI form ({scheme}://{endpoint})
+#
+case "${server}" in
+ *://*) # URI form
+ uri=${server}
+ rem_printer=$(expr "${server}" : ".*://.*/\([^/]*\)")
+ server=$(expr "${server}" : ".*://\([^/]*\)/.*")
+ ;;
+ *@*) # RCMD form
+ rem_printer=$(expr "${server}" : "\(.*\)@.*")
+ server=$(expr "${server}" : ".*@\(.*\)")
+ ;;
+ *!*) # UUCP form
+ rem_printer=$(expr "${server}" : ".*!\(.*\)")
+ server=$(expr "${server}" : "\(.*\)!.*")
+ ;;
+ *) # hostname
+ rem_printer=${printer}
+ ;;
+esac
+
+# if there is a "device" or LP configuration, it's local
+if [[ -n "${device}" || -f /etc/lp/printers/${printer}/configuration || \
+ -f /etc/lp/classes/${printer} ]] ; then
+ local="true"
+fi
+
+# Do the LP configuration for a local printer served by lpsched
+if [[ -x ${LPADMIN} && -n "${local}" ]] ; then
+ # enumerate LP configured printers before modification
+ PRE=$(${MKTEMP} lpadmin-pre.XXXXXX)
+ if [[ -z "${PRE}" ]] ; then
+ gettext "lpadmin: System error; cannot create temporary file\n" 1>&2
+ exit 2
+ fi
+
+ (/bin/ls /etc/lp/printers 2>/dev/null ; /bin/ls /etc/lp/classes \
+ 2>/dev/null) >${PRE}
+
+ # if there are no printers configured, enable LP service(s)
+ [[ ! -s "${PRE}" ]] && lp_config_service enable
+
+ # add filters to LP service
+ lp_config_filters
+
+ # add new ppd file to PPD file repositories
+ if [[ -n "${ppd_file}" && -x ${PPDMGR} ]] ; then
+ add_new_ppd_file "${ppd_file}"
+ fi
+
+ # modify LP destination(s)
+ CMD="${PFEXEC} ${LPADMIN}"
+ while [[ -n "$*" ]] ; do # to deal with multi-word arguments
+ CMD="$CMD \"$1\""
+ # replace the ppd_file originally specified with the -n option
+ # with the one returned from call to ppdmgr
+ if [[ "${1}" = "-n" ]] ; then
+ CMD="$CMD \"${ppd_file}\""
+ shift
+ fi
+ shift
+ done
+ case "$CMD" in
+ *\"-D\")
+ CMD="$CMD \"\""
+ ;;
+ esac
+
+ # execute the LP lpadmin command
+ eval $CMD
+ exit_code=$?
+
+ # enumerate LP configured printers after modification
+ POST=$(${MKTEMP} lpadmin-post.XXXXXX)
+ if [[ -z "${POST}" ]] ; then
+ gettext "lpadmin: System error; cannot create temporary file\n" 1>&2
+ /bin/rm -f ${PRE} >/dev/null 2>&1
+ exit 2
+ fi
+
+ (/bin/ls /etc/lp/printers 2>/dev/null ; /bin/ls /etc/lp/classes \
+ 2>/dev/null) >${POST}
+
+ # if there are no destinations, disable the service(s)
+ [[ ! -s "${POST}" ]] && lp_config_service disable
+
+ # sync printers.conf with LP configuration
+ lp_config_sync_pconf "${PRE}" "${POST}"
+
+ /bin/rm -f ${PRE} ${POST}
+fi
+
+# Do any printers.conf configuration that is required
+if [[ -n "${delete}" ]] ; then
+ if [[ "${delete}" = "all" ]] ; then
+ [[ $exit_code -eq 0 ]] && delete_all
+ elif [[ -z "${local}" ]] ; then
+ ${LPSET} -n system -x ${delete}
+ exit_code=$?
+ fi
+else
+ if [[ -z "${local}" ]] ; then
+ # if we need a uri, find the "best" one.
+ if [[ -z "${uri}" ]] ; then
+ uri="ipp://${server}/printers/${rem_printer}"
+ ${LPSTAT} -p ${uri} >/dev/null 2>&1
+ if [[ $? -ne 0 ]] ; then
+ uri="lpd://${server}/printers/${rem_printer}#Solaris"
+ fi
+ fi
+ # set the bsdaddr
+ bsdaddr="${server},${rem_printer},Solaris"
+
+ if [[ -n "${printer}" && -n "${server}" ]] ; then
+ ${LPSET} -n system \
+ -a "printer-uri-supported=${uri}" \
+ -a "bsdaddr=${bsdaddr}" ${printer}
+ exit_code=$?
+ fi
+
+ fi
+
+ if [[ -n "${printer}" && -n "${description}" ]] ; then
+ ${LPSET} -n system \
+ -a "description=${description}" ${printer}
+ exit_code=$?
+ fi
+fi
+
+# if the "default" doesn't resolve a "bsdaddr", the printer is gone, remove it
+${LPGET} -n system -k bsdaddr _default >/dev/null 2>&1 ||
+ ${LPSET} -n system -x _default >/dev/null 2>&1
+
+exit $exit_code
diff --git a/usr/src/cmd/print/scripts/lpsystem b/usr/src/cmd/print/scripts/lpsystem
new file mode 100644
index 0000000000..fdf08de324
--- /dev/null
+++ b/usr/src/cmd/print/scripts/lpsystem
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+# This interface is obsolete, do nothing and always succeed for the sake
+# of any shell scripts that may still make a call to it.
+#
+exit 0
diff --git a/usr/src/cmd/print/scripts/manufaliases b/usr/src/cmd/print/scripts/manufaliases
new file mode 100644
index 0000000000..4e6d489c36
--- /dev/null
+++ b/usr/src/cmd/print/scripts/manufaliases
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+Canon:Canon Inc.
+Dymo:Dymo-CoStar
+Epson
+HP:hewlett-packard
+Minolta:minolta-qms
+Okidata:oki:OKI DATA CORP
+Xerox
+Lexmark:Lexmark International
diff --git a/usr/src/cmd/print/scripts/ppdfilename2mmp b/usr/src/cmd/print/scripts/ppdfilename2mmp
new file mode 100644
index 0000000000..1d24c0af99
--- /dev/null
+++ b/usr/src/cmd/print/scripts/ppdfilename2mmp
@@ -0,0 +1,100 @@
+#!/usr/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+#
+# Get the make/model/nickname as well as the repository/label from ppdfilename
+#
+
+# Input
+# ppdfilename
+# /var/lp/ppd/user/HP/foo.ppd.gz
+# Output
+# make
+# model
+# label(repository letter): driver
+#
+# Lexmark
+# IBM Page Printer 3112
+# foomatic(L): Foomatic/hpijs
+#
+
+if [[ $# -lt 1 ]]; then
+ exit 1
+fi
+
+cachefile=/var/lp/ppd/ppdcache
+[[ -f $cachefile ]] || exit 1
+
+cacheentry=$(/bin/grep "$1" $cachefile)
+[[ -n "$cacheentry" ]] || exit 1
+
+#
+# Retrieve the manufacturer (make)
+# Use only the first word in manufacturer entry
+#
+manuf=$(echo "$cacheentry" |
+nawk '{FS=":"; print $1}' |
+nawk '{print $1}')
+
+# Retrieve the model
+model=$(echo "$cacheentry" | nawk '{FS=":"; print $2}')
+
+# Retrieve the driver
+driver=$(echo "$cacheentry" | nawk '{FS=":"; print $3}')
+
+#
+# Retrieve the PPD path. Parse the PPD path to get the
+# label path and to figure out the repository letter
+# associated with the label path. Note:
+# the PPD file name is the 6th colon separated entry
+# in the cache entry. This is may need to be modified if the
+# format changes.
+#
+ppdpath=$(echo "$cacheentry" | /bin/nawk '{FS=":"; print $6}' )
+manupath=$(/bin/dirname "$ppdpath")
+labelpath=$(/bin/dirname "$manupath")
+
+case "$labelpath" in
+/usr/share/ppd/*)
+ repltr=S
+ ;;
+/opt/share/ppd/*)
+ repltr=V
+ ;;
+/usr/local/share/ppd/*)
+ repltr=A
+ ;;
+/var/lp/ppd/*)
+ repltr=U
+ ;;
+esac
+
+[[ -n "${repltr}" ]] || exit 1
+echo "${manuf}\n${model}"
+echo "$(/bin/basename "$labelpath")(${repltr}): $driver"
+
+exit 0
diff --git a/usr/src/cmd/print/scripts/ppdmgr b/usr/src/cmd/print/scripts/ppdmgr
new file mode 100644
index 0000000000..335c01da7d
--- /dev/null
+++ b/usr/src/cmd/print/scripts/ppdmgr
@@ -0,0 +1,1765 @@
+#!/bin/ksh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# Description: Script to generate the Solaris printmgr 'ppdcache' file from the
+# ppd files installed in the given ppd database directory
+#
+# ppdmgr -a <ppd_filename_path> [ -L <label> ] [-w]
+# ppdmgr -g <ppd_filename_path> [ -L <label> ] [ -R <ppd_repository> ]
+# ppdmgr -r [ -L <label> ] [ -R <ppd_repository> ]
+# ppdmgr -u [ -L <label> ] [ -R <ppd_repository> ]
+#
+# Options:
+# -a <ppd_filename_path> - Add a new PPD file to the specified
+# label in the "user" repository, and
+# updates to the "user" repository
+# in the ppdcache.
+# -g <ppd_filename_path> - Generate a cache file entry
+# for the specified PPD file
+# on standard out.
+# -L <label> - Label name. <label>
+# can be any characters from the
+# portable character set, however
+# may not contain a semi-colon (':').
+# The following are the defaults
+# for <label> for each option:
+# OPTION DEFAULT LABEL
+# ------ -------------
+# -a <label> from <ppd_filename_path>
+# if <ppd_filename_path>
+# is from a known repository,
+# otherwise defaults to "user".
+# -g <label> from <ppd_filename_path>
+# if <ppd_filename_path>
+# is from a known repository,
+# otherwise defaults to "user".
+# -r all
+# -u all
+# The following are reserved labels:
+# caches - may never be specified
+# ppdcache - may never be specified
+# manufaliases - may never be specified
+# all - applies specified
+# action to all labels
+# in a repository.
+# Can only be specified
+# with -r or -u.
+# SUNW* - anything starting with
+# SUNW is reserved for
+# use by Sun, but not
+# prohibited.
+# -r - Rebuild the cache information for the
+# specified label in the specified
+# repository. Similar to -u, however,
+# the cache file is removed to force an
+# update to the ppdcache.
+# -R <ppd_repository> - PPD repository name.
+# Defaults to "user".
+# The following are the possible
+# values for <ppd_repository> and
+# location in the system:
+# REP LOCATION
+# --- --------
+# user /var/lp/ppd
+# admin /usr/local/share/ppd
+# vendor /opt/share/ppd
+# system /usr/share/ppd
+# all all repositories
+#
+# Note: When specified with the -a option
+# only "user" and "admin" are valid.
+# "vendor", "system", and "all" will be
+# considered reserved.
+# -u - Update the PPD cache information
+# for the specified label in the specified
+# repository if needed. If the cache
+# update was required, then the updated
+# cache information is reflected in
+# the ppdcache.
+# -w - Display full path of where the
+# ppd file is located on the system.
+# Only valid with -a, otherwise the
+# option is ignored.
+#
+# If -a, -g, -r, or -u are specified on the command line, only the last action
+# specified will be performed.
+#
+# Cache file entry format:
+# <ModifiedManufacturerName>:<Model>:<NickName>:<1284DeviceIDManufacturer>:<1284DeviceIDModel>:<FullPPDFilePath>
+# HP:HP DeskJet 450:Foomatic/hpijs (recommended):dj450:hp:/usr/share/ppd/HP/HP-DeskJet_450-hpijs.ppd.gz
+#
+
+PATH=/bin:/usr/bin:/usr/sbin export PATH
+set -o noclobber
+
+TEXTDOMAIN="SUNW_OST_OSCMD"
+export TEXTDOMAIN
+
+#
+# Generates debug output for calling routine.
+# If calling routine's name is passed in, then
+# will also generate the name of the calling routine.
+#
+# $1 - Name of calling routine
+debugger()
+{
+ [[ ${debug} -eq 1 ]] || return 1
+ if [[ -n "${1}" ]] ; then
+ echo "In ${1}..." 1>&2
+ fi
+ return 0
+}
+
+#
+# Set the ownership and permissions on a file.
+#
+# $1 - Mode
+# $2 - Owner:Group
+# $3 - Full path to file
+#
+set_perms()
+{
+ /bin/chmod -f ${1} "${3}" >/dev/null 2>&1
+ /bin/chown -f ${2} "${3}" >/dev/null 2>&1
+}
+
+#
+# Create administrator repository directories, /usr/local/share/ppd,
+# if needed. This is a special case a Solaris doesn't deliver
+# /usr/local/share and it has different permissions than the
+# user repository.
+#
+# $1 - destination repository name
+#
+create_adminrep_dirs()
+{
+ if debugger "check_adminrep_dirs" ; then
+ set -x
+ fi
+
+ # Only create administrator repository directories, if needed.
+ [[ "${1}" = "${ADMIN}" ]] || return 0
+
+ # Check /usr/local/share/ppd
+ [[ ! -d "${ADMINREP}" ]] || return 0
+
+ # Check /usr/local/share
+ admpar=$(/bin/dirname "${ADMINREP}")
+ if [[ ! -d "${admpar}" ]] ; then
+
+ # Check /usr/local
+ admppar=$(/bin/dirname "${admpar}")
+ if [[ ! -d "${admppar}" ]] ; then
+ make_dir ${DIRMODE} ${ADMINOWNER} "${admppar}" || \
+ return 1
+ fi
+ make_dir ${DIRMODE} ${ADMINOWNER} "${admpar}" || return 1
+ fi
+ make_dir ${DIRMODE} ${ADMINOWNER} ${ADMINREP} || return 1
+ return 0
+}
+
+#
+# Returns full path to PPD file that was added to the system.
+#
+# $1 - Full path to source PPD file
+# $2 - PPD file name
+# $3 - Full path to repository
+# $4 - Repository name
+# $5 - Label name
+#
+# Return codes:
+# 0 - File successfully added
+# 1 - Error
+# 2 - Duplicate file already exists
+#
+add_ppd()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ verify_ppd_file "${1}"
+ if [[ $? -ne 0 ]] ; then
+ gettext "invalid PPD file: ${1}" 2>/dev/null
+ return 3
+ fi
+
+ # The destination path can now be set
+ dstlabelpath="${3}/${5}"
+ dstmanufpath="${dstlabelpath}/${modmanuf}"
+ dstpath="${dstmanufpath}/${2}"
+
+ #
+ # If a version (either compressed or not compressed) of the PPD
+ # file exists in the destination in the label/repository,
+ # then just return as there no work to be done.
+ dst_copy_path=$(variant_copy "${1}" "${dstpath}" "${6}" "${ppdfname}")
+ ap_rc=$?
+ if [[ ${ap_rc} -ne 0 ]] ; then
+ echo "${dst_copy_path}"
+ return ${ap_rc}
+ fi
+
+ #
+ # Can only add a PPD file to the "user" or "admin" repository.
+ # Note: this check is here instead of at the top of this
+ # function as we don't want to cause an error if a user
+ # specifies the same repository and label as a the specified
+ # ppd file and the repository of the specified ppd file
+ # exists in a known repository.
+ #
+ if [[ "${4}" != "${USER}" && "${4}" != "${ADMIN}" ]] ; then
+ gettext "invalid PPD file repository name: ${4}" 2>/dev/null
+ return 3
+ fi
+
+ # Ensure destination directories exist
+ if ! create_adminrep_dirs ${4} ${DIRMODE} ${ADMINOWNER} || \
+ ! make_dir ${DIRMODE} ${DIROWNER} "${3}" || \
+ ! make_dir ${DIRMODE} ${DIROWNER} "${dstlabelpath}" || \
+ ! make_dir ${DIRMODE} ${DIROWNER} "${dstmanufpath}" ; then
+ gettext "unable to create destination directories" 2>/dev/null
+ return 3
+ fi
+
+ # Copy source PPD file, and compress if needed, to destination
+ if [[ "${ppdfileext}" = "${PEXT}" ]] ; then
+ ${GZIP} "${1}" >"${dst_copy_path}" 2>/dev/null
+ if [[ $? -eq 1 ]] ; then
+ gettext "unable to copy PPD file " 2>/dev/null
+ gettext "to destination" 2>/dev/null
+ return 3
+ fi
+ else
+ /bin/cp -f "${1}" "${dst_copy_path}" >/dev/null 2>&1
+ if [[ $? -ne 0 ]] ; then
+ gettext "unable to copy PPD file " 2>/dev/null
+ gettext "to destination" 2>/dev/null
+ return 3
+ fi
+ fi
+ set_perms ${FILEMODE} ${FILEOWNER} "${dst_copy_path}"
+
+ echo "${dst_copy_path}"
+
+ return 0
+}
+
+#
+# Returns 0 if the cache needs to be modified, otherwise
+# returns 1.
+#
+# $1 - Full path to cache
+# $2 - Full path to cache replacement candidate
+#
+changes_in_cache()
+{
+ if debugger "changes_in_cache" ; then
+ set -x
+ fi
+
+ if [[ "${action}" = "${REBUILD}" ]] ; then
+ return 0
+ fi
+ [[ "${2}" -nt "${1}" ]] || return 1
+ if $(${CMP} "${1}" "${2}" >/dev/null 2>&1) ; then
+ # No differences. Just update timestamp
+ /bin/touch -r "${2}" "${1}" >/dev/null 2>&1
+ return 1
+ else
+ return 0
+ fi
+}
+
+#
+# Generate a new golden cache file (/var/lp/ppd/ppdcache), by
+# concatenating and sorting all existing cache files in /var/lp/ppd/caches.
+#
+# If there are difference between the newly generated golden cache file and
+# the existing one (if it exists) then the newly generated one replaces the
+# existing one at /var/lp/ppd/ppdcache.
+#
+update_golden_cache()
+{
+
+ if debugger "update_golden_cache" ; then
+ set -x
+ fi
+
+ #
+ # Remove any cache files that don't have an associated
+ # label.
+ #
+ for cname in $(/bin/ls ${VARCACHES} 2>/dev/null) ; do
+ repname="${cname%%:*}"
+ cfile="${cname#*:}"
+ checkdir="$(get_rep_path ${repname})/${cfile}"
+ remove_unassociated_cache "${checkdir}" "${cname}"
+ done
+
+ #
+ # Combine the contents of all cache files into a
+ # temporary golden cache file.
+ #
+ tmpgoldencache=$ppdmgrtmpdir/tmpgoldencache
+
+ /bin/sort "${VARCACHES}"/* >>"${tmpgoldencache}" 2>/dev/null
+
+ if [[ ! -s "${tmpgoldencache}" ]] ; then
+ # No cache files. Remove golden cache.
+ /bin/rm -f "${GOLDCACHE}" >/dev/null 2>&1
+ /bin/rm -f "${tmpgoldencache}" >/dev/null 2>&1
+ elif [[ -e "${GOLDCACHE}" ]] ; then
+ #
+ # Use the newly generated "temporary" golden cache file if there
+ # differences between the current and newly generated ppdcache
+ # or if a rebuild is being performed.
+ #
+ if [[ "${VARCACHES}" -nt "${GOLDCACHE}" ]] || \
+ changes_in_cache "${GOLDCACHE}" "${tmpgoldencache}" ; then
+ set_perms ${FILEMODE} ${FILEOWNER} "${tmpgoldencache}"
+ /bin/mv -f "${tmpgoldencache}" \
+ "${GOLDCACHE}" >/dev/null 2>&1
+ else
+ /bin/rm -f "${tmpgoldencache}" >/dev/null 2>&1
+ fi
+ else
+ # There wasn't an existing ppdcache. Install the newly
+ # generated ppdcache file to the golden ppdcache.
+ set_perms ${FILEMODE} ${FILEOWNER} "${tmpgoldencache}"
+ /bin/mv -f "${tmpgoldencache}" "${GOLDCACHE}" >/dev/null 2>&1
+ fi
+}
+
+#
+# Returns a list of PPD files that exist.
+#
+# $1 - Full path to cache file
+#
+remove_invalid_cache_entries()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ [[ -s "${1}" ]] || return
+
+ IFS="$NoSpaceTabIFS"
+ for centry in $(/bin/cat "${1}" 2>/dev/null) ; do
+ IFS="$SaveIFS"
+ #
+ # Keep the entry from the ppd cache if it still
+ # exists and there haven't been any modifications
+ # since the last update to the cache.
+ #
+ if [[ -n "${centry}" ]] ; then
+ ppdfile="${centry##*:}"
+ if [[ -n "${ppdfile}" && -e "${ppdfile}" &&
+ "${1}" -nt "${ppdfile}" ]] ; then
+ echo "${centry}"
+ fi
+ fi
+ IFS="$NoSpaceTabIFS"
+ done
+ IFS="$SaveIFS"
+}
+
+#
+# Returns 0 if the path to the PPD is as follows:
+# <PPD file repository>/<label>/<manufacturer>/<PPD file>
+# otherwise, returns 1
+#
+# $1 Full path to PPD file
+#
+verify_ppd_location()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ #
+ # Strip off what should be <label>/<manufacturer>/<PPD file>
+ # and verify the PPD file repository matches one of the
+ # known PPD file repositories.
+ #
+ ppd_file_repository=${1%/*/*/*}
+ found=1
+ for repository in ${REPOSITORIES} ; do
+ if [[ "${repository}" = "${ppd_file_repository}" ]] ; then
+ found=0
+ break
+ fi
+ done
+ return ${found}
+}
+
+#
+# Generate, and sort, cache entries for each PPD files in the specified
+# list to the specified file.
+#
+# $1 - List of full paths to PPD files
+# $2 - Full path to current cache file
+# $3 - Full path to label
+# $4 - Full path to new cache file to generate
+#
+# Return code:
+# 0 success
+# 1 unsuccessful
+#
+generate_label_cache_file()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ #
+ # Generate a cache file containing cache entries for
+ # all files in the label.
+ #
+ ucfile=$ppdmgrtmpdir/unsortedcache
+
+ #
+ # Before processing new files, remove any cache entries
+ # which may be invalid.
+ #
+ valid_files=
+ if [[ -e "${2}" && "${action}" != "${REBUILD}" ]] ; then
+ valid_files=$(remove_invalid_cache_entries "${2}")
+ if [[ -n "${valid_files}" ]] ; then
+ echo "${valid_files}" >>${ucfile}
+ fi
+ fi
+
+ #
+ # If there are no valid PPD files in the current cache file,
+ # and there are no new PPD files to process, the only thing
+ # left to do is to remove the current cache file.
+ #
+ if [[ -z "${valid_files}" && -z "${1}" ]] ; then
+ /bin/rm -f "${2}" >/dev/null 2>&1
+ /bin/rm -f "${ucfile}" >/dev/null 2>&1
+ return 0
+ fi
+
+ #
+ # For each of the label's PPD files, generate
+ # a cache file entry and add it to the cache file.
+ #
+ vpl_rc=0
+ vpf_rc=0
+ vpl_msg=
+ vpf_msg=
+ IFS="$NoSpaceTabIFS"
+ for fname in ${1} ; do
+ IFS="$SaveIFS"
+ if [[ -n "${fname}" ]] ; then
+ verify_ppd_location "${fname}"
+ vpl_rc=$?
+ if [[ ${vpl_rc} -ne 0 ]] ; then
+ vpl_msg="${vpl_msg}\t${fname}\n"
+ fi
+
+ verify_ppd_file "${fname}"
+ vpf_rc=$?
+ if [[ ${vpf_rc} -ne 0 ]] ; then
+ vpf_msg="${vpf_msg}\t${fname}\n"
+ fi
+
+ if [[ ${vpl_rc} -eq 0 && ${vpf_rc} -eq 0 ]] ; then
+ echo "$(generate_cache_file_entry \
+ "${modmanuf}" "${model}" "${nickn}" \
+ "${devidmfg}" "${devidmdl}" "${fname}")"
+ fi
+ fi
+ IFS="$NoSpaceTabIFS"
+ done >>"${ucfile}"
+ IFS="$SaveIFS"
+ /bin/sort -u "${ucfile}" >>"${4}" 2>/dev/null
+ /bin/rm -f "${ucfile}" >/dev/null 2>&1
+
+ [[ -n "${vpl_msg}" || -n "${vpf_msg}" ]] || return 0
+ if [[ -n ${vpl_msg} ]] ; then
+ gettext " PPD file(s) not in valid location\n" 2>/dev/null
+ gettext \
+ " (<repository>/<label>/<manufacturer>/<PPD file>):\n" 2>/dev/null
+ echo "${vpl_msg}"
+ fi
+ if [[ -n ${vpf_msg} ]] ; then
+ gettext " invalid PPD file(s):\n" 2>/dev/null
+ echo "${vpf_msg}"
+ fi
+ return 1
+}
+
+#
+# Update current cache file with candidate cache file if there are
+# differences.
+#
+# $1 - Current cache file
+# $2 - Candidate cache file to update
+# $3 - Repository name
+#
+update_current_cache_file()
+{
+ if debugger "update_current_cache_file" ; then
+ set -x
+ fi
+
+ if [[ ! -s "${2}" ]] ; then
+ #
+ # Candidate cache has zero size (label
+ # directory with no PPD files under it).
+ # Delete the empty candidate cache
+ # file and delete the current cache
+ # file.
+ #
+ /bin/rm -f "${1}" >/dev/null 2>&1
+ /bin/rm -f "${2}" >/dev/null 2>&1
+ elif [[ -e "${1}" ]] ; then
+ #
+ # If there are differences between the current
+ # cache file and the newly generated one, then
+ # replace the current one with the new one, and
+ # set the flag to update the golden ppdcache
+ # file.
+ #
+ if changes_in_cache "${1}" "${2}" ; then
+ set_perms ${FILEMODE} ${FILEOWNER} "${2}"
+ /bin/mv -f "${2}" "${1}" >/dev/null 2>&1
+ else
+ /bin/rm -f "${2}" >/dev/null 2>&1
+ fi
+ else
+
+ #
+ # There is no current cache file. Move the candidate
+ # to the caches directory.
+ #
+ set_perms ${FILEMODE} ${FILEOWNER} "${2}"
+ /bin/mv -f "${2}" "${1}" >/dev/null 2>&1
+ fi
+}
+
+#
+# Returns 0 if there are files in $1 with newer timestamp
+# than $2 or if deletions have occurred under $1,
+# otherwise returns 1.
+#
+# $1 - Full path to the destination label
+# $2 - Full path to label cache file
+#
+changes_under_label()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ # First check for newer files in the directory
+ if [[ -e "${2}" && "${action}" != "${REBUILD}" ]] ; then
+ newfiles=$(/bin/find "${1}" -type f -newer "${2}")
+ else
+ newfiles=$(/bin/find "${1}" -type f)
+ fi
+ echo "${newfiles}"
+ [[ -z "${newfiles}" ]] || return 0
+
+ #
+ # Need to detect if PPD files have been deleted by checking
+ # timestamps on label and manufacturer directories.
+ #
+ [[ ! "${1}" -nt "${2}" ]] || return 0
+ /bin/find "${1}" -type d -newer "${2}" >/dev/null 2>&1 || return 1
+ return 0
+}
+
+#
+# If -R was specified, or the timestamp on the specified label's
+# directory or any of the PPD files under the specified label in
+# the specified PPD file respository is newer than the cache file
+# associated with the label, then generate a new sorted cache file.
+#
+# The new cache will replace the existing one (if any) only if there
+# are differences. Note: if -r was specified, then a new cache file
+# file will always be installed at
+# /var/lp/ppd/caches/<PPD file repository name>-<label name>
+#
+# $1 - Full path of the destination PPD file repository
+# $2 - Destination PPD file repository name
+# $3 - Destination label name
+#
+update_label_cache()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ dstlabelpath="${1}/${3}"
+ replabelcachepath="${1}/${CACHES}/${3}"
+ varlabelcachepath="${VARCACHES}/${2}${SEP}${3}"
+
+ ulc_rc=0
+ if [[ -d "${dstlabelpath}" ]] ; then
+
+ #
+ # If the cache doesn't exist for a label,
+ # or if there were any changes under a label
+ # (i.e., the timestamp on the label directory or any
+ # of the PPD files under it is newer than the
+ # existing cache file), then generate a new cache file.
+ #
+ tmpcachepath=$ppdmgrtmpdir/tmpcachepath
+
+ # if this is a system repository, check for a prepopulated cache
+ if [[ "${2}" = "${SYSTEM}" && -e ${FOOCACHEDIR}/${3}.cache ]] ; then
+ # copy prepopulated cache
+ /bin/cp -f ${FOOCACHEDIR}/${3}.cache ${tmpcachepath}
+
+ else
+ newfileslist=$(changes_under_label "${dstlabelpath}" \
+ "${varlabelcachepath}")
+ if [[ $? -eq 0 ]] ; then
+ err_files=$(generate_label_cache_file \
+ "${newfileslist}" "${varlabelcachepath}" \
+ "${dstlabelpath}" "${tmpcachepath}")
+ if [[ $? -ne 0 ]] ; then
+ #
+ # At least one PPD file was invalid.
+ # Don't return yet, as the cache info
+ # for the valid PPD files can still be
+ # used to generate a cache file.
+ #
+ echo "${err_files}"
+ ulc_rc=1
+ fi
+ fi
+ fi
+
+ if [[ -e "${tmpcachepath}" ]] ; then
+ update_current_cache_file \
+ "${varlabelcachepath}" "${tmpcachepath}" "${2}"
+ /bin/rm -f "${tmpcachepath}" >/dev/null 2>&1
+ fi
+ else
+ #
+ # If there is a cache file in /var/lp/ppd/caches associated
+ # with the label which no longer exists, remove it.
+ #
+ /bin/rm -f "${varlabelcachepath}" >/dev/null 2>&1
+ fi
+ return ${ulc_rc}
+}
+
+#
+# Returns the alias for the specified real manufacturer's name.
+#
+# $1 - Real manufacturer's name
+# $2 - File containing list of files that have manufacturers aliases
+#
+manuf_name_alias()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ #
+ # Found a couple of PPD files which had special characters
+ # in the Manufacturer name (i.e, the following is the Manufacturer
+ # entry:
+ # *Manufacturer: "Canon Inc. (Kosugi Offic"
+ # We'll only search the alias file for "Canon Inc."
+ #
+ tmpmanuf="${1% *\(*}"
+
+ # Search alias files for a match on the real manufacturer name
+ if [[ -s "${2}" ]] ; then
+ #
+ # Check the manufacturer aliases file for case
+ # insensitive match of the Manufacturer entry
+ # from the PPD file. If a match is found,
+ # then modify the manufacturer entry to
+ # be that of the specified alias.
+ #
+ manufaliases=$(/bin/egrep -i \
+ "^${tmpmanuf}:|:${tmpmanuf}:|:${tmpmanuf}$" "${2}")
+ if [[ -n "${manufaliases}" ]] ; then
+ echo "${manufaliases%%:*}"
+ break
+ else
+ echo "${tmpmanuf}"
+ fi
+ else
+ echo "${tmpmanuf}"
+ fi
+}
+
+#
+# Returns 0 if the extension to the specified PPD file is a known
+# extension, otherwise returns 1.
+#
+# $1 - Full path to PPD file
+#
+# Set upon return:
+# ppdfileext - PPD file ext (.ppd or .ppd.gz)
+#
+verify_file_ext()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ if [[ "${1%.gz}".gz = "${1}" ]] ; then
+ ppdfileext=${GEXT}
+ elif [[ "${1%.ppd}".ppd = "${1}" ]] ; then
+ ppdfileext=${PEXT}
+ else
+ # invalid PPD file name extension
+ return 1
+ fi
+
+ return 0
+}
+
+#
+# Return the lines from the specified PPD file matching the specified
+# spec items.
+#
+# $1 - spec entries from PPD file
+# $2 - spec item
+#
+# $1 example - 1 string with substrings separated by newline:
+# *PPD-Adobe: "4.3"
+# *Manufacturer: "HP"
+# *Product: "(officejet 4200 series)"
+# *ModelName: "HP OfficeJet 4200"
+# *NickName: "HP OfficeJet 4200 Foomatic/hpijs (recommended)"
+# $2 example:
+# ^\*Manufacturer
+#
+spec_entry()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ item=$(echo "${1}" | /bin/grep ${2})
+ # Remove everything up to and including the first quote
+ item=${item#*\"}
+ # Remove the end quote
+ echo "${item%\"}"
+}
+
+#
+# Return the lines from the specified PPD file matching the specified
+# spec items.
+#
+# Note: this is similar to spec_entry() except the tokens in the
+# spec entry are different.
+#
+# $1 - spec entries from PPD file
+# $2 - spec item
+#
+devid_spec_entry()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ item=$(echo "${1}" | /bin/grep ${2})
+ # Remove everything up to and including the first semi-colon
+ item=${item#*\:}
+ # Remove the end quote
+ echo ${item%\;}
+
+}
+
+#
+# Verifies that the specified PPD file
+# - has a valid extension
+# - has the following required spec file entries:
+# *PPD-Adobe: "4.3"
+# Manufacturer
+# Product
+# ModelName
+# NickName
+#
+# In addition, the manufacture and model from the IEEE1284 device id
+# information will be gathered here, although it's not an error that
+# it isn't in the PPD file as many don't contain the IEEE1284 info.
+#
+# $1 - Full path to PPD file
+#
+# Return codes:
+# 0 success
+# 1 invalid PPD file
+#
+verify_ppd_file()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ ADOBESPEC="PPD-Adobe"
+ MANUF="Manufacturer"
+ PRODUCT="Product"
+ MODEL="ModelName"
+ NICKNAME="NickName"
+ DEVID="1284DeviceID"
+
+ # Verify the PPD file extension
+ verify_file_ext "${1}" || return 1
+
+ # Query for the required spec items
+ searchentries="^\*${ADOBESPEC}:|^\*${MANUF}:|^\*${PRODUCT}:"
+ searchentries="${searchentries}|^\*${MODEL}:|^\*${NICKNAME}:"
+ searchentries="${searchentries}|^\*${DEVID}:"
+ ppd_info="$(/bin/gzgrep -e "${searchentries}" "${1}")"
+
+ #
+ # Process the query results to verify each of the required spec
+ # file items appears in the PPD file.
+ #
+ for spec_item in ${ADOBESPEC} ${MANUF} ${PRODUCT} ${MODEL} \
+ ${NICKNAME} ; do
+ entry=$(spec_entry "${ppd_info}" "^\*${spec_item}:")
+ [[ ! -z "${entry}" ]] || return 1
+ case ${spec_item} in
+ ${MANUF})
+ realmanuf="${entry}"
+ ;;
+ ${PRODUCT})
+ product="${entry}"
+ ;;
+ ${MODEL})
+ model="${entry}"
+ ;;
+ ${NICKNAME})
+ #
+ # Remove the model and any commas and spaces
+ # which appear before the driver
+ #
+ nickn="${entry#$model[, ]*}"
+ ;;
+ esac
+
+ done
+
+ # Save IEEE1284 device id information
+ if $(echo "${ppd_info}" | grep "${DEVID}" >/dev/null 2>&1) ; then
+ DMDL="MDL"
+ DMFG="MFG"
+ devid="$(/bin/gzgrep -e "^[ ]*${DMDL}:|^[ ]*${DMFG}:" "${1}")"
+ devidmdl="$(devid_spec_entry "${devid}" "${DMDL}")"
+ devidmfg="$(devid_spec_entry "${devid}" "${DMFG}")"
+ else
+ devidmdl=
+ devidmfg=
+ fi
+ modmanuf=$(manuf_name_alias "${realmanuf}" ${aliasfile})
+
+ return 0
+}
+
+#
+# generate_cache_file_entry()
+#
+# Returns a cache file entry for the specified PPD file.
+#
+# $1 - modmanuf
+# $2 - model
+# $3 - nickn
+# $4 - devidmfg
+# $5 - devidmdl
+# $6 - Full path to the specified PPD file
+#
+generate_cache_file_entry()
+{
+ if debugger "generate_cache_file_entry" ; then
+ set -x
+ fi
+
+ echo "${1}":"${2}":"${3}":"${4}":"${5}":"${6}"
+}
+
+#
+# Expand specified file to the full path.
+#
+# $1 - File path to expand
+#
+# Return code set to 0 if expanded successfully, otherwise set to 1.
+#
+ppd_pathname()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ if [[ -f "${1}" && -s "${1}" ]] ; then
+ (cd "$(/bin/dirname "${1}")" ; \
+ echo "$(/bin/pwd)/$(/bin/basename "${1}")") || return 1
+ return 0
+ else
+ return 1
+ fi
+}
+
+#
+# Returns the PPD repsitory path associated with the specified
+# PPD repository name.
+#
+# $1 - Repository name
+#
+get_rep_path()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ case ${1} in
+ ${SYSTEM})
+ echo "${SYSTEMREP}"
+ ;;
+ ${VENDOR})
+ echo "${VENDORREP}"
+ ;;
+ ${ADMIN})
+ echo "${ADMINREP}"
+ ;;
+ ${USER})
+ echo "${USERREP}"
+ ;;
+ *)
+ echo "${UNSET}"
+ ;;
+ esac
+}
+
+#
+# Returns the PPD respository name from the repository path
+#
+# $1 - PPD repository path
+#
+get_rep_name()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ case ${1} in
+ ${SYSTEMREP})
+ echo "${SYSTEM}"
+ ;;
+ ${VENDORREP})
+ echo "${VENDOR}"
+ ;;
+ ${ADMINREP})
+ echo "${ADMIN}"
+ ;;
+ ${USERREP})
+ echo "${USER}"
+ ;;
+ "all")
+ echo "all"
+ ;;
+ *)
+ echo "${UNSET}"
+ ;;
+ esac
+}
+
+#
+# Returns 0 if a matching label name is found in the specified repository,
+# otherwise returns 1.
+#
+# $1 - repository path
+# $2 - label name
+#
+label_path_in_repository()
+{
+ if debugger "label_path_in_repository" ; then
+ set -x
+ fi
+
+ [[ "${1}" != "" && "${2}" != "" ]] || return 1
+ lpir_rc=1
+ for repository in ${REPOSITORIES} ; do
+ if [[ "${repository}" = "${1}" && -d "${1}/${2}" ]] ; then
+ lpir_rc=0
+ break
+ fi
+ done
+ return ${lpir_rc}
+}
+
+#
+# Returns 0 if the source label path is the same
+# as the destination label path, otherwise returns 1.
+#
+# $1 - full path to source PPD file (source label path)
+# $2 - destination repository path
+# $3 - destination label name
+#
+label_path_match()
+{
+ if debugger "label_path_match" ; then
+ set -x
+ fi
+
+ # dest repository not specified
+ if [[ "${2}" = "${UNSET}" ]] ; then
+ # dest label not specified
+ if [[ "${3}" = "${UNSET}" ]] ; then
+ #
+ # We've found a match if the label path is in a known
+ # repository.
+ #
+ lpath="${1%/*/*}"
+ label_path_in_repository \
+ "${1%/*/*/*}" "${lpath##*/}" || return 1
+ else
+ #
+ # If the source label path exists in the
+ # in a known repository, and the destination
+ # label is the same as the source label,
+ # then we'll assume the default destination
+ # repository is the same as the source
+ # destination repository.
+ #
+ [[ "${1%/*/*}" = "${1%/*/*/*}/${3}" ]] || return 1
+ label_path_in_repository "${1%/*/*/*}" "${3}" || \
+ return 1
+ fi
+
+ # dest repository specified, dest label not specified
+ elif [[ "${3}" = "${UNSET}" ]] ; then
+ #
+ # If the destination repository path is the same as the
+ # source repository, and if the source label exists in the
+ # destination repository path, then we'll assume the default
+ # destination label is the same as the source label.
+ #
+ [[ "${2}" = "${1%/*/*/*}" ]] || return 1
+ lpath="${1%/*/*}"
+ label_path_in_repository "${2}" "${lpath##*/}" || return 1
+
+ # dest repository and dest label specified.
+ else
+ #
+ # We've found a match if the destination and label
+ # match those of the source label path, and the source
+ # label path is in a known repository.
+ #
+ [[ "${1%/*/*}" = "${2}/${3}" ]] || return 1
+ label_path_in_repository "${2}" "${3}" || return 1
+ fi
+ return 0
+}
+
+#
+# Returns 0 if specified label name is a reserved label, otherwise
+# returns 1.
+#
+# $1 - label name
+#
+reserved_label()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ rl_rc=1
+ for labelname in ${RESERVEDLABELS} ; do
+ if [[ "${1}" = "${labelname}" ]] ; then
+ rl_rc=0
+ break
+ fi
+ done
+ return ${rl_rc}
+}
+
+#
+# Returns a list of all labels that exist in a repository that are
+# not reserved labels.
+#
+# $1 - Full path of repository
+# $2 - Repository name
+#
+get_rep_label_list()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ #
+ # Get a list of all labels that exist in all of the
+ # PPD file repository.
+ #
+ for lname in $(/bin/ls "${1}" 2>/dev/null) ; do
+ if [[ -d "${1}/${lname}" ]] ; then
+ if ! reserved_label "${lname}" ; then
+ echo "${lname} "
+ fi
+ fi
+ done
+}
+
+#
+# Returns a valid PPD label.
+#
+# Verifies the specified PPD label is a valid label. If the
+# label is not set, then it is set to a default value.
+#
+# Return code set to 0 if the specified PPD label is valid, otherwise 1.
+#
+# $1 - PPD label
+#
+valid_specified_label()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ # Verify the specified label
+ vsl_rc=0
+ case "${1}" in
+ "all")
+ # Reserved label name with -a or -g options
+ if [[ "${action}" = "${ADD}" || \
+ "${action}" = "${GENERATEENTRY}" ]] ; then
+ print -n "$myprog: " 1>&2
+ gettext "reserved PPD label name: ${1}\n" 1>&2
+ vsl_rc=1
+ else
+ echo "${1}"
+ fi
+ ;;
+
+ "ppdcache" | "caches" | "manufaliases")
+ # Reserved label names with any option
+ print -n "$myprog: " 1>&2
+ gettext "reserved PPD label name: ${1}\n" 1>&2
+ vsl_rc=1
+ ;;
+
+ "" | "${UNSET}")
+ # Label name not specified. Set the default label name.
+ # For -g and -a, default is "user", otherwise, default
+ # is "all".
+ if [[ "${action}" = "${ADD}" || \
+ "${action}" = "${GENERATEENTRY}" ]] ; then
+ echo "${USER}"
+ else
+ echo "all"
+ fi
+ ;;
+
+ *)
+ # label cannot be "." or ".."
+ if [[ "${1}" = "." || "${1}" = ".." ]] ; then
+ print -n "$myprog: " 1>&2
+ gettext "PPD label name cannot be " 1>&2
+ gettext "\".\" or \"..\"\n" 1>&2
+ vsl_rc=1
+ fi
+
+ # Label name cannot contain special characters
+ echo "${1}" | /bin/egrep "${SPECIALCHARS}" >/dev/null
+ if [[ $? -eq 0 ]] ; then
+ print -n "$myprog: " 1>&2
+ gettext "PPD label name contains " 1>&2
+ gettext "an invalid character: ${1}\n" 1>&2
+ vsl_rc=1
+ else
+ echo "${1}"
+ fi
+ ;;
+ esac
+ return ${vsl_rc}
+}
+
+#
+# Returns the full path of any variant copy of the source file in
+# the destination label/repository.
+#
+# $1 - Full path to source PPD file
+# $2 - Full path to destination PPD file
+#
+# Return code set to
+# 0 - Copy doesn't exist
+# 1 - Duplicate copy exists
+# 2 - Variant copy exists
+#
+variant_copy()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ #
+ # First make sure there is not a .ppd and a .ppd.gz version
+ # of the destination file; users should know not to do this.
+ #
+ if [[ -e "${2%.gz}" && -e "${2%.gz}.gz" ]] ; then
+ /bin/rm -f "${2%.gz}" >/dev/null 2>&1
+ fi
+
+ # Use gzcmp to compare PPD files as it can deal with
+ # gzipped or regular files.
+ if $(${GZCMP} "${1}" "${2}"* >/dev/null 2>&1) ; then
+ echo "${2}"*
+ return 1
+ elif [[ -e "${2%.gz}" ]] ; then
+ echo "${2%.gz}"
+ return 2
+ elif [[ -e "${2%.gz}.gz" ]] ; then
+ echo "${2%.gz}.gz"
+ return 2
+ else
+ #
+ # A PPD file doesn't exist in the destination
+ # repository under the destination label.
+ # Just display the source PPD file, ensuring
+ # it has a gzip extension as we will always
+ # try to gzip the copy in the destination.
+ #
+ if [[ "${1#*.ppd}" = ".gz" ]] ; then
+ echo "${2}"
+ else
+ echo "${2}.gz"
+ fi
+ return 0
+ fi
+}
+
+#
+# $1 - Directory mode
+# $2 - Directory owner (i.e., root:lp)
+# $3 - Directory to create
+#
+make_dir()
+{
+ if debugger "make_dir" ; then
+ set -x
+ fi
+
+ [[ ! -d "${3}" ]] || return 0
+ /bin/mkdir "${3}" >/dev/null 2>&1 || return 1
+ set_perms ${1} ${2} "${3}"
+ return 0
+}
+
+#
+# Remove a ppdmgr generated cache (in /var/lp/ppd/cache)
+# if it doesn't have an associated label in the repository.
+#
+# $1 - Full path to label
+# $2 - Cache name
+#
+remove_unassociated_cache()
+{
+ if debugger "remove_unassociated_cache" ; then
+ set -x
+ fi
+
+ if [[ "${1}" != "${UNSET}" ]] ; then
+ if [[ -n "${1}" && ! -d "${1}" ]] ; then
+ #
+ # The label doesn't exist, so delete
+ # the associated cache file.
+ #
+ /bin/rm -f "${VARCACHES}/${2}" >/dev/null 2>&1
+ fi
+ fi
+}
+
+#
+# Sorted copies of cache files for each label in each PPD repository
+# are maintained in /var/lp/ppd/caches/<PPD respository>-<label>.
+# This is done so that changes in delivered cache files can be
+# detected. If a difference in cache files is detected, or a
+# cache file is either added or removed, then we know that
+# the ppdcache file needs to be updated.
+#
+# Get a list of all cache files and compare against the list
+# of labels in all of the PPD file repositories. They should
+# be the same. If there is a label in one of the PPD file
+# repositories that doesn't have an associated cache file, then
+# we don't worry about it now, as that will be resolved when
+# we update the cache for that label. However, if there is
+# a cache file associated with a label that no longer exists, then
+# remove the cache file.
+#
+# $1 - Full path to repository (or "all")
+# $2 - Label name
+#
+update_cache()
+{
+ if debugger ; then
+ set -x
+ fi
+
+ #
+ # Determine which labels in which PPD repository the
+ # cache file will be updated for.
+ #
+ if [[ "${1}" = "all" ]] ; then
+ rname="${REPOSITORIES}"
+ else
+ rname="${1}"
+ fi
+
+ uc_rc=0
+ for dstreppath in ${rname} ; do
+ labellist=
+ if [[ "${2}" = "all" ]] ; then
+ dstrepname=$(get_rep_name "${dstreppath}")
+ labellist=$(get_rep_label_list "${dstreppath}" \
+ "${dstrepname}")
+ else
+
+ # Ensure the label exists in the PPD file repository.
+ if [[ -d "${dstreppath}/${2}" ]] ; then
+ labellist="${2}"
+ fi
+ fi
+
+ #
+ # Update the cache for each label in the PPD repository
+ #
+ for dstlabel in ${labellist} ; do
+ ulc_msg=$(update_label_cache "${dstreppath}" \
+ "${dstrepname}" "${dstlabel}")
+ if [[ $? -ne 0 ]] ; then
+ echo "${ulc_msg}"
+ uc_rc=1
+ fi
+ done
+ done
+
+ # Update the golden cache file.
+ update_golden_cache
+ return ${uc_rc}
+}
+
+# $1 - exit status
+ppdmgr_exit()
+{
+ if debugger "ppdmgr_exit" ; then
+ set -x
+ fi
+
+ /bin/rm -rf "${ppdmgrtmpdir}" >/dev/null 2>&1
+ exit ${1}
+}
+
+
+usage()
+{
+ gettext "usage:\n" 1>&2
+ print -n "\t$myprog: " 1>&2
+ gettext "-a <ppd_filename_path> [ -L <label> ]\n" 1>&2
+ gettext "\t\t[ -R <ppd_repository> ] [-w]\n" 1>&2
+ print -n "\t$myprog: " 1>&2
+ gettext "-r [ -L <label> ] [ -R <ppd_repository> ]\n" 1>&2
+ print -n "\t$myprog: " 1>&2
+ gettext "-u [ -L <label> ] [ -R <ppd_repository> ]\n" 1>&2
+
+ ppdmgr_exit ${FAIL}
+}
+
+##########################################################################
+# main
+##########################################################################
+
+myprog=$(/bin/basename $0)
+
+SaveIFS="$IFS"
+NoSpaceTabIFS='
+'
+
+# Updatable PPD repository
+VARDIR=/var/lp/ppd
+
+# Delivered PPD respository
+SYSTEMREP=/usr/share/ppd
+ADMINREP=/usr/local/share/ppd
+VENDORREP=/opt/share/ppd
+USERREP=${VARDIR}
+
+RESERVEDREPS="${SYSTEMREP} ${ADMINREP} ${VENDORREP}"
+REPOSITORIES="${USERREP} ${RESERVEDREPS}"
+RESERVEDLABELS="all caches ppdcache manufaliases"
+
+# Directory where system:SUNWfoomatic is delivered
+FOOCACHEDIR=/usr/lib/lp/caches
+
+# Deliveries
+SYSTEM=system
+VENDOR=vendor
+ADMIN=admin
+USER=user
+
+# Sytem PPD cache name used by printmgr
+GOLDCACHE=${USERREP}/ppdcache
+
+# Delivered caches directory
+CACHES=caches
+MANUFALIASES=manufaliases
+
+# Updated caches directory
+VARCACHES=${VARDIR}/${CACHES}
+
+# valid PPD file name extensions
+PEXT=ppd
+GEXT=gz
+FILEEXTS=".${PEXT} .${PEXT}.${GEXT}"
+
+# Default modes and owners
+DIRMODE=755
+DIROWNER=root:lp
+ADMINOWNER=root:root
+FILEMODE=444
+FILEOWNER=root:lp
+
+# ppdmgr actions
+ADD=add
+GENERATEENTRY=generateentry
+UPDATE=update
+REBUILD=rebuild
+
+SUCCESS=0
+FAIL=1
+WARN=2
+
+MAXLABELNAME=256
+GZIP="/bin/gzip -c"
+GZCMP="/bin/gzcmp -s"
+CMP="/bin/cmp -s"
+SPECIALCHARS=":"
+SEP=":"
+
+debug=0
+wflag=0
+status=${SUCCESS}
+
+UNSET=" "
+ppdlabel=${UNSET}
+ppdrepname=${UNSET}
+ppdreppath=${UNSET}
+modmanuf=
+model=
+nickn=
+devidmdl=
+devidmfg=
+
+ppdmgrtmpdir=$(/usr/bin/mktemp -t -d ppdmgr.XXXXXX)
+if [ -z "$ppdmgrtmpdir" ] ; then
+ print -n "$myprog: " 1>&2
+ gettext "Fatal error: could not create temporary directory\n" 1>&2
+ exit 1
+fi
+
+aliasfile=${USERREP}/manufaliases
+tmpfilepath=
+
+
+OPTS=a:g:L:rR:uwZ
+while getopts "$OPTS" arg ; do
+ case ${arg} in
+ a) # add PPD file
+ action=${ADD}
+ origsrcppdpath=${OPTARG}
+ ;;
+
+ g) # create cache entry
+ action=${GENERATEENTRY}
+ origsrcppdpath=${OPTARG}
+ ;;
+
+ L) # PPD label name
+ ppdlabel=${OPTARG}
+ ;;
+
+ r) # rebuild cache
+ action=${REBUILD}
+ ;;
+
+ R) # PPD file repository to use
+ ppdrepname=${OPTARG}
+ ;;
+
+ u) # update cache
+ action=${UPDATE}
+ ;;
+
+ w) # display PPD file path
+ wflag=1
+ ;;
+
+ Z) # debug
+ debug=1
+ ;;
+
+ ?)
+ usage
+ ;;
+ esac
+done
+
+if debugger "Main" ; then
+ set -x
+fi
+
+if [[ $# -lt 1 || -z "${action}" ]] ; then
+ usage
+fi
+
+# ignore wflag unless specified with -a
+if [[ ${wflag} -eq 1 && "${action}" != ${ADD} ]] ; then
+ wflag=0
+fi
+
+#
+# Ensure the destination PPD repository directory is set
+# to match the specified repository. If the
+# destination PPD file repository was specified, then
+# it must be one of the following:
+# "user"
+# "admin"
+# "vendor"
+# "system"
+# "all"
+#
+case "${ppdrepname}" in
+"${SYSTEM}")
+ ppdreppath="${SYSTEMREP}"
+ ;;
+"${ADMIN}")
+ ppdreppath="${ADMINREP}"
+ ;;
+"${VENDOR}")
+ ppdreppath="${VENDORREP}"
+ ;;
+"${USER}")
+ ppdreppath="${USERREP}"
+ ;;
+"all")
+ if [[ "${action}" = "${ADD}" || \
+ "${action}" = "${GENERATEENTRY}" ]] ; then
+ print -n "$myprog: " 1>&2
+ gettext "reserved PPD repository name: " 1>&2
+ gettext "${ppdrepname}\n" 1>&2
+ ppdmgr_exit ${FAIL}
+ fi
+ ppdreppath="all"
+ ;;
+"${UNSET}"|"")
+ ppdreppath="${UNSET}"
+ ;;
+
+*)
+ print -n "$myprog: " 1>&2
+ gettext "invalid PPD repository name: ${ppdrepname}\n" 1>&2
+ ppdmgr_exit ${FAIL}
+ ;;
+esac
+
+#
+# When a source PPD file's path is from a known repository, the
+# destination repository and desination label are assumed to be the
+# same as the source PPD file's unless a differing repository or label
+# was specified.
+#
+if [[ "${action}" = "${ADD}" || "${action}" = "${GENERATEENTRY}" ]] ; then
+
+ srcppdpath=$(ppd_pathname "${origsrcppdpath}")
+ ppd_pathname_rc=$?
+ if [[ ${ppd_pathname_rc} -ne 0 ]] ; then
+ print -n "$myprog: " 1>&2
+ gettext "invalid PPD file: ${origsrcppdpath}\n" 1>&2
+ ppdmgr_exit ${ppd_pathname_rc}
+ fi
+
+ # Path cannot contain special characters
+ echo "${srcppdpath}" | /bin/egrep "${SPECIALCHARS}" >/dev/null
+ if [[ $? -eq 0 ]] ; then
+ print -n "$myprog: " 1>&2
+ gettext "PPD path contains " 1>&2
+ gettext "an invalid character: ${ppd_pathname}\n" 1>&2
+ ppdmgr_exit ${FAIL}
+ fi
+ ppdfname=$(/bin/basename "${origsrcppdpath}")
+
+ #
+ # Check to see if there's any work to be done. If the source file
+ # is already in the destination repository under the destination
+ # label, then there's nothing left to do. We exit rather than
+ # going on to do an update on the label in the repository as
+ # it could possible take a long time to update. If an add was
+ # requested, it could have come from an application, so we want
+ # to return quickly.
+ #
+ if label_path_match "${srcppdpath}" "${ppdreppath}" "${ppdlabel}" ; then
+ if [[ ${wflag} -eq 1 || \
+ "${action}" = "${GENERATEENTRY}" ]] ; then
+ echo "${srcppdpath}"
+ fi
+ ppdmgr_exit ${SUCCESS}
+ fi
+fi
+
+ppdlabel=$(valid_specified_label "${ppdlabel}")
+if [[ $? -ne 0 ]] ; then
+ ppdmgr_exit ${FAIL}
+fi
+
+if [[ "${ppdreppath}" = "${UNSET}" ]] ; then
+ ppdreppath="${USERREP}"
+fi
+
+dstrepname=$(get_rep_name "${ppdreppath}")
+
+case "${action}" in
+"${ADD}")
+ #
+ # Attempt to add the PPD file to the repository under the
+ # specified label. If any errors occur, final_dst_ppd_path
+ # will contain the error message rather than the path to the
+ # PPD file.
+ #
+ final_dst_ppd_path=$(add_ppd "${srcppdpath}" "${ppdfname}" \
+ "${ppdreppath}" "${dstrepname}" "${ppdlabel}")
+ add_ppd_rc=$?
+ case ${add_ppd_rc} in
+ 0) #
+ # The PPD file was added. Update the specified
+ # cache associated with the label if the PPD file
+ # was added successfully and was not a duplicate.
+ # Ensure any changes are also reflected in the
+ # golden cache.
+ #
+ add_ppd_msg=$(update_label_cache "${ppdreppath}" \
+ "${dstrepname}" "${ppdlabel}")
+ apm_rc=$?
+
+ echo "${add_ppd_msg}" | /bin/grep "${final_dst_ppd_path}"
+ path_in_msg=$?
+
+ #
+ # Only report cache update errors if the file that was
+ # added was one that was reported as not being added
+ # to the cache. This really should happen as the file
+ # was verified during the add.
+ #
+ if [[ ${apm_rc} -ne 0 && ${path_in_msg} -eq 0 ]] ; then
+ print -n "$myprog: " 1>&2
+ gettext "printer information does not reflect " 1>&2
+ gettext "the\nfollowing PPD file(s):\n" 1>&2
+ print "${add_ppd_msg}" 1>&2
+ status=${FAIL}
+ else
+ update_golden_cache
+
+ #
+ # Display the full path to the added PPD file,
+ # if requested (-w).
+ #
+ if [[ ${wflag} -eq 1 ]] ; then
+ print "${final_dst_ppd_path}"
+ fi
+ fi
+ ;;
+
+ 1) # Duplicate copy exists
+ if [[ ${wflag} -eq 1 ]] ; then
+ print "${final_dst_ppd_path}"
+ fi
+ ;;
+
+ 2) # Varying copy exists
+ print -n "$myprog: " 1>&2
+ gettext "differing variant of source PPD file " 1>&2
+ gettext "already exists at\n" 1>&2
+ gettext "${final_dst_ppd_path}\n" 1>&2
+ status=${FAIL}
+ ;;
+ *) # The PPD file was not added as a problem occurred.
+ # Display the error message.
+ print -n "$myprog: " 1>&2
+ print "${final_dst_ppd_path}" 1>&2
+ status=${FAIL}
+ ;;
+
+ esac
+ ;;
+
+"${GENERATEENTRY}")
+ #
+ # Create a cache file entry for the specified PPD file and
+ # display it on standard out.
+ #
+ verify_ppd_file "${srcppdpath}"
+ if [[ $? -eq 0 ]] ; then
+ dstdir="${ppdreppath}/${ppdlabel}/${modmanuf}"
+ final_dst_path="${dstdir}/$(/bin/basename ${srcppdpath})"
+ verify_ppd_location "${final_dst_path}"
+ if [[ $? -eq 0 ]] ; then
+ # Generate the cache file entry
+ print "$(generate_cache_file_entry "${modmanuf}" \
+ "${model}" "${nickn}" "${devidmfg}" "${devidmdl}" \
+ "${final_dst_path}")"
+ else
+ print -n "$myprog: " 1>&2
+ gettext "PPD file not in valid location\n" 1>&2
+ gettext \
+ "(<repository>/<label>/<manufacturer>/<PPD file>):\n\t${1}\n" 1>&2
+ status=${FAIL}
+ fi
+
+ else
+ print -n "$myprog: " 1>&2
+ gettext "invalid PPD file: ${1}\n" 1>&2
+ status=${FAIL}
+ fi
+ ;;
+
+"${REBUILD}" | "${UPDATE}")
+ update_msg=$(update_cache "${ppdreppath}" "${ppdlabel}")
+ if [[ $? -ne 0 ]] ; then
+ print -n "$myprog: " 1>&2
+ gettext "printer information does not reflect " 1>&2
+ gettext "the\nfollowing PPD file(s):\n" 1>&2
+ print "${update_msg}" 1>&2
+ status=${WARN}
+ fi
+ ;;
+
+*)
+ usage
+ ;;
+esac
+
+ppdmgr_exit ${status}
diff --git a/usr/src/cmd/print/scripts/printers.conf b/usr/src/cmd/print/scripts/printers.conf
new file mode 100644
index 0000000000..69327e9915
--- /dev/null
+++ b/usr/src/cmd/print/scripts/printers.conf
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 1996 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+#
+# If you hand edit this file, comments and structure may change.
+# The prefered method of modifying this file is though the use of
+# lpset(1M) or lpadmin(1M)
+#
diff --git a/usr/src/cmd/print/selector/Makefile b/usr/src/cmd/print/selector/Makefile
new file mode 100644
index 0000000000..9cd5704869
--- /dev/null
+++ b/usr/src/cmd/print/selector/Makefile
@@ -0,0 +1,54 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../../Makefile.cmd
+
+SBINPROG = print-service
+BINPROG = desktop-print-management-applet
+LPBINLINKS = lp lpstat cancel enable disable
+LPRBINLINKS = lpr lpq lprm lpc
+DESKTOPLINKS = desktop-print-management desktop-print-management-prefs
+BINLINKS = $(LPBINLINKS) $(LPRBINLINKS) $(DESKTOPLINKS)
+SBINLINKS = accept reject lpmove lpadmin
+
+ROOTUSRSBINPROG = $(SBINPROG:%=$(ROOTUSRSBIN)/%)
+ROOTUSRBINPROG = $(BINPROG:%=$(ROOTBIN)/%)
+ROOTUSRBINLINKS = $(BINLINKS:%=$(ROOTBIN)/%)
+ROOTUSRSBINLINKS = $(SBINLINKS:%=$(ROOTUSRSBIN)/%)
+
+FILEMODE = 0555
+
+$(ROOTUSRBINLINKS):
+ $(RM) $@; $(SYMLINK) ../sbin/$(SBINPROG) $@
+
+$(ROOTUSRSBINLINKS):
+ $(RM) $@; $(SYMLINK) $(SBINPROG) $@
+
+.KEEP_STATE:
+
+all check clean clobber lint:
+
+install: $(ROOTUSRSBINPROG) $(ROOTUSRBINPROG) $(ROOTUSRBINLINKS) $(ROOTUSRSBINLINKS)
+
diff --git a/usr/src/cmd/print/selector/desktop-print-management-applet b/usr/src/cmd/print/selector/desktop-print-management-applet
new file mode 100755
index 0000000000..88dd74799d
--- /dev/null
+++ b/usr/src/cmd/print/selector/desktop-print-management-applet
@@ -0,0 +1,90 @@
+#!/usr/perl5/bin/perl
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+use Errno qw(EINTR :POSIX);
+
+my $SVC_CUPS_SCHEDULER = 'cups/scheduler';
+my $SVCPROP = '/usr/bin/svcprop';
+my $reexec = 0;
+
+sub svcprop {
+ local ($fmri, $property) = @_;
+ my $FH;
+
+ open($FH, "$SVCPROP -C -p $property $fmri 2>/dev/null |");
+ $result = <$FH>;
+ close($FH);
+
+ return ($result);
+}
+
+sub print_service {
+ my $service;
+
+ $service = svcprop("$SVC_CUPS_SCHEDULER:default", "general/active");
+ ($service =~ /true/) && ($service = 'cups') || ($service = 'lp');
+
+ return ($service);
+}
+
+sub kill_running_applets {
+ $reexec = 1;
+ # cups applet daemon
+ system("pkill -f '/system-config-printer/applet.py'");
+ # lp applet daemon
+ system("pkill ospm-applet");
+}
+
+sub handle_signal {
+ kill_running_applets ();
+}
+
+$SIG{USR1} = \&handle_signal;
+
+my $pid = fork();
+if (! defined($pid)) {
+ die "Error: fork() failed\n";
+}
+elsif ($pid == 0) {
+ my $service = print_service();
+ if ($service eq 'lp') {
+ exec('/usr/lib/lp/bin/desktop-print-management-applet');
+ }
+ else {
+ exec('/usr/lib/cups/bin/desktop-print-management-applet');
+ }
+
+}
+else {
+ my $retid;
+ while ((($retid = waitpid($pid, 0)) < 0) && $!{EINTR}) {
+ }
+
+ if ($retid == $pid && $reexec) {
+ exec('/usr/bin/desktop-print-management-applet');
+ }
+}
+
+exit(0);
diff --git a/usr/src/cmd/print/selector/print-service b/usr/src/cmd/print/selector/print-service
new file mode 100755
index 0000000000..7f90256aac
--- /dev/null
+++ b/usr/src/cmd/print/selector/print-service
@@ -0,0 +1,298 @@
+#!/usr/perl5/bin/perl
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+#
+# This program manages the "active" print service selection.
+# If called as 'print-service', it takes one of four options.
+# Options:
+# [-s[et] service [-m]] Select the "active" print service, optionally
+# migrating basic print queue configuration.
+# [-q[uery]] Display the "active" print service.
+# [-e[xport] file] Export basic print queue configuration to
+# a file.
+# [-i[mport] file] Import basic print queue configuration from
+# a file.
+#
+# If called by any other name, it will look for a corresponding command
+# under /usr/lib/{active-service}/bin/{command} and execute that program
+# with the original arguments.
+#
+
+use Getopt::Long;
+use File::Basename;
+use File::Copy;
+use File::Temp qw/ :POSIX /;
+
+my $cmd = basename($0);
+
+my $LPSTAT = '/usr/bin/lpstat';
+my $LPADMIN = '/usr/sbin/lpadmin';
+my $ENABLE = '/usr/bin/enable';
+my $ACCEPT = '/usr/sbin/accept';
+my $SVCADM = '/usr/sbin/svcadm';
+my $SVCPROP = '/usr/bin/svcprop';
+my $SVCCFG = '/usr/sbin/svccfg';
+my $SVC_LP_SCHEDULER = 'print/server';
+my $SVC_LP_LPD = 'print/rfc1179';
+my $SVC_LP_IPP = 'print/ipp-listener';
+my $SVC_LP_PPD = 'print/ppd-cache-update';
+my $SVC_CUPS_SCHEDULER = 'cups/scheduler';
+my $SVC_CUPS_LPD = 'cups/in-lpd';
+
+sub fatal {
+ ($ENV{"DESKTOP_LAUNCHED"}) &&
+ exec("/bin/zenity", "--error", "--text=@_");
+ print STDERR @_;
+ exit(1);
+}
+
+sub usage {
+ print STDERR <<EOF ;
+Usage:
+ $cmd [-s[et] service [-m]] Select the \"active\" print service,
+ optionally migrating basic print queue
+ configuration.
+ $cmd [-q[uery]] Display the "active" print service.
+ $cmd [-e[xport] file] Export basic print queue configuration
+ to a file.
+ $cmd [-i[mport] file] Import basic print queue configuration
+ from a file.
+EOF
+ exit(1);
+}
+
+sub svcprop {
+ local ($fmri, $property) = @_;
+ my $FH;
+
+ open($FH, "$SVCPROP -C -p $property $fmri 2>/dev/null |");
+ $result = <$FH>;
+ close($FH);
+
+ return ($result);
+}
+
+sub svccfg {
+ local ($fmri, $operation) = @_;
+ my $FH;
+
+ open($FH, "$SVCCFG -s $fmri \"$operation\" 2>/dev/null |");
+ $result = <$FH>;
+ close($FH);
+
+ return ($result);
+}
+
+sub svcadm {
+ local ($operation, @fmris) = @_;
+
+ system("$SVCADM $operation -s @fmris");
+}
+
+
+sub print_service {
+ my $service;
+
+ $service = svcprop("$SVC_CUPS_SCHEDULER:default", "general/active");
+ ($service =~ /true/) && ($service = 'cups') || ($service = 'lp');
+
+ return ($service);
+}
+
+sub print_command {
+ local($command, @av) = @_;
+ my $service = print_service();
+
+ if (!defined($service)) {
+ fatal("failed to detect active print service: $!\n");
+ }
+
+ if (! -d "/usr/lib/$service/bin") {
+ fatal("print service: $service is not installed\n");
+ }
+
+ my $executable = "/usr/lib/$service/bin/$command";
+ # CUPS has it's own names for enable and disable
+ ($command =~ /(en|dis)able/) && ($service eq 'cups') &&
+ (! -x $executable) &&
+ ($executable = "/usr/lib/$service/bin/$service$command");
+
+ if (! -x $executable) {
+ fatal("$command is not available from $service print service\n");
+ }
+
+ exec($executable, @ARGV);
+}
+
+sub export_print_queues {
+ local ($path) = @_;
+ my $service = print_service();
+
+ if ($service eq 'lp') {
+ my $FH, $DFH;
+
+ open($FH, ">$path");
+ open($DFH, "$LPSTAT -v|");
+ while (<$DFH>) {
+ if (/device for (.+): (.+)/) {
+ my $EFH;
+
+ print $FH "<Printer $1>\nDeviceURI $2\n";
+ open($EFH, "$LPSTAT -p $1 -l |");
+ while (<$EFH>) {
+ (/Description: (.+)/) &&
+ print $FH "Info $1\n";
+ }
+ close($EFH);
+ print $FH "</Printer>\n";
+ }
+ }
+ close($DFH);
+ close($FH);
+ } else {
+ copy('/etc/cups/printers.conf', $path);
+ }
+}
+
+sub psystem {
+ print " @_\n";
+ system(@_);
+}
+
+sub import_print_queues {
+ local ($path) = @_;
+ my $service = print_service();
+ my $FH, %printer, @options;
+
+ # store queue info in the 'active' print service
+ open($FH, "<$path");
+ while (<$FH>) {
+ if (/<Printer (.+)>/) {
+ $printer{'Printer'} = $1;
+ @options = ();
+ push(@options, "-p", $1);
+ } elsif (/([^\s]+)\s(.+)/) {
+ $printer{$1} = $2;
+ my $value = $2;
+ ($1 eq 'DeviceURI') &&
+ push(@options, "-v", $value);
+ ($1 eq 'Info') &&
+ push(@options, "-D", $value);
+ } elsif (/<\/Printer>/) {
+ ($service eq 'lp') &&
+ push(@options, "-m", "uri");
+ print "importing $printer{'Printer'}...\n";
+ # create a queue
+ psystem($LPADMIN, @options);
+ psystem($ENABLE, $printer{'Printer'});
+ ($printer{'Accepting'} eq 'Yes') &&
+ psystem($ACCEPT, $printer{'Printer'});
+ $printer = ();
+ }
+ }
+ close($FH);
+}
+
+sub select_service {
+ my ($service, $migrate) = @_;
+ my $FH, $queues;
+
+ if (! -d "/usr/lib/$service/bin") {
+ fatal("print service: $service is not installed\n");
+ }
+
+ if ($migrate == 1) {
+ # export old print queue configuration (if migrating)
+ $queues = tmpnam();
+ export_print_queues($queues);
+ }
+
+ # enable/disable the services
+ if ($service eq 'cups') {
+ (-f '/etc/printers.conf') && (! -f '/etc/lp/printers.conf') &&
+ rename('/etc/printers.conf', '/etc/lp/printers.conf');
+ print("disabling LP services...\n");
+ svcadm("disable", $SVC_LP_SCHEDULER, $SVC_LP_IPP, $SVC_LP_LPD,
+ $SVC_LP_PPD);
+ print("enabling CUPS services...\n");
+ svcadm("enable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
+ svccfg("cups/scheduler:default",
+ "setprop general/active = boolean: true");
+ system("pkill -USR1 -f '/desktop-print-management-applet'");
+ } else {
+ print("disabling CUPS services...\n");
+ svcadm("disable", $SVC_CUPS_SCHEDULER, $SVC_CUPS_LPD);
+ print("enabling LP services...\n");
+ svcadm("enable", $SVC_LP_SCHEDULER, $SVC_LP_IPP, $SVC_LP_LPD,
+ $SVC_LP_PPD);
+ (-f '/etc/lp/printers.conf') &&
+ rename('/etc/lp/printers.conf', '/etc/printers.conf');
+ svccfg("cups/scheduler:default", "delprop general/active");
+ system("pkill -USR1 -f '/desktop-print-management-applet'");
+ }
+
+ # import the new print queue configuration (if migrating)
+ defined($queues) && import_print_queues($queues);
+}
+
+sub query_service {
+ my $service = print_service();
+
+ if (!defined($service)) {
+ fatal("failed to detect active print service: $!\n");
+ }
+ print "active print service: $service\n";
+}
+
+if ($cmd eq 'print-service') {
+ my ($import_path, $export_path, $svc_name, $query, $migrate) = ();
+
+ my $res = GetOptions('q|query' => \$query, 's|set=s' => \$service,
+ 'm|migrate' => \$migrate, 'e|export=s' => \$export_path,
+ 'i|import=s' => \$import_path);
+
+ ($res) || usage();
+
+ if (defined($import_path) && !defined($export_path) &&
+ !defined($query) && !defined($service) && !defined($migrate)) {
+ import_print_queues($import_path);
+ } elsif (!defined($import_path) && defined($export_path) &&
+ !defined($query) && !defined($service) && !defined($migrate)) {
+ export_print_queues($export_path);
+ } elsif (!defined($import_path) && !defined($export_path) &&
+ defined($query) && !defined($service) && !defined($migrate)) {
+ query_service();
+ } elsif (!defined($import_path) && !defined($export_path) &&
+ !defined($query) && defined($service)) {
+ select_service($service, $migrate);
+ } else {
+ usage();
+ }
+} else {
+ print_command($cmd, @ARGV);
+}
+
+exit(0);
diff --git a/usr/src/lib/print/Makefile b/usr/src/lib/print/Makefile
new file mode 100644
index 0000000000..fd931373e8
--- /dev/null
+++ b/usr/src/lib/print/Makefile
@@ -0,0 +1,94 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+SUBDIRS = \
+ libprint \
+ libpapi-common \
+ libpapi-dynamic \
+ libpapi-lpd \
+ libipp-core \
+ libhttp-core \
+ libpapi-ipp \
+ libipp-listener \
+ mod_ipp
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+install_h := TARGET = install_h
+lint := TARGET = lint
+
+include $(SRC)/Makefile.master
+
+TEXT_DOMAIN= SUNW_OST_OSLIB
+POFILE= print-lib.po
+
+.KEEP_STATE:
+
+all: $(TXTS) $(SUBDIRS)
+
+#
+# Each message catalog file is generated in each sub
+# directory and copied to the usr/src/cmd/lp/ directory.
+# Those message catalog files are consolidated into one
+# message catalog file. The consolidated one will be copied
+# into the $(ROOT)/catalog/SUNW_OST_OSCMD/ directory.
+#
+
+_msg: $(MSGDOMAIN)
+ @$(RM) $(POFILE)
+ $(XGETTEXT) -s `/bin/find . -type d -name SCCS -prune -o -type f -name '*.c' -print`
+ @/bin/cat messages.po | sed '/domain/d' > $(POFILE)
+ @$(RM) messages.po
+ $(RM) $(MSGDOMAIN)/$(POFILE)
+ /bin/cp $(POFILE) $(MSGDOMAIN)
+
+install: $(ROOTDIRS) $(ROOTSYMLINKDIRS) $(SUBDIRS)
+
+install_h clean strip lint: $(SUBDIRS)
+
+clobber: $(SUBDIRS) local_clobber
+
+local_clobber:
+ $(RM) $(CLOBBERFILES) $(POFILE)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/Makefile.msg.targ
+
+# Dependencies
+libpapi-dynamic: libpapi-common
+libpapi-lpd: libpapi-dynamic
+libipp-core: libpapi-common
+libpapi-ipp: libpapi-common libipp-core libhttp-core
+libipp-listener: libpapi-dynamic libipp-core
+mod_ipp: libipp-listener
+
diff --git a/usr/src/lib/print/libhttp-core/Makefile b/usr/src/lib/print/libhttp-core/Makefile
new file mode 100644
index 0000000000..b92d620b10
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+#HDRS = papi.h
+#HDRDIR = common
+SUBDIRS = $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install: .WAIT $(SUBDIRS)
+
+lint: # $(SUBDIRS)
+
+install_h: # $(ROOTHDRS)
+
+check: # $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/libhttp-core/Makefile.com b/usr/src/lib/print/libhttp-core/Makefile.com
new file mode 100644
index 0000000000..cfb8ae8730
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/Makefile.com
@@ -0,0 +1,63 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libhttp-core.a
+VERS = .1
+OBJECTS = http-addr.o http-support.o http.o
+
+ROOTLIBDIR = $(ROOT)/usr/lib/print
+
+include ../../../Makefile.lib
+include ../../../Makefile.rootfs
+
+SRCDIR = ../common
+
+ROOTLIBDIR= $(ROOT)/usr/lib/print
+ROOTLIBDIR64= $(ROOT)/usr/lib/print/$(MACH)
+
+LIBS = $(DYNLIB)
+
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR)
+CPPFLAGS += -I../../libpapi-common/common
+
+MAPFILES = $(SRCDIR)/mapfile
+
+LDLIBS += -lsocket -lnsl -lc
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+$(ROOTLIBDIR):
+ $(INS.dir)
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/print/libhttp-core/common/LICENSE.txt b/usr/src/lib/print/libhttp-core/common/LICENSE.txt
new file mode 100644
index 0000000000..797ee5db95
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/LICENSE.txt
@@ -0,0 +1,964 @@
+ Common UNIX Printing System License Agreement
+
+ Copyright 1997-2006 by Easy Software Products
+ 44141 AIRPORT VIEW DR STE 204
+ HOLLYWOOD, MARYLAND 20636 USA
+
+ Voice: +1.301.373.9600
+ Email: cups-info@cups.org
+ WWW: http://www.cups.org
+
+
+INTRODUCTION
+
+The Common UNIX Printing System(tm), ("CUPS(tm)"), is provided
+under the GNU General Public License ("GPL") and GNU Library
+General Public License ("LGPL"), Version 2, with exceptions for
+Apple operating systems and the OpenSSL toolkit. A copy of the
+exceptions and licenses follow this introduction.
+
+The GNU LGPL applies to the CUPS API library, located in the
+"cups" subdirectory of the CUPS source distribution and in the
+"cups" include directory and library files in the binary
+distributions. The GNU GPL applies to the remainder of the CUPS
+distribution, including the "pdftops" filter which is based upon
+Xpdf and the CUPS imaging library.
+
+For those not familiar with the GNU GPL, the license basically
+allows you to:
+
+ - Use the CUPS software at no charge.
+ - Distribute verbatim copies of the software in source or
+ binary form.
+ - Sell verbatim copies of the software for a media fee, or
+ sell support for the software.
+ - Distribute or sell printer drivers and filters that use
+ CUPS so long as source code is made available under the
+ GPL.
+
+What this license *does not* allow you to do is make changes or
+add features to CUPS and then sell a binary distribution without
+source code. You must provide source for any new drivers,
+changes, or additions to the software, and all code must be
+provided under the GPL or LGPL as appropriate. The only
+exceptions to this are the portions of the CUPS software covered
+by the Apple operating system license exceptions outlined later
+in this license agreement.
+
+The GNU LGPL relaxes the "link-to" restriction, allowing you to
+develop applications that use the CUPS API library under other
+licenses and/or conditions as appropriate for your application.
+
+
+LICENSE EXCEPTIONS
+
+In addition, as the copyright holder of CUPS, Easy Software
+Products grants the following special exceptions:
+
+ 1. Apple Operating System Development License Exception;
+
+ a. Software that is developed by any person or entity
+ for an Apple Operating System ("Apple OS-Developed
+ Software"), including but not limited to Apple and
+ third party printer drivers, filters, and backends
+ for an Apple Operating System, that is linked to the
+ CUPS imaging library or based on any sample filters
+ or backends provided with CUPS shall not be
+ considered to be a derivative work or collective work
+ based on the CUPS program and is exempt from the
+ mandatory source code release clauses of the GNU GPL.
+ You may therefore distribute linked combinations of
+ the CUPS imaging library with Apple OS-Developed
+ Software without releasing the source code of the
+ Apple OS-Developed Software. You may also use sample
+ filters and backends provided with CUPS to develop
+ Apple OS-Developed Software without releasing the
+ source code of the Apple OS-Developed Software.
+
+ b. An Apple Operating System means any operating system
+ software developed and/or marketed by Apple Computer,
+ Inc., including but not limited to all existing
+ releases and versions of Apple's Darwin, Mac OS X,
+ and Mac OS X Server products and all follow-on
+ releases and future versions thereof.
+
+ c. This exception is only available for Apple
+ OS-Developed Software and does not apply to software
+ that is distributed for use on other operating
+ systems.
+
+ d. All CUPS software that falls under this license
+ exception have the following text at the top of each
+ source file:
+
+ This file is subject to the Apple OS-Developed
+ Software exception.
+
+ 2. OpenSSL Toolkit License Exception;
+
+ a. Easy Software Products explicitly allows the
+ compilation and distribution of the CUPS software
+ with the OpenSSL Toolkit.
+
+No developer is required to provide these exceptions in a
+derived work.
+
+
+TRADEMARKS
+
+Easy Software Products has trademarked the Common UNIX Printing
+System, CUPS, and CUPS logo. You may use these names and logos
+in any direct port or binary distribution of CUPS. Please
+contact Easy Software Products for written permission to use
+them in derivative products. Our intention is to protect the
+value of these trademarks and ensure that any derivative product
+meets the same high-quality standards as the original.
+
+
+BINARY DISTRIBUTION RIGHTS
+
+Easy Software Products also sells rights to the CUPS source code
+under a binary distribution license for vendors that are unable
+to release source code for their drivers, additions, and
+modifications to CUPS under the GNU GPL and LGPL. For
+information please contact us at the address shown above.
+
+The Common UNIX Printing System provides a "pdftops" filter that
+is based on the Xpdf software. For binary distribution licensing
+of this software, please contact:
+
+ Derek B. Noonburg
+ Email: derekn@glyphandcog.com
+ WWW: http://www.glyphandcog.com/
+
+
+SUPPORT
+
+Easy Software Products sells software support for CUPS as well
+as a commercial printing product based on CUPS called ESP Print
+Pro. You can find out more at our web site:
+
+ http://www.easysw.com/
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ [This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/usr/src/lib/print/libhttp-core/common/LICENSE.txt.descrip b/usr/src/lib/print/libhttp-core/common/LICENSE.txt.descrip
new file mode 100644
index 0000000000..7c846a0987
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/LICENSE.txt.descrip
@@ -0,0 +1 @@
+CUPS
diff --git a/usr/src/lib/print/libhttp-core/common/debug.h b/usr/src/lib/print/libhttp-core/common/debug.h
new file mode 100644
index 0000000000..aebc790017
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/debug.h
@@ -0,0 +1,70 @@
+/*
+ * "$Id: debug.h 148 2006-04-25 16:54:17Z njacobs $
+ *
+ * Debugging macros for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_DEBUG_H_
+#define _CUPS_DEBUG_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Include necessary headers...
+ */
+
+# include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * The debug macros are used if you compile with DEBUG defined.
+ *
+ * Usage:
+ *
+ * DEBUG_puts("string")
+ * DEBUG_printf(("format string", arg, arg, ...));
+ *
+ * Note the extra parenthesis around the DEBUG_printf macro...
+ */
+
+# ifdef DEBUG
+# define DEBUG_puts(x) puts(x)
+# define DEBUG_printf(x) printf x
+# else
+# define DEBUG_puts(x)
+# define DEBUG_printf(x)
+# endif /* DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_CUPS_DEBUG_H_ */
+
+/*
+ * End of "$Id: debug.h 148 2006-04-25 16:54:17Z njacobs $"
+ */
diff --git a/usr/src/lib/print/libhttp-core/common/http-addr.c b/usr/src/lib/print/libhttp-core/common/http-addr.c
new file mode 100644
index 0000000000..a872d4d3fd
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/http-addr.c
@@ -0,0 +1,371 @@
+/*
+ * "$Id: http-addr.c 148 2006-04-25 16:54:17Z njacobs $"
+ *
+ * HTTP address routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * Contents:
+ *
+ * httpAddrAny() - Check for the "any" address.
+ * httpAddrEqual() - Compare two addresses.
+ * httpAddrLoad() - Load a host entry address into an HTTP address.
+ * httpAddrLocalhost() - Check for the local loopback address.
+ * httpAddrLookup() - Lookup the hostname associated with the address.
+ * httpAddrString() - Convert an IP address to a dotted string.
+ * httpGetHostByName() - Lookup a hostname or IP address, and return
+ * address records for the specified name.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "http.h"
+#include "debug.h"
+#include "string.h"
+#include <ctype.h>
+
+
+/*
+ * 'httpAddrAny()' - Check for the "any" address.
+ */
+
+int /* O - 1 if "any", 0 otherwise */
+httpAddrAny(const http_addr_t *addr) /* I - Address to check */
+{
+#ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))
+ return (1);
+#endif /* AF_INET6 */
+
+ if (addr->addr.sa_family == AF_INET &&
+ ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000)
+ return (1);
+
+ return (0);
+}
+
+
+/*
+ * 'httpAddrEqual()' - Compare two addresses.
+ */
+
+int /* O - 1 if equal, 0 if != */
+httpAddrEqual(const http_addr_t *addr1, /* I - First address */
+ const http_addr_t *addr2) /* I - Second address */
+{
+ if (addr1->addr.sa_family != addr2->addr.sa_family)
+ return (0);
+
+#ifdef AF_INET6
+ if (addr1->addr.sa_family == AF_INET6)
+ return (memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16) == 0);
+#endif /* AF_INET6 */
+
+ return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr);
+}
+
+
+/*
+ * 'httpAddrLoad()' - Load a host entry address into an HTTP address.
+ */
+
+void
+httpAddrLoad(const struct hostent *host, /* I - Host entry */
+ int port, /* I - Port number */
+ int n, /* I - Index into host entry */
+ http_addr_t *addr) /* O - Address to load */
+{
+#ifdef AF_INET6
+ if (host->h_addrtype == AF_INET6)
+ {
+# ifdef WIN32
+ addr->ipv6.sin6_port = htons((u_short)port);
+# else
+ addr->ipv6.sin6_port = htons(port);
+# endif /* WIN32 */
+
+ memcpy((char *)&(addr->ipv6.sin6_addr), host->h_addr_list[n],
+ host->h_length);
+ addr->ipv6.sin6_family = AF_INET6;
+ }
+ else
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ if (host->h_addrtype == AF_LOCAL)
+ {
+ addr->un.sun_family = AF_LOCAL;
+ strlcpy(addr->un.sun_path, host->h_addr_list[n], sizeof(addr->un.sun_path));
+ }
+ else
+#endif /* AF_LOCAL */
+ if (host->h_addrtype == AF_INET)
+ {
+# ifdef WIN32
+ addr->ipv4.sin_port = htons((u_short)port);
+# else
+ addr->ipv4.sin_port = htons(port);
+# endif /* WIN32 */
+
+ memcpy((char *)&(addr->ipv4.sin_addr), host->h_addr_list[n],
+ host->h_length);
+ addr->ipv4.sin_family = AF_INET;
+ }
+}
+
+
+/*
+ * 'httpAddrLocalhost()' - Check for the local loopback address.
+ */
+
+int /* O - 1 if local host, 0 otherwise */
+httpAddrLocalhost(const http_addr_t *addr)
+ /* I - Address to check */
+{
+#ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)))
+ return (1);
+#endif /* AF_INET6 */
+
+#ifdef AF_LOCAL
+ if (addr->addr.sa_family == AF_LOCAL)
+ return (1);
+#endif /* AF_LOCAL */
+
+ if (addr->addr.sa_family == AF_INET &&
+ ntohl(addr->ipv4.sin_addr.s_addr) == 0x7f000001)
+ return (1);
+
+ return (0);
+}
+
+
+#ifdef __sgi
+# define ADDR_CAST (struct sockaddr *)
+#else
+# define ADDR_CAST (char *)
+#endif /* __sgi */
+
+
+/*
+ * 'httpAddrLookup()' - Lookup the hostname associated with the address.
+ */
+
+char * /* O - Host name */
+httpAddrLookup(const http_addr_t *addr, /* I - Address to lookup */
+ char *name, /* I - Host name buffer */
+ int namelen) /* I - Size of name buffer */
+{
+ struct hostent *host; /* Host from name service */
+
+
+ DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)\n",
+ addr, name, namelen));
+
+#ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6)
+ host = gethostbyaddr(ADDR_CAST &(addr->ipv6.sin6_addr),
+ sizeof(struct in6_addr), AF_INET6);
+ else
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ if (addr->addr.sa_family == AF_LOCAL)
+ {
+ strlcpy(name, addr->un.sun_path, namelen);
+ return (name);
+ }
+ else
+#endif /* AF_LOCAL */
+ if (addr->addr.sa_family == AF_INET)
+ host = gethostbyaddr(ADDR_CAST &(addr->ipv4.sin_addr),
+ sizeof(struct in_addr), AF_INET);
+ else
+ host = NULL;
+
+ if (host == NULL)
+ {
+ httpAddrString(addr, name, namelen);
+ return (NULL);
+ }
+
+ strlcpy(name, host->h_name, namelen);
+
+ return (name);
+}
+
+
+/*
+ * 'httpAddrString()' - Convert an IP address to a dotted string.
+ */
+
+char * /* O - IP string */
+httpAddrString(const http_addr_t *addr, /* I - Address to convert */
+ char *s, /* I - String buffer */
+ int slen) /* I - Length of string */
+{
+ DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)\n",
+ addr, s, slen));
+
+#ifdef AF_INET6
+ if (addr->addr.sa_family == AF_INET6)
+ snprintf(s, slen, "%u.%u.%u.%u",
+ ntohl(addr->ipv6.sin6_addr.s6_addr32[0]),
+ ntohl(addr->ipv6.sin6_addr.s6_addr32[1]),
+ ntohl(addr->ipv6.sin6_addr.s6_addr32[2]),
+ ntohl(addr->ipv6.sin6_addr.s6_addr32[3]));
+ else
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ if (addr->addr.sa_family == AF_LOCAL)
+ strlcpy(s, addr->un.sun_path, slen);
+ else
+#endif /* AF_LOCAL */
+ if (addr->addr.sa_family == AF_INET)
+ {
+ unsigned temp; /* Temporary address */
+
+
+ temp = ntohl(addr->ipv4.sin_addr.s_addr);
+
+ snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255,
+ (temp >> 16) & 255, (temp >> 8) & 255, temp & 255);
+ }
+ else
+ strlcpy(s, "UNKNOWN", slen);
+
+ DEBUG_printf(("httpAddrString: returning \"%s\"...\n", s));
+
+ return (s);
+}
+
+
+/*
+ * 'httpGetHostByName()' - Lookup a hostname or IP address, and return
+ * address records for the specified name.
+ */
+
+struct hostent * /* O - Host entry */
+httpGetHostByName(const char *name) /* I - Hostname or IP address */
+{
+ const char *nameptr; /* Pointer into name */
+ unsigned ip[4]; /* IP address components */
+ static unsigned packed_ip; /* Packed IPv4 address */
+ static char *packed_ptr[2]; /* Pointer to packed address */
+ static struct hostent host_ip; /* Host entry for IP/domain address */
+
+
+ DEBUG_printf(("httpGetHostByName(name=\"%s\")\n", name));
+
+#if defined(__APPLE__)
+ /* OS X hack to avoid it's ocassional long delay in lookupd */
+ static const char sLoopback[] = "127.0.0.1";
+ if (strcmp(name, "localhost") == 0)
+ name = sLoopback;
+#endif /* __APPLE__ */
+
+ /*
+ * This function is needed because some operating systems have a
+ * buggy implementation of gethostbyname() that does not support
+ * IP addresses. If the first character of the name string is a
+ * number, then sscanf() is used to extract the IP components.
+ * We then pack the components into an IPv4 address manually,
+ * since the inet_aton() function is deprecated. We use the
+ * htonl() macro to get the right byte order for the address.
+ *
+ * We also support domain sockets when supported by the underlying
+ * OS...
+ */
+
+#ifdef AF_LOCAL
+ if (name[0] == '/')
+ {
+ /*
+ * A domain socket address, so make an AF_LOCAL entry and return it...
+ */
+
+ host_ip.h_name = (char *)name;
+ host_ip.h_aliases = NULL;
+ host_ip.h_addrtype = AF_LOCAL;
+ host_ip.h_length = strlen(name) + 1;
+ host_ip.h_addr_list = packed_ptr;
+ packed_ptr[0] = (char *)name;
+ packed_ptr[1] = NULL;
+
+ DEBUG_puts("httpGetHostByName: returning domain socket address...");
+
+ return (&host_ip);
+ }
+#endif /* AF_LOCAL */
+
+ for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++);
+
+ if (!*nameptr)
+ {
+ /*
+ * We have an IP address; break it up and provide the host entry
+ * to the caller. Currently only supports IPv4 addresses, although
+ * it should be trivial to support IPv6 in CUPS 1.2.
+ */
+
+ if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4)
+ return (NULL); /* Must have 4 numbers */
+
+ if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
+ return (NULL); /* Invalid byte ranges! */
+
+ packed_ip = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | ip[3]));
+
+ /*
+ * Fill in the host entry and return it...
+ */
+
+ host_ip.h_name = (char *)name;
+ host_ip.h_aliases = NULL;
+ host_ip.h_addrtype = AF_INET;
+ host_ip.h_length = 4;
+ host_ip.h_addr_list = packed_ptr;
+ packed_ptr[0] = (char *)(&packed_ip);
+ packed_ptr[1] = NULL;
+
+ DEBUG_puts("httpGetHostByName: returning IPv4 address...");
+
+ return (&host_ip);
+ }
+ else
+ {
+ /*
+ * Use the gethostbyname() function to get the IP address for
+ * the name...
+ */
+
+ DEBUG_puts("httpGetHostByName: returning domain lookup address(es)...");
+
+ return (gethostbyname(name));
+ }
+}
+
+
+/*
+ * End of "$Id: http-addr.c 148 2006-04-25 16:54:17Z njacobs $".
+ */
diff --git a/usr/src/lib/print/libhttp-core/common/http-private.h b/usr/src/lib/print/libhttp-core/common/http-private.h
new file mode 100644
index 0000000000..a11b8bbb5e
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/http-private.h
@@ -0,0 +1,115 @@
+/*
+ * "$Id: http-private.h 148 2006-04-25 16:54:17Z njacobs $"
+ *
+ * Private HTTP definitions for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_HTTP_PRIVATE_H_
+#define _CUPS_HTTP_PRIVATE_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Include necessary headers...
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+# include "config.h"
+
+
+# ifdef __sun
+/*
+ * Define FD_SETSIZE to CUPS_MAX_FDS on Solaris to get the correct version of
+ * select() for large numbers of file descriptors.
+ */
+
+#define CUPS_MAX_FDS 1024
+
+# define FD_SETSIZE CUPS_MAX_FDS
+# include <sys/select.h>
+# endif /* __sun */
+
+# include "http.h"
+
+# if defined HAVE_LIBSSL
+/*
+ * The OpenSSL library provides its own SSL/TLS context structure for its
+ * IO and protocol management...
+ */
+
+# include <openssl/err.h>
+# include <openssl/rand.h>
+# include <openssl/ssl.h>
+
+typedef SSL http_tls_t;
+
+# elif defined HAVE_GNUTLS
+/*
+ * The GNU TLS library is more of a "bare metal" SSL/TLS library...
+ */
+# include <gnutls/gnutls.h>
+
+typedef struct
+{
+ gnutls_session session; /* GNU TLS session object */
+ void *credentials; /* GNU TLS credentials object */
+} http_tls_t;
+
+# elif defined(HAVE_CDSASSL)
+/*
+ * Darwin's Security framework provides its own SSL/TLS context structure
+ * for its IO and protocol management...
+ */
+
+# include <Security/SecureTransport.h>
+
+typedef SSLConnectionRef http_tls_t;
+
+# endif /* HAVE_LIBSSL */
+
+/*
+ * Some OS's don't have hstrerror(), most notably Solaris...
+ */
+
+# ifndef HAVE_HSTRERROR
+extern const char *cups_hstrerror(int error);
+# define hstrerror cups_hstrerror
+# elif defined(_AIX) || defined(__osf__)
+/*
+ * AIX and Tru64 UNIX don't provide a prototype but do provide the function...
+ */
+extern const char *hstrerror(int error);
+# endif /* !HAVE_HSTRERROR */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_CUPS_HTTP_PRIVATE_H_ */
+
+/*
+ * End of "$Id: http-private.h 148 2006-04-25 16:54:17Z njacobs $"
+ */
diff --git a/usr/src/lib/print/libhttp-core/common/http-support.c b/usr/src/lib/print/libhttp-core/common/http-support.c
new file mode 100644
index 0000000000..2ef3911058
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/http-support.c
@@ -0,0 +1,379 @@
+/*
+ * "$Id: http-support.c 148 2006-04-25 16:54:17Z njacobs $"
+ *
+ * HTTP support routines for the Common UNIX Printing System (CUPS) scheduler.
+ *
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * httpSeparate() - Separate a Universal Resource Identifier into its
+ * components.
+ * httpSeparate2() - Separate a Universal Resource Identifier into its
+ * components.
+ * httpStatus() - Return a short string describing a HTTP status code.
+ * cups_hstrerror() - hstrerror() emulation function for Solaris and others...
+ * http_copy_decode() - Copy and decode a URI.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include "string.h"
+
+#include "http.h"
+
+
+/*
+ * Local functions...
+ */
+
+static const char *http_copy_decode(char *dst, const char *src,
+ int dstsize, const char *term);
+
+
+/*
+ * 'httpSeparate()' - Separate a Universal Resource Identifier into its
+ * components.
+ */
+
+void
+httpSeparate(const char *uri, /* I - Universal Resource Identifier */
+ char *method, /* O - Method [32] (http, https, etc.) */
+ char *username, /* O - Username [1024] */
+ char *host, /* O - Hostname [1024] */
+ int *port, /* O - Port number to use */
+ char *resource) /* O - Resource/filename [1024] */
+{
+ httpSeparate2(uri, method, 32, username, HTTP_MAX_URI, host, HTTP_MAX_URI,
+ port, resource, HTTP_MAX_URI);
+}
+
+
+/*
+ * 'httpSeparate2()' - Separate a Universal Resource Identifier into its
+ * components.
+ */
+
+void
+httpSeparate2(const char *uri, /* I - Universal Resource Identifier */
+ char *method, /* O - Method (http, https, etc.) */
+ int methodlen, /* I - Size of method buffer */
+ char *username, /* O - Username */
+ int usernamelen, /* I - Size of username buffer */
+ char *host, /* O - Hostname */
+ int hostlen, /* I - Size of hostname buffer */
+ int *port, /* O - Port number to use */
+ char *resource, /* O - Resource/filename */
+ int resourcelen) /* I - Size of resource buffer */
+{
+ char *ptr; /* Pointer into string... */
+ const char *atsign, /* @ sign */
+ *slash; /* Separator */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (uri == NULL || method == NULL || username == NULL || host == NULL ||
+ port == NULL || resource == NULL)
+ return;
+
+ /*
+ * Grab the method portion of the URI...
+ */
+
+ if (strncmp(uri, "//", 2) == 0)
+ {
+ /*
+ * Workaround for HP IPP client bug...
+ */
+
+ strlcpy(method, "ipp", methodlen);
+ }
+ else
+ {
+ /*
+ * Standard URI with method...
+ */
+
+ uri = http_copy_decode(host, uri, hostlen, ":");
+
+ if (*uri == ':')
+ uri ++;
+
+ /*
+ * If the method contains a period or slash, then it's probably
+ * hostname/filename...
+ */
+
+ if (strchr(host, '.') != NULL || strchr(host, '/') != NULL || *uri == '\0')
+ {
+ if ((ptr = strchr(host, '/')) != NULL)
+ {
+ strlcpy(resource, ptr, resourcelen);
+ *ptr = '\0';
+ }
+ else
+ resource[0] = '\0';
+
+ if (isdigit(*uri & 255))
+ {
+ /*
+ * OK, we have "hostname:port[/resource]"...
+ */
+
+ *port = strtol(uri, (char **)&uri, 10);
+
+ if (*uri == '/')
+ strlcpy(resource, uri, resourcelen);
+ }
+ else
+ *port = 631;
+
+ strlcpy(method, "http", methodlen);
+ username[0] = '\0';
+ return;
+ }
+ else
+ strlcpy(method, host, methodlen);
+ }
+
+ /*
+ * If the method starts with less than 2 slashes then it is a local resource...
+ */
+
+ if (strncmp(uri, "//", 2) != 0)
+ {
+ strlcpy(resource, uri, resourcelen);
+
+ username[0] = '\0';
+ host[0] = '\0';
+ *port = 0;
+ return;
+ }
+
+ /*
+ * Grab the username, if any...
+ */
+
+ uri += 2;
+
+ if ((slash = strchr(uri, '/')) == NULL)
+ slash = uri + strlen(uri);
+
+ if ((atsign = strchr(uri, '@')) != NULL && atsign < slash)
+ {
+ /*
+ * Got a username:password combo...
+ */
+
+ uri = http_copy_decode(username, uri, usernamelen, "@") + 1;
+ }
+ else
+ username[0] = '\0';
+
+ /*
+ * Grab the hostname...
+ */
+
+ uri = http_copy_decode(host, uri, hostlen, ":/");
+
+ if (*uri != ':')
+ {
+ if (strcasecmp(method, "http") == 0)
+ *port = 80;
+ else if (strcasecmp(method, "https") == 0)
+ *port = 443;
+ else if (strcasecmp(method, "ipp") == 0)
+ *port = 631;
+ else if (strcasecmp(method, "lpd") == 0)
+ *port = 515;
+ else if (strcasecmp(method, "socket") == 0) /* Not registered yet... */
+ *port = 9100;
+ else
+ *port = 0;
+ }
+ else
+ {
+ /*
+ * Parse port number...
+ */
+
+ *port = strtol(uri + 1, (char **)&uri, 10);
+ }
+
+ if (*uri == '\0')
+ {
+ /*
+ * Hostname but no port or path...
+ */
+
+ resource[0] = '/';
+ resource[1] = '\0';
+ return;
+ }
+
+ /*
+ * The remaining portion is the resource string...
+ */
+
+ http_copy_decode(resource, uri, resourcelen, "");
+}
+
+
+/*
+ * 'httpStatus()' - Return a short string describing a HTTP status code.
+ */
+
+const char * /* O - String or NULL */
+httpStatus(http_status_t status) /* I - HTTP status code */
+{
+ switch (status)
+ {
+ case HTTP_CONTINUE :
+ return ("Continue");
+ case HTTP_SWITCHING_PROTOCOLS :
+ return ("Switching Protocols");
+ case HTTP_OK :
+ return ("OK");
+ case HTTP_CREATED :
+ return ("Created");
+ case HTTP_ACCEPTED :
+ return ("Accepted");
+ case HTTP_NO_CONTENT :
+ return ("No Content");
+ case HTTP_NOT_MODIFIED :
+ return ("Not Modified");
+ case HTTP_BAD_REQUEST :
+ return ("Bad Request");
+ case HTTP_UNAUTHORIZED :
+ return ("Unauthorized");
+ case HTTP_FORBIDDEN :
+ return ("Forbidden");
+ case HTTP_NOT_FOUND :
+ return ("Not Found");
+ case HTTP_REQUEST_TOO_LARGE :
+ return ("Request Entity Too Large");
+ case HTTP_URI_TOO_LONG :
+ return ("URI Too Long");
+ case HTTP_UPGRADE_REQUIRED :
+ return ("Upgrade Required");
+ case HTTP_NOT_IMPLEMENTED :
+ return ("Not Implemented");
+ case HTTP_NOT_SUPPORTED :
+ return ("Not Supported");
+ default :
+ return ("Unknown");
+ }
+}
+
+
+#ifndef HAVE_HSTRERROR
+/*
+ * 'cups_hstrerror()' - hstrerror() emulation function for Solaris and others...
+ */
+
+const char * /* O - Error string */
+cups_hstrerror(int error) /* I - Error number */
+{
+ static const char * const errors[] = /* Error strings */
+ {
+ "OK",
+ "Host not found.",
+ "Try again.",
+ "Unrecoverable lookup error.",
+ "No data associated with name."
+ };
+
+
+ if (error < 0 || error > 4)
+ return ("Unknown hostname lookup error.");
+ else
+ return (errors[error]);
+}
+#endif /* !HAVE_HSTRERROR */
+
+
+/*
+ * 'http_copy_decode()' - Copy and decode a URI.
+ */
+
+static const char * /* O - New source pointer */
+http_copy_decode(char *dst, /* O - Destination buffer */
+ const char *src, /* I - Source pointer */
+ int dstsize, /* I - Destination size */
+ const char *term) /* I - Terminating characters */
+{
+ char *ptr, /* Pointer into buffer */
+ *end; /* End of buffer */
+ int quoted; /* Quoted character */
+
+
+ /*
+ * Copy the src to the destination until we hit a terminating character
+ * or the end of the string.
+ */
+
+ for (ptr = dst, end = dst + dstsize - 1; *src && !strchr(term, *src); src ++)
+ if (ptr < end)
+ {
+ if (*src == '%' && isxdigit(src[1] & 255) && isxdigit(src[2] & 255))
+ {
+ /*
+ * Grab a hex-encoded character...
+ */
+
+ src ++;
+ if (isalpha(*src))
+ quoted = (tolower(*src) - 'a' + 10) << 4;
+ else
+ quoted = (*src - '0') << 4;
+
+ src ++;
+ if (isalpha(*src))
+ quoted |= tolower(*src) - 'a' + 10;
+ else
+ quoted |= *src - '0';
+
+ *ptr++ = quoted;
+ }
+ else
+ *ptr++ = *src;
+ }
+
+ *ptr = '\0';
+
+ return (src);
+}
+
+
+/*
+ * End of "$Id: http-support.c 148 2006-04-25 16:54:17Z njacobs $"
+ */
diff --git a/usr/src/lib/print/libhttp-core/common/http.c b/usr/src/lib/print/libhttp-core/common/http.c
new file mode 100644
index 0000000000..b32b1eb3bc
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/http.c
@@ -0,0 +1,2569 @@
+/*
+ * "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
+ *
+ * HTTP routines for the Common UNIX Printing System (CUPS).
+ *
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ * httpInitialize() - Initialize the HTTP interface library and set the
+ * default HTTP proxy (if any).
+ * httpCheck() - Check to see if there is a pending response from
+ * the server.
+ * httpClearCookie() - Clear the cookie value(s).
+ * httpClose() - Close an HTTP connection...
+ * httpConnect() - Connect to a HTTP server.
+ * httpConnectEncrypt() - Connect to a HTTP server using encryption.
+ * httpEncryption() - Set the required encryption on the link.
+ * httpReconnect() - Reconnect to a HTTP server...
+ * httpGetSubField() - Get a sub-field value.
+ * httpSetField() - Set the value of an HTTP header.
+ * httpDelete() - Send a DELETE request to the server.
+ * httpGet() - Send a GET request to the server.
+ * httpHead() - Send a HEAD request to the server.
+ * httpOptions() - Send an OPTIONS request to the server.
+ * httpPost() - Send a POST request to the server.
+ * httpPut() - Send a PUT request to the server.
+ * httpTrace() - Send an TRACE request to the server.
+ * httpFlush() - Flush data from a HTTP connection.
+ * httpRead() - Read data from a HTTP connection.
+ * httpSetCookie() - Set the cookie value(s)...
+ * httpWait() - Wait for data available on a connection.
+ * httpWrite() - Write data to a HTTP connection.
+ * httpGets() - Get a line of text from a HTTP connection.
+ * httpPrintf() - Print a formatted string to a HTTP connection.
+ * httpGetDateString() - Get a formatted date/time string from a time value.
+ * httpGetDateTime() - Get a time value from a formatted date/time string.
+ * httpUpdate() - Update the current HTTP state for incoming data.
+ * httpDecode64() - Base64-decode a string.
+ * httpDecode64_2() - Base64-decode a string.
+ * httpEncode64() - Base64-encode a string.
+ * httpEncode64_2() - Base64-encode a string.
+ * httpGetLength() - Get the amount of data remaining from the
+ * content-length or transfer-encoding fields.
+ * http_field() - Return the field index for a field name.
+ * http_send() - Send a request with all fields and the trailing
+ * blank line.
+ * http_wait() - Wait for data available on a connection.
+ * http_upgrade() - Force upgrade to TLS encryption.
+ * http_setup_ssl() - Set up SSL/TLS on a connection.
+ * http_shutdown_ssl() - Shut down SSL/TLS on a connection.
+ * http_read_ssl() - Read from a SSL/TLS connection.
+ * http_write_ssl() - Write to a SSL/TLS connection.
+ * CDSAReadFunc() - Read function for CDSA decryption code.
+ * CDSAWriteFunc() - Write function for CDSA encryption code.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Include necessary headers...
+ */
+
+#include "http-private.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include "string.h"
+#include <fcntl.h>
+#include <errno.h>
+
+#include "http.h"
+#include "debug.h"
+
+#ifndef WIN32
+# include <signal.h>
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif /* !WIN32 */
+
+
+/*
+ * Some operating systems have done away with the Fxxxx constants for
+ * the fcntl() call; this works around that "feature"...
+ */
+
+#ifndef FNONBLK
+# define FNONBLK O_NONBLOCK
+#endif /* !FNONBLK */
+
+
+/*
+ * Local functions...
+ */
+
+static http_field_t http_field(const char *name);
+static int http_send(http_t *http, http_state_t request,
+ const char *uri);
+static int http_wait(http_t *http, int msec);
+#ifdef HAVE_SSL
+static int http_upgrade(http_t *http);
+static int http_setup_ssl(http_t *http);
+static void http_shutdown_ssl(http_t *http);
+static int http_read_ssl(http_t *http, char *buf, int len);
+static int http_write_ssl(http_t *http, const char *buf, int len);
+# ifdef HAVE_CDSASSL
+static OSStatus CDSAReadFunc(SSLConnectionRef connection, void *data, size_t *dataLength);
+static OSStatus CDSAWriteFunc(SSLConnectionRef connection, const void *data, size_t *dataLength);
+# endif /* HAVE_CDSASSL */
+#endif /* HAVE_SSL */
+
+
+/*
+ * Local globals...
+ */
+
+static const char * const http_fields[] =
+ {
+ "Accept-Language",
+ "Accept-Ranges",
+ "Authorization",
+ "Connection",
+ "Content-Encoding",
+ "Content-Language",
+ "Content-Length",
+ "Content-Location",
+ "Content-MD5",
+ "Content-Range",
+ "Content-Type",
+ "Content-Version",
+ "Date",
+ "Host",
+ "If-Modified-Since",
+ "If-Unmodified-since",
+ "Keep-Alive",
+ "Last-Modified",
+ "Link",
+ "Location",
+ "Range",
+ "Referer",
+ "Retry-After",
+ "Transfer-Encoding",
+ "Upgrade",
+ "User-Agent",
+ "WWW-Authenticate"
+ };
+static const char * const days[7] =
+ {
+ "Sun",
+ "Mon",
+ "Tue",
+ "Wed",
+ "Thu",
+ "Fri",
+ "Sat"
+ };
+static const char * const months[12] =
+ {
+ "Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"
+ };
+
+void
+httpDumpData(FILE *fp, const char *tag, const char *buffer, int bytes)
+{
+ int i, j, ch;
+
+ fprintf(fp, "%s %d(0x%x) bytes...\n", tag, bytes, bytes);
+ for (i = 0; i < bytes; i += 16) {
+ fprintf(fp, "%s ", (tag ? tag : ""));
+
+ for (j = 0; j < 16 && (i + j) < bytes; j ++)
+ fprintf(fp, " %02X", buffer[i + j] & 255);
+
+ while (j < 16) {
+ fprintf(fp, " ");
+ j++;
+ }
+
+ fprintf(fp, " ");
+ for (j = 0; j < 16 && (i + j) < bytes; j ++) {
+ ch = buffer[i + j] & 255;
+ if (ch < ' ' || ch == 127)
+ ch = '.';
+ putc(ch, fp);
+ }
+ putc('\n', fp);
+ }
+}
+
+
+/*
+ * 'httpInitialize()' - Initialize the HTTP interface library and set the
+ * default HTTP proxy (if any).
+ */
+
+void
+httpInitialize(void)
+{
+#ifdef HAVE_LIBSSL
+# ifndef WIN32
+ struct timeval curtime; /* Current time in microseconds */
+# endif /* !WIN32 */
+ int i; /* Looping var */
+ unsigned char data[1024]; /* Seed data */
+#endif /* HAVE_LIBSSL */
+
+#ifdef WIN32
+ WSADATA winsockdata; /* WinSock data */
+ static int initialized = 0; /* Has WinSock been initialized? */
+
+
+ if (!initialized)
+ WSAStartup(MAKEWORD(1,1), &winsockdata);
+#elif defined(HAVE_SIGSET)
+ sigset(SIGPIPE, SIG_IGN);
+#elif defined(HAVE_SIGACTION)
+ struct sigaction action; /* POSIX sigaction data */
+
+
+ /*
+ * Ignore SIGPIPE signals...
+ */
+
+ memset(&action, 0, sizeof(action));
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif /* WIN32 */
+
+#ifdef HAVE_GNUTLS
+ gnutls_global_init();
+#endif /* HAVE_GNUTLS */
+
+#ifdef HAVE_LIBSSL
+ SSL_load_error_strings();
+ SSL_library_init();
+
+ /*
+ * Using the current time is a dubious random seed, but on some systems
+ * it is the best we can do (on others, this seed isn't even used...)
+ */
+
+#ifdef WIN32
+#else
+ gettimeofday(&curtime, NULL);
+ srand(curtime.tv_sec + curtime.tv_usec);
+#endif /* WIN32 */
+
+ for (i = 0; i < sizeof(data); i ++)
+ data[i] = rand(); /* Yes, this is a poor source of random data... */
+
+ RAND_seed(&data, sizeof(data));
+#endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * 'httpCheck()' - Check to see if there is a pending response from the server.
+ */
+
+int /* O - 0 = no data, 1 = data available */
+httpCheck(http_t *http) /* I - HTTP connection */
+{
+ return (httpWait(http, 0));
+}
+
+
+/*
+ * 'httpClearCookie()' - Clear the cookie value(s).
+ */
+
+void
+httpClearCookie(http_t *http) /* I - Connection */
+{
+ if (!http)
+ return;
+
+ if (http->cookie)
+ {
+ free(http->cookie);
+ http->cookie = NULL;
+ }
+}
+
+
+/*
+ * 'httpClose()' - Close an HTTP connection...
+ */
+
+void
+httpClose(http_t *http) /* I - Connection to close */
+{
+ DEBUG_printf(("httpClose(http=%p)\n", http));
+
+ if (!http)
+ return;
+
+ if (http->input_set)
+ free(http->input_set);
+
+ if (http->cookie)
+ free(http->cookie);
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ http_shutdown_ssl(http);
+#endif /* HAVE_SSL */
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif /* WIN32 */
+
+ free(http);
+}
+
+
+/*
+ * 'httpConnect()' - Connect to a HTTP server.
+ */
+
+http_t * /* O - New HTTP connection */
+httpConnect(const char *host, /* I - Host to connect to */
+ int port) /* I - Port number */
+{
+ http_encryption_t encrypt; /* Type of encryption to use */
+
+
+ /*
+ * Set the default encryption status...
+ */
+
+ if (port == 443)
+ encrypt = HTTP_ENCRYPT_ALWAYS;
+ else
+ encrypt = HTTP_ENCRYPT_IF_REQUESTED;
+
+ return (httpConnectEncrypt(host, port, encrypt));
+}
+
+
+/*
+ * 'httpConnectEncrypt()' - Connect to a HTTP server using encryption.
+ */
+
+http_t * /* O - New HTTP connection */
+httpConnectEncrypt(const char *host, /* I - Host to connect to */
+ int port, /* I - Port number */
+ http_encryption_t encrypt)
+ /* I - Type of encryption to use */
+{
+ int i; /* Looping var */
+ http_t *http; /* New HTTP connection */
+ struct hostent *hostaddr; /* Host address data */
+
+
+ DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encrypt=%d)\n",
+ host ? host : "(null)", port, encrypt));
+
+ if (!host)
+ return (NULL);
+
+ httpInitialize();
+
+ /*
+ * Lookup the host...
+ */
+
+ if ((hostaddr = httpGetHostByName(host)) == NULL)
+ {
+ /*
+ * This hack to make users that don't have a localhost entry in
+ * their hosts file or DNS happy...
+ */
+
+ if (strcasecmp(host, "localhost") != 0)
+ return (NULL);
+ else if ((hostaddr = httpGetHostByName("127.0.0.1")) == NULL)
+ return (NULL);
+ }
+
+ /*
+ * Verify that it is an IPv4, IPv6, or domain address...
+ */
+
+ if ((hostaddr->h_addrtype != AF_INET || hostaddr->h_length != 4)
+#ifdef AF_INET6
+ && (hostaddr->h_addrtype != AF_INET6 || hostaddr->h_length != 16)
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ && (hostaddr->h_addrtype != AF_LOCAL)
+#endif /* AF_LOCAL */
+ )
+ return (NULL);
+
+ /*
+ * Allocate memory for the structure...
+ */
+
+ http = calloc(sizeof(http_t), 1);
+ if (http == NULL)
+ return (NULL);
+
+ http->version = HTTP_1_1;
+ http->blocking = 1;
+ http->activity = time(NULL);
+ http->fd = -1;
+
+ /*
+ * Set the encryption status...
+ */
+
+ if (port == 443) /* Always use encryption for https */
+ http->encryption = HTTP_ENCRYPT_ALWAYS;
+ else
+ http->encryption = encrypt;
+
+ /*
+ * Loop through the addresses we have until one of them connects...
+ */
+
+ strlcpy(http->hostname, host, sizeof(http->hostname));
+
+ for (i = 0; hostaddr->h_addr_list[i]; i ++)
+ {
+ /*
+ * Load the address...
+ */
+
+ httpAddrLoad(hostaddr, port, i, &(http->hostaddr));
+
+ /*
+ * Connect to the remote system...
+ */
+
+ if (!httpReconnect(http))
+ return (http);
+ }
+
+ /*
+ * Could not connect to any known address - bail out!
+ */
+
+ free(http);
+ return (NULL);
+}
+
+
+/*
+ * 'httpEncryption()' - Set the required encryption on the link.
+ */
+
+int /* O - -1 on error, 0 on success */
+httpEncryption(http_t *http, /* I - HTTP data */
+ http_encryption_t e) /* I - New encryption preference */
+{
+ DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e));
+
+#ifdef HAVE_SSL
+ if (!http)
+ return (0);
+
+ http->encryption = e;
+
+ if ((http->encryption == HTTP_ENCRYPT_ALWAYS && !http->tls) ||
+ (http->encryption == HTTP_ENCRYPT_NEVER && http->tls))
+ return (httpReconnect(http));
+ else if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
+ return (http_upgrade(http));
+ else
+ return (0);
+#else
+ if (e == HTTP_ENCRYPT_ALWAYS || e == HTTP_ENCRYPT_REQUIRED)
+ return (-1);
+ else
+ return (0);
+#endif /* HAVE_SSL */
+}
+
+
+/*
+ * 'httpReconnect()' - Reconnect to a HTTP server...
+ */
+
+int /* O - 0 on success, non-zero on failure */
+httpReconnect(http_t *http) /* I - HTTP data */
+{
+ int val; /* Socket option value */
+ int status; /* Connect status */
+
+
+ DEBUG_printf(("httpReconnect(http=%p)\n", http));
+
+ if (!http)
+ return (-1);
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ http_shutdown_ssl(http);
+#endif /* HAVE_SSL */
+
+ /*
+ * Close any previously open socket...
+ */
+
+ if (http->fd >= 0)
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif /* WIN32 */
+
+ /*
+ * Create the socket and set options to allow reuse.
+ */
+
+ if ((http->fd = socket(http->hostaddr.addr.sa_family, SOCK_STREAM, 0)) < 0)
+ {
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+
+#ifdef FD_CLOEXEC
+ fcntl(http->fd, F_SETFD, FD_CLOEXEC); /* Close this socket when starting *
+ * other processes... */
+#endif /* FD_CLOEXEC */
+
+ val = 1;
+ setsockopt(http->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+
+#ifdef SO_REUSEPORT
+ val = 1;
+ setsockopt(http->fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
+#endif /* SO_REUSEPORT */
+
+ /*
+ * Using TCP_NODELAY improves responsiveness, especially on systems
+ * with a slow loopback interface... Since we write large buffers
+ * when sending print files and requests, there shouldn't be any
+ * performance penalty for this...
+ */
+
+ val = 1;
+#ifdef WIN32
+ setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+#else
+ setsockopt(http->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
+#endif /* WIN32 */
+
+ /*
+ * Connect to the server...
+ */
+
+#ifdef AF_INET6
+ if (http->hostaddr.addr.sa_family == AF_INET6)
+ status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
+ sizeof(http->hostaddr.ipv6));
+ else
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ if (http->hostaddr.addr.sa_family == AF_LOCAL)
+ status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
+ SUN_LEN(&(http->hostaddr.un)));
+ else
+#endif /* AF_LOCAL */
+ status = connect(http->fd, (struct sockaddr *)&(http->hostaddr),
+ sizeof(http->hostaddr.ipv4));
+
+ if (status < 0)
+ {
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ http->error = errno;
+#endif /* WIN32 */
+ http->status = HTTP_ERROR;
+
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif
+
+ http->fd = -1;
+
+ return (-1);
+ }
+
+ http->error = 0;
+ http->status = HTTP_CONTINUE;
+
+#ifdef HAVE_SSL
+ if (http->encryption == HTTP_ENCRYPT_ALWAYS)
+ {
+ /*
+ * Always do encryption via SSL.
+ */
+
+ if (http_setup_ssl(http) != 0)
+ {
+#ifdef WIN32
+ closesocket(http->fd);
+#else
+ close(http->fd);
+#endif /* WIN32 */
+
+ return (-1);
+ }
+ }
+ else if (http->encryption == HTTP_ENCRYPT_REQUIRED)
+ return (http_upgrade(http));
+#endif /* HAVE_SSL */
+
+ return (0);
+}
+
+
+/*
+ * 'httpGetSubField()' - Get a sub-field value.
+ */
+
+char * /* O - Value or NULL */
+httpGetSubField(http_t *http, /* I - HTTP data */
+ http_field_t field, /* I - Field index */
+ const char *name, /* I - Name of sub-field */
+ char *value) /* O - Value string */
+{
+ const char *fptr; /* Pointer into field */
+ char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */
+ *ptr; /* Pointer into string buffer */
+
+
+ DEBUG_printf(("httpGetSubField(http=%p, field=%d, name=\"%s\", value=%p)\n",
+ http, field, name, value));
+
+ if (http == NULL ||
+ field < HTTP_FIELD_ACCEPT_LANGUAGE ||
+ field > HTTP_FIELD_WWW_AUTHENTICATE ||
+ name == NULL || value == NULL)
+ return (NULL);
+
+ for (fptr = http->fields[field]; *fptr;)
+ {
+ /*
+ * Skip leading whitespace...
+ */
+
+ while (isspace(*fptr & 255))
+ fptr ++;
+
+ if (*fptr == ',')
+ {
+ fptr ++;
+ continue;
+ }
+
+ /*
+ * Get the sub-field name...
+ */
+
+ for (ptr = temp;
+ *fptr && *fptr != '=' && !isspace(*fptr & 255) && ptr < (temp + sizeof(temp) - 1);
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ DEBUG_printf(("httpGetSubField: name=\"%s\"\n", temp));
+
+ /*
+ * Skip trailing chars up to the '='...
+ */
+
+ while (isspace(*fptr & 255))
+ fptr ++;
+
+ if (!*fptr)
+ break;
+
+ if (*fptr != '=')
+ continue;
+
+ /*
+ * Skip = and leading whitespace...
+ */
+
+ fptr ++;
+
+ while (isspace(*fptr & 255))
+ fptr ++;
+
+ if (*fptr == '\"')
+ {
+ /*
+ * Read quoted string...
+ */
+
+ for (ptr = value, fptr ++;
+ *fptr && *fptr != '\"' && ptr < (value + HTTP_MAX_VALUE - 1);
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ while (*fptr && *fptr != '\"')
+ fptr ++;
+
+ if (*fptr)
+ fptr ++;
+ }
+ else
+ {
+ /*
+ * Read unquoted string...
+ */
+
+ for (ptr = value;
+ *fptr && !isspace(*fptr & 255) && *fptr != ',' && ptr < (value + HTTP_MAX_VALUE - 1);
+ *ptr++ = *fptr++);
+
+ *ptr = '\0';
+
+ while (*fptr && !isspace(*fptr & 255) && *fptr != ',')
+ fptr ++;
+ }
+
+ DEBUG_printf(("httpGetSubField: value=\"%s\"\n", value));
+
+ /*
+ * See if this is the one...
+ */
+
+ if (strcmp(name, temp) == 0)
+ return (value);
+ }
+
+ value[0] = '\0';
+
+ return (NULL);
+}
+
+
+/*
+ * 'httpSetField()' - Set the value of an HTTP header.
+ */
+
+void
+httpSetField(http_t *http, /* I - HTTP data */
+ http_field_t field, /* I - Field index */
+ const char *value) /* I - Value */
+{
+ if (http == NULL ||
+ field < HTTP_FIELD_ACCEPT_LANGUAGE ||
+ field > HTTP_FIELD_WWW_AUTHENTICATE ||
+ value == NULL)
+ return;
+
+ strlcpy(http->fields[field], value, HTTP_MAX_VALUE);
+}
+
+
+/*
+ * 'httpDelete()' - Send a DELETE request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpDelete(http_t *http, /* I - HTTP data */
+ const char *uri) /* I - URI to delete */
+{
+ return (http_send(http, HTTP_DELETE, uri));
+}
+
+
+/*
+ * 'httpGet()' - Send a GET request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpGet(http_t *http, /* I - HTTP data */
+ const char *uri) /* I - URI to get */
+{
+ return (http_send(http, HTTP_GET, uri));
+}
+
+
+/*
+ * 'httpHead()' - Send a HEAD request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpHead(http_t *http, /* I - HTTP data */
+ const char *uri) /* I - URI for head */
+{
+ return (http_send(http, HTTP_HEAD, uri));
+}
+
+
+/*
+ * 'httpOptions()' - Send an OPTIONS request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpOptions(http_t *http, /* I - HTTP data */
+ const char *uri) /* I - URI for options */
+{
+ return (http_send(http, HTTP_OPTIONS, uri));
+}
+
+
+/*
+ * 'httpPost()' - Send a POST request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpPost(http_t *http, /* I - HTTP data */
+ const char *uri) /* I - URI for post */
+{
+ httpGetLength(http);
+
+ return (http_send(http, HTTP_POST, uri));
+}
+
+
+/*
+ * 'httpPut()' - Send a PUT request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpPut(http_t *http, /* I - HTTP data */
+ const char *uri) /* I - URI to put */
+{
+ httpGetLength(http);
+
+ return (http_send(http, HTTP_PUT, uri));
+}
+
+
+/*
+ * 'httpTrace()' - Send an TRACE request to the server.
+ */
+
+int /* O - Status of call (0 = success) */
+httpTrace(http_t *http, /* I - HTTP data */
+ const char *uri) /* I - URI for trace */
+{
+ return (http_send(http, HTTP_TRACE, uri));
+}
+
+
+/*
+ * 'httpFlush()' - Flush data from a HTTP connection.
+ */
+
+void
+httpFlush(http_t *http) /* I - HTTP data */
+{
+ char buffer[8192]; /* Junk buffer */
+
+
+ DEBUG_printf(("httpFlush(http=%p), state=%d\n", http, http->state));
+
+ while (httpRead(http, buffer, sizeof(buffer)) > 0);
+}
+
+
+/*
+ * 'httpRead()' - Read data from a HTTP connection.
+ */
+
+int /* O - Number of bytes read */
+httpRead(http_t *http, /* I - HTTP data */
+ char *buffer, /* I - Buffer for data */
+ int length) /* I - Maximum number of bytes */
+{
+ int bytes; /* Bytes read */
+ char len[32]; /* Length string */
+
+
+ DEBUG_printf(("httpRead(http=%p, buffer=%p, length=%d)\n",
+ http, buffer, length));
+
+ if (http == NULL || buffer == NULL)
+ return (-1);
+
+ http->activity = time(NULL);
+
+ if (length <= 0)
+ return (0);
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED &&
+ http->data_remaining <= 0)
+ {
+ DEBUG_puts("httpRead: Getting chunk length...");
+
+ if (httpGets(len, sizeof(len), http) == NULL)
+ {
+ DEBUG_puts("httpRead: Could not get length!");
+ return (0);
+ }
+
+ http->data_remaining = strtol(len, NULL, 16);
+ if (http->data_remaining < 0)
+ {
+ DEBUG_puts("httpRead: Negative chunk length!");
+ return (0);
+ }
+ }
+
+ DEBUG_printf(("httpRead: data_remaining=%d\n", http->data_remaining));
+
+ if (http->data_remaining <= 0)
+ {
+ /*
+ * A zero-length chunk ends a transfer; unless we are reading POST
+ * data, go idle...
+ */
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ httpGets(len, sizeof(len), http);
+
+ if (http->state == HTTP_POST_RECV)
+ http->state ++;
+ else
+ http->state = HTTP_WAITING;
+
+ /*
+ * Prevent future reads for this request...
+ */
+
+ http->data_encoding = HTTP_ENCODE_LENGTH;
+
+ return (0);
+ }
+ else if (length > http->data_remaining)
+ length = http->data_remaining;
+
+ if (http->used == 0 && length <= 256)
+ {
+ /*
+ * Buffer small reads for better performance...
+ */
+
+ if (!http->blocking && !httpWait(http, 1000))
+ return (0);
+
+ if (http->data_remaining > sizeof(http->buffer))
+ bytes = sizeof(http->buffer);
+ else
+ bytes = http->data_remaining;
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ bytes = http_read_ssl(http, http->buffer, bytes);
+ else
+#endif /* HAVE_SSL */
+ {
+ DEBUG_printf(("httpRead: reading %d bytes from socket into buffer...\n",
+ bytes));
+
+ bytes = recv(http->fd, http->buffer, bytes, 0);
+
+ DEBUG_printf(("httpRead: read %d bytes from socket into buffer...\n",
+ bytes));
+#ifdef DEBUG_HTTP
+ httpDumpData(stdout, "httpRead:", http->buffer, bytes);
+#endif
+ }
+
+ if (bytes > 0)
+ http->used = bytes;
+ else if (bytes < 0)
+ {
+#ifdef WIN32
+ http->error = WSAGetLastError();
+ return (-1);
+#else
+ if (errno != EINTR)
+ {
+ http->error = errno;
+ return (-1);
+ }
+#endif /* WIN32 */
+ }
+ else
+ {
+ http->error = EPIPE;
+ return (0);
+ }
+ }
+
+ if (http->used > 0)
+ {
+ if (length > http->used)
+ length = http->used;
+
+ bytes = length;
+
+ DEBUG_printf(("httpRead: grabbing %d bytes from input buffer...\n", bytes));
+
+ memcpy(buffer, http->buffer, length);
+ http->used -= length;
+
+ if (http->used > 0)
+ memmove(http->buffer, http->buffer + length, http->used);
+ }
+#ifdef HAVE_SSL
+ else if (http->tls)
+ {
+ if (!http->blocking && !httpWait(http, 1000))
+ return (0);
+
+ bytes = http_read_ssl(http, buffer, length);
+ }
+#endif /* HAVE_SSL */
+ else
+ {
+ if (!http->blocking && !httpWait(http, 1000))
+ return (0);
+
+ DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length));
+
+ while ((bytes = recv(http->fd, buffer, length, 0)) < 0)
+ if (errno != EINTR)
+ break;
+ DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes));
+ }
+#ifdef DEBUG_HTTP
+ httpDumpData(stdout, "httpRead:", buffer, bytes);
+#endif
+
+ if (bytes > 0)
+ http->data_remaining -= bytes;
+ else if (bytes < 0)
+ {
+#ifdef WIN32
+ http->error = WSAGetLastError();
+#else
+ if (errno == EINTR)
+ bytes = 0;
+ else
+ http->error = errno;
+#endif /* WIN32 */
+ }
+ else
+ {
+ http->error = EPIPE;
+ return (0);
+ }
+
+ if (http->data_remaining == 0)
+ {
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ httpGets(len, sizeof(len), http);
+
+ if (http->data_encoding != HTTP_ENCODE_CHUNKED)
+ {
+ if (http->state == HTTP_POST_RECV)
+ http->state ++;
+ else
+ http->state = HTTP_WAITING;
+ }
+ }
+
+ return (bytes);
+}
+
+
+/*
+ * 'httpSetCookie()' - Set the cookie value(s)...
+ */
+
+void
+httpSetCookie(http_t *http, /* I - Connection */
+ const char *cookie) /* I - Cookie string */
+{
+ if (!http)
+ return;
+
+ if (http->cookie)
+ free(http->cookie);
+
+ if (cookie)
+ http->cookie = strdup(cookie);
+ else
+ http->cookie = NULL;
+}
+
+
+/*
+ * 'httpWait()' - Wait for data available on a connection.
+ */
+
+int /* O - 1 if data is available, 0 otherwise */
+httpWait(http_t *http, /* I - HTTP data */
+ int msec) /* I - Milliseconds to wait */
+{
+ /*
+ * First see if there is data in the buffer...
+ */
+
+ if (http == NULL)
+ return (0);
+
+ if (http->used)
+ return (1);
+
+ /*
+ * If not, check the SSL/TLS buffers and do a select() on the connection...
+ */
+
+ return (http_wait(http, msec));
+}
+
+
+/*
+ * 'httpWrite()' - Write data to a HTTP connection.
+ */
+
+int /* O - Number of bytes written */
+httpWrite(http_t *http, /* I - HTTP data */
+ const char *buffer, /* I - Buffer for data */
+ int length) /* I - Number of bytes to write */
+{
+ int tbytes, /* Total bytes sent */
+ bytes; /* Bytes sent */
+
+
+ if (http == NULL || buffer == NULL)
+ return (-1);
+
+ http->activity = time(NULL);
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ {
+ if (httpPrintf(http, "%x\r\n", length) < 0)
+ return (-1);
+
+ if (length == 0)
+ {
+ /*
+ * A zero-length chunk ends a transfer; unless we are sending POST
+ * or PUT data, go idle...
+ */
+
+ DEBUG_printf(("httpWrite: changing states from %d", http->state));
+
+ if (http->state == HTTP_POST_RECV)
+ http->state ++;
+ else if (http->state == HTTP_PUT_RECV)
+ http->state = HTTP_STATUS;
+ else
+ http->state = HTTP_WAITING;
+ DEBUG_printf((" to %d\n", http->state));
+
+ if (httpPrintf(http, "\r\n") < 0)
+ return (-1);
+
+ return (0);
+ }
+ }
+
+ tbytes = 0;
+
+ while (length > 0)
+ {
+#ifdef HAVE_SSL
+ if (http->tls)
+ bytes = http_write_ssl(http, buffer, length);
+ else
+#endif /* HAVE_SSL */
+ bytes = send(http->fd, buffer, length, 0);
+
+#ifdef DEBUG_HTTP
+ if (bytes >= 0)
+ httpDumpData(stdout, "httpWrite:", buffer, bytes);
+#endif /* DEBUG */
+
+
+ if (bytes < 0)
+ {
+#ifdef WIN32
+ if (WSAGetLastError() != http->error)
+ {
+ http->error = WSAGetLastError();
+ continue;
+ }
+#else
+ if (errno == EINTR)
+ continue;
+ else if (errno != http->error && errno != ECONNRESET)
+ {
+ http->error = errno;
+ continue;
+ }
+#endif /* WIN32 */
+
+ DEBUG_puts("httpWrite: error writing data...\n");
+
+ return (-1);
+ }
+
+ buffer += bytes;
+ tbytes += bytes;
+ length -= bytes;
+ if (http->data_encoding == HTTP_ENCODE_LENGTH)
+ http->data_remaining -= bytes;
+ }
+
+ if (http->data_encoding == HTTP_ENCODE_CHUNKED)
+ if (httpPrintf(http, "\r\n") < 0)
+ return (-1);
+
+ if (http->data_remaining == 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
+ {
+ /*
+ * Finished with the transfer; unless we are sending POST or PUT
+ * data, go idle...
+ */
+
+ DEBUG_printf(("httpWrite: changing states from %d", http->state));
+
+ if (http->state == HTTP_POST_RECV)
+ http->state ++;
+ else if (http->state == HTTP_PUT_RECV)
+ http->state = HTTP_STATUS;
+ else
+ http->state = HTTP_WAITING;
+
+ DEBUG_printf((" to %d\n", http->state));
+ }
+
+ return (tbytes);
+}
+
+
+/*
+ * 'httpGets()' - Get a line of text from a HTTP connection.
+ */
+
+char * /* O - Line or NULL */
+httpGets(char *line, /* I - Line to read into */
+ int length, /* I - Max length of buffer */
+ http_t *http) /* I - HTTP data */
+{
+ char *lineptr, /* Pointer into line */
+ *bufptr, /* Pointer into input buffer */
+ *bufend; /* Pointer to end of buffer */
+ int bytes; /* Number of bytes read */
+
+
+ DEBUG_printf(("httpGets(line=%p, length=%d, http=%p)\n", line, length, http));
+
+ if (http == NULL || line == NULL)
+ return (NULL);
+
+ /*
+ * Pre-scan the buffer and see if there is a newline in there...
+ */
+
+#ifdef WIN32
+ WSASetLastError(0);
+#else
+ errno = 0;
+#endif /* WIN32 */
+
+ do
+ {
+ bufptr = http->buffer;
+ bufend = http->buffer + http->used;
+
+ while (bufptr < bufend)
+ if (*bufptr == 0x0a)
+ break;
+ else
+ bufptr ++;
+
+ if (bufptr >= bufend && http->used < HTTP_MAX_BUFFER)
+ {
+ /*
+ * No newline; see if there is more data to be read...
+ */
+
+ if (!http->blocking && !http_wait(http, 1000))
+ return (NULL);
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ bytes = http_read_ssl(http, bufend, HTTP_MAX_BUFFER - http->used);
+ else
+#endif /* HAVE_SSL */
+ bytes = recv(http->fd, bufend, HTTP_MAX_BUFFER - http->used, 0);
+
+ DEBUG_printf(("httpGets: read %d bytes...\n", bytes));
+#ifdef DEBUG_HTTP
+ httpDumpData(stdout, "httpGets:", bufend, bytes);
+#endif
+
+ if (bytes < 0)
+ {
+ /*
+ * Nope, can't get a line this time...
+ */
+
+#ifdef WIN32
+ if (WSAGetLastError() != http->error)
+ {
+ http->error = WSAGetLastError();
+ continue;
+ }
+
+ DEBUG_printf(("httpGets: recv() error %d!\n", WSAGetLastError()));
+#else
+ DEBUG_printf(("httpGets: recv() error %d!\n", errno));
+
+ if (errno == EINTR)
+ continue;
+ else if (errno != http->error)
+ {
+ http->error = errno;
+ continue;
+ }
+#endif /* WIN32 */
+
+ return (NULL);
+ }
+ else if (bytes == 0)
+ {
+ http->error = EPIPE;
+
+ return (NULL);
+ }
+
+ /*
+ * Yup, update the amount used and the end pointer...
+ */
+
+ http->used += bytes;
+ bufend += bytes;
+ bufptr = bufend;
+ }
+ }
+ while (bufptr >= bufend && http->used < HTTP_MAX_BUFFER);
+
+ http->activity = time(NULL);
+
+ /*
+ * Read a line from the buffer...
+ */
+
+ lineptr = line;
+ bufptr = http->buffer;
+ bytes = 0;
+ length --;
+
+ while (bufptr < bufend && bytes < length)
+ {
+ bytes ++;
+
+ if (*bufptr == 0x0a)
+ {
+ bufptr ++;
+ break;
+ }
+ else if (*bufptr == 0x0d)
+ bufptr ++;
+ else
+ *lineptr++ = *bufptr++;
+ }
+
+ if (bytes > 0)
+ {
+ *lineptr = '\0';
+
+ http->used -= bytes;
+ if (http->used > 0)
+ memmove(http->buffer, bufptr, http->used);
+
+ DEBUG_printf(("httpGets: Returning \"%s\"\n", line));
+ return (line);
+ }
+
+ DEBUG_puts("httpGets: No new line available!");
+
+ return (NULL);
+}
+
+
+/*
+ * 'httpPrintf()' - Print a formatted string to a HTTP connection.
+ */
+
+int /* O - Number of bytes written */
+httpPrintf(http_t *http, /* I - HTTP data */
+ const char *format, /* I - printf-style format string */
+ ...) /* I - Additional args as needed */
+{
+ int bytes, /* Number of bytes to write */
+ nbytes, /* Number of bytes written */
+ tbytes; /* Number of bytes all together */
+ char buf[HTTP_MAX_BUFFER], /* Buffer for formatted string */
+ *bufptr; /* Pointer into buffer */
+ va_list ap; /* Variable argument pointer */
+
+
+ DEBUG_printf(("httpPrintf: httpPrintf(http=%p, format=\"%s\", ...)\n", http, format));
+
+ va_start(ap, format);
+ bytes = vsnprintf(buf, sizeof(buf), format, ap);
+ va_end(ap);
+
+ DEBUG_printf(("httpPrintf: %s", buf));
+
+ for (tbytes = 0, bufptr = buf; tbytes < bytes; tbytes += nbytes, bufptr += nbytes)
+ {
+#ifdef HAVE_SSL
+ if (http->tls)
+ nbytes = http_write_ssl(http, bufptr, bytes - tbytes);
+ else
+#endif /* HAVE_SSL */
+ nbytes = send(http->fd, bufptr, bytes - tbytes, 0);
+
+#ifdef DEBUG_HTTP
+ if (nbytes >= 0)
+ httpDumpData(stdout, "httpPrintf:", bufptr, nbytes);
+#endif
+
+ if (nbytes < 0)
+ {
+ nbytes = 0;
+
+#ifdef WIN32
+ if (WSAGetLastError() != http->error)
+ {
+ http->error = WSAGetLastError();
+ continue;
+ }
+#else
+ if (errno == EINTR)
+ continue;
+ else if (errno != http->error)
+ {
+ http->error = errno;
+ continue;
+ }
+#endif /* WIN32 */
+
+ return (-1);
+ }
+ }
+
+ return (bytes);
+}
+
+
+/*
+ * 'httpGetDateString()' - Get a formatted date/time string from a time value.
+ */
+
+const char * /* O - Date/time string */
+httpGetDateString(time_t t) /* I - UNIX time */
+{
+ struct tm *tdate;
+ static char datetime[256];
+
+
+ tdate = gmtime(&t);
+ snprintf(datetime, sizeof(datetime), "%s, %02d %s %d %02d:%02d:%02d GMT",
+ days[tdate->tm_wday], tdate->tm_mday, months[tdate->tm_mon],
+ tdate->tm_year + 1900, tdate->tm_hour, tdate->tm_min, tdate->tm_sec);
+
+ return (datetime);
+}
+
+
+/*
+ * 'httpGetDateTime()' - Get a time value from a formatted date/time string.
+ */
+
+time_t /* O - UNIX time */
+httpGetDateTime(const char *s) /* I - Date/time string */
+{
+ int i; /* Looping var */
+ struct tm tdate; /* Time/date structure */
+ char mon[16]; /* Abbreviated month name */
+ int day, year; /* Day of month and year */
+ int hour, min, sec; /* Time */
+
+
+ if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6)
+ return (0);
+
+ for (i = 0; i < 12; i ++)
+ if (strcasecmp(mon, months[i]) == 0)
+ break;
+
+ if (i >= 12)
+ return (0);
+
+ tdate.tm_mon = i;
+ tdate.tm_mday = day;
+ tdate.tm_year = year - 1900;
+ tdate.tm_hour = hour;
+ tdate.tm_min = min;
+ tdate.tm_sec = sec;
+ tdate.tm_isdst = 0;
+
+ return (mktime(&tdate));
+}
+
+
+/*
+ * 'httpUpdate()' - Update the current HTTP state for incoming data.
+ */
+
+http_status_t /* O - HTTP status */
+httpUpdate(http_t *http) /* I - HTTP data */
+{
+ char line[1024], /* Line from connection... */
+ *value; /* Pointer to value on line */
+ http_field_t field; /* Field index */
+ int major, minor, /* HTTP version numbers */
+ status; /* Request status */
+
+
+ DEBUG_printf(("httpUpdate(http=%p), state=%d\n", http, http->state));
+
+ /*
+ * If we haven't issued any commands, then there is nothing to "update"...
+ */
+
+ if (http->state == HTTP_WAITING)
+ return (HTTP_CONTINUE);
+
+ /*
+ * Grab all of the lines we can from the connection...
+ */
+
+ line[0] = '\0';
+ while (httpGets(line, sizeof(line), http) != NULL)
+ {
+ DEBUG_printf(("httpUpdate: Got \"%s\"\n", line));
+
+ if (line[0] == '\0')
+ {
+ /*
+ * Blank line means the start of the data section (if any). Return
+ * the result code, too...
+ *
+ * If we get status 100 (HTTP_CONTINUE), then we *don't* change states.
+ * Instead, we just return HTTP_CONTINUE to the caller and keep on
+ * tryin'...
+ */
+
+ if (http->status == HTTP_CONTINUE)
+ return (http->status);
+
+ if (http->status < HTTP_BAD_REQUEST)
+ http->digest_tries = 0;
+
+#ifdef HAVE_SSL
+ if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls)
+ {
+ if (http_setup_ssl(http) != 0)
+ {
+# ifdef WIN32
+ closesocket(http->fd);
+# else
+ close(http->fd);
+# endif /* WIN32 */
+
+ return (HTTP_ERROR);
+ }
+
+ return (HTTP_CONTINUE);
+ }
+#endif /* HAVE_SSL */
+
+ httpGetLength(http);
+
+ switch (http->state)
+ {
+ case HTTP_GET :
+ case HTTP_POST :
+ case HTTP_POST_RECV :
+ case HTTP_PUT :
+ http->state ++;
+ case HTTP_POST_SEND :
+ break;
+
+ default :
+ http->state = HTTP_WAITING;
+ break;
+ }
+
+ return (http->status);
+ }
+ else if (strncmp(line, "HTTP/", 5) == 0)
+ {
+ /*
+ * Got the beginning of a response...
+ */
+
+ if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3)
+ return (HTTP_ERROR);
+
+ http->version = (http_version_t)(major * 100 + minor);
+ http->status = (http_status_t)status;
+ }
+ else if ((value = strchr(line, ':')) != NULL)
+ {
+ /*
+ * Got a value...
+ */
+
+ *value++ = '\0';
+ while (isspace(*value & 255))
+ value ++;
+
+ /*
+ * Be tolerants of servers that send unknown attribute fields...
+ */
+
+ if (!strcasecmp(line, "expect"))
+ {
+ /*
+ * "Expect: 100-continue" or similar...
+ */
+
+ http->expect = (http_status_t)atoi(value);
+ }
+ else if (!strcasecmp(line, "cookie"))
+ {
+ /*
+ * "Cookie: name=value[; name=value ...]" - replaces previous cookies...
+ */
+
+ httpSetCookie(http, value);
+ }
+ else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN)
+ {
+ DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line));
+ continue;
+ }
+ else
+ httpSetField(http, field, value);
+ }
+ else
+ {
+ http->status = HTTP_ERROR;
+ return (HTTP_ERROR);
+ }
+ }
+
+ /*
+ * See if there was an error...
+ */
+
+ if (http->error == EPIPE && http->status > HTTP_CONTINUE)
+ return (http->status);
+
+ if (http->error)
+ {
+ DEBUG_printf(("httpUpdate: socket error %d - %s\n", http->error,
+ strerror(http->error)));
+ http->status = HTTP_ERROR;
+ return (HTTP_ERROR);
+ }
+
+ /*
+ * If we haven't already returned, then there is nothing new...
+ */
+
+ return (HTTP_CONTINUE);
+}
+
+
+/*
+ * 'httpDecode64()' - Base64-decode a string.
+ */
+
+char * /* O - Decoded string */
+httpDecode64(char *out, /* I - String to write to */
+ const char *in) /* I - String to read from */
+{
+ int outlen; /* Output buffer length */
+
+
+ /*
+ * Use the old maximum buffer size for binary compatibility...
+ */
+
+ outlen = 512;
+
+ return (httpDecode64_2(out, &outlen, in));
+}
+
+
+/*
+ * 'httpDecode64_2()' - Base64-decode a string.
+ */
+
+char * /* O - Decoded string */
+httpDecode64_2(char *out, /* I - String to write to */
+ int *outlen, /* IO - Size of output string */
+ const char *in) /* I - String to read from */
+{
+ int pos, /* Bit position */
+ base64; /* Value of this character */
+ char *outptr, /* Output pointer */
+ *outend; /* End of output buffer */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!out || !outlen || *outlen < 1 || !in || !*in)
+ return (NULL);
+
+ /*
+ * Convert from base-64 to bytes...
+ */
+
+ for (outptr = out, outend = out + *outlen - 1, pos = 0; *in != '\0'; in ++)
+ {
+ /*
+ * Decode this character into a number from 0 to 63...
+ */
+
+ if (*in >= 'A' && *in <= 'Z')
+ base64 = *in - 'A';
+ else if (*in >= 'a' && *in <= 'z')
+ base64 = *in - 'a' + 26;
+ else if (*in >= '0' && *in <= '9')
+ base64 = *in - '0' + 52;
+ else if (*in == '+')
+ base64 = 62;
+ else if (*in == '/')
+ base64 = 63;
+ else if (*in == '=')
+ break;
+ else
+ continue;
+
+ /*
+ * Store the result in the appropriate chars...
+ */
+
+ switch (pos)
+ {
+ case 0 :
+ if (outptr < outend)
+ *outptr = base64 << 2;
+ pos ++;
+ break;
+ case 1 :
+ if (outptr < outend)
+ *outptr++ |= (base64 >> 4) & 3;
+ if (outptr < outend)
+ *outptr = (base64 << 4) & 255;
+ pos ++;
+ break;
+ case 2 :
+ if (outptr < outend)
+ *outptr++ |= (base64 >> 2) & 15;
+ if (outptr < outend)
+ *outptr = (base64 << 6) & 255;
+ pos ++;
+ break;
+ case 3 :
+ if (outptr < outend)
+ *outptr++ |= base64;
+ pos = 0;
+ break;
+ }
+ }
+
+ *outptr = '\0';
+
+ /*
+ * Return the decoded string and size...
+ */
+
+ *outlen = (int)(outptr - out);
+
+ return (out);
+}
+
+
+/*
+ * 'httpEncode64()' - Base64-encode a string.
+ */
+
+char * /* O - Encoded string */
+httpEncode64(char *out, /* I - String to write to */
+ const char *in) /* I - String to read from */
+{
+ return (httpEncode64_2(out, 512, in, strlen(in)));
+}
+
+
+/*
+ * 'httpEncode64_2()' - Base64-encode a string.
+ */
+
+char * /* O - Encoded string */
+httpEncode64_2(char *out, /* I - String to write to */
+ int outlen, /* I - Size of output string */
+ const char *in, /* I - String to read from */
+ int inlen) /* I - Size of input string */
+{
+ char *outptr, /* Output pointer */
+ *outend; /* End of output buffer */
+ static const char base64[] = /* Base64 characters... */
+ {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "+/"
+ };
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!out || outlen < 1 || !in || inlen < 1)
+ return (NULL);
+
+ /*
+ * Convert bytes to base-64...
+ */
+
+ for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --)
+ {
+ /*
+ * Encode the up to 3 characters as 4 Base64 numbers...
+ */
+
+ if (outptr < outend)
+ *outptr ++ = base64[(in[0] & 255) >> 2];
+ if (outptr < outend)
+ *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63];
+
+ in ++;
+ inlen --;
+ if (inlen <= 0)
+ {
+ if (outptr < outend)
+ *outptr ++ = '=';
+ if (outptr < outend)
+ *outptr ++ = '=';
+ break;
+ }
+
+ if (outptr < outend)
+ *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63];
+
+ in ++;
+ inlen --;
+ if (inlen <= 0)
+ {
+ if (outptr < outend)
+ *outptr ++ = '=';
+ break;
+ }
+
+ if (outptr < outend)
+ *outptr ++ = base64[in[0] & 63];
+ }
+
+ *outptr = '\0';
+
+ /*
+ * Return the encoded string...
+ */
+
+ return (out);
+}
+
+
+/*
+ * 'httpGetLength()' - Get the amount of data remaining from the
+ * content-length or transfer-encoding fields.
+ */
+
+int /* O - Content length */
+httpGetLength(http_t *http) /* I - HTTP data */
+{
+ DEBUG_printf(("httpGetLength(http=%p), state=%d\n", http, http->state));
+
+ if (strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked") == 0)
+ {
+ DEBUG_puts("httpGetLength: chunked request!");
+
+ http->data_encoding = HTTP_ENCODE_CHUNKED;
+ http->data_remaining = 0;
+ }
+ else
+ {
+ http->data_encoding = HTTP_ENCODE_LENGTH;
+
+ /*
+ * The following is a hack for HTTP servers that don't send a
+ * content-length or transfer-encoding field...
+ *
+ * If there is no content-length then the connection must close
+ * after the transfer is complete...
+ */
+
+ if (http->fields[HTTP_FIELD_CONTENT_LENGTH][0] == '\0')
+ http->data_remaining = 2147483647;
+ else
+ http->data_remaining = atoi(http->fields[HTTP_FIELD_CONTENT_LENGTH]);
+
+ DEBUG_printf(("httpGetLength: content_length=%d\n", http->data_remaining));
+ }
+
+ return (http->data_remaining);
+}
+
+
+/*
+ * 'http_field()' - Return the field index for a field name.
+ */
+
+static http_field_t /* O - Field index */
+http_field(const char *name) /* I - String name */
+{
+ int i; /* Looping var */
+
+
+ for (i = 0; i < HTTP_FIELD_MAX; i ++)
+ if (strcasecmp(name, http_fields[i]) == 0)
+ return ((http_field_t)i);
+
+ return (HTTP_FIELD_UNKNOWN);
+}
+
+
+/*
+ * 'http_send()' - Send a request with all fields and the trailing blank line.
+ */
+
+static int /* O - 0 on success, non-zero on error */
+http_send(http_t *http, /* I - HTTP data */
+ http_state_t request, /* I - Request code */
+ const char *uri) /* I - URI */
+{
+ int i; /* Looping var */
+ char *ptr, /* Pointer in buffer */
+ buf[1024]; /* Encoded URI buffer */
+ static const char * const codes[] =
+ { /* Request code strings */
+ NULL,
+ "OPTIONS",
+ "GET",
+ NULL,
+ "HEAD",
+ "POST",
+ NULL,
+ NULL,
+ "PUT",
+ NULL,
+ "DELETE",
+ "TRACE",
+ "CLOSE"
+ };
+ static const char hex[] = "0123456789ABCDEF";
+ /* Hex digits */
+
+
+ DEBUG_printf(("http_send(http=%p, request=HTTP_%s, uri=\"%s\")\n",
+ http, codes[request], uri));
+
+ if (http == NULL || uri == NULL)
+ return (-1);
+
+ /*
+ * Encode the URI as needed...
+ */
+
+ for (ptr = buf; *uri != '\0' && ptr < (buf + sizeof(buf) - 1); uri ++)
+ if (*uri <= ' ' || *uri >= 127)
+ {
+ if (ptr < (buf + sizeof(buf) - 1))
+ *ptr ++ = '%';
+ if (ptr < (buf + sizeof(buf) - 1))
+ *ptr ++ = hex[(*uri >> 4) & 15];
+ if (ptr < (buf + sizeof(buf) - 1))
+ *ptr ++ = hex[*uri & 15];
+ }
+ else
+ *ptr ++ = *uri;
+
+ *ptr = '\0';
+
+ /*
+ * See if we had an error the last time around; if so, reconnect...
+ */
+
+ if (http->status == HTTP_ERROR || http->status >= HTTP_BAD_REQUEST)
+ httpReconnect(http);
+
+ /*
+ * Send the request header...
+ */
+
+ http->state = request;
+ if (request == HTTP_POST || request == HTTP_PUT)
+ http->state ++;
+
+ http->status = HTTP_CONTINUE;
+
+#ifdef HAVE_SSL
+ if (http->encryption == HTTP_ENCRYPT_REQUIRED && !http->tls)
+ {
+ httpSetField(http, HTTP_FIELD_CONNECTION, "Upgrade");
+ httpSetField(http, HTTP_FIELD_UPGRADE, "TLS/1.0,SSL/2.0,SSL/3.0");
+ }
+#endif /* HAVE_SSL */
+
+ if (httpPrintf(http, "%s %s HTTP/1.1\r\n", codes[request], buf) < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+
+ for (i = 0; i < HTTP_FIELD_MAX; i ++)
+ if (http->fields[i][0] != '\0')
+ {
+ DEBUG_printf(("%s: %s\n", http_fields[i], http->fields[i]));
+
+ if (httpPrintf(http, "%s: %s\r\n", http_fields[i], http->fields[i]) < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+ }
+
+ if (httpPrintf(http, "\r\n") < 1)
+ {
+ http->status = HTTP_ERROR;
+ return (-1);
+ }
+
+ httpClearFields(http);
+
+ return (0);
+}
+
+
+/*
+ * 'http_wait()' - Wait for data available on a connection.
+ */
+
+static int /* O - 1 if data is available, 0 otherwise */
+http_wait(http_t *http, /* I - HTTP data */
+ int msec) /* I - Milliseconds to wait */
+{
+#ifndef WIN32
+ struct rlimit limit; /* Runtime limit */
+#endif /* !WIN32 */
+ struct timeval timeout; /* Timeout */
+ int nfds; /* Result from select() */
+ int set_size; /* Size of select set */
+
+
+ DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec));
+
+ /*
+ * Check the SSL/TLS buffers for data first...
+ */
+
+#ifdef HAVE_SSL
+ if (http->tls)
+ {
+# ifdef HAVE_LIBSSL
+ if (SSL_pending((SSL *)(http->tls)))
+ return (1);
+# elif defined(HAVE_GNUTLS)
+ if (gnutls_record_check_pending(((http_tls_t *)(http->tls))->session))
+ return (1);
+# elif defined(HAVE_CDSASSL)
+ size_t bytes; /* Bytes that are available */
+
+ if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0)
+ return;
+# endif /* HAVE_LIBSSL */
+ }
+#endif /* HAVE_SSL */
+
+ /*
+ * Then try doing a select() to poll the socket...
+ */
+
+ if (!http->input_set)
+ {
+#ifdef WIN32
+ /*
+ * Windows has a fixed-size select() structure, different (surprise,
+ * surprise!) from all UNIX implementations. Just allocate this
+ * fixed structure...
+ */
+
+ http->input_set = calloc(1, sizeof(fd_set));
+#else
+ /*
+ * Allocate the select() input set based upon the max number of file
+ * descriptors available for this process...
+ */
+
+ getrlimit(RLIMIT_NOFILE, &limit);
+
+ set_size = (limit.rlim_cur + 31) / 8 + 4;
+ if (set_size < sizeof(fd_set))
+ set_size = sizeof(fd_set);
+
+ http->input_set = calloc(1, set_size);
+#endif /* WIN32 */
+
+ if (!http->input_set)
+ return (0);
+ }
+
+ do
+ {
+ FD_SET(http->fd, http->input_set);
+
+ if (msec >= 0)
+ {
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+
+ nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout);
+ }
+ else
+ nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL);
+ }
+#ifdef WIN32
+ while (nfds < 0 && WSAGetLastError() == WSAEINTR);
+#else
+ while (nfds < 0 && errno == EINTR);
+#endif /* WIN32 */
+
+ FD_CLR(http->fd, http->input_set);
+
+ return (nfds > 0);
+}
+
+
+#ifdef HAVE_SSL
+/*
+ * 'http_upgrade()' - Force upgrade to TLS encryption.
+ */
+
+static int /* O - Status of connection */
+http_upgrade(http_t *http) /* I - HTTP data */
+{
+ int ret; /* Return value */
+ http_t myhttp; /* Local copy of HTTP data */
+
+
+ DEBUG_printf(("http_upgrade(%p)\n", http));
+
+ /*
+ * Copy the HTTP data to a local variable so we can do the OPTIONS
+ * request without interfering with the existing request data...
+ */
+
+ memcpy(&myhttp, http, sizeof(myhttp));
+
+ /*
+ * Send an OPTIONS request to the server, requiring SSL or TLS
+ * encryption on the link...
+ */
+
+ httpClearFields(&myhttp);
+ httpSetField(&myhttp, HTTP_FIELD_CONNECTION, "upgrade");
+ httpSetField(&myhttp, HTTP_FIELD_UPGRADE, "TLS/1.0, SSL/2.0, SSL/3.0");
+
+ if ((ret = httpOptions(&myhttp, "*")) == 0)
+ {
+ /*
+ * Wait for the secure connection...
+ */
+
+ while (httpUpdate(&myhttp) == HTTP_CONTINUE);
+ }
+
+ httpFlush(&myhttp);
+
+ /*
+ * Copy the HTTP data back over, if any...
+ */
+
+ http->fd = myhttp.fd;
+ http->error = myhttp.error;
+ http->activity = myhttp.activity;
+ http->status = myhttp.status;
+ http->version = myhttp.version;
+ http->keep_alive = myhttp.keep_alive;
+ http->used = myhttp.used;
+
+ if (http->used)
+ memcpy(http->buffer, myhttp.buffer, http->used);
+
+ http->auth_type = myhttp.auth_type;
+ http->nonce_count = myhttp.nonce_count;
+
+ memcpy(http->nonce, myhttp.nonce, sizeof(http->nonce));
+
+ http->tls = myhttp.tls;
+ http->encryption = myhttp.encryption;
+
+ /*
+ * See if we actually went secure...
+ */
+
+ if (!http->tls)
+ {
+ /*
+ * Server does not support HTTP upgrade...
+ */
+
+ DEBUG_puts("Server does not support HTTP upgrade!");
+
+# ifdef WIN32
+ closesocket(http->fd);
+# else
+ close(http->fd);
+# endif
+
+ http->fd = -1;
+
+ return (-1);
+ }
+ else
+ return (ret);
+}
+
+
+/*
+ * 'http_setup_ssl()' - Set up SSL/TLS support on a connection.
+ */
+
+static int /* O - Status of connection */
+http_setup_ssl(http_t *http) /* I - HTTP data */
+{
+# ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
+# elif defined(HAVE_GNUTLS)
+ http_tls_t *conn; /* TLS session object */
+ gnutls_certificate_client_credentials *credentials;
+ /* TLS credentials */
+# elif defined(HAVE_CDSASSL)
+ SSLContextRef conn; /* Context for encryption */
+ OSStatus error; /* Error info */
+# endif /* HAVE_LIBSSL */
+
+
+ DEBUG_printf(("http_setup_ssl(http=%p)\n", http));
+
+# ifdef HAVE_LIBSSL
+ context = SSL_CTX_new(SSLv23_client_method());
+
+ SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */
+
+ conn = SSL_new(context);
+
+ SSL_set_fd(conn, http->fd);
+ if (SSL_connect(conn) != 1)
+ {
+# ifdef DEBUG
+ unsigned long error; /* Error code */
+
+ while ((error = ERR_get_error()) != 0)
+ printf("http_setup_ssl: %s\n", ERR_error_string(error, NULL));
+# endif /* DEBUG */
+
+ SSL_CTX_free(context);
+ SSL_free(conn);
+
+# ifdef WIN32
+ http->error = WSAGetLastError();
+# else
+ http->error = errno;
+# endif /* WIN32 */
+ http->status = HTTP_ERROR;
+
+ return (HTTP_ERROR);
+ }
+
+# elif defined(HAVE_GNUTLS)
+ conn = (http_tls_t *)malloc(sizeof(http_tls_t));
+
+ if (conn == NULL)
+ {
+ http->error = errno;
+ http->status = HTTP_ERROR;
+
+ return (-1);
+ }
+
+ credentials = (gnutls_certificate_client_credentials *)
+ malloc(sizeof(gnutls_certificate_client_credentials));
+ if (credentials == NULL)
+ {
+ free(conn);
+
+ http->error = errno;
+ http->status = HTTP_ERROR;
+
+ return (-1);
+ }
+
+ gnutls_certificate_allocate_credentials(credentials);
+
+ gnutls_init(&(conn->session), GNUTLS_CLIENT);
+ gnutls_set_default_priority(conn->session);
+ gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials);
+ gnutls_transport_set_ptr(conn->session, http->fd);
+
+ if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS)
+ {
+ http->error = errno;
+ http->status = HTTP_ERROR;
+
+ return (-1);
+ }
+
+ conn->credentials = credentials;
+
+# elif defined(HAVE_CDSASSL)
+ error = SSLNewContext(false, &conn);
+
+ if (!error)
+ error = SSLSetIOFuncs(conn, CDSAReadFunc, CDSAWriteFunc);
+
+ if (!error)
+ error = SSLSetConnection(conn, (SSLConnectionRef)http->fd);
+
+ if (!error)
+ error = SSLSetAllowsExpiredCerts(conn, true);
+
+ if (!error)
+ error = SSLSetAllowsAnyRoot(conn, true);
+
+ if (!error)
+ error = SSLHandshake(conn);
+
+ if (error != 0)
+ {
+ http->error = error;
+ http->status = HTTP_ERROR;
+
+ SSLDisposeContext(conn);
+
+ close(http->fd);
+
+ return (-1);
+ }
+# endif /* HAVE_CDSASSL */
+
+ http->tls = conn;
+ return (0);
+}
+
+
+/*
+ * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection.
+ */
+
+static void
+http_shutdown_ssl(http_t *http) /* I - HTTP data */
+{
+# ifdef HAVE_LIBSSL
+ SSL_CTX *context; /* Context for encryption */
+ SSL *conn; /* Connection for encryption */
+
+
+ conn = (SSL *)(http->tls);
+ context = SSL_get_SSL_CTX(conn);
+
+ SSL_shutdown(conn);
+ SSL_CTX_free(context);
+ SSL_free(conn);
+
+# elif defined(HAVE_GNUTLS)
+ http_tls_t *conn; /* Encryption session */
+ gnutls_certificate_client_credentials *credentials;
+ /* TLS credentials */
+
+
+ conn = (http_tls_t *)(http->tls);
+ credentials = (gnutls_certificate_client_credentials *)(conn->credentials);
+
+ gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(conn->session);
+ gnutls_certificate_free_credentials(*credentials);
+ free(credentials);
+ free(conn);
+
+# elif defined(HAVE_CDSASSL)
+ SSLClose((SSLContextRef)http->tls);
+ SSLDisposeContext((SSLContextRef)http->tls);
+# endif /* HAVE_LIBSSL */
+
+ http->tls = NULL;
+}
+
+
+/*
+ * 'http_read_ssl()' - Read from a SSL/TLS connection.
+ */
+
+static int /* O - Bytes read */
+http_read_ssl(http_t *http, /* I - HTTP data */
+ char *buf, /* I - Buffer to store data */
+ int len) /* I - Length of buffer */
+{
+# if defined(HAVE_LIBSSL)
+ return (SSL_read((SSL *)(http->tls), buf, len));
+
+# elif defined(HAVE_GNUTLS)
+ return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len));
+
+# elif defined(HAVE_CDSASSL)
+ OSStatus error; /* Error info */
+ size_t processed; /* Number of bytes processed */
+
+
+ error = SSLRead((SSLContextRef)http->tls, buf, len, &processed);
+
+ if (error == 0)
+ return (processed);
+ else
+ {
+ http->error = error;
+
+ return (-1);
+ }
+# endif /* HAVE_LIBSSL */
+}
+
+
+/*
+ * 'http_write_ssl()' - Write to a SSL/TLS connection.
+ */
+
+static int /* O - Bytes written */
+http_write_ssl(http_t *http, /* I - HTTP data */
+ const char *buf, /* I - Buffer holding data */
+ int len) /* I - Length of buffer */
+{
+# if defined(HAVE_LIBSSL)
+ return (SSL_write((SSL *)(http->tls), buf, len));
+
+# elif defined(HAVE_GNUTLS)
+ return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len));
+# elif defined(HAVE_CDSASSL)
+ OSStatus error; /* Error info */
+ size_t processed; /* Number of bytes processed */
+
+
+ error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed);
+
+ if (error == 0)
+ return (processed);
+ else
+ {
+ http->error = error;
+ return (-1);
+ }
+# endif /* HAVE_LIBSSL */
+}
+
+
+# if defined(HAVE_CDSASSL)
+/*
+ * 'CDSAReadFunc()' - Read function for CDSA decryption code.
+ */
+
+static OSStatus /* O - -1 on error, 0 on success */
+CDSAReadFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */
+ void *data, /* I - Data buffer */
+ size_t *dataLength) /* IO - Number of bytes */
+{
+ ssize_t bytes; /* Number of bytes read */
+
+#ifdef DEBUG_HTTP
+ httpDumpData(stdout, "CDSAReadFunc:", data, *dataLength);
+#endif
+ bytes = recv((int)connection, data, *dataLength, 0);
+ if (bytes >= 0)
+ {
+ *dataLength = bytes;
+ return (0);
+ }
+ else
+ return (-1);
+}
+
+
+/*
+ * 'CDSAWriteFunc()' - Write function for CDSA encryption code.
+ */
+
+static OSStatus /* O - -1 on error, 0 on success */
+CDSAWriteFunc(SSLConnectionRef connection, /* I - SSL/TLS connection */
+ const void *data, /* I - Data buffer */
+ size_t *dataLength) /* IO - Number of bytes */
+{
+ ssize_t bytes;
+
+
+ bytes = write((int)connection, data, *dataLength);
+ if (bytes >= 0)
+ {
+ *dataLength = bytes;
+ return (0);
+ }
+ else
+ return (-1);
+}
+# endif /* HAVE_CDSASSL */
+#endif /* HAVE_SSL */
+
+
+/*
+ * End of "$Id: http.c 148 2006-04-25 16:54:17Z njacobs $"
+ */
diff --git a/usr/src/lib/print/libhttp-core/common/http.h b/usr/src/lib/print/libhttp-core/common/http.h
new file mode 100644
index 0000000000..593b7b68f6
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/http.h
@@ -0,0 +1,439 @@
+/*
+ * "$Id: http.h 148 2006-04-25 16:54:17Z njacobs $"
+ *
+ * Hyper-Text Transport Protocol definitions for the Common UNIX Printing
+ * System (CUPS).
+ *
+ * Copyright 1997-2005 by Easy Software Products, all rights reserved.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Easy Software Products and are protected by Federal
+ * copyright law. Distribution and use rights are outlined in the file
+ * "LICENSE.txt" which should have been included with this file. If this
+ * file is missing or damaged please contact Easy Software Products
+ * at:
+ *
+ * Attn: CUPS Licensing Information
+ * Easy Software Products
+ * 44141 Airport View Drive, Suite 204
+ * Hollywood, Maryland 20636 USA
+ *
+ * Voice: (301) 373-9600
+ * EMail: cups-info@cups.org
+ * WWW: http://www.cups.org
+ *
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+#ifndef _CUPS_HTTP_H_
+#define _CUPS_HTTP_H_
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Include necessary headers...
+ */
+
+# include <string.h>
+# include <time.h>
+# ifdef WIN32
+# include <winsock.h>
+# else
+# include <unistd.h>
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# if !defined(__APPLE__) || !defined(TCP_NODELAY)
+# include <netinet/tcp.h>
+# endif /* !__APPLE__ || !TCP_NODELAY */
+# ifdef AF_LOCAL
+# include <sys/un.h>
+# endif /* AF_LOCAL */
+# endif /* WIN32 */
+
+
+/*
+ * C++ magic...
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Oh, the wonderful world of IPv6 compatibility. Apparently some
+ * implementations expose the (more logical) 32-bit address parts
+ * to everyone, while others only expose it to kernel code... To
+ * make supporting IPv6 even easier, each vendor chose different
+ * core structure and union names, so the same defines or code
+ * can't be used on all platforms.
+ *
+ * The following will likely need tweeking on new platforms that
+ * support IPv6 - the "s6_addr32" define maps to the 32-bit integer
+ * array in the in6_addr union, which is named differently on various
+ * platforms.
+ */
+
+#if defined(AF_INET6) && !defined(s6_addr32)
+# if defined(__sun)
+# define s6_addr32 _S6_un._S6_u32
+# elif defined(__FreeBSD__) || defined(__APPLE__)
+# define s6_addr32 __u6_addr.__u6_addr32
+# endif /* __sun */
+#endif /* AF_INET6 && !s6_addr32 */
+
+
+/*
+ * Limits...
+ */
+
+# define HTTP_MAX_URI 1024 /* Max length of URI string */
+# define HTTP_MAX_HOST 256 /* Max length of hostname string */
+# define HTTP_MAX_BUFFER 2048 /* Max length of data buffer */
+# define HTTP_MAX_VALUE 256 /* Max header field value length */
+
+
+/*
+ * HTTP state values...
+ */
+
+typedef enum /* States are server-oriented */
+{
+ HTTP_WAITING, /* Waiting for command */
+ HTTP_OPTIONS, /* OPTIONS command, waiting for blank line */
+ HTTP_GET, /* GET command, waiting for blank line */
+ HTTP_GET_SEND, /* GET command, sending data */
+ HTTP_HEAD, /* HEAD command, waiting for blank line */
+ HTTP_POST, /* POST command, waiting for blank line */
+ HTTP_POST_RECV, /* POST command, receiving data */
+ HTTP_POST_SEND, /* POST command, sending data */
+ HTTP_PUT, /* PUT command, waiting for blank line */
+ HTTP_PUT_RECV, /* PUT command, receiving data */
+ HTTP_DELETE, /* DELETE command, waiting for blank line */
+ HTTP_TRACE, /* TRACE command, waiting for blank line */
+ HTTP_CLOSE, /* CLOSE command, waiting for blank line */
+ HTTP_STATUS /* Command complete, sending status */
+} http_state_t;
+
+
+/*
+ * HTTP version numbers...
+ */
+
+typedef enum
+{
+ HTTP_0_9 = 9, /* HTTP/0.9 */
+ HTTP_1_0 = 100, /* HTTP/1.0 */
+ HTTP_1_1 = 101 /* HTTP/1.1 */
+} http_version_t;
+
+
+/*
+ * HTTP keep-alive values...
+ */
+
+typedef enum
+{
+ HTTP_KEEPALIVE_OFF = 0,
+ HTTP_KEEPALIVE_ON
+} http_keepalive_t;
+
+
+/*
+ * HTTP transfer encoding values...
+ */
+
+typedef enum
+{
+ HTTP_ENCODE_LENGTH, /* Data is sent with Content-Length */
+ HTTP_ENCODE_CHUNKED /* Data is chunked */
+} http_encoding_t;
+
+
+/*
+ * HTTP encryption values...
+ */
+
+typedef enum
+{
+ HTTP_ENCRYPT_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */
+ HTTP_ENCRYPT_NEVER, /* Never encrypt */
+ HTTP_ENCRYPT_REQUIRED, /* Encryption is required (TLS upgrade) */
+ HTTP_ENCRYPT_ALWAYS /* Always encrypt (SSL) */
+} http_encryption_t;
+
+
+/*
+ * HTTP authentication types...
+ */
+
+typedef enum
+{
+ HTTP_AUTH_NONE, /* No authentication in use */
+ HTTP_AUTH_BASIC, /* Basic authentication in use */
+ HTTP_AUTH_MD5, /* Digest authentication in use */
+ HTTP_AUTH_MD5_SESS, /* MD5-session authentication in use */
+ HTTP_AUTH_MD5_INT, /* Digest authentication in use for body */
+ HTTP_AUTH_MD5_SESS_INT /* MD5-session authentication in use for body */
+} http_auth_t;
+
+
+/*
+ * HTTP status codes...
+ */
+
+typedef enum
+{
+ HTTP_ERROR = -1, /* An error response from httpXxxx() */
+
+ HTTP_CONTINUE = 100, /* Everything OK, keep going... */
+ HTTP_SWITCHING_PROTOCOLS, /* HTTP upgrade to TLS/SSL */
+
+ HTTP_OK = 200, /* OPTIONS/GET/HEAD/POST/TRACE command was successful */
+ HTTP_CREATED, /* PUT command was successful */
+ HTTP_ACCEPTED, /* DELETE command was successful */
+ HTTP_NOT_AUTHORITATIVE, /* Information isn't authoritative */
+ HTTP_NO_CONTENT, /* Successful command, no new data */
+ HTTP_RESET_CONTENT, /* Content was reset/recreated */
+ HTTP_PARTIAL_CONTENT, /* Only a partial file was recieved/sent */
+
+ HTTP_MULTIPLE_CHOICES = 300, /* Multiple files match request */
+ HTTP_MOVED_PERMANENTLY, /* Document has moved permanently */
+ HTTP_MOVED_TEMPORARILY, /* Document has moved temporarily */
+ HTTP_SEE_OTHER, /* See this other link... */
+ HTTP_NOT_MODIFIED, /* File not modified */
+ HTTP_USE_PROXY, /* Must use a proxy to access this URI */
+
+ HTTP_BAD_REQUEST = 400, /* Bad request */
+ HTTP_UNAUTHORIZED, /* Unauthorized to access host */
+ HTTP_PAYMENT_REQUIRED, /* Payment required */
+ HTTP_FORBIDDEN, /* Forbidden to access this URI */
+ HTTP_NOT_FOUND, /* URI was not found */
+ HTTP_METHOD_NOT_ALLOWED, /* Method is not allowed */
+ HTTP_NOT_ACCEPTABLE, /* Not Acceptable */
+ HTTP_PROXY_AUTHENTICATION, /* Proxy Authentication is Required */
+ HTTP_REQUEST_TIMEOUT, /* Request timed out */
+ HTTP_CONFLICT, /* Request is self-conflicting */
+ HTTP_GONE, /* Server has gone away */
+ HTTP_LENGTH_REQUIRED, /* A content length or encoding is required */
+ HTTP_PRECONDITION, /* Precondition failed */
+ HTTP_REQUEST_TOO_LARGE, /* Request entity too large */
+ HTTP_URI_TOO_LONG, /* URI too long */
+ HTTP_UNSUPPORTED_MEDIATYPE, /* The requested media type is unsupported */
+ HTTP_UPGRADE_REQUIRED = 426, /* Upgrade to SSL/TLS required */
+
+ HTTP_SERVER_ERROR = 500, /* Internal server error */
+ HTTP_NOT_IMPLEMENTED, /* Feature not implemented */
+ HTTP_BAD_GATEWAY, /* Bad gateway */
+ HTTP_SERVICE_UNAVAILABLE, /* Service is unavailable */
+ HTTP_GATEWAY_TIMEOUT, /* Gateway connection timed out */
+ HTTP_NOT_SUPPORTED /* HTTP version not supported */
+} http_status_t;
+
+
+/*
+ * HTTP field names...
+ */
+
+typedef enum
+{
+ HTTP_FIELD_UNKNOWN = -1,
+ HTTP_FIELD_ACCEPT_LANGUAGE,
+ HTTP_FIELD_ACCEPT_RANGES,
+ HTTP_FIELD_AUTHORIZATION,
+ HTTP_FIELD_CONNECTION,
+ HTTP_FIELD_CONTENT_ENCODING,
+ HTTP_FIELD_CONTENT_LANGUAGE,
+ HTTP_FIELD_CONTENT_LENGTH,
+ HTTP_FIELD_CONTENT_LOCATION,
+ HTTP_FIELD_CONTENT_MD5,
+ HTTP_FIELD_CONTENT_RANGE,
+ HTTP_FIELD_CONTENT_TYPE,
+ HTTP_FIELD_CONTENT_VERSION,
+ HTTP_FIELD_DATE,
+ HTTP_FIELD_HOST,
+ HTTP_FIELD_IF_MODIFIED_SINCE,
+ HTTP_FIELD_IF_UNMODIFIED_SINCE,
+ HTTP_FIELD_KEEP_ALIVE,
+ HTTP_FIELD_LAST_MODIFIED,
+ HTTP_FIELD_LINK,
+ HTTP_FIELD_LOCATION,
+ HTTP_FIELD_RANGE,
+ HTTP_FIELD_REFERER,
+ HTTP_FIELD_RETRY_AFTER,
+ HTTP_FIELD_TRANSFER_ENCODING,
+ HTTP_FIELD_UPGRADE,
+ HTTP_FIELD_USER_AGENT,
+ HTTP_FIELD_WWW_AUTHENTICATE,
+ HTTP_FIELD_MAX
+} http_field_t;
+
+
+/*
+ * HTTP address structure (makes using IPv6 a little easier and more portable.)
+ */
+
+typedef union
+{
+ struct sockaddr addr; /* Base structure for family value */
+ struct sockaddr_in ipv4; /* IPv4 address */
+#ifdef AF_INET6
+ struct sockaddr_in6 ipv6; /* IPv6 address */
+#endif /* AF_INET6 */
+#ifdef AF_LOCAL
+ struct sockaddr_un un; /* Domain socket file */
+#endif /* AF_LOCAL */
+ char pad[128]; /* Pad to ensure binary compatibility */
+} http_addr_t;
+
+/*
+ * HTTP connection structure...
+ */
+
+typedef struct
+{
+ int fd; /* File descriptor for this socket */
+ int blocking; /* To block or not to block */
+ int error; /* Last error on read */
+ time_t activity; /* Time since last read/write */
+ http_state_t state; /* State of client */
+ http_status_t status; /* Status of last request */
+ http_version_t version; /* Protocol version */
+ http_keepalive_t keep_alive; /* Keep-alive supported? */
+ struct sockaddr_in oldaddr; /* Address of connected host */
+ char hostname[HTTP_MAX_HOST],
+ /* Name of connected host */
+ fields[HTTP_FIELD_MAX][HTTP_MAX_VALUE];
+ /* Field values */
+ char *data; /* Pointer to data buffer */
+ http_encoding_t data_encoding; /* Chunked or not */
+ int data_remaining; /* Number of bytes left */
+ int used; /* Number of bytes used in buffer */
+ char buffer[HTTP_MAX_BUFFER];
+ /* Buffer for messages */
+ int auth_type; /* Authentication in use */
+ char nonce[HTTP_MAX_VALUE];
+ /* Nonce value */
+ int nonce_count; /* Nonce count */
+ void *tls; /* TLS state information */
+ http_encryption_t encryption; /* Encryption requirements */
+ /**** New in CUPS 1.1.19 ****/
+ fd_set *input_set; /* select() set for httpWait() */
+ http_status_t expect; /* Expect: header */
+ char *cookie; /* Cookie value(s) */
+ /**** New in CUPS 1.1.20 ****/
+ char authstring[HTTP_MAX_VALUE],
+ /* Current Authentication value */
+ userpass[HTTP_MAX_VALUE];
+ /* Username:password string */
+ int digest_tries; /* Number of tries for digest auth */
+ /**** New in CUPS 1.2 ****/
+ http_addr_t hostaddr; /* Host address and port */
+} http_t;
+
+
+/*
+ * Prototypes...
+ */
+
+# define httpBlocking(http,b) (http)->blocking = (b)
+extern int httpCheck(http_t *http);
+# define httpClearFields(http) memset((http)->fields, 0, sizeof((http)->fields)),\
+ httpSetField((http), HTTP_FIELD_HOST, (http)->hostname)
+extern void httpClose(http_t *http);
+extern http_t *httpConnect(const char *host, int port);
+extern http_t *httpConnectEncrypt(const char *host, int port,
+ http_encryption_t encrypt);
+extern int httpDelete(http_t *http, const char *uri);
+extern int httpEncryption(http_t *http, http_encryption_t e);
+# define httpError(http) ((http)->error)
+extern void httpFlush(http_t *http);
+extern int httpGet(http_t *http, const char *uri);
+extern char *httpGets(char *line, int length, http_t *http);
+extern const char *httpGetDateString(time_t t);
+extern time_t httpGetDateTime(const char *s);
+# define httpGetField(http,field) (http)->fields[field]
+extern struct hostent *httpGetHostByName(const char *name);
+extern char *httpGetSubField(http_t *http, http_field_t field,
+ const char *name, char *value);
+extern int httpHead(http_t *http, const char *uri);
+extern void httpInitialize(void);
+extern int httpOptions(http_t *http, const char *uri);
+extern int httpPost(http_t *http, const char *uri);
+extern int httpPrintf(http_t *http, const char *format, ...)
+# ifdef __GNUC__
+__attribute__ ((__format__ (__printf__, 2, 3)))
+# endif /* __GNUC__ */
+;
+extern int httpPut(http_t *http, const char *uri);
+extern int httpRead(http_t *http, char *buffer, int length);
+extern int httpReconnect(http_t *http);
+extern void httpSeparate(const char *uri, char *method,
+ char *username, char *host, int *port,
+ char *resource);
+extern void httpSetField(http_t *http, http_field_t field,
+ const char *value);
+extern const char *httpStatus(http_status_t status);
+extern int httpTrace(http_t *http, const char *uri);
+extern http_status_t httpUpdate(http_t *http);
+extern int httpWrite(http_t *http, const char *buffer, int length);
+extern char *httpEncode64(char *out, const char *in);
+extern char *httpDecode64(char *out, const char *in);
+extern int httpGetLength(http_t *http);
+extern char *httpMD5(const char *, const char *, const char *,
+ char [33]);
+extern char *httpMD5Final(const char *, const char *, const char *,
+ char [33]);
+extern char *httpMD5String(const unsigned char *, char [33]);
+
+/**** New in CUPS 1.1.19 ****/
+extern void httpClearCookie(http_t *http);
+#define httpGetCookie(http) ((http)->cookie)
+extern void httpSetCookie(http_t *http, const char *cookie);
+extern int httpWait(http_t *http, int msec);
+
+/**** New in CUPS 1.1.21 ****/
+extern char *httpDecode64_2(char *out, int *outlen, const char *in);
+extern char *httpEncode64_2(char *out, int outlen, const char *in,
+ int inlen);
+extern void httpSeparate2(const char *uri,
+ char *method, int methodlen,
+ char *username, int usernamelen,
+ char *host, int hostlen, int *port,
+ char *resource, int resourcelen);
+
+/**** New in CUPS 1.2 ****/
+extern int httpAddrAny(const http_addr_t *addr);
+extern int httpAddrEqual(const http_addr_t *addr1,
+ const http_addr_t *addr2);
+extern void httpAddrLoad(const struct hostent *host, int port,
+ int n, http_addr_t *addr);
+extern int httpAddrLocalhost(const http_addr_t *addr);
+extern char *httpAddrLookup(const http_addr_t *addr,
+ char *name, int namelen);
+extern char *httpAddrString(const http_addr_t *addr,
+ char *s, int slen);
+
+#include <stdio.h>
+extern void httpDumpData(FILE *, const char *, const char *, int);
+
+
+/*
+ * C++ magic...
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_CUPS_HTTP_H_ */
+
+/*
+ * End of "$Id: http.h 148 2006-04-25 16:54:17Z njacobs $"
+ */
diff --git a/usr/src/lib/print/libhttp-core/common/mapfile b/usr/src/lib/print/libhttp-core/common/mapfile
new file mode 100644
index 0000000000..1d641d73e1
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/common/mapfile
@@ -0,0 +1,71 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# $Id: mapfile.in,v 1.2 2006/03/02 06:31:36 njacobs Exp $
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+#
+# Common interfaces that are most likely to be shared amongst the various
+# PAPI implementations.
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate_1.0 {
+ global:
+ httpCheck ;
+ httpClose ;
+ httpConnectEncrypt ;
+ httpDumpData ;
+ httpEncode64 ;
+ httpEncryption ;
+ httpFlush ;
+ httpGetSubField ;
+ httpPost ;
+ httpRead ;
+ httpReconnect ;
+ httpSetField ;
+ httpUpdate ;
+ httpWait ;
+ httpWrite ;
+
+ local:
+ * ;
+} ;
diff --git a/usr/src/lib/print/libhttp-core/i386/Makefile b/usr/src/lib/print/libhttp-core/i386/Makefile
new file mode 100644
index 0000000000..0bc3313291
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/print/libhttp-core/sparc/Makefile b/usr/src/lib/print/libhttp-core/sparc/Makefile
new file mode 100644
index 0000000000..0bc3313291
--- /dev/null
+++ b/usr/src/lib/print/libhttp-core/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS)
diff --git a/usr/src/lib/print/libipp-core/Makefile b/usr/src/lib/print/libipp-core/Makefile
new file mode 100644
index 0000000000..b92d620b10
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+#HDRS = papi.h
+#HDRDIR = common
+SUBDIRS = $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install: .WAIT $(SUBDIRS)
+
+lint: # $(SUBDIRS)
+
+install_h: # $(ROOTHDRS)
+
+check: # $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/libipp-core/Makefile.com b/usr/src/lib/print/libipp-core/Makefile.com
new file mode 100644
index 0000000000..26f48c2dbb
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/Makefile.com
@@ -0,0 +1,59 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = libipp-core.a
+VERS = .0
+OBJECTS = ipp.o ipp_types.o read.o strings.o write.o
+
+include ../../../Makefile.lib
+include ../../../Makefile.rootfs
+
+SRCDIR = ../common
+
+ROOTLIBDIR= $(ROOT)/usr/lib
+
+LIBS = $(DYNLIB)
+
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR)
+CPPFLAGS += -I../../libpapi-common/common
+
+CERRWARN += -_gcc=-Wno-unused-variable
+CERRWARN += -_gcc=-Wno-char-subscripts
+CERRWARN += -_gcc=-Wno-switch
+
+MAPFILES = $(SRCDIR)/mapfile
+
+LDLIBS += -lpapi-common -lc
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/print/libipp-core/common/ipp.c b/usr/src/lib/print/libipp-core/common/ipp.c
new file mode 100644
index 0000000000..133fb0ad13
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/common/ipp.c
@@ -0,0 +1,136 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: ipp.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <papi.h>
+#include "ipp.h"
+
+/*
+ * IPP requests/responses are represented as attribute lists. An IPP request
+ * attribute list will contain header information attributes:
+ * version-major (int)
+ * version-minor (int)
+ * request-id (int)
+ * operation-id (int)
+ * It will also contain 1 or more attribute groups (collections)
+ * operational-attribute-group
+ * ...
+ * this routine validates that the request falls within the guidelines of
+ * the protocol specification (or some other level of conformance if the
+ * restrictions have been specified at the top level of the request using
+ * a "conformance" attribute.
+ */
+papi_status_t
+ipp_validate_request(papi_attribute_t **request, papi_attribute_t ***response)
+{
+ papi_attribute_t **attributes = NULL;
+ papi_status_t result = PAPI_OK;
+ char *s;
+
+ if ((request == NULL) || (response == NULL) || (*response == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* validate the operational attributes group */
+ result = papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &attributes);
+ if (result != PAPI_OK) {
+ ipp_set_status(response, result,
+ "operational attribute group: %s",
+ papiStatusString(result));
+ return (result);
+ }
+
+ result = papiAttributeListGetString(attributes, NULL,
+ "attributes-charset", &s);
+ if (result != PAPI_OK) {
+ ipp_set_status(response, result, "attributes-charset: %s",
+ papiStatusString(result));
+ return (result);
+ }
+
+ result = papiAttributeListGetString(attributes, NULL,
+ "attributes-natural-language", &s);
+ if (result != PAPI_OK) {
+ ipp_set_status(response, result,
+ "attributes-natural-language: %s",
+ papiStatusString(result));
+ return (result);
+ }
+
+ return (result);
+}
+
+/*
+ * Add/Modify the statuse-code and status-message in an IPP response's
+ * operational attributes group.
+ */
+void
+ipp_set_status(papi_attribute_t ***message, papi_status_t status,
+ char *format, ...)
+{
+ if (message == NULL)
+ return;
+
+ if (format != NULL) {
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **saved;
+ char mesg[256]; /* status-message is type text(255) */
+ va_list ap;
+
+ (void) papiAttributeListGetCollection(*message, NULL,
+ "operational-attributes-group",
+ &operational);
+ saved = operational;
+
+ va_start(ap, format);
+ (void) vsnprintf(mesg, sizeof (mesg), format, ap);
+ va_end(ap);
+
+ (void) papiAttributeListAddString(&operational,
+ PAPI_ATTR_APPEND, "status-message", mesg);
+
+ /*
+ * We need to check and see if adding the status-message caused
+ * the operational attributes group to be relocated in memory.
+ * If it has been, we will need to re-add the collection to
+ * the message.
+ */
+ if (saved != operational)
+ (void) papiAttributeListAddCollection(message,
+ PAPI_ATTR_REPLACE,
+ "operational-attributes-group",
+ operational);
+ }
+
+ (void) papiAttributeListAddInteger(message, PAPI_ATTR_APPEND,
+ "status-code", status);
+}
diff --git a/usr/src/lib/print/libipp-core/common/ipp.h b/usr/src/lib/print/libipp-core/common/ipp.h
new file mode 100644
index 0000000000..c13728e334
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/common/ipp.h
@@ -0,0 +1,348 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _IPP_H
+#define _IPP_H
+
+/* $Id: ipp.h 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <sys/time.h>
+#include <papi.h>
+#include <inttypes.h>
+
+
+typedef ssize_t (*ipp_reader_t)(void *fd, void *buffer, size_t buffer_size);
+typedef ssize_t (*ipp_writer_t)(void *fd, void *buffer, size_t buffer_size);
+
+enum {
+ IPP_TYPE_UNKNOWN = 0,
+ IPP_TYPE_REQUEST = 1,
+ IPP_TYPE_RESPONSE = 2
+};
+
+/*
+ * How closely do we conform to the spec when parsing? Do we
+ * a) Stop parsing only when we encounter an error that prevents us from
+ * continuing parsing (a server error or ridiculously malformed request)?
+ * b) Stop parsing when we know the server wouldn't be able to act on the
+ * response correctly, even if we can make sense of some of the data?
+ * c) Jawohl, Mein IPP Spec!
+ * The answer will usually be b, though a will be useful for debugging.
+ */
+enum {
+ IPP_PARSE_CONFORMANCE_RASH = 0,
+ IPP_PARSE_CONFORMANCE_LOOSE = 1,
+ IPP_PARSE_CONFORMANCE_STRICT = 2
+};
+
+
+/* Operation IDs */
+enum {
+ OPID_MIN = 0x0000, /* 0x0000 */
+ OPID_RESERVED_0000 = 0x0000, /* 0x0000 */
+ OPID_RESERVED_0001, /* 0x0001 */
+ OPID_PRINT_JOB, /* 0x0002 */
+ OPID_PRINT_URI, /* 0x0003 */
+ OPID_VALIDATE_JOB, /* 0x0004 */
+ OPID_CREATE_JOB, /* 0x0005 */
+ OPID_SEND_DOCUMENT, /* 0x0006 */
+ OPID_SEND_URI, /* 0x0007 */
+ OPID_CANCEL_JOB, /* 0x0008 */
+ OPID_GET_JOB_ATTRIBUTES, /* 0x0009 */
+ OPID_GET_JOBS, /* 0x000a */
+ OPID_GET_PRINTER_ATTRIBUTES, /* 0x000b */
+ OPID_HOLD_JOB, /* 0x000c */
+ OPID_RELEASE_JOB, /* 0x000d */
+ OPID_RESTART_JOB, /* 0x000e */
+ OPID_RESERVED_000F, /* 0x000f */
+ OPID_PAUSE_PRINTER, /* 0x0010 */
+ OPID_RESUME_PRINTER, /* 0x0011 */
+ OPID_PURGE_JOBS, /* 0x0012 */
+ OPID_SET_PRINTER_ATTRIBUTES, /* 0x0013 */
+ OPID_SET_JOB_ATTRIBUTES, /* 0x0014 */
+ OPID_GET_PRINTER_SUPPORTED_VALUES, /* 0x0015 */
+ OPID_CREATE_PRINTER_SUBSCRIPTION, /* 0x0016 */
+ OPID_CREATE_JOB_SUBSCRIPTION, /* 0x0017 */
+ OPID_GET_SUBSCRIPTION_ATTRIBUTES, /* 0x0018 */
+ OPID_GET_SUBSCRIPTIONS, /* 0x0019 */
+ OPID_RENEW_SUBSCRIPTION, /* 0x001a */
+ OPID_CANCEL_SUBSCRIPTION, /* 0x001b */
+ OPID_GET_NOTIFICATIONS, /* 0x001c */
+ OPID_SEND_NOTIFICATIONS, /* 0x001d */
+ OPID_GET_RESOURCE_ATTRIBUTES, /* 0x001e */
+ OPID_GET_RESOURCE_DATA, /* 0x001f */
+ OPID_GET_RESOURCES, /* 0x0020 */
+ OPID_GET_PRINT_SUPPORT_FILES, /* 0x0021 */
+ OPID_ENABLE_PRINTER, /* 0x0022 */
+ OPID_DISABLE_PRINTER, /* 0x0023 */
+ OPID_PAUSE_PRINTER_AFTER_CURRENT_JOB, /* 0x0024 */
+ OPID_HOLD_NEW_JOBS, /* 0x0025 */
+ OPID_RELEASE_HELD_NEW_JOBS, /* 0x0026 */
+ OPID_DEACTIVATE_PRINTER, /* 0x0027 */
+ OPID_ACTIVATE_PRINTER, /* 0x0028 */
+ OPID_RESTART_PRINTER, /* 0x0029 */
+ OPID_SHUTDOWN_PRINTER, /* 0x002a */
+ OPID_STARTUP_PRINTER, /* 0x002b */
+ OPID_REPROCESS_JOB, /* 0x002c */
+ OPID_CANCEL_CURRENT_JOB, /* 0x002d */
+ OPID_SUSPEND_CURRENT_JOB, /* 0x002e */
+ OPID_RESUME_JOB, /* 0x002f */
+ OPID_PROMOTE_JOB, /* 0x0030 */
+ OPID_SCHEDULE_JOB_AFTER, /* 0x0031 */
+ OPID_RESERVED_MIN, /* 0x0032 */
+ OPID_RESERVED_0032 = 0x0032, /* 0x0032 */
+ /* ... */
+ OPID_RESERVED_3FFF = 0x3fff, /* 0x3fff */
+ OPID_RESERVED_MAX = 0x3fff, /* 0x3fff */
+ OPID_RESERVED_VENDOR_MIN = 0x4000, /* 0x4000 */
+ OPID_RESERVED_VENDOR_4000 = 0x4000, /* 0x4000 */
+ /* ... */
+ OPID_RESERVED_VENDOR_8FFF = 0x8fff, /* 0x8fff */
+ OPID_RESERVED_VENDOR_MAX = 0x8fff, /* 0x8fff */
+ OPID_MAX = 0x8fff /* 0x8fff */
+};
+
+enum {
+ /* Delimiter Tags */
+ DTAG_MIN = 0x00, /* 0x00 */
+ DTAG_RESERVED_DELIMITER_00 = 0x00, /* 0x00 */
+ DTAG_OPERATION_ATTRIBUTES, /* 0x01 */
+ DTAG_JOB_ATTRIBUTES, /* 0x02 */
+ DTAG_END_OF_ATTRIBUTES, /* 0x03 */
+ DTAG_PRINTER_ATTRIBUTES, /* 0x04 */
+ DTAG_UNSUPPORTED_ATTRIBUTES, /* 0x05 */
+ DTAG_SUBSCRIPTION_ATTRIBUTES, /* 0x06 */
+ DTAG_EVENT_NOTIFICATION_ATTRIBUTES, /* 0x07 */
+ DTAG_RESERVED_DELIMITER_08, /* 0x08 */
+ DTAG_RESERVED_DELIMITER_09, /* 0x09 */
+ DTAG_RESERVED_DELIMITER_0A, /* 0x0a */
+ DTAG_RESERVED_DELIMITER_0B, /* 0x0b */
+ DTAG_RESERVED_DELIMITER_0C, /* 0x0c */
+ DTAG_RESERVED_DELIMITER_0D, /* 0x0d */
+ DTAG_RESERVED_DELIMITER_0E, /* 0x0e */
+ DTAG_RESERVED_DELIMITER_0F, /* 0x0f */
+ DTAG_MAX = 0x0f, /* 0x0f */
+
+ /* Value Tags */
+ VTAG_MIN = 0x10, /* 0x10 */
+ VTAG_UNSUPPORTED = 0x10, /* 0x10 */
+ VTAG_RESERVED_DEFAULT, /* 0x11 */
+ VTAG_UNKNOWN, /* 0x12 */
+ VTAG_NOVALUE, /* 0x13 */
+ VTAG_RESERVED_OOB_14, /* 0x14 */
+ VTAG_NOT_SETTABLE, /* 0x15 */
+ VTAG_DELETE_ATTRIBUTE, /* 0x16 */
+ VTAG_ADMIN_DEFINE, /* 0x17 */
+ VTAG_RESERVED_OOB_18, /* 0x18 */
+ VTAG_RESERVED_OOB_19, /* 0x19 */
+ VTAG_RESERVED_OOB_1A, /* 0x1a */
+ VTAG_RESERVED_OOB_1B, /* 0x1b */
+ VTAG_RESERVED_OOB_1C, /* 0x1c */
+ VTAG_RESERVED_OOB_1D, /* 0x1d */
+ VTAG_RESERVED_OOB_1E, /* 0x1e */
+ VTAG_RESERVED_OOB_1F, /* 0x1f */
+ VTAG_RESERVED_INT_GEN, /* 0x20 */
+ VTAG_INTEGER, /* 0x21 */
+ VTAG_BOOLEAN, /* 0x22 */
+ VTAG_ENUM, /* 0x23 */
+ VTAG_RESERVED_INT_24, /* 0x24 */
+ VTAG_RESERVED_INT_25, /* 0x25 */
+ VTAG_RESERVED_INT_26, /* 0x26 */
+ VTAG_RESERVED_INT_27, /* 0x27 */
+ VTAG_RESERVED_INT_28, /* 0x28 */
+ VTAG_RESERVED_INT_29, /* 0x29 */
+ VTAG_RESERVED_INT_2A, /* 0x2a */
+ VTAG_RESERVED_INT_2B, /* 0x2b */
+ VTAG_RESERVED_INT_2C, /* 0x2c */
+ VTAG_RESERVED_INT_2D, /* 0x2d */
+ VTAG_RESERVED_INT_2E, /* 0x2e */
+ VTAG_RESERVED_INT_2F, /* 0x2f */
+ VTAG_OCTET_STRING, /* 0x30 */
+ VTAG_DATE_TIME, /* 0x31 */
+ VTAG_RESOLUTION, /* 0x32 */
+ VTAG_RANGE_OF_INTEGER, /* 0x33 */
+ VTAG_BEGIN_COLLECTION, /* 0x34 */
+ VTAG_TEXT_WITH_LANGUAGE, /* 0x35 */
+ VTAG_NAME_WITH_LANGUAGE, /* 0x36 */
+ VTAG_END_COLLECTION, /* 0x37 */
+ VTAG_RESERVED_STRING_38, /* 0x38 */
+ VTAG_RESERVED_STRING_39, /* 0x39 */
+ VTAG_RESERVED_STRING_3A, /* 0x3a */
+ VTAG_RESERVED_STRING_3B, /* 0x3b */
+ VTAG_RESERVED_STRING_3C, /* 0x3c */
+ VTAG_RESERVED_STRING_3D, /* 0x3d */
+ VTAG_RESERVED_STRING_3E, /* 0x3e */
+ VTAG_RESERVED_STRING_3F, /* 0x3f */
+ VTAG_RESERVED_CHAR_GEN, /* 0x40 */
+ VTAG_TEXT_WITHOUT_LANGUAGE, /* 0x41 */
+ VTAG_NAME_WITHOUT_LANGUAGE, /* 0x42 */
+ VTAG_RESERVED_43, /* 0x43 */
+ VTAG_KEYWORD, /* 0x44 */
+ VTAG_URI, /* 0x45 */
+ VTAG_URI_SCHEME, /* 0x46 */
+ VTAG_CHARSET, /* 0x47 */
+ VTAG_NATURAL_LANGUAGE, /* 0x48 */
+ VTAG_MIME_MEDIA_TYPE, /* 0x49 */
+ VTAG_MEMBER_ATTR_NAME, /* 0x4a */
+ VTAG_RESERVED_STRING_4B, /* 0x4b */
+ VTAG_RESERVED_STRING_4C, /* 0x4c */
+ VTAG_RESERVED_STRING_4D, /* 0x4d */
+ VTAG_RESERVED_STRING_4E, /* 0x4e */
+ VTAG_RESERVED_STRING_4F, /* 0x4f */
+ VTAG_RESERVED_STRING_50, /* 0x50 */
+ VTAG_RESERVED_STRING_51, /* 0x51 */
+ VTAG_RESERVED_STRING_52, /* 0x52 */
+ VTAG_RESERVED_STRING_53, /* 0x53 */
+ VTAG_RESERVED_STRING_54, /* 0x54 */
+ VTAG_RESERVED_STRING_55, /* 0x55 */
+ VTAG_RESERVED_STRING_56, /* 0x56 */
+ VTAG_RESERVED_STRING_57, /* 0x57 */
+ VTAG_RESERVED_STRING_58, /* 0x58 */
+ VTAG_RESERVED_STRING_59, /* 0x59 */
+ VTAG_RESERVED_STRING_5A, /* 0x5a */
+ VTAG_RESERVED_STRING_5B, /* 0x5b */
+ VTAG_RESERVED_STRING_5C, /* 0x5c */
+ VTAG_RESERVED_STRING_5D, /* 0x5d */
+ VTAG_RESERVED_STRING_5E, /* 0x5e */
+ VTAG_RESERVED_STRING_5F, /* 0x5f */
+ VTAG_RESERVED_MAX = 0x5f, /* 0x5f */
+ VTAG_MAX = 0x5f, /* 0x5f */
+ VTAG_EXTEND = 0x7f /* 0x7f */
+};
+
+/* Response codes */
+enum {
+ IPP_OK_MIN = 0x0000,
+ IPP_OK = 0x0000, /* 0x0000 */
+ IPP_OK_IGNORED_ATTRIBUTES, /* 0x0001 */
+ IPP_OK_CONFLICTING_ATTRIBUTES, /* 0x0002 */
+ IPP_OK_IGNORED_SUBSCRIPTIONS, /* 0x0003 */
+ IPP_OK_IGNORED_NOTIFICATIONS, /* 0x0004 */
+ IPP_OK_TOO_MANY_EVENTS, /* 0x0005 */
+ IPP_OK_BUT_CANCEL_SUBSCRIPTION, /* 0x0006 */
+ IPP_OK_MAX = IPP_OK_BUT_CANCEL_SUBSCRIPTION,
+
+ IPP_REDIR_MIN = 0x0300,
+ IPP_REDIR_OTHER_SIZE = 0x0300, /* 0x0300 */
+ IPP_REDIR_MAX = 0x0300,
+
+ IPP_CERR_MIN = 0x0400,
+ IPP_CERR_BAD_REQUEST = 0x0400, /* 0x0400 */
+ IPP_CERR_FORBIDDEN, /* 0x0401 */
+ IPP_CERR_NOT_AUTHENTICATED, /* 0x0402 */
+ IPP_CERR_NOT_AUTHORIZED, /* 0x0403 */
+ IPP_CERR_NOT_POSSIBLE, /* 0x0404 */
+ IPP_CERR_TIMEOUT, /* 0x0405 */
+ IPP_CERR_NOT_FOUND, /* 0x0406 */
+ IPP_CERR_GONE, /* 0x0407 */
+ IPP_CERR_REQUEST_ENTITY, /* 0x0408 */
+ IPP_CERR_REQUEST_VALUE, /* 0x0409 */
+ IPP_CERR_DOCUMENT_FORMAT, /* 0x040a */
+ IPP_CERR_ATTRIBUTES, /* 0x040b */
+ IPP_CERR_URI_SCHEME, /* 0x040c */
+ IPP_CERR_CHARSET, /* 0x040d */
+ IPP_CERR_CONFLICT, /* 0x040e */
+ IPP_CERR_COMPRESSION_NOT_SUPPORTED, /* 0x040f */
+ IPP_CERR_COMPRESSION_ERROR, /* 0x0410 */
+ IPP_CERR_DOCUMENT_FORMAT_ERROR, /* 0x0411 */
+ IPP_CERR_DOCUMENT_ACCESS_ERROR, /* 0x0412 */
+ IPP_CERR_ATTRIBUTES_NOT_SETTABLE, /* 0x0413 */
+ IPP_CERR_IGNORED_ALL_SUBSCRIPTIONS, /* 0x0414 */
+ IPP_CERR_TOO_MANY_SUBSCRIPTIONS, /* 0x0415 */
+ IPP_CERR_IGNORED_ALL_NOTIFICATIONS, /* 0x0416 */
+ IPP_CERR_PRINT_SUPPORT_FILE_NOT_FOUND, /* 0x0417 */
+ IPP_CERR_MAX = IPP_CERR_PRINT_SUPPORT_FILE_NOT_FOUND,
+
+ IPP_SERR_MIN = 0x0500,
+ IPP_SERR_INTERNAL = 0x0500, /* 0x0500 */
+ IPP_SERR_OPERATION_NOT_SUPPORTED, /* 0x0501 */
+ IPP_SERR_SERVICE_UNAVAILABLE, /* 0x0502 */
+ IPP_SERR_VERSION_NOT_SUPPORTED, /* 0x0503 */
+ IPP_SERR_DEVICE_ERROR, /* 0x0504 */
+ IPP_SERR_TEMPORARY_ERROR, /* 0x0505 */
+ IPP_SERR_NOT_ACCEPTING, /* 0x0506 */
+ IPP_SERR_BUSY, /* 0x0507 */
+ IPP_SERR_CANCELLED, /* 0x0508 */
+ IPP_SERR_MULTIPLE_DOCS_NOT_SUPPORTED, /* 0x0509 */
+ IPP_SERR_PRINTER_IS_DEACTIVATED, /* 0x050a */
+ IPP_SERR_MAX = IPP_SERR_PRINTER_IS_DEACTIVATED
+};
+
+/* Job state codes */
+enum {
+ IPP_JOB_STATE_PENDING = 3,
+ IPP_JOB_STATE_PENDING_HELD = 4,
+ IPP_JOB_STATE_PROCESSING = 5,
+ IPP_JOB_STATE_PROCESSING_STOPPED = 6,
+ IPP_JOB_STATE_CANCELED = 7,
+ IPP_JOB_STATE_ABORTED = 8,
+ IPP_JOB_STATE_COMPLETED = 9
+};
+
+/* exported functions */
+extern papi_status_t ipp_read_message(ipp_reader_t iread, void *fd,
+ papi_attribute_t ***message, char type);
+
+extern papi_status_t ipp_write_message(ipp_writer_t iwrite, void *fd,
+ papi_attribute_t **message);
+
+/* internal functions shared between modules */
+extern void ipp_set_status(papi_attribute_t ***message, papi_status_t status,
+ char *format, ...);
+extern papi_status_t ipp_validate_request(papi_attribute_t **request,
+ papi_attribute_t ***response);
+
+extern int ipp_severity(int16_t status);
+
+extern int16_t ipp_charset_supported(char *charset);
+
+extern void *string_to_ipp_attr_value(int8_t type, char *value);
+
+extern char *ipp_uri_to_printer(char *uri);
+extern void *papi_attribute_to_ipp_attr(int8_t type, papi_attribute_t *attr);
+
+extern int8_t name_to_ipp_type(char *name);
+extern char *job_template[];
+extern char *job_description[];
+extern char *printer_description[];
+extern char *ipp_tag_string(int8_t tag, char *buf, size_t bufsiz);
+extern size_t min_val_len(int8_t type, char *name);
+extern size_t max_val_len(int8_t type, char *name);
+extern int is_keyword(char *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IPP_H */
diff --git a/usr/src/lib/print/libipp-core/common/ipp_types.c b/usr/src/lib/print/libipp-core/common/ipp_types.c
new file mode 100644
index 0000000000..47fc32c259
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/common/ipp_types.c
@@ -0,0 +1,303 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: ipp_types.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ipp.h>
+#include <errno.h>
+#include <values.h>
+
+#ifndef MININT
+#define MININT (-MAXINT - 1)
+#endif
+
+typedef struct {
+ char *name;
+ int8_t ipp_type;
+ int min;
+ int max;
+} attr_info_list_t;
+
+static attr_info_list_t attr_list[] = {
+ {"operation-attribute-group", DTAG_OPERATION_ATTRIBUTES, 0, 0},
+ {"job-attribute-group", DTAG_JOB_ATTRIBUTES, 0, 0},
+ {"printer-attribute-group", DTAG_PRINTER_ATTRIBUTES, 0, 0},
+ {"unsupported-attribute-group", DTAG_UNSUPPORTED_ATTRIBUTES, 0, 0},
+ {"subscription-attribute-group", DTAG_SUBSCRIPTION_ATTRIBUTES, 0, 0},
+ {"even-notificaton-attribute-group",
+ DTAG_EVENT_NOTIFICATION_ATTRIBUTES, 0, 0},
+ {"attributes-charset", VTAG_CHARSET, 0, 255},
+ {"attributes-natural-language", VTAG_NATURAL_LANGUAGE, 0, 255},
+ {"charset-configured", VTAG_CHARSET, 0, 255},
+ {"charset-supported", VTAG_CHARSET, 0, 255},
+ {"color-supported", VTAG_BOOLEAN, 0, 1},
+ {"compression", VTAG_KEYWORD, 1, 255},
+ {"compression-supported", VTAG_KEYWORD, 1, 255},
+ {"copies", VTAG_INTEGER, 1, MAXINT},
+ {"copies-default", VTAG_INTEGER, 1, MAXINT},
+ {"copies-supported", VTAG_RANGE_OF_INTEGER, 1, MAXINT},
+ {"date-at-completed", VTAG_DATE_TIME, 0, 0},
+ {"date-at-creation", VTAG_DATE_TIME, 0, 0},
+ {"date-at-processing", VTAG_DATE_TIME, 0, 0},
+ {"detailed-status-message", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 1023},
+ {"document-access-error", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 1023},
+ {"document-format", VTAG_MIME_MEDIA_TYPE, 0, 255},
+ {"document-format-default", VTAG_MIME_MEDIA_TYPE, 0, 255},
+ {"document-format-supported", VTAG_MIME_MEDIA_TYPE, 0, 255},
+ {"document-name", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"document-name", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"document-natural-language", VTAG_NATURAL_LANGUAGE, 0, 255},
+ {"finishing", VTAG_ENUM, 3, 31},
+ {"finishing-default", VTAG_ENUM, 3, 31},
+ {"finishing-supported", VTAG_ENUM, 3, 31},
+ {"generated-natural-language-supported", VTAG_NATURAL_LANGUAGE, 0, 255},
+ {"ipp-attribute-fidelity", VTAG_BOOLEAN, 0, 1},
+ {"ipp-versions-supported", VTAG_KEYWORD, 1, 255},
+ {"job-detailed-status-messages", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 1023},
+ {"job-document-access-errors", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 1023},
+ {"job-hold-until", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"job-hold-until-default", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"job-hold-until-supported", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"job-id", VTAG_INTEGER, 1, MAXINT},
+ {"job-impressions", VTAG_INTEGER, 0, MAXINT},
+ {"job-impressions-completed", VTAG_INTEGER, 0, MAXINT},
+ {"job-impressions-supported", VTAG_RANGE_OF_INTEGER, 0, MAXINT},
+ {"job-k-octets", VTAG_INTEGER, 0, MAXINT},
+ {"job-k-octets-processed", VTAG_INTEGER, 0, MAXINT},
+ {"job-k-octets-supported", VTAG_RANGE_OF_INTEGER, 0, MAXINT},
+ {"job-media-sheets", VTAG_INTEGER, 0, MAXINT},
+ {"job-media-sheets-completed", VTAG_INTEGER, 0, MAXINT},
+ {"job-media-sheets-supported", VTAG_RANGE_OF_INTEGER, 0, MAXINT},
+ {"job-message-from-operator", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 127},
+ {"job-more-info", VTAG_URI, 0, 1023},
+ {"job-name", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"job-originating-user-name", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"job-printer-up-time", VTAG_INTEGER, 1, MAXINT},
+ {"job-printer-uri", VTAG_URI, 0, 1023},
+ {"job-priority", VTAG_INTEGER, 1, 100},
+ {"job-priority-default", VTAG_INTEGER, 1, 100},
+ {"job-priority-supported", VTAG_INTEGER, 1, 100},
+ {"job-sheets", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"job-sheets-default", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"job-sheets-supported", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"job-state", VTAG_ENUM, 3, 9},
+ {"job-state-message", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 1023},
+ {"job-state-reasons", VTAG_KEYWORD, 1, 255},
+ {"job-uri", VTAG_URI, 0, 1023},
+ {"last-document", VTAG_BOOLEAN, 0, 1},
+ {"limit", VTAG_INTEGER, 1, MAXINT},
+ {"media", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"media-default", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"media-supported", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"message", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 127},
+ {"multiple-document-handling", VTAG_KEYWORD, 1, 255},
+ {"multiple-document-handling-default", VTAG_KEYWORD, 1, 255},
+ {"multiple-document-handling-supported", VTAG_KEYWORD, 1, 255},
+ {"multiple-document-jobs-supported", VTAG_BOOLEAN, 0, 1},
+ {"multiple-operation-time-out", VTAG_INTEGER, 1, MAXINT},
+ {"my-jobs", VTAG_BOOLEAN, 0, 1},
+ {"natural-language-configured", VTAG_NATURAL_LANGUAGE, 0, 255},
+ {"number-of-documents", VTAG_INTEGER, 0, MAXINT},
+ {"number-of-intervening-jobs", VTAG_INTEGER, 0, MAXINT},
+ {"number-up", VTAG_INTEGER, 1, MAXINT},
+ {"number-up-default", VTAG_INTEGER, 1, MAXINT},
+ {"number-up-supported", VTAG_INTEGER, 1, MAXINT},
+ {"operations-supported", VTAG_ENUM, 1, 0x8FFF},
+ {"orientation-requested", VTAG_ENUM, 3, 6},
+ {"orientation-requested-default", VTAG_ENUM, 3, 6},
+ {"orientation-requested-supported", VTAG_ENUM, 3, 6},
+ {"output-device-assigned", VTAG_NAME_WITHOUT_LANGUAGE, 0, 127},
+ {"page-ranges", VTAG_RANGE_OF_INTEGER, 1, MAXINT},
+ {"page-ranges-supported", VTAG_BOOLEAN, 0, 1},
+ {"pages-per-minute", VTAG_INTEGER, 0, MAXINT},
+ {"pages-per-minute-color", VTAG_INTEGER, 0, MAXINT},
+ {"pdl-override-supported", VTAG_KEYWORD, 1, 255},
+ {"print-quality", VTAG_ENUM, 3, 5},
+ {"print-quality-default", VTAG_ENUM, 3, 5},
+ {"print-quality-supported", VTAG_ENUM, 3, 5},
+ {"printer-current-time", VTAG_DATE_TIME, 0, 1},
+ {"printer-driver-installer", VTAG_URI, 0, 1023},
+ {"printer-id", VTAG_INTEGER, 1, MAXINT},
+ {"printer-info", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 127},
+ {"printer-is-accepting-jobs", VTAG_BOOLEAN, 0, 1},
+ {"printer-location", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 127},
+ {"printer-make-and-model", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 127},
+ {"printer-message-from-operator", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 127},
+ {"printer-more-info", VTAG_URI, 0, 1023},
+ {"printer-more-info-manufacturer", VTAG_URI, 0, 1023},
+ {"printer-name", VTAG_NAME_WITHOUT_LANGUAGE, 0, 127},
+ {"printer-resolution", VTAG_RESOLUTION, 0, 0},
+ {"printer-resolution-default", VTAG_RESOLUTION, 0, 0},
+ {"printer-resolution-supported", VTAG_RESOLUTION, 0, 0},
+ {"printer-state", VTAG_ENUM, 3, 5},
+ {"printer-state-message", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 1023},
+ {"printer-state-reasons", VTAG_KEYWORD, 1, 255},
+ {"printer-up-time", VTAG_INTEGER, 1, MAXINT},
+ {"printer-uri", VTAG_URI, 0, 1023},
+ {"printer-uri-supported", VTAG_URI, 0, 1023},
+ {"queued-job-count", VTAG_INTEGER, 0, MAXINT},
+ {"reference-uri-schemes-supported", VTAG_URI_SCHEME, 0, 63},
+ {"requested-attributes", VTAG_KEYWORD, 1, 255},
+ {"requesting-user-name", VTAG_NAME_WITHOUT_LANGUAGE, 0, 255},
+ {"sides", VTAG_KEYWORD, 1, 255},
+ {"sides-default", VTAG_KEYWORD, 1, 255},
+ {"sides-supported", VTAG_KEYWORD, 1, 255},
+ {"status-code", VTAG_ENUM, 1, 0x7FFF},
+ {"status-message", VTAG_TEXT_WITHOUT_LANGUAGE, 0, 255},
+ {"time-at-completed", VTAG_INTEGER, MININT, MAXINT},
+ {"time-at-creation", VTAG_INTEGER, MININT, MAXINT},
+ {"time-at-processing", VTAG_INTEGER, MININT, MAXINT},
+ {"uri-authentication-supported", VTAG_KEYWORD, 1, 255},
+ {"uri-security-supported", VTAG_KEYWORD, 1, 255},
+ {"which-jobs", VTAG_KEYWORD, 1, 255},
+ {NULL, 0, 0, 0}
+};
+
+
+static attr_info_list_t *
+get_attr_info_by_name(char *name)
+{
+ if (name != NULL) {
+ int i;
+
+ for (i = 0; attr_list[i].name != NULL; i++)
+ if (strcasecmp(attr_list[i].name, name) == 0)
+ return (&attr_list[i]);
+ }
+
+ return (NULL);
+}
+
+size_t
+max_val_len(int8_t type, char *name)
+{
+ attr_info_list_t *t;
+ int result;
+
+ switch (type) {
+ case VTAG_INTEGER:
+ case VTAG_RANGE_OF_INTEGER:
+ case VTAG_ENUM:
+ result = MAXINT;
+ break;
+ case VTAG_URI:
+ case VTAG_OCTET_STRING:
+ case VTAG_TEXT_WITHOUT_LANGUAGE:
+ result = 1023;
+ break;
+ case VTAG_NATURAL_LANGUAGE:
+ case VTAG_URI_SCHEME:
+ case VTAG_CHARSET:
+ result = 63;
+ break;
+ case VTAG_NAME_WITHOUT_LANGUAGE:
+ case VTAG_MIME_MEDIA_TYPE:
+ case VTAG_KEYWORD:
+ result = 255;
+ break;
+ default:
+ result = MAXINT;
+ }
+
+#define min(a, b) ((a < b) ? a : b)
+ if ((t = get_attr_info_by_name(name)) != NULL)
+ result = min(t->max, result);
+#undef min
+
+ return (result);
+}
+
+size_t
+min_val_len(int8_t type, char *name)
+{
+ attr_info_list_t *t;
+ int result;
+
+ switch (type) {
+ case VTAG_INTEGER:
+ case VTAG_RANGE_OF_INTEGER:
+ result = MININT;
+ break;
+ case VTAG_ENUM:
+ result = 1;
+ break;
+ case VTAG_URI:
+ case VTAG_OCTET_STRING:
+ case VTAG_TEXT_WITHOUT_LANGUAGE:
+ case VTAG_MIME_MEDIA_TYPE:
+ case VTAG_NAME_WITHOUT_LANGUAGE:
+ case VTAG_URI_SCHEME:
+ case VTAG_CHARSET:
+ case VTAG_NATURAL_LANGUAGE:
+ result = 0;
+ break;
+ case VTAG_KEYWORD:
+ result = 1;
+ break;
+ default:
+ result = MININT;
+ }
+
+#define max(a, b) ((a > b) ? a : b)
+ if ((t = get_attr_info_by_name(name)) != NULL)
+ result = max(t->min, result);
+#undef max
+
+ return (result);
+}
+
+int
+is_keyword(char *k)
+{
+ /* [a-z][a-z0-9._-]* */
+ if (*k < 'a' && *k > 'z')
+ return (0);
+ while (*(++k) != '\0')
+ if (*k < 'a' && *k > 'z' && *k < '0' && *k > '9' &&
+ *k != '.' && *k != '_' && *k != '-')
+ return (0);
+ return (1);
+}
+
+int8_t
+name_to_ipp_type(char *name)
+{
+ int i;
+
+ if (name != NULL)
+ for (i = 0; attr_list[i].name != NULL; i++)
+ if (strcasecmp(attr_list[i].name, name) == 0)
+ return (attr_list[i].ipp_type);
+
+ return (0);
+}
diff --git a/usr/src/lib/print/libipp-core/common/mapfile b/usr/src/lib/print/libipp-core/common/mapfile
new file mode 100644
index 0000000000..19a947feb5
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/common/mapfile
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# $Id: mapfile 151 2006-04-25 16:55:34Z njacobs $
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+#
+# Common interfaces that are most likely to be shared amongst the various
+# PAPI implementations.
+#
+
+SYMBOL_VERSION SUNWprivate_1.0 {
+ global:
+ ipp_read_message ;
+ ipp_write_message ;
+ ipp_validate_request ;
+ ipp_set_status ;
+
+ local:
+ * ;
+} ;
diff --git a/usr/src/lib/print/libipp-core/common/read.c b/usr/src/lib/print/libipp-core/common/read.c
new file mode 100644
index 0000000000..6127958f66
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/common/read.c
@@ -0,0 +1,666 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: read.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include <papi.h>
+#include <ipp.h>
+
+
+#define _ipp_tag_string(id) ipp_tag_string((id), buf, sizeof (buf))
+
+static papi_status_t
+read_name_with_language(ipp_reader_t iread, void *fd,
+ papi_attribute_t ***message)
+{
+ char *string;
+ uint16_t size;
+
+ /* read the language */
+ if (iread(fd, &size, 2) != 2) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "read failed: lang len\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ size = (uint16_t)ntohs(size);
+
+ if ((string = alloca(size + 1)) == NULL) {
+ ipp_set_status(message, PAPI_TEMPORARY_ERROR,
+ "Memory allocation failed");
+ return (PAPI_TEMPORARY_ERROR);
+ }
+ if (iread(fd, string, size) != size) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "read failed: lang\n");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /* read the text */
+ if (iread(fd, &size, 2) != 2) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "read failed: text len\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ size = (uint16_t)ntohs(size);
+
+ if ((string = alloca(size + 1)) == NULL) {
+ ipp_set_status(message, PAPI_TEMPORARY_ERROR,
+ "Memory allocation failed");
+ return (PAPI_TEMPORARY_ERROR);
+ }
+ if (iread(fd, string, size) != size) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "read failed: text\n");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ return (PAPI_OK);
+}
+
+
+static struct {
+ int8_t ipp_type;
+ int8_t size;
+} type_info[] = {
+ { VTAG_INTEGER, 4 },
+ { VTAG_ENUM, 4 },
+ { VTAG_BOOLEAN, 1 },
+ { VTAG_RANGE_OF_INTEGER, 8 },
+ { VTAG_RESOLUTION, 9 },
+ { VTAG_DATE_TIME, 11 },
+ { DTAG_MIN, 0 }
+};
+
+/* verify that the IPP type and size are compatible */
+static int
+validate_length(int8_t type, int8_t size)
+{
+ int i;
+
+ for (i = 0; type_info[i].ipp_type != DTAG_MIN; i++)
+ if (type_info[i].ipp_type == type)
+ return ((type_info[i].size == size) ? 0 : -1);
+ return (0);
+}
+
+/* convert tyep IPP type to a type that is marginally compatible */
+static int8_t
+base_type(int8_t i)
+{
+ switch (i) {
+ case VTAG_ENUM:
+ case VTAG_INTEGER:
+ return (VTAG_INTEGER);
+ case VTAG_URI:
+ case VTAG_OCTET_STRING:
+ case VTAG_TEXT_WITHOUT_LANGUAGE:
+ case VTAG_URI_SCHEME:
+ case VTAG_CHARSET:
+ case VTAG_NATURAL_LANGUAGE:
+ case VTAG_MIME_MEDIA_TYPE:
+ case VTAG_NAME_WITHOUT_LANGUAGE:
+ case VTAG_KEYWORD:
+ return (VTAG_TEXT_WITHOUT_LANGUAGE);
+ case VTAG_BOOLEAN:
+ case VTAG_RANGE_OF_INTEGER:
+ case VTAG_DATE_TIME:
+ case VTAG_RESOLUTION:
+ default:
+ return (i);
+ }
+}
+
+/* verify that the IPP type is correct for the named attribute */
+static papi_status_t
+validate_type(char *name, int8_t type)
+{
+ int8_t t = name_to_ipp_type(name);
+
+ if (t == 0) /* The attribute is not defined in the RFC */
+ return (PAPI_NOT_FOUND);
+ else if (t == type) /* The supplied type matched the RFC type */
+ return (PAPI_OK);
+ else { /* The supplied type doesn't match the RFC */
+ if (base_type(t) == base_type(type))
+ return (PAPI_OK);
+
+ return (PAPI_CONFLICT);
+ }
+}
+
+/* verify that the IPP value is within specification for the named attribute */
+static int
+validate_value(papi_attribute_t ***message, char *name, int8_t type, ...)
+{
+#define within(a, b, c) ((b >= a) && (b <= c))
+ va_list ap;
+ int rc = -1;
+ int min = min_val_len(type, name),
+ max = max_val_len(type, name);
+ char buf[64]; /* For _ipp_<...>_string() */
+
+ va_start(ap, type);
+ switch (type) {
+ case VTAG_ENUM:
+ case VTAG_INTEGER: {
+ int32_t i = (int32_t)va_arg(ap, int32_t);
+
+ if (within(min, i, max))
+ rc = 0;
+ else
+ ipp_set_status(message, PAPI_BAD_ARGUMENT,
+ "%s(%s): %d: out of range (%d - %d)", name,
+ _ipp_tag_string(type), i, min, max);
+ }
+ break;
+ case VTAG_BOOLEAN: {
+ int8_t v = (int8_t)va_arg(ap, int);
+
+ if (within(0, v, 1))
+ rc = 0;
+ else
+ ipp_set_status(message, PAPI_BAD_ARGUMENT,
+ "%s(%s): %d: out of range (0 - 1)", name,
+ _ipp_tag_string(type), v);
+ }
+ break;
+ case VTAG_RANGE_OF_INTEGER: {
+ int32_t lower = (int32_t)va_arg(ap, int32_t);
+ int32_t upper = (int32_t)va_arg(ap, int32_t);
+
+ if (within(min, lower, max) &&
+ within(min, upper, max))
+ rc = 0;
+ else
+ ipp_set_status(message, PAPI_BAD_ARGUMENT,
+ "%s(%s): %d - %d: out of range (%d - %d)", name,
+ _ipp_tag_string(type), lower, upper, min, max);
+ }
+ break;
+ case VTAG_URI:
+ case VTAG_OCTET_STRING:
+ case VTAG_TEXT_WITHOUT_LANGUAGE:
+ case VTAG_URI_SCHEME:
+ case VTAG_CHARSET:
+ case VTAG_NATURAL_LANGUAGE:
+ case VTAG_MIME_MEDIA_TYPE:
+ case VTAG_NAME_WITHOUT_LANGUAGE: {
+ char *v = (char *)va_arg(ap, char *);
+
+ if (strlen(v) < max)
+ rc = 0;
+ else
+ ipp_set_status(message, PAPI_BAD_ARGUMENT,
+ "%s(%s): %s: too long (max length: %d)", name,
+ _ipp_tag_string(type), v, max);
+ }
+ break;
+ case VTAG_KEYWORD: {
+ char *v = (char *)va_arg(ap, char *);
+
+ if (strlen(v) >= max)
+ ipp_set_status(message, PAPI_BAD_ARGUMENT,
+ "%s(%s): %s: too long (max length: %d)", name,
+ _ipp_tag_string(type), v, max);
+ else if (is_keyword(v) == 0)
+ ipp_set_status(message, PAPI_BAD_ARGUMENT,
+ "%s(%s): %s: invalid keyword", name,
+ _ipp_tag_string(type), v);
+ else
+ rc = 0;
+ }
+ break;
+ case VTAG_DATE_TIME:
+ case VTAG_RESOLUTION:
+ default:
+ rc = 0;
+ }
+ va_end(ap);
+
+ return (rc);
+#undef within
+}
+
+/*
+ * read_attr_group() reads in enough of the message data to parse an entire
+ * attribute group. Since to determine that the group is finished you have to
+ * read the character that determines the type of the next group, this function
+ * must return that character, in order that our caller knows how to call us for
+ * the next group. Thus type is used both as an input parameter (the type of
+ * attribute group to read in) and an output parameter (the type of the next
+ * attribute group).
+ */
+
+static papi_status_t
+ipp_read_attribute_group(ipp_reader_t iread, void *fd, int8_t *type,
+ papi_attribute_t ***message)
+{
+ int8_t value_tag;
+ uint16_t name_length, value_length;
+ papi_attribute_t **attributes = NULL;
+ char *name = NULL;
+ int i;
+ char buf[64]; /* For _ipp_<...>_string() */
+
+ /*
+ * RFC2910 3.3 says we need to handle `An expected but missing
+ * "begin-attribute-group-tag" field. How?
+ */
+ if (*type > DTAG_MAX) {
+ /* Scream bloody murder, or assign a new type? */
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "Bad attribute group tag 0x%.2hx (%s)",
+ *type, _ipp_tag_string(*type));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /* This loops through *values* not *attributes*! */
+ for (i = 0; ; i++) {
+ papi_status_t valid = PAPI_OK;
+ if (iread(fd, &value_tag, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: value tag\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ /* are we done with this group ? */
+ if (value_tag <= DTAG_MAX)
+ break;
+
+ if (iread(fd, &name_length, 2) != 2) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: name length\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ name_length = (uint16_t)ntohs(name_length);
+
+ /* Not just another value for the previous attribute */
+ if (name_length != 0) {
+ if ((name = alloca(name_length + 1)) == NULL) {
+ ipp_set_status(message, PAPI_TEMPORARY_ERROR,
+ "alloca(): failed\n");
+ return (PAPI_TEMPORARY_ERROR);
+ }
+ (void) memset(name, 0, name_length + 1);
+
+ if (iread(fd, name, name_length) != name_length) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: name\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ }
+
+ valid = validate_type(name, value_tag);
+ if ((valid != PAPI_OK) && (valid != PAPI_NOT_FOUND))
+ ipp_set_status(message, valid, "%s(%s): %s", name,
+ _ipp_tag_string(value_tag),
+ papiStatusString(valid));
+
+ if (iread(fd, &value_length, 2) != 2) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: value length\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ value_length = (uint16_t)ntohs(value_length);
+
+ if (validate_length(value_tag, value_length) < 0) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "Bad value length (%d) for type %s",
+ value_length, _ipp_tag_string(value_tag));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ switch (value_tag) {
+ case VTAG_INTEGER:
+ case VTAG_ENUM: {
+ int32_t v;
+
+ if (iread(fd, &v, value_length) != value_length) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: int/enum\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ v = (int32_t)ntohl(v);
+ (void) validate_value(message, name, value_tag, v);
+ papiAttributeListAddInteger(&attributes,
+ PAPI_ATTR_APPEND, name, v);
+
+ }
+ break;
+ case VTAG_BOOLEAN: {
+ int8_t v;
+
+ if (iread(fd, &v, value_length) != value_length) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: boolean\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ (void) validate_value(message, name, value_tag, v);
+ papiAttributeListAddBoolean(&attributes,
+ PAPI_ATTR_APPEND, name, v);
+ }
+ break;
+ case VTAG_RANGE_OF_INTEGER: {
+ int32_t min, max;
+
+ if (iread(fd, &min, 4) != 4) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: min\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ if (iread(fd, &max, 4) != 4) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: max\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ min = (int32_t)ntohl(min);
+ max = (int32_t)ntohl(max);
+ (void) validate_value(message, name, value_tag,
+ min, max);
+ papiAttributeListAddRange(&attributes, PAPI_ATTR_APPEND,
+ name, min, max);
+ }
+ break;
+ case VTAG_RESOLUTION: {
+ int32_t x, y;
+ int8_t units;
+
+ if (iread(fd, &x, 4) != 4) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: x\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ if (iread(fd, &y, 4) != 4) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: y\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ if (iread(fd, &units, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: units\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ x = (int32_t)ntohl(x);
+ y = (int32_t)ntohl(y);
+ papiAttributeListAddResolution(&attributes,
+ PAPI_ATTR_APPEND, name, x, y,
+ (papi_resolution_unit_t)units);
+ }
+ break;
+ case VTAG_DATE_TIME: {
+ struct tm tm;
+ time_t v;
+ int8_t c;
+ uint16_t s;
+
+ (void) memset(&tm, 0, sizeof (tm));
+ if (iread(fd, &s, 2) != 2) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: year\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ tm.tm_year = (uint16_t)ntohs(s) - 1900;
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: month\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ tm.tm_mon = c - 1;
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: day\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ tm.tm_mday = c;
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: hour\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ tm.tm_hour = c;
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: minutes\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ tm.tm_min = c;
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: seconds\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ tm.tm_sec = c;
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: decisec\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ /* tm.deciseconds = c; */
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: utc_dir\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ /* tm.utc_dir = c; */
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: utc_hour\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ /* tm.utc_hours = c; */
+ if (iread(fd, &c, 1) != 1) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: utc_min\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ /* tm.utc_minutes = c; */
+
+ v = mktime(&tm);
+
+ (void) validate_value(message, name, value_tag, v);
+ papiAttributeListAddDatetime(&attributes,
+ PAPI_ATTR_APPEND, name, v);
+ }
+ break;
+ case VTAG_NAME_WITH_LANGUAGE:
+ case VTAG_TEXT_WITH_LANGUAGE:
+ /*
+ * we are dropping this because we don't support
+ * name with language at this time.
+ */
+ (void) read_name_with_language(iread, fd, message);
+ break;
+ case VTAG_NAME_WITHOUT_LANGUAGE:
+ case VTAG_TEXT_WITHOUT_LANGUAGE:
+ case VTAG_URI:
+ case VTAG_KEYWORD:
+ case VTAG_CHARSET: {
+ char *v;
+
+ if ((v = calloc(1, value_length + 1)) == NULL) {
+ ipp_set_status(message, PAPI_TEMPORARY_ERROR,
+ "calloc(): failed\n");
+ return (PAPI_TEMPORARY_ERROR);
+ }
+#ifdef NOTDEF
+ if (iread(fd, v, value_length) != value_length) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: stringy\n");
+ return (PAPI_BAD_REQUEST);
+ }
+#else
+ {
+ int rc, i = value_length;
+ char *p = v;
+
+ while ((rc = iread(fd, p, i)) != i) {
+ if (rc <= 0) {
+ ipp_set_status(message,
+ PAPI_BAD_REQUEST,
+ "bad read: stringy\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ i -= rc;
+ p += rc;
+ }
+ }
+#endif
+ (void) validate_value(message, name, value_tag, v);
+ papiAttributeListAddString(&attributes,
+ PAPI_ATTR_APPEND, name, v);
+ }
+ break;
+ case VTAG_UNKNOWN:
+ case VTAG_NOVALUE:
+ case VTAG_UNSUPPORTED:
+ papiAttributeListAddValue(&attributes, PAPI_ATTR_EXCL,
+ name, PAPI_COLLECTION, NULL);
+ break;
+ default: {
+ char *v;
+
+ if ((v = calloc(1, value_length + 1)) == NULL) {
+ ipp_set_status(message, PAPI_TEMPORARY_ERROR,
+ "calloc(): failed\n");
+ return (PAPI_TEMPORARY_ERROR);
+ }
+ if (iread(fd, v, value_length) != value_length) {
+ ipp_set_status(message, PAPI_BAD_REQUEST,
+ "bad read: other\n");
+ return (PAPI_BAD_REQUEST);
+ }
+ papiAttributeListAddString(&attributes,
+ PAPI_ATTR_APPEND, name, v);
+ }
+ break;
+ }
+ }
+
+ if (attributes != NULL) {
+ char name[32];
+
+ (void) ipp_tag_string(*type, name, sizeof (name));
+ papiAttributeListAddCollection(message, PAPI_ATTR_APPEND, name,
+ attributes);
+ }
+
+ *type = value_tag;
+
+ return (PAPI_OK);
+}
+
+
+static papi_status_t
+ipp_read_header(ipp_reader_t iread, void *fd, papi_attribute_t ***message,
+ char type)
+{
+ char *attr_name = "status-code"; /* default to a response */
+ char buf[8];
+ int8_t c;
+ uint16_t s;
+ int32_t i;
+
+ if ((iread == NULL) || (fd == NULL) || (message == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /*
+ * Apache 1.X uses the buffer supplied to it's read call to read in
+ * the chunk size when chunking is used. This causes problems
+ * reading the header a piece at a time, because we don't have
+ * enough room to read in the chunk size prior to reading the
+ * chunk.
+ */
+
+ if (iread(fd, buf, 8) != 8)
+ return (PAPI_BAD_REQUEST);
+
+ c = buf[0];
+ (void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
+ "version-major", c);
+
+ c = buf[1];
+ (void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
+ "version-minor", c);
+
+ memcpy(&s, &buf[2], 2);
+ s = (uint16_t)ntohs(s);
+ if (type == IPP_TYPE_REQUEST)
+ attr_name = "operation-id";
+ (void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
+ attr_name, s);
+
+ memcpy(&i, &buf[4], 4);
+ i = (uint32_t)ntohl(i);
+ (void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
+ "request-id", i);
+
+ return (PAPI_OK);
+}
+
+static papi_status_t
+ipp_read_attribute_groups(ipp_reader_t iread, void *fd,
+ papi_attribute_t ***message)
+{
+ papi_status_t result = PAPI_OK;
+ int8_t tag;
+
+ /* start reading the attribute groups */
+ if (iread(fd, &tag, 1) != 1) /* prime the pump */
+ return (PAPI_BAD_REQUEST);
+
+ while ((tag != DTAG_END_OF_ATTRIBUTES) && (result == PAPI_OK)) {
+ result = ipp_read_attribute_group(iread, fd, &tag, message);
+ }
+
+ return (result);
+}
+
+papi_status_t
+ipp_read_message(ipp_reader_t iread, void *fd, papi_attribute_t ***message,
+ char type)
+{
+ papi_status_t result = PAPI_OK;
+
+ if ((iread == NULL) || (fd == NULL) || (message == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ result = ipp_read_header(iread, fd, message, type);
+ if (result == PAPI_OK)
+ result = ipp_read_attribute_groups(iread, fd, message);
+
+ return (result);
+}
diff --git a/usr/src/lib/print/libipp-core/common/strings.c b/usr/src/lib/print/libipp-core/common/strings.c
new file mode 100644
index 0000000000..b47449b8cc
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/common/strings.c
@@ -0,0 +1,411 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: strings.c 151 2006-04-25 16:55:34Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ipp.h"
+
+static char *tag_strings[] = {
+ /* delimiter tags */
+ "reserved-delimiter-00",
+ "operational-attributes-group",
+ "job-attributes-group",
+ "end-of-attributes-group",
+ "printer-attributes-group",
+ "unsupported-attributes-group",
+ "subscription-attributes-group",
+ "event-notification-attributes-group",
+ "reserved-delimiter-08",
+ "reserved-delimiter-09",
+ "reserved-delimiter-0a",
+ "reserved-delimiter-0b",
+ "reserved-delimiter-0c",
+ "reserved-delimiter-0d",
+ "reserved-delimiter-0e",
+ "reserved-delimiter-0f",
+ /* value tags */
+ "unsupported",
+ "reserved-default",
+ "unknown",
+ "no-value",
+ "reserved-out-of-band-14",
+ "not-settable",
+ "delete-attribute",
+ "admin-define",
+ "reserved-out-of-band-18",
+ "reserved-out-of-band-19",
+ "reserved-out-of-band-1a",
+ "reserved-out-of-band-1b",
+ "reserved-out-of-band-1c",
+ "reserved-out-of-band-1d",
+ "reserved-out-of-band-1e",
+ "reserved-out-of-band-1f",
+ "reserved",
+ "integer",
+ "boolean",
+ "enum",
+ "reserved-integer-type-24",
+ "reserved-integer-type-25",
+ "reserved-integer-type-26",
+ "reserved-integer-type-27",
+ "reserved-integer-type-28",
+ "reserved-integer-type-29",
+ "reserved-integer-type-2a",
+ "reserved-integer-type-2b",
+ "reserved-integer-type-2c",
+ "reserved-integer-type-2d",
+ "reserved-integer-type-2e",
+ "reserved-integer-type-2f",
+ "octetString",
+ "dateTime",
+ "resolution",
+ "rangeOfInteger",
+ "begCollection",
+ "textWithLanguage",
+ "nameWithLanguage",
+ "endCollection",
+ "reserved-octetString-38",
+ "reserved-octetString-39",
+ "reserved-octetString-3a",
+ "reserved-octetString-3b",
+ "reserved-octetString-3c",
+ "reserved-octetString-3d",
+ "reserved-octetString-3e",
+ "reserved-octetString-3f",
+ "reserved",
+ "textWithoutLanguage",
+ "nameWithoutLanguage",
+ "reserved",
+ "keyword",
+ "uri",
+ "uriScheme",
+ "charset",
+ "naturalLanguage",
+ "mimeMediaType",
+ "memberAttrName",
+ "reserved-charString-4b",
+ "reserved-charString-4c",
+ "reserved-charString-4d",
+ "reserved-charString-4e",
+ "reserved-charString-4f",
+ "reserved-charString-50",
+ "reserved-charString-51",
+ "reserved-charString-52",
+ "reserved-charString-53",
+ "reserved-charString-54",
+ "reserved-charString-55",
+ "reserved-charString-56",
+ "reserved-charString-57",
+ "reserved-charString-58",
+ "reserved-charString-59",
+ "reserved-charString-5a",
+ "reserved-charString-5b",
+ "reserved-charString-5c",
+ "reserved-charString-5d",
+ "reserved-charString-5e",
+ "reserved-charString-5f",
+};
+
+static char *opid_strings[] = {
+ "reserved-0x0000",
+ "reserved-0x0001",
+ "Print-Job",
+ "Print-URI",
+ "Validate-Job",
+ "Create-Job",
+ "Send-Document",
+ "Send-URI",
+ "Cancel-Job",
+ "Get-Job-Attributes",
+ "Get-Jobs",
+ "Get-Printer-Attributes",
+ "Hold-Job",
+ "Release-Job",
+ "Restart-Job",
+ "reserved-0x000f",
+ "Pause-Printer",
+ "Resume-Printer",
+ "Purge-Jobs",
+ "Set-Printer-Attributes",
+ "Set-Job-Attributes",
+ "Get-Printer-Supported-Values",
+ "Create-Printer-Subscription",
+ "Create-Job-Subscription",
+ "Get-Subscription-Attributes",
+ "Get-Subscriptions",
+ "Renew-Subscription",
+ "Cancel-Subscription",
+ "Get-Notifications",
+ "Send-Notifications",
+ "Get-Resource-Attributes-deleted",
+ "Get-Resource-Data-deleted",
+ "Get-Resources-deleted",
+ "Get-Print-Support-Files",
+ "Disable-Printer",
+ "Pause-Printer-After-Current-Job",
+ "Hold-New-Jobs",
+ "Release-Held-New-Jobs",
+ "Deactivate-Printer",
+ "Activate-Printer",
+ "Restart-Printer",
+ "Shutdown-Printer",
+ "Startup-Printer",
+ "Reprocess-Job",
+ "Cancel-Current-Job",
+ "Suspend-Current-Job",
+ "Resume-Job",
+ "Promote-Job",
+ "Schedule-Job-After",
+ NULL
+};
+
+static char *res_opid_strings[] = {
+ "Microsoft-0x4000",
+ "CUPS-Get-Default",
+ "CUPS-Get-Printers",
+ "CUPS-Add-Printer",
+ "CUPS-Delete-Printer",
+ "CUPS-Get-Classes",
+ "CUPS-Add-Class",
+ "CUPS-Delete-Class",
+ "CUPS-Accept-Jobs",
+ "CUPS-Reject-Jobs",
+ "CUPS-Set-Default",
+ "CUPS-Get-Devices",
+ "CUPS-Get-PPDs",
+ "CUPS-Move-Job",
+ "CUPS-0x400e",
+ "CUPS-0x400f",
+ "Peerless-0x4010",
+ NULL
+};
+#define KNOWN_RESERVED_MIN 0x4000
+#define KNOWN_RESERVED_MAX 0x4010
+
+static char *ok_status_strings[] = {
+ "successful-ok",
+ "successful-ok-ignored-or-substituted-attributes",
+ "successful-ok-conflicting-attributes",
+ "successful-ok-ignored-subscriptions",
+ "successful-ok-ignored-notifications",
+ "successful-ok-too-many-events",
+ "successful-ok-but-cancel-subscription"
+};
+
+static char *redir_status_strings[] = {
+ "redirection-other-site"
+};
+
+static char *client_error_status_strings[] = {
+ "client-error-bad-request",
+ "client-error-forbidden",
+ "client-error-not-authenticated",
+ "client-error-not-authorized",
+ "client-error-not-possible",
+ "client-error-timeout",
+ "client-error-not-found",
+ "client-error-gone",
+ "client-error-request-entity-too-large",
+ "client-error-request-value-too-long",
+ "client-error-document-format-not-supported",
+ "client-error-attributes-or-values-not-supported",
+ "client-error-uri-scheme-not-supported",
+ "client-error-charset-not-supported",
+ "client-error-conflicting-attributes",
+ "client-error-compression-not-supported",
+ "client-error-compression-error",
+ "client-error-document-format-error",
+ "client-error-document-access-error",
+ "client-error-attributes-not-settable",
+ "client-error-ignored-all-subscriptions",
+ "client-error-too-many-subscriptions",
+ "client-error-ignored-all-notifications",
+ "client-error-print-support-file-not-found"
+};
+
+static char *server_error_status_strings[] = {
+ "server-error-internal-error",
+ "server-error-operation-not-supported",
+ "server-error-service-unavailable",
+ "server-error-version-not-supported",
+ "server-error-device-error",
+ "server-error-temporary-error",
+ "server-error-not-accepting-jobs",
+ "server-error-busy",
+ "server-error-job-canceled",
+ "server-error-multiple-document-jobs-not-supported",
+ "server-error-printer-is-deactivated"
+};
+
+char *
+ipp_tag_string(int8_t id, char *ret, size_t len)
+{
+ if (id < VTAG_MAX)
+ (void) strlcpy(ret, tag_strings[id], len);
+ else if (id == VTAG_EXTEND)
+ (void) strlcpy(ret, "extension", len);
+ else
+ (void) snprintf(ret, len, "bogus-0x%.2x", id);
+
+ return (ret);
+}
+
+char *
+ipp_opid_string(int16_t id, char *ret, size_t len)
+{
+ if (id < OPID_RESERVED_MIN)
+ (void) strlcpy(ret, opid_strings[id], len);
+ else if (id < OPID_RESERVED_VENDOR_MIN)
+ (void) snprintf(ret, len, "reserved-0x%.4x", id);
+ else if (id <= KNOWN_RESERVED_MAX)
+ (void) strlcpy(ret,
+ res_opid_strings[id - KNOWN_RESERVED_MIN], len);
+ else /* if (id <= OPID_RESERVED_VENDOR_MAX) */
+ (void) snprintf(ret, len, "reserved-vendor-0x%.4x", id);
+
+ return (ret);
+}
+
+int16_t
+ipp_string_opid(char *string)
+{
+ int i;
+
+ for (i = 0; opid_strings[i] != NULL; i++)
+ if (strcasecmp(opid_strings[i], string) == 0)
+ return (i);
+
+ for (i = 0; res_opid_strings[i] != NULL; i++)
+ if (strcasecmp(res_opid_strings[i], string) == 0)
+ return (0x4000 + i);
+
+ return (-1);
+}
+
+char *
+ipp_status_string(int16_t id, char *ret, size_t len)
+{
+ if (id <= IPP_OK_MAX)
+ (void) strlcpy(ret, ok_status_strings[id], len);
+ else if (id >= IPP_REDIR_MIN && id <= IPP_REDIR_MAX)
+ (void) strlcpy(ret,
+ redir_status_strings[id - IPP_REDIR_MIN], len);
+ else if (id >= IPP_CERR_MIN && id <= IPP_CERR_MAX)
+ (void) strlcpy(ret,
+ client_error_status_strings[id - IPP_CERR_MIN], len);
+ else if (id >= IPP_SERR_MIN && id <= IPP_SERR_MAX)
+ (void) strlcpy(ret,
+ server_error_status_strings[id - IPP_SERR_MIN], len);
+ else
+ (void) snprintf(ret, len, "bogus-0x%.4hx", id);
+
+ return (ret);
+}
+
+
+
+/*
+ * attribute template handling routines
+ */
+char *job_template[] = {
+ "copies",
+ "finishing",
+ "job-hold-until",
+ "job-priority",
+ "job-sheets",
+ "media",
+ "multiple-document-handling",
+ "number-up",
+ "page-ranges-supported",
+ "print-quality",
+ "printer-resoultion",
+ "sides",
+ NULL
+};
+
+char *job_description[] = {
+ "copies-default", "copies-supported",
+ "finishing-default", "finishing-supported",
+ "job-hold-until-default", "job-hold-until-supported",
+ "job-priority-default", "job-priority-supported",
+ "job-sheets-default", "job-sheets-supported",
+ "media-default", "media-supported",
+ "multiple-document-handling-default",
+ "multiple-document-handling-supported",
+ "number-up-default", "number-up-supported",
+ "page-ranges-supported",
+ "print-quality-default", "print-quality-supported",
+ "printer-resoultion-default", "printer-resoultion-supported",
+ "sides-default", "sides-supported",
+ NULL
+};
+
+char *printer_description[] = {
+ "printer-uri-supported",
+ "uri-security-supported",
+ "uri-authentication-supported",
+ "printer-name",
+ "printer-location",
+ "printer-info",
+ "printer-more-info",
+ "printer-driver-installer",
+ "printer-make-and-model",
+ "printer-more-info-manufacturer",
+ "printer-state",
+ "printer-state-reasons",
+ "printer-state-message",
+ "ipp-versions-supported",
+ "multiple-document-jobs-supported",
+ "charset-configured",
+ "charset-supported",
+ "natural-language-configured",
+ "generated-natural-language-supported",
+ "document-format-default",
+ "document-format-supported",
+ "printer-is-accepting-jobs",
+ "queued-job-count",
+ "printer-message-from-operator",
+ "color-supported",
+ "reference-uri-schemes-supported",
+ "pdl-override-supported",
+ "printer-up-time",
+ "printer-current-time",
+ "multiple-operation-time-out",
+ "compression-supported",
+ "job-k-octets-supported",
+ "job-impressions-supported",
+ "job-media-sheets-supported",
+ "pages-per-minute",
+ "pages-per-minute-color",
+ NULL
+};
diff --git a/usr/src/lib/print/libipp-core/common/write.c b/usr/src/lib/print/libipp-core/common/write.c
new file mode 100644
index 0000000000..aef693a365
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/common/write.c
@@ -0,0 +1,415 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: write.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+
+#include <papi.h>
+#include <ipp.h>
+
+static int8_t
+papi_attribute_to_ipp_type(papi_attribute_value_type_t type)
+{
+ switch (type) {
+ case PAPI_INTEGER:
+ return (VTAG_INTEGER);
+ case PAPI_BOOLEAN:
+ return (VTAG_BOOLEAN);
+ case PAPI_RANGE:
+ return (VTAG_RANGE_OF_INTEGER);
+ case PAPI_RESOLUTION:
+ return (VTAG_RESOLUTION);
+ case PAPI_DATETIME:
+ return (VTAG_DATE_TIME);
+ case PAPI_STRING:
+ return (VTAG_TEXT_WITHOUT_LANGUAGE);
+ }
+
+ return (0);
+}
+
+static papi_status_t
+papi_ipp_type_match(papi_attribute_value_type_t papi, int8_t ipp)
+{
+ switch (papi) {
+ case PAPI_STRING:
+ switch (ipp) {
+ case VTAG_URI:
+ case VTAG_OCTET_STRING:
+ case VTAG_TEXT_WITHOUT_LANGUAGE:
+ case VTAG_URI_SCHEME:
+ case VTAG_CHARSET:
+ case VTAG_NATURAL_LANGUAGE:
+ case VTAG_MIME_MEDIA_TYPE:
+ case VTAG_NAME_WITHOUT_LANGUAGE:
+ case VTAG_KEYWORD:
+ break;
+ default:
+ return (PAPI_CONFLICT);
+ }
+ break;
+ case PAPI_INTEGER:
+ switch (ipp) {
+ case VTAG_ENUM:
+ case VTAG_INTEGER:
+ break;
+ default:
+ return (PAPI_CONFLICT);
+ }
+ break;
+ case PAPI_BOOLEAN:
+ if (ipp != VTAG_BOOLEAN)
+ return (PAPI_CONFLICT);
+ break;
+ case PAPI_RANGE:
+ if (ipp != VTAG_RANGE_OF_INTEGER)
+ return (PAPI_CONFLICT);
+ break;
+ case PAPI_RESOLUTION:
+ if (ipp != VTAG_RESOLUTION)
+ return (PAPI_CONFLICT);
+ break;
+ case PAPI_DATETIME:
+ if (ipp != VTAG_DATE_TIME)
+ return (PAPI_CONFLICT);
+ break;
+ case PAPI_COLLECTION:
+ /* don't need to match */
+ break;
+ }
+
+ return (PAPI_OK);
+}
+
+static papi_status_t
+ipp_write_attribute(ipp_writer_t iwrite, void *fd, papi_attribute_t *attribute)
+{
+ papi_status_t status;
+ papi_attribute_value_t **values;
+ int8_t type;
+ int i;
+ char *name;
+
+ name = attribute->name;
+ values = attribute->values;
+
+ if ((type = name_to_ipp_type(name)) == 0)
+ type = papi_attribute_to_ipp_type(attribute->type);
+
+ /* The types don't match, so don't send the attribute */
+ if ((status = papi_ipp_type_match(attribute->type, type)) != PAPI_OK)
+ return (status);
+
+ if (values == NULL) {
+ uint16_t length;
+
+ type = VTAG_UNSUPPORTED;
+ if (iwrite(fd, &type, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+
+ if (name != NULL) { /* first value gets named */
+ length = (uint16_t)htons(strlen(name));
+
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, name, strlen(name)) != strlen(name))
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ length = (uint16_t)htons(0);
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+
+ return (PAPI_OK);
+ }
+
+
+
+ for (i = 0; values[i] != NULL; i++) {
+ papi_attribute_value_t *value = values[i];
+ uint16_t length = 0;
+
+ if (iwrite(fd, &type, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+
+ if (name != NULL) { /* first value gets named */
+ length = (uint16_t)htons(strlen(name));
+
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, name, strlen(name)) != strlen(name))
+ return (PAPI_DEVICE_ERROR);
+ name = NULL;
+ } else {
+ length = (uint16_t)htons(0);
+
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ }
+
+ switch (attribute->type) {
+ case PAPI_STRING: {
+ char *v = (char *)value->string;
+
+ if (v != NULL) {
+ size_t str_length = strlen(v);
+
+ /*
+ * if the length is more than 16 bits can
+ * express, send what can be represented
+ * in 16 bits. IPP "strings" can only be
+ * that large.
+ */
+ if (str_length > 0xFFFF)
+ str_length = 0xFFFF;
+
+ length = (uint16_t)htons(str_length);
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, v, str_length) != str_length)
+ return (PAPI_DEVICE_ERROR);
+ } else
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ }
+ break;
+ case PAPI_BOOLEAN: {
+ int8_t v = (int8_t)value->boolean;
+
+ length = (uint16_t)htons(1);
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, &v, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ }
+ break;
+ case PAPI_INTEGER: {
+ int32_t v = (int32_t)value->integer;
+
+ length = (uint16_t)htons(4);
+ v = (int32_t)htonl(v);
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, &v, 4) != 4)
+ return (PAPI_DEVICE_ERROR);
+ }
+ break;
+ case PAPI_RANGE: {
+ int32_t min = (int32_t)htonl((int)(value->range).lower),
+ max = (int32_t)htonl((int)(value->range).upper);
+
+ length = (uint16_t)htons(8);
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, &min, 4) != 4)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, &max, 4) != 4)
+ return (PAPI_DEVICE_ERROR);
+ }
+ break;
+ case PAPI_RESOLUTION: {
+ int32_t x = (int)(value->resolution).xres,
+ y = (int)(value->resolution).yres;
+ int8_t units = (int8_t)(value->resolution).units;
+
+ length = (uint16_t)htons(9);
+ x = (int32_t)htonl(x);
+ y = (int32_t)htonl(y);
+
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, &x, 4) != 4)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, &y, 4) != 4)
+ return (PAPI_DEVICE_ERROR);
+ if (iwrite(fd, &units, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ }
+ break;
+ case PAPI_DATETIME: {
+ struct tm *v = gmtime(&value->datetime);
+ int8_t c;
+ uint16_t s;
+
+ length = (uint16_t)htons(11);
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ s = (uint16_t)htons(v->tm_year + 1900);
+ if (iwrite(fd, &s, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ c = v->tm_mon + 1;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ c = v->tm_mday;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ c = v->tm_hour;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ c = v->tm_min;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ c = v->tm_sec;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ c = /* v->deciseconds */ 0;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ c = /* v->utc_dir */ 0;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ c = /* v->utc_hours */ 0;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ c = /* v->utc_minutes */ 0;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+ }
+ break;
+ default: {
+ /*
+ * If there is a value, it is not one of our
+ * types, so we couldn't use it anyway. We assume
+ * that it was an OOB type with no value
+ */
+ length = (uint16_t)htons(0);
+ if (iwrite(fd, &length, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+ }
+ break;
+ }
+ }
+
+ return (PAPI_OK);
+}
+
+static papi_status_t
+ipp_write_attribute_group(ipp_writer_t iwrite, void *fd, int8_t type,
+ papi_attribute_t **attributes)
+{
+ papi_status_t result = PAPI_OK;
+ int i;
+
+ /* write group tag */
+ if (iwrite(fd, &type, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+
+ /* write values */
+ for (i = 0; ((attributes[i] != NULL) && (result == PAPI_OK)); i++)
+ result = ipp_write_attribute(iwrite, fd, attributes[i]);
+
+ return (result);
+}
+
+static papi_status_t
+ipp_write_attribute_groups(ipp_writer_t iwrite, void *fd,
+ papi_attribute_t **groups)
+{
+ papi_status_t result = PAPI_OK;
+ int8_t c;
+
+ for (c = DTAG_MIN; c <= DTAG_MAX; c++) {
+ papi_status_t status;
+ papi_attribute_t **group = NULL;
+ void *iter = NULL;
+ char name[32];
+
+ (void) ipp_tag_string(c, name, sizeof (name));
+ for (status = papiAttributeListGetCollection(groups, &iter,
+ name, &group);
+ ((status == PAPI_OK) && (result == PAPI_OK));
+ status = papiAttributeListGetCollection(groups, &iter,
+ NULL, &group))
+ result = ipp_write_attribute_group(iwrite, fd,
+ c, group);
+ }
+
+ c = DTAG_END_OF_ATTRIBUTES;
+ if (iwrite(fd, &c, 1) != 1)
+ result = PAPI_DEVICE_ERROR;
+
+ return (result);
+}
+
+static papi_status_t
+ipp_write_message_header(ipp_writer_t iwrite, void *fd,
+ papi_attribute_t **message)
+{
+ int tmp;
+ int8_t c;
+ uint16_t s;
+ int32_t i;
+
+ /* write the version */
+ papiAttributeListGetInteger(message, NULL, "version-major", &tmp);
+ c = tmp;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+
+ papiAttributeListGetInteger(message, NULL, "version-minor", &tmp);
+ c = tmp;
+ if (iwrite(fd, &c, 1) != 1)
+ return (PAPI_DEVICE_ERROR);
+
+ /* write the request/status code */
+ papiAttributeListGetInteger(message, NULL, "status-code", &tmp);
+ papiAttributeListGetInteger(message, NULL, "operation-id", &tmp);
+ s = (uint16_t)htons(tmp);
+ if (iwrite(fd, &s, 2) != 2)
+ return (PAPI_DEVICE_ERROR);
+
+ /* write the request id */
+ papiAttributeListGetInteger(message, NULL, "request-id", &tmp);
+ i = (uint32_t)htonl(tmp);
+ if (iwrite(fd, &i, 4) != 4)
+ return (PAPI_DEVICE_ERROR);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+ipp_write_message(ipp_writer_t iwrite, void *fd, papi_attribute_t **message)
+{
+ papi_status_t result;
+
+ if ((iwrite == NULL) || (fd == NULL) || (message == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ result = ipp_write_message_header(iwrite, fd, message);
+ if (result == PAPI_OK)
+ result = ipp_write_attribute_groups(iwrite, fd, message);
+
+ return (result);
+}
diff --git a/usr/src/lib/print/libipp-core/i386/Makefile b/usr/src/lib/print/libipp-core/i386/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libipp-core/sparc/Makefile b/usr/src/lib/print/libipp-core/sparc/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libipp-core/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libipp-listener/Makefile b/usr/src/lib/print/libipp-listener/Makefile
new file mode 100644
index 0000000000..b92d620b10
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+#HDRS = papi.h
+#HDRDIR = common
+SUBDIRS = $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install: .WAIT $(SUBDIRS)
+
+lint: # $(SUBDIRS)
+
+install_h: # $(ROOTHDRS)
+
+check: # $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/libipp-listener/Makefile.com b/usr/src/lib/print/libipp-listener/Makefile.com
new file mode 100644
index 0000000000..4db2966ceb
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/Makefile.com
@@ -0,0 +1,68 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+LIBRARY = libipp-listener.a
+VERS = .0
+OBJECTS = \
+ cancel-job.o common.o create-job.o cups-accept-jobs.o \
+ cups-get-classes.o cups-get-default.o cups-get-printers.o \
+ cups-move-job.o cups-reject-jobs.o disable-printer.o enable-printer.o \
+ get-job-attributes.o get-jobs.o get-printer-attributes.o hold-job.o \
+ ipp-listener.o pause-printer.o print-job.o purge-jobs.o release-job.o \
+ restart-job.o resume-printer.o send-document.o set-job-attributes.o \
+ set-printer-attributes.o validate-job.o
+
+include ../../../Makefile.lib
+include ../../../Makefile.rootfs
+
+SRCDIR = ../common
+
+ROOTLIBDIR= $(ROOT)/usr/lib
+
+LIBS = $(DYNLIB)
+
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -DSOLARIS_PRIVATE_POST_0_9
+CPPFLAGS += -I$(SRCDIR)
+CPPFLAGS += -I../../libpapi-common/common
+CPPFLAGS += -I../../libipp-core/common
+
+CERRWARN += -_gcc=-Wno-unused-variable
+CERRWARN += -_gcc=-Wno-uninitialized
+
+MAPFILES = $(SRCDIR)/mapfile
+
+LDLIBS += -lipp-core -lpapi -lc -lsocket -lnsl
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/print/libipp-listener/common/cancel-job.c b/usr/src/lib/print/libipp-listener/common/cancel-job.c
new file mode 100644
index 0000000000..49ad1980f8
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/cancel-job.c
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: cancel-job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_cancel_job(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *message = NULL;
+ char *queue = NULL;
+ int id = -1;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * the operational-attributes-group must contain:
+ * job-uri (or printer-uri/job-id)
+ */
+ get_printer_id(operational, &queue, &id);
+ if (id < 0) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-uri or job-id");
+ return (PAPI_BAD_REQUEST);
+ } else if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * the operational-attributes-group may contain:
+ * message
+ */
+ (void) papiAttributeListGetString(operational, NULL,
+ "message", &message);
+
+ status = papiJobCancel(svc, queue, id);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status,
+ "cancel failed: %s-%d: %s",
+ (queue ? queue : "(null)"), id,
+ ipp_svc_status_mesg(svc, status));
+ } else if (message != NULL) { /* add unsupported attribute group */
+ papi_attribute_t **unsupported = NULL;
+
+ papiAttributeListAddValue(&unsupported, PAPI_ATTR_EXCL,
+ "message", PAPI_COLLECTION, NULL);
+ (void) papiAttributeListAddCollection(response,
+ PAPI_ATTR_REPLACE, "unsupported-attributes-group",
+ unsupported);
+ papiAttributeListFree(unsupported);
+
+ status = PAPI_OK_SUBST;
+ ipp_set_status(response, status,
+ "unsupported attribute in request");
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/common.c b/usr/src/lib/print/libipp-listener/common/common.c
new file mode 100644
index 0000000000..a8fbe45098
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/common.c
@@ -0,0 +1,309 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: common.c 155 2006-04-26 02:34:54Z ktou $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <papi.h>
+#include <ipp-listener.h>
+
+char *
+ipp_svc_status_mesg(papi_service_t svc, papi_status_t status)
+{
+ char *mesg = papiServiceGetStatusMessage(svc);
+
+ if (mesg == NULL)
+ mesg = papiStatusString(status);
+
+ return (mesg);
+}
+
+char *
+destination_from_printer_uri(char *uri)
+{
+ static char buf[64];
+ char *result = NULL;
+
+ if (uri != NULL)
+ result = strrchr(uri, '/');
+
+ if (result == NULL)
+ result = uri;
+ else
+ result++;
+
+#ifdef FORCE_LPSCHED_URI
+ snprintf(buf, sizeof (buf), "lpsched://localhost/printers/%s", result);
+ result = buf;
+#endif /* FORCE_LPSCHED_URI */
+
+ return (result);
+}
+
+void
+get_printer_id(papi_attribute_t **attributes, char **printer, int *id)
+{
+ papi_status_t result;
+ char *job = NULL;
+ char *fodder;
+ int junk;
+
+ if (printer == NULL)
+ printer = &fodder;
+ if (id == NULL)
+ id = &junk;
+
+ *printer = NULL;
+ *id = -1;
+
+ result = papiAttributeListGetString(attributes, NULL, "job-uri", &job);
+ if (result != PAPI_OK) {
+ result = papiAttributeListGetString(attributes, NULL,
+ "printer-uri", printer);
+ if (result == PAPI_OK)
+ papiAttributeListGetInteger(attributes, NULL,
+ "job-id", id);
+ } else {
+ *printer = job;
+ if ((job = strrchr(*printer, '/')) != NULL) {
+ *job = '\0';
+ *id = atoi(++job);
+ }
+ }
+}
+
+void
+get_string_list(papi_attribute_t **attributes, char *name, char ***values)
+{
+ papi_status_t result;
+
+ void *iterator = NULL;
+ char *value = NULL;
+
+ for (result = papiAttributeListGetString(attributes, &iterator,
+ name, &value);
+ result == PAPI_OK;
+ result = papiAttributeListGetString(attributes, &iterator,
+ NULL, &value))
+ list_append(values, value);
+}
+
+void
+add_default_attributes(papi_attribute_t ***attributes)
+{
+
+ (void) papiAttributeListAddString(attributes, PAPI_ATTR_APPEND,
+ "ipp-versions-supported", "1.0");
+ (void) papiAttributeListAddString(attributes, PAPI_ATTR_APPEND,
+ "ipp-versions-supported", "1.1");
+ (void) papiAttributeListAddBoolean(attributes, PAPI_ATTR_EXCL,
+ "multiple-document-jobs-supported", 0);
+ /*
+ * Should be able to ask the web server if it supports SSL or TLS, but
+ * for now, we pick only "none"
+ */
+ (void) papiAttributeListAddString(attributes, PAPI_ATTR_EXCL,
+ "uri-security-supported", "none");
+
+ /*
+ * For now, we only "none". As we support more authentication methods,
+ * we will need to add the associated uri for each. Valid values would
+ * be:
+ * "none", "requesting-user-name", "basic", "digest", "certificate"
+ * See RFC2911 page 127 for more information.
+ */
+ (void) papiAttributeListAddString(attributes, PAPI_ATTR_EXCL,
+ "uri-authentication-supported", "requesting-user-name");
+ (void) papiAttributeListAddString(attributes, PAPI_ATTR_EXCL,
+ "uri-security-supported", "none");
+ /* printer-uri-supported is added in the service based attributes */
+
+ (void) papiAttributeListAddInteger(attributes, PAPI_ATTR_EXCL,
+ "multiple-operation-time-out", 60);
+
+ /* I18N related */
+ (void) papiAttributeListAddString(attributes, PAPI_ATTR_EXCL,
+ "charset-configured", "utf-8");
+ (void) papiAttributeListAddString(attributes, PAPI_ATTR_EXCL,
+ "charset-supported", "utf-8");
+ (void) papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "natural-language-configured", "en-us");
+}
+
+static void
+massage_printer_attributes_group(papi_attribute_t **group, char *printer_uri)
+{
+ if (papiAttributeListFind(group, "printer-uri-supported") != NULL)
+ papiAttributeListAddString(&group, PAPI_ATTR_REPLACE,
+ "printer-uri-supported", printer_uri);
+}
+
+static void
+massage_job_attributes_group(papi_attribute_t **group, char *printer_uri)
+{
+ if (papiAttributeListFind(group, "job-printer-uri") != NULL)
+ papiAttributeListAddString(&group, PAPI_ATTR_REPLACE,
+ "job-printer-uri", printer_uri);
+
+ if (papiAttributeListFind(group, "job-printer-uri") != NULL) {
+ char buf[BUFSIZ];
+ int32_t id = -1;
+
+ papiAttributeListGetInteger(group, NULL, "job-id", &id);
+ snprintf(buf, sizeof (buf), "%s/%d", printer_uri, id);
+ papiAttributeListAddString(&group, PAPI_ATTR_REPLACE,
+ "job-uri", buf);
+ }
+}
+
+/*
+ * This function will replace the job/printer URIs with the requested
+ * uri because the print service may return a URI that isn't IPP based.
+ */
+void
+massage_response(papi_attribute_t **request, papi_attribute_t **response)
+{
+ papi_status_t status;
+ papi_attribute_t **group = NULL;
+ void *iter = NULL;
+ char *host = "localhost";
+ char *path = "/printers/";
+ int port = 631;
+ char buf[BUFSIZ];
+
+ (void) papiAttributeListGetString(request, NULL, "uri-host", &host);
+ (void) papiAttributeListGetString(request, NULL, "uri-path", &path);
+ (void) papiAttributeListGetInteger(request, NULL, "uri-port", &port);
+
+ if (port == 631)
+ snprintf(buf, sizeof (buf), "ipp://%s%s", host, path);
+ else
+ snprintf(buf, sizeof (buf), "http://%s:%d%s", host, port, path);
+
+ for (status = papiAttributeListGetCollection(response, &iter,
+ "printer-attributes-group", &group);
+ status == PAPI_OK;
+ status = papiAttributeListGetCollection(NULL, &iter,
+ NULL, &group))
+ massage_printer_attributes_group(group, buf);
+
+ iter = NULL;
+ for (status = papiAttributeListGetCollection(response, &iter,
+ "job-attributes-group", &group);
+ status == PAPI_OK;
+ status = papiAttributeListGetCollection(NULL, &iter,
+ NULL, &group))
+ massage_job_attributes_group(group, buf);
+}
+
+/*
+ * This walks through the locale tab and returns the installed
+ * locales. There must be a better way.
+ */
+void
+add_supported_locales(papi_attribute_t ***attributes)
+{
+ FILE *fp;
+
+ papiAttributeListAddString(attributes, PAPI_ATTR_REPLACE,
+ "generated-natural-language-supported", "en-us");
+
+#ifndef __linux__ /* this is Solaris specific */
+ if ((fp = fopen("/usr/lib/locale/lcttab", "r")) != NULL) {
+ char buf[1024];
+
+ while (fgets(buf, sizeof (buf), fp) != NULL) {
+ char *name, *file;
+ int i, passed = 1;
+
+ name = strtok(buf, " \t\n");
+
+ for (i = 0; ((passed == 1) && (name[i] != NULL)); i++)
+ if (isalpha(name[i]) != 0)
+ name[i] = tolower(name[i]);
+ else if ((name[i] == '_') || (name[i] == '-'))
+ name[i] = '-';
+ else
+ passed = 0;
+
+ if ((passed == 1) &&
+ ((file = strtok(NULL, " \t\n")) != NULL)) {
+ char path[1024];
+
+ snprintf(path, sizeof (path),
+ "/usr/lib/locale/%s", file);
+
+ if (access(path, F_OK) == 0)
+ papiAttributeListAddString(attributes,
+ PAPI_ATTR_APPEND,
+ "generated-natural-language-supported",
+ name);
+ }
+ }
+ }
+#endif
+}
+
+void
+papi_to_ipp_printer_group(papi_attribute_t ***response,
+ papi_attribute_t **request, int flags, papi_printer_t p)
+{
+ papi_attribute_t **ipp_group = NULL;
+
+ copy_attributes(&ipp_group, papiPrinterGetAttributeList(p));
+
+ /* Windows clients appear to have a problem with very large values */
+ papiAttributeListDelete(&ipp_group, "lpsched-printer-ppd-contents");
+
+ add_default_attributes(&ipp_group);
+ ipp_operations_supported(&ipp_group, request);
+
+ (void) papiAttributeListAddCollection(response, flags,
+ "printer-attributes-group", ipp_group);
+ papiAttributeListFree(ipp_group);
+}
+
+void
+papi_to_ipp_job_group(papi_attribute_t ***response,
+ papi_attribute_t **request, int flags, papi_job_t j)
+{
+ papi_attribute_t **ipp_group = NULL;
+
+ copy_attributes(&ipp_group, papiJobGetAttributeList(j));
+
+ (void) papiAttributeListAddCollection(response, flags,
+ "job-attributes-group", ipp_group);
+ papiAttributeListFree(ipp_group);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/create-job.c b/usr/src/lib/print/libipp-listener/common/create-job.c
new file mode 100644
index 0000000000..996b235cea
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/create-job.c
@@ -0,0 +1,108 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: create-job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_create_job(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_job_t j = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **job_attributes = NULL;
+ char *queue = NULL;
+ char *keys[] = { "attributes-natural-language", "attributes-charset",
+ "printer-uri", NULL };
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * The operational-attributes-group may contain:
+ * job-name
+ * ipp-attribute-fidelity
+ * document-name
+ * compression
+ * document-format
+ * document-natural-language
+ * job-k-octets
+ * job-impressions
+ * job-media-sheets
+ * Simply copy the entire contents of the operational-attributes-group
+ * for the PAPI call's possible use.
+ */
+
+ /* copy the pointers only, not the elements */
+ split_and_copy_attributes(keys, operational, NULL, &job_attributes);
+
+ /* copy any job-attributes-group attributes for the PAPI call */
+ if (papiAttributeListGetCollection(request, NULL,
+ "job-attributes-group", &operational) == PAPI_OK)
+ copy_attributes(&job_attributes, operational);
+
+ /*
+ * request job creation, using Sun extention to PAPI. The
+ * functionality in this extension is expected to make the
+ * next revision of the PAPI.
+ */
+ status = papiJobCreate(svc, queue, job_attributes, NULL, &j);
+ papiAttributeListFree(job_attributes);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "job creation: %s",
+ ipp_svc_status_mesg(svc, status));
+ return (status);
+ }
+
+ /* add the job attributes to the response in a job-attributes-group */
+ if (j != NULL) {
+ papi_to_ipp_job_group(response, request, PAPI_ATTR_REPLACE, j);
+ papiJobFree(j);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/cups-accept-jobs.c b/usr/src/lib/print/libipp-listener/common/cups-accept-jobs.c
new file mode 100644
index 0000000000..01a91ba5fd
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/cups-accept-jobs.c
@@ -0,0 +1,68 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: cups-accept-jobs.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+cups_accept_jobs(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *queue = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ if ((status = papiPrinterResume(svc, queue)) != PAPI_OK) {
+ ipp_set_status(response, status, "accept failed: %s: %s",
+ (queue ? queue : "(null)"),
+ ipp_svc_status_mesg(svc, status));
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/cups-get-classes.c b/usr/src/lib/print/libipp-listener/common/cups-get-classes.c
new file mode 100644
index 0000000000..a6aea61908
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/cups-get-classes.c
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: cups-get-classes.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+cups_get_classes(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_printer_t *p = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_filter_t filt;
+
+ char **req_attrs = NULL;
+ int limit = 0;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group may contain:
+ * limit
+ * printer-info
+ * printer-location
+ * printer-type
+ * printer-type-mask
+ * requested-attributes
+ */
+
+ papiAttributeListGetInteger(operational, NULL, "limit", &limit);
+
+ get_string_list(operational, "requested-attributes", &req_attrs);
+
+ /* only ask for the classes */
+ filt.type = PAPI_FILTER_BITMASK;
+ filt.filter.bitmask.mask = ~PAPI_PRINTER_CLASS;
+ filt.filter.bitmask.value = PAPI_PRINTER_CLASS;
+
+ status = papiPrintersList(svc, req_attrs, &filt, &p);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "query printers: %s",
+ ipp_svc_status_mesg(svc, status));
+ papiPrinterFree(p); /* we shouldn't have a printer */
+ return (status);
+ }
+
+ if (p != NULL) {
+ int i;
+
+ for (i = 0; p[i] != NULL; i++)
+ papi_to_ipp_printer_group(response, request,
+ PAPI_ATTR_APPEND, p[i]);
+ papiPrinterListFree(p);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/cups-get-default.c b/usr/src/lib/print/libipp-listener/common/cups-get-default.c
new file mode 100644
index 0000000000..0bb084ac9e
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/cups-get-default.c
@@ -0,0 +1,81 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: cups-get-default.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+#include <config-site.h>
+
+papi_status_t
+cups_get_default(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_printer_t p = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **printer_attributes = NULL;
+
+ char **req_attrs = NULL;
+ int limit = 0;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group may contain:
+ * requested-attributes
+ */
+ get_string_list(operational, "requested-attributes", &req_attrs);
+
+ status = papiPrinterQuery(svc, DEFAULT_DEST, req_attrs, NULL, &p);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "query default: %s",
+ ipp_svc_status_mesg(svc, status));
+ papiPrinterFree(p); /* we shouldn't have a printer */
+ return (status);
+ }
+
+ /*
+ * add the printer attributes to the response in a
+ * printer-attributes-group
+ */
+ printer_attributes = papiPrinterGetAttributeList(p);
+ add_default_attributes(&printer_attributes);
+ (void) papiAttributeListAddCollection(response, PAPI_ATTR_REPLACE,
+ "printer-attributes-group", printer_attributes);
+
+ papiPrinterFree(p);
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/cups-get-printers.c b/usr/src/lib/print/libipp-listener/common/cups-get-printers.c
new file mode 100644
index 0000000000..e883543381
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/cups-get-printers.c
@@ -0,0 +1,91 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: cups-get-printers.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+cups_get_printers(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_printer_t *p = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_filter_t filt;
+
+ char **req_attrs = NULL;
+ int limit = 0;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group may contain:
+ * limit
+ * printer-info
+ * printer-location
+ * printer-type
+ * printer-type-mask
+ * requested-attributes
+ */
+
+ papiAttributeListGetInteger(operational, NULL, "limit", &limit);
+
+ get_string_list(operational, "requested-attributes", &req_attrs);
+
+ /* only ask for the classes */
+ filt.type = PAPI_FILTER_BITMASK;
+ filt.filter.bitmask.mask = ~PAPI_PRINTER_CLASS;
+ filt.filter.bitmask.value = PAPI_PRINTER_LOCAL | PAPI_PRINTER_REMOTE;
+
+ /* query the print service for printers information */
+ status = papiPrintersList(svc, req_attrs, &filt, &p);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "query printers: %s",
+ ipp_svc_status_mesg(svc, status));
+ papiPrinterListFree(p); /* we shouldn't have any printers */
+ return (status);
+ }
+
+ if (p != NULL) {
+ int i;
+
+ for (i = 0; p[i] != NULL; i++)
+ papi_to_ipp_printer_group(response, request,
+ PAPI_ATTR_APPEND, p[i]);
+ papiPrinterListFree(p);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/cups-move-job.c b/usr/src/lib/print/libipp-listener/common/cups-move-job.c
new file mode 100644
index 0000000000..137a507f93
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/cups-move-job.c
@@ -0,0 +1,103 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: cups-move-job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+cups_move_job(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL, **job = NULL;
+
+ char *message = NULL;
+ char *job_printer_uri = NULL;
+ char *queue = NULL;
+ char *dest = NULL;
+ int id = -1;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * Get job attributes from the request
+ */
+ status = papiAttributeListGetCollection(request, NULL,
+ "job-attributes-group", &job);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status,
+ "job-attributes-group: %s",
+ papiStatusString(status));
+ return (status);
+ }
+
+ /*
+ * the operational-attributes-group must contain:
+ * job-uri (or printer-uri/job-id)
+ */
+ get_printer_id(operational, &queue, &id);
+ if (id < 0) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-uri or job-id");
+ return (PAPI_BAD_REQUEST);
+ } else if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * the job-attributes-group must contain:
+ * job-printer-uri
+ */
+ job_printer_uri = NULL;
+ (void) papiAttributeListGetString(job, NULL,
+ "job-printer-uri", &job_printer_uri);
+ if (job_printer_uri == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-printer-uri");
+ return (PAPI_BAD_REQUEST);
+ } else
+ dest = destination_from_printer_uri(job_printer_uri);
+
+ if ((status = papiJobMove(svc, queue, id, dest)) != PAPI_OK)
+ ipp_set_status(response, status,
+ "move failed: %s-%d to %s: %s",
+ (queue ? queue : "(null)"), id,
+ (dest ? dest : "(null)"),
+ ipp_svc_status_mesg(svc, status));
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/cups-reject-jobs.c b/usr/src/lib/print/libipp-listener/common/cups-reject-jobs.c
new file mode 100644
index 0000000000..1a35acdf62
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/cups-reject-jobs.c
@@ -0,0 +1,68 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: cups-reject-jobs.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+cups_reject_jobs(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *queue = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ if ((status = papiPrinterPause(svc, queue, NULL)) != PAPI_OK) {
+ ipp_set_status(response, status, "pause failed: %s: %s",
+ (queue ? queue : "(null)"),
+ ipp_svc_status_mesg(svc, status));
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/disable-printer.c b/usr/src/lib/print/libipp-listener/common/disable-printer.c
new file mode 100644
index 0000000000..e1c2fd3b5c
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/disable-printer.c
@@ -0,0 +1,77 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: disable-printer.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_disable_printer(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *queue = NULL;
+ char *message = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * The operational-attributes-group may contain:
+ * printer-message-from-operator
+ */
+ (void) papiAttributeListGetString(operational, NULL,
+ "printer-message-from-operator", &message);
+
+ if ((status = papiPrinterDisable(svc, queue, message)) != PAPI_OK) {
+ ipp_set_status(response, status, "disable failed: %s: %s",
+ (queue ? queue : "(null)"),
+ ipp_svc_status_mesg(svc, status));
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/enable-printer.c b/usr/src/lib/print/libipp-listener/common/enable-printer.c
new file mode 100644
index 0000000000..0d5419d51d
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/enable-printer.c
@@ -0,0 +1,68 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: enable-printer.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_enable_printer(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *queue = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ if ((status = papiPrinterEnable(svc, queue)) != PAPI_OK) {
+ ipp_set_status(response, status, "enable failed: %s: %s",
+ (queue ? queue : "(null)"),
+ ipp_svc_status_mesg(svc, status));
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/get-job-attributes.c b/usr/src/lib/print/libipp-listener/common/get-job-attributes.c
new file mode 100644
index 0000000000..7f74054ebe
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/get-job-attributes.c
@@ -0,0 +1,89 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: get-job-attributes.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_get_job_attributes(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_job_t j = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **job_attributes = NULL;
+
+ char **req_attrs = NULL;
+ char *queue = NULL;
+ int id = -1;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * the operational-attributes-group must contain:
+ * job-uri (or printer-uri/job-id)
+ */
+ get_printer_id(operational, &queue, &id);
+ if (id < 0) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-uri or job-id");
+ return (PAPI_BAD_REQUEST);
+ } else if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * the operational-attributes-group should contain:
+ * requested-attributes
+ */
+ get_string_list(operational, "requested-attributes", &req_attrs);
+
+ if ((status = papiJobQuery(svc, queue, id, req_attrs, &j)) != PAPI_OK) {
+ ipp_set_status(response, status, "query job: %s",
+ ipp_svc_status_mesg(svc, status));
+ papiJobFree(j); /* we shouldn't have a job, but just in case */
+ return (status);
+ }
+
+ /* add the job attributes to the response in a job-attributes-group */
+ if (j != NULL) {
+ papi_to_ipp_job_group(response, request, PAPI_ATTR_REPLACE, j);
+ papiJobFree(j);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/get-jobs.c b/usr/src/lib/print/libipp-listener/common/get-jobs.c
new file mode 100644
index 0000000000..0e5e56f44c
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/get-jobs.c
@@ -0,0 +1,99 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: get-jobs.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_get_jobs(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_job_t *j = NULL;
+ papi_attribute_t **operational = NULL;
+
+ char **req_attrs = NULL;
+ char *queue = NULL;
+ int limit = 0;
+ char my_jobs = PAPI_FALSE;
+ char *which;
+ int type = 0;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * The operational-attributes-group may contain:
+ * limit
+ * requested-attributes
+ * which-jobs
+ * my-jobs
+ */
+ (void) papiAttributeListGetString(operational, NULL,
+ "which-jobs", &which);
+ (void) papiAttributeListGetBoolean(operational, NULL,
+ "my-jobs", &my_jobs);
+ (void) papiAttributeListGetInteger(operational, NULL, "limit", &limit);
+ get_string_list(operational, "requested-attributes", &req_attrs);
+
+ status = papiPrinterListJobs(svc, queue, req_attrs, type, limit, &j);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "query jobs: %s",
+ ipp_svc_status_mesg(svc, status));
+ return (status);
+ }
+
+ /* add any job's attributes to the response in job-attribute-groups */
+ if (j != NULL) {
+ int i;
+
+ for (i = 0; j[i] != NULL; i++)
+ papi_to_ipp_job_group(response, request,
+ PAPI_ATTR_APPEND, j[i]);
+ papiJobListFree(j);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/get-printer-attributes.c b/usr/src/lib/print/libipp-listener/common/get-printer-attributes.c
new file mode 100644
index 0000000000..2f33d0039c
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/get-printer-attributes.c
@@ -0,0 +1,92 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: get-printer-attributes.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_get_printer_attributes(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_printer_t p = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **printer_attributes = NULL;
+
+ char **req_attrs = NULL;
+ char *doc_fmt = NULL;
+ char *queue = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * The operational-attributes-group may contain:
+ * requested-attributes
+ * document-format
+ */
+ get_string_list(operational, "requested-attributes", &req_attrs);
+ (void) papiAttributeListGetString(operational, NULL,
+ "document-format", &doc_fmt);
+ status = papiPrinterQuery(svc, queue, req_attrs, NULL, &p);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "query printer: %s",
+ ipp_svc_status_mesg(svc, status));
+ papiPrinterFree(p); /* we shouldn't have a printer */
+ return (status);
+ }
+
+ /*
+ * add the printer attributes to the response in a
+ * printer-attributes-group
+ */
+ if (p != NULL) {
+ papi_to_ipp_printer_group(response, request,
+ PAPI_ATTR_REPLACE, p);
+ papiPrinterFree(p);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/hold-job.c b/usr/src/lib/print/libipp-listener/common/hold-job.c
new file mode 100644
index 0000000000..fcb1409df6
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/hold-job.c
@@ -0,0 +1,96 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: hold-job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_hold_job(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *message = NULL;
+ char *queue = NULL;
+ int id = -1;
+
+ /* Get operational attributes from the request */
+ papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * the operational-attributes-group must contain:
+ * job-uri (or printer-uri/job-id)
+ */
+ get_printer_id(operational, &queue, &id);
+ if (id < 0) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-uri or job-id");
+ return (PAPI_BAD_REQUEST);
+ } else if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * the operational-attributes-group may contain:
+ * message
+ * job-hold-until (ingored)
+ */
+ (void) papiAttributeListGetString(operational, NULL,
+ "message", &message);
+
+ if ((status = papiJobHold(svc, queue, id)) != PAPI_OK) {
+ ipp_set_status(response, status,
+ "hold failed: %s-%d: %s",
+ (queue ? queue : "(null)"), id,
+ ipp_svc_status_mesg(svc, status));
+ } else if (message != NULL) { /* add unsupported attribute group */
+ papi_attribute_t **unsupported = NULL;
+
+ papiAttributeListAddValue(&unsupported, PAPI_ATTR_EXCL,
+ "message", PAPI_COLLECTION, NULL);
+ (void) papiAttributeListAddCollection(response,
+ PAPI_ATTR_REPLACE, "unsupported-attributes-group",
+ unsupported);
+ papiAttributeListFree(unsupported);
+
+ status = PAPI_OK_SUBST;
+ ipp_set_status(response, status,
+ "unsupported attribute in request");
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/ipp-listener.c b/usr/src/lib/print/libipp-listener/common/ipp-listener.c
new file mode 100644
index 0000000000..42f23f85e7
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/ipp-listener.c
@@ -0,0 +1,520 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: ipp-listener.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <assert.h>
+#include <errno.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/systeminfo.h>
+
+#include <papi.h>
+#include <ipp-listener.h>
+#include <uri.h>
+
+typedef papi_status_t (ipp_handler_t)(papi_service_t svc,
+ papi_attribute_t **request,
+ papi_attribute_t ***response,
+ ipp_reader_t iread, void *fd);
+
+/*
+ * protocol request handlers are inserted below. The handler must be
+ * declared extern immediately below this comment and then an entry
+ * must be inserted in the "handlers" table a little further down.
+ */
+extern ipp_handler_t ipp_print_job;
+extern ipp_handler_t ipp_validate_job;
+extern ipp_handler_t ipp_create_job;
+extern ipp_handler_t ipp_get_printer_attributes;
+extern ipp_handler_t ipp_get_jobs;
+extern ipp_handler_t ipp_pause_printer;
+extern ipp_handler_t ipp_resume_printer;
+extern ipp_handler_t ipp_disable_printer;
+extern ipp_handler_t ipp_enable_printer;
+extern ipp_handler_t ipp_purge_jobs;
+extern ipp_handler_t ipp_send_document;
+extern ipp_handler_t ipp_cancel_job;
+extern ipp_handler_t ipp_get_job_attributes;
+extern ipp_handler_t ipp_release_job;
+extern ipp_handler_t ipp_hold_job;
+extern ipp_handler_t ipp_restart_job;
+extern ipp_handler_t ipp_set_job_attributes;
+extern ipp_handler_t ipp_set_printer_attributes;
+extern ipp_handler_t cups_get_default;
+extern ipp_handler_t cups_get_printers;
+extern ipp_handler_t cups_get_classes;
+extern ipp_handler_t cups_accept_jobs;
+extern ipp_handler_t cups_reject_jobs;
+extern ipp_handler_t cups_move_job;
+
+/* ARGSUSED0 */
+static papi_status_t
+default_handler(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response, ipp_reader_t iread, void *fd)
+{
+ int result = (int)PAPI_INTERNAL_ERROR;
+
+ if (response != NULL)
+ (void) papiAttributeListGetInteger(*response, NULL,
+ "status-code", &result);
+
+ return ((papi_status_t)result);
+}
+
+static struct {
+ int16_t id;
+ char *name;
+ ipp_handler_t *function;
+ enum { OP_REQUIRED, OP_OPTIONAL, OP_VENDOR } type;
+} handlers[] = {
+ /* Printer Operations */
+ { 0x0002, "print-job", ipp_print_job, OP_REQUIRED },
+ { 0x0003, "print-uri", NULL, OP_OPTIONAL },
+ { 0x0004, "validate-job", ipp_validate_job,
+ OP_REQUIRED },
+ { 0x0005, "create-job", ipp_create_job, OP_OPTIONAL },
+ { 0x000a, "get-jobs", ipp_get_jobs, OP_REQUIRED },
+ { 0x000b, "get-printer-attributes", ipp_get_printer_attributes,
+ OP_REQUIRED },
+ { 0x0010, "pause-printer", ipp_pause_printer,
+ OP_OPTIONAL },
+ { 0x0011, "resume-printer", ipp_resume_printer,
+ OP_OPTIONAL },
+ { 0x0012, "purge-jobs", ipp_purge_jobs, OP_OPTIONAL },
+ { 0x0013, "set-printer-attributes", ipp_set_printer_attributes,
+ OP_OPTIONAL },
+ { 0x0014, "set-job-attributes", ipp_set_job_attributes,
+ OP_OPTIONAL },
+ { 0x0022, "enable-printer", ipp_enable_printer,
+ OP_OPTIONAL },
+ { 0x0023, "disable-printer", ipp_disable_printer,
+ OP_OPTIONAL },
+ /* Job Operations */
+ { 0x0006, "send-document", ipp_send_document,
+ OP_OPTIONAL },
+ { 0x0007, "send-uri", NULL, OP_OPTIONAL },
+ { 0x0008, "cancel-job", ipp_cancel_job, OP_REQUIRED },
+ { 0x0009, "get-job-attributes", ipp_get_job_attributes,
+ OP_REQUIRED },
+ { 0x000c, "hold-job", ipp_hold_job, OP_OPTIONAL },
+ { 0x000d, "release-job", ipp_release_job,
+ OP_OPTIONAL },
+ { 0x000e, "restart-job", ipp_restart_job,
+ OP_OPTIONAL },
+ /* Other Operations */
+ { 0x4001, "cups-get-default", cups_get_default,
+ OP_VENDOR },
+ { 0x4002, "cups-get-printers", cups_get_printers,
+ OP_VENDOR },
+ { 0x4005, "cups-get-classes", cups_get_classes,
+ OP_VENDOR },
+ { 0x4008, "cups-accept-jobs", cups_accept_jobs,
+ OP_VENDOR },
+ { 0x4009, "cups-reject-jobs", cups_reject_jobs,
+ OP_VENDOR },
+ { 0x400D, "cups-move-job", cups_move_job, OP_VENDOR },
+ { 0, NULL, NULL, OP_VENDOR }
+};
+
+static int
+ipp_operation_name_to_index(char *name)
+{
+ int i;
+
+ for (i = 0; handlers[i].name != NULL; i++)
+ if (strcasecmp(name, handlers[i].name) == 0)
+ return (i);
+
+ return (-1);
+}
+
+static int
+ipp_operation_id_to_index(int16_t id)
+{
+ int i;
+
+ for (i = 0; handlers[i].name != NULL; i++)
+ if (id == handlers[i].id)
+ return (i);
+
+ return (-1);
+}
+
+static ipp_handler_t *
+ipp_operation_handler(papi_attribute_t **request, papi_attribute_t ***response)
+{
+ int id = 0;
+ int index;
+ papi_attribute_t **ops = NULL;
+ papi_status_t status;
+ char configured = PAPI_FALSE;
+
+ /* get the operation from the request */
+ status = papiAttributeListGetInteger(request, NULL,
+ "operation-id", &id);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, PAPI_BAD_ARGUMENT,
+ "no operation specified in request");
+ return (default_handler);
+ }
+
+ /* find the operation in the handler table */
+ index = ipp_operation_id_to_index(id);
+#ifdef DEBUG
+ if (index == -1)
+ fprintf(stderr, "Operation: 0x%4.4x\n", id);
+ else
+ fprintf(stderr, "Operation: 0x%4.4x(%s)\n", id,
+ handlers[index].name);
+ fflush(stderr);
+#endif
+
+ if ((index == -1) || (handlers[index].function == NULL)) {
+ ipp_set_status(response, PAPI_OPERATION_NOT_SUPPORTED,
+ "operation (0x%4.4x) not implemented by server",
+ id);
+ return (default_handler);
+ }
+
+ /* find the configured operations */
+ status = papiAttributeListGetCollection(request, NULL,
+ "operations", &ops);
+ if (status != PAPI_OK) { /* this should not be possible */
+ ipp_set_status(response, PAPI_INTERNAL_ERROR,
+ "sofware error, no operations configured");
+ return (default_handler);
+ }
+
+ /* check if the requested operation is configured */
+ status = papiAttributeListGetBoolean(ops, NULL,
+ handlers[index].name, &configured);
+ if ((status != PAPI_OK) || (configured != PAPI_TRUE)) {
+ ipp_set_status(response, PAPI_OPERATION_NOT_SUPPORTED,
+ "operation (%s 0x%4.4x) not enabled on server",
+ handlers[index].name, id);
+ return (default_handler);
+ }
+
+ return (handlers[index].function);
+}
+
+static char
+type_to_boolean(char *type)
+{
+ char result = PAPI_FALSE;
+
+ if ((strcasecmp(type, "true") == 0) ||
+ (strcasecmp(type, "yes") == 0) ||
+ (strcasecmp(type, "on") == 0) ||
+ (strcasecmp(type, "enable") == 0))
+ result = PAPI_TRUE;
+
+ return (result);
+}
+
+static papi_status_t
+ipp_configure_required_operations(papi_attribute_t ***list, char boolean)
+{
+ papi_status_t result = PAPI_OK;
+ int i;
+
+ for (i = 0; ((result == PAPI_OK) && (handlers[i].name != NULL)); i++)
+ if (handlers[i].type == OP_REQUIRED)
+ result = papiAttributeListAddBoolean(list,
+ PAPI_ATTR_REPLACE, handlers[i].name,
+ boolean);
+
+ return (result);
+
+}
+
+static papi_status_t
+ipp_configure_all_operations(papi_attribute_t ***list, char boolean)
+{
+ papi_status_t result = PAPI_OK;
+ int i;
+
+ for (i = 0; ((result == PAPI_OK) && (handlers[i].name != NULL)); i++)
+ result = papiAttributeListAddBoolean(list, PAPI_ATTR_REPLACE,
+ handlers[i].name, boolean);
+
+ return (result);
+}
+
+papi_status_t
+ipp_configure_operation(papi_attribute_t ***list, char *operation, char *type)
+{
+ papi_status_t result = PAPI_OPERATION_NOT_SUPPORTED;
+ char boolean = PAPI_FALSE;
+
+ if ((list == NULL) || (operation == NULL) || (type == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ boolean = type_to_boolean(type);
+
+ if (strcasecmp(operation, "all") == 0) {
+ result = ipp_configure_all_operations(list, boolean);
+ } else if (strcasecmp(operation, "required") == 0) {
+ result = ipp_configure_required_operations(list, boolean);
+ } else if (ipp_operation_name_to_index(operation) != -1) {
+ result = papiAttributeListAddBoolean(list, PAPI_ATTR_REPLACE,
+ operation, boolean);
+ }
+
+ return (result);
+}
+
+void
+ipp_operations_supported(papi_attribute_t ***list, papi_attribute_t **request)
+{
+ papi_attribute_t **group = NULL;
+
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operations", &group);
+ if (group != NULL) {
+ int i;
+
+ for (i = 0; handlers[i].name != NULL; i++) {
+ char boolean = PAPI_FALSE;
+ (void) papiAttributeListGetBoolean(group, NULL,
+ handlers[i].name, &boolean);
+
+ if (boolean == PAPI_TRUE)
+ (void) papiAttributeListAddInteger(list,
+ PAPI_ATTR_APPEND,
+ "operations-supported",
+ handlers[i].id);
+ }
+ }
+}
+
+static papi_status_t
+ipp_initialize_response(papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_attribute_t **operational = NULL;
+ int i;
+
+ if ((request == NULL) || (response == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* If the response was initialized, start over */
+ if (*response != NULL) {
+ papiAttributeListFree(*response);
+ *response = NULL;
+ }
+
+ /* Add the basic ipp header information to the response */
+ (void) papiAttributeListGetInteger(request, NULL, "version-major", &i);
+ (void) papiAttributeListAddInteger(response, PAPI_ATTR_REPLACE,
+ "version-major", i);
+ (void) papiAttributeListGetInteger(request, NULL, "version-minor", &i);
+ (void) papiAttributeListAddInteger(response, PAPI_ATTR_REPLACE,
+ "version-minor", i);
+
+ (void) papiAttributeListGetInteger(request, NULL, "request-id", &i);
+ (void) papiAttributeListAddInteger(response, PAPI_ATTR_REPLACE,
+ "request-id", i);
+
+ /* Add a default operational attributes group to the response */
+ (void) papiAttributeListAddString(&operational, PAPI_ATTR_EXCL,
+ "attributes-charset", "utf-8");
+ (void) papiAttributeListAddString(&operational, PAPI_ATTR_EXCL,
+ "attributes-natural-language", "en-us");
+
+ (void) papiAttributeListAddCollection(response, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", operational);
+ papiAttributeListFree(operational);
+
+ return (PAPI_OK);
+}
+
+/* simplistic check for cyclical service references */
+static int
+cyclical_service_check(char *svc_name, int port)
+{
+ papi_attribute_t **list;
+ char buf[BUFSIZ];
+ uri_t *uri = NULL;
+ char *s = NULL;
+
+ /* was there a service_uri? */
+ if (svc_name == NULL)
+ return (0);
+
+ if ((list = getprinterbyname(svc_name, NULL)) == NULL)
+ return (0); /* if it doesnt' resolve, we will fail later */
+
+ papiAttributeListGetString(list, NULL, "printer-uri-supported", &s);
+ if ((s == NULL) || (strcasecmp(svc_name, s) != 0))
+ return (0); /* they don't match */
+
+ /* is it in uri form? */
+ if (uri_from_string(s, &uri) < 0)
+ return (0);
+
+ if ((uri == NULL) || (uri->scheme == NULL) || (uri->host == NULL)) {
+ uri_free(uri);
+ return (0);
+ }
+
+ /* is it ipp form */
+ if (strcasecmp(uri->scheme, "ipp") != 0) {
+ uri_free(uri);
+ return (0);
+ }
+
+ /* does the host match up */
+ if (is_localhost(uri->host) != 0) {
+ uri_free(uri);
+ return (0);
+ }
+
+ /* does the port match our own */
+ if (((uri->port == NULL) && (port != 631)) ||
+ ((uri->port != NULL) && (atoi(uri->port) != port))) {
+ uri_free(uri);
+ return (0);
+ }
+
+ uri_free(uri);
+
+ return (1);
+}
+
+static papi_status_t
+print_service_connect(papi_service_t *svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+ char *printer_uri = NULL;
+ char *svc_name = NULL;
+ char *user = NULL;
+ int port = 631;
+
+ /* Get the operational attributes group from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /* get the user name */
+ (void) papiAttributeListGetString(request, NULL, "default-user", &user);
+ (void) papiAttributeListGetString(operational, NULL,
+ "requesting-user-name", &user);
+
+ /* get the printer or service name */
+ (void) papiAttributeListGetString(request, NULL,
+ "default-service", &svc_name);
+ get_printer_id(operational, &svc_name, NULL);
+
+ /* get the port that we are listening on */
+ (void) papiAttributeListGetInteger(request, NULL, "uri-port", &port);
+
+ if (cyclical_service_check(svc_name, port) != 0) {
+ status = PAPI_NOT_POSSIBLE;
+ ipp_set_status(response, status, "printer-uri is cyclical");
+ return (status);
+ }
+
+ status = papiServiceCreate(svc, svc_name, user, NULL, NULL,
+ PAPI_ENCRYPT_NEVER, NULL);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "print service: %s",
+ papiStatusString(status));
+ return (status);
+ }
+
+ /*
+ * Trusted Solaris can't be trusting of intermediaries. Pass
+ * the socket connection to the print service to retrieve the
+ * sensativity label off of a multi-level port.
+ */
+ {
+ int fd = -1;
+
+ (void) papiAttributeListGetInteger(request, NULL,
+ "peer-socket", &fd);
+ if (fd != -1)
+ papiServiceSetPeer(*svc, fd);
+ }
+
+ return (status);
+}
+
+papi_status_t
+ipp_process_request(papi_attribute_t **request, papi_attribute_t ***response,
+ ipp_reader_t iread, void *fd)
+{
+ papi_status_t result = PAPI_OK;
+
+ ipp_initialize_response(request, response);
+
+#ifdef DEBUG
+ fprintf(stderr, "REQUEST:");
+ papiAttributeListPrint(stderr, request, " %d ", getpid());
+ fprintf(stderr, "\n");
+#endif
+
+ /* verify that the request is "well-formed" */
+ if ((result = ipp_validate_request(request, response)) == PAPI_OK) {
+ papi_service_t svc = NULL;
+ ipp_handler_t *handler;
+
+ result = print_service_connect(&svc, request, response);
+ handler = ipp_operation_handler(request, response);
+
+ /* process the request */
+ if ((result == PAPI_OK) && (handler != NULL))
+ result = (handler)(svc, request, response, iread, fd);
+#ifdef DEBUG
+ fprintf(stderr, "RESULT: %s\n", papiStatusString(result));
+#endif
+ papiServiceDestroy(svc);
+ }
+
+ (void) papiAttributeListAddInteger(response, PAPI_ATTR_EXCL,
+ "status-code", result);
+ massage_response(request, *response);
+
+#ifdef DEBUG
+ fprintf(stderr, "RESPONSE:");
+ papiAttributeListPrint(stderr, *response, " %d ", getpid());
+ fprintf(stderr, "\n");
+#endif
+
+ return (result);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/ipp-listener.h b/usr/src/lib/print/libipp-listener/common/ipp-listener.h
new file mode 100644
index 0000000000..5a8718477e
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/ipp-listener.h
@@ -0,0 +1,70 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _IPP_LISTENER_H
+#define _IPP_LISTENER_H
+
+/* $Id: ipp-listener.h 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ipp.h>
+
+/* exported functions */
+extern papi_status_t ipp_configure_operation(papi_attribute_t ***list,
+ char *operation, char *type);
+extern papi_status_t ipp_process_request(papi_attribute_t **request,
+ papi_attribute_t ***response,
+ ipp_reader_t iread, void *fd);
+
+/* shared internal functions */
+extern char *ipp_svc_status_mesg(papi_service_t svc, papi_status_t status);
+extern char *destination_from_printer_uri(char *);
+extern void get_printer_id(papi_attribute_t **attributes, char **printer,
+ int *id);
+extern void ipp_operations_supported(papi_attribute_t ***list,
+ papi_attribute_t **request);
+extern void get_string_list(papi_attribute_t **attributes, char *name,
+ char ***values);
+extern void add_default_attributes(papi_attribute_t ***attributes);
+extern void papi_to_ipp_printer_group(papi_attribute_t ***response,
+ papi_attribute_t **request, int flags,
+ papi_printer_t p);
+extern void papi_to_ipp_job_group(papi_attribute_t ***response,
+ papi_attribute_t **request, int flags, papi_job_t j);
+extern void massage_response(papi_attribute_t **request,
+ papi_attribute_t **response);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IPP_LISTENER_H */
diff --git a/usr/src/lib/print/libipp-listener/common/mapfile b/usr/src/lib/print/libipp-listener/common/mapfile
new file mode 100644
index 0000000000..8aaaebddb2
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/mapfile
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# $Id: mapfile 151 2006-04-25 16:55:34Z njacobs $
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate_1.0 {
+ global:
+ ipp_configure_operation;
+ ipp_process_request;
+ local:
+ *;
+};
diff --git a/usr/src/lib/print/libipp-listener/common/pause-printer.c b/usr/src/lib/print/libipp-listener/common/pause-printer.c
new file mode 100644
index 0000000000..0afe4aadf0
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/pause-printer.c
@@ -0,0 +1,68 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: pause-printer.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_pause_printer(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *queue = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ if ((status = papiPrinterPause(svc, queue, NULL)) != PAPI_OK) {
+ ipp_set_status(response, status, "pause failed: %s: %s",
+ (queue ? queue : "(null)"),
+ ipp_svc_status_mesg(svc, status));
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/print-job.c b/usr/src/lib/print/libipp-listener/common/print-job.c
new file mode 100644
index 0000000000..29d6b5c5be
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/print-job.c
@@ -0,0 +1,184 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: print-job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_print_job(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response, ipp_reader_t iread, void *fd)
+{
+ papi_status_t status;
+ papi_stream_t s = NULL;
+ papi_job_t j = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **job_attributes = NULL;
+ char *queue = NULL;
+ ssize_t rc;
+ char buf[BUFSIZ];
+ char *host = NULL;
+ int fp = -1;
+ char *keys[] = { "attributes-natural-language", "attributes-charset",
+ "printer-uri", NULL };
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * The operational-attributes-group may contain:
+ * job-name
+ * ipp-attribute-fidelity
+ * document-name
+ * compression
+ * document-format
+ * document-natural-language
+ * job-k-octets
+ * job-impressions
+ * job-media-sheets
+ * Simply copy the entire contents of the operational-attributes-group
+ * for the PAPI call's possible use.
+ */
+ split_and_copy_attributes(keys, operational, NULL, &job_attributes);
+
+ /* copy any job-attributes-group attributes for the PAPI call */
+ if (papiAttributeListGetCollection(request, NULL,
+ "job-attributes-group", &operational) == PAPI_OK) {
+ char *user = NULL;
+
+ copy_attributes(&job_attributes, operational);
+
+ if (papiAttributeListGetString(operational, NULL,
+ "requesting-user-name", &user) == PAPI_OK) {
+ papiAttributeListAddString(&job_attributes,
+ PAPI_ATTR_REPLACE, "requesting-user-name", user);
+ }
+ }
+
+ /* Set "job-originating-host-name" in next block */
+ (void) papiAttributeListGetInteger(request, NULL,
+ "peer-socket", &fp);
+
+ if (fp != -1) {
+ struct sockaddr_in peer;
+ socklen_t peer_len = sizeof (peer);
+
+ /* who is our peer ? */
+ if (getpeername(fp, (struct sockaddr *)&peer,
+ &peer_len) == 0) {
+ struct hostent *he;
+ int error_num;
+
+ /*
+ * get their name or return a string containing
+ * their address
+ */
+ if ((he = getipnodebyaddr((const char *)&peer.sin_addr,
+ sizeof (peer.sin_addr), peer.sin_family,
+ &error_num)) == NULL) {
+ char tmp_buf[INET6_ADDRSTRLEN];
+ papiAttributeListAddString(
+ &job_attributes,
+ PAPI_ATTR_REPLACE,
+ "job-originating-host-name",
+ (char *)inet_ntop(peer.sin_family,
+ &peer.sin_addr, tmp_buf,
+ sizeof (tmp_buf)));
+
+ } else {
+ if (is_localhost(he->h_name) != 0)
+ papiAttributeListAddString(
+ &job_attributes,
+ PAPI_ATTR_REPLACE,
+ "job-originating-host-name",
+ "localhost");
+ else if (he->h_name != NULL)
+ papiAttributeListAddString(
+ &job_attributes,
+ PAPI_ATTR_REPLACE,
+ "job-originating-host-name",
+ he->h_name);
+ }
+ }
+ }
+
+ /* request job creation with a resulting stream that we can write to */
+ status = papiJobStreamOpen(svc, queue, job_attributes, NULL, &s);
+ papiAttributeListFree(job_attributes);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "job submission: %s",
+ ipp_svc_status_mesg(svc, status));
+ return (status);
+ }
+
+ /* copy the document data from the IPP connection to the stream */
+ while ((status == PAPI_OK) && ((rc = iread(fd, buf, sizeof (buf))) > 0))
+ status = papiJobStreamWrite(svc, s, buf, rc);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "write job data: %s",
+ ipp_svc_status_mesg(svc, status));
+ return (status);
+ }
+
+ /* close the stream, committing the job */
+ status = papiJobStreamClose(svc, s, &j);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "close job stream: %s",
+ ipp_svc_status_mesg(svc, status));
+ papiJobFree(j); /* we shouldn't have a job, but just in case */
+ return (status);
+ }
+
+ /* add the job attributes to the response in a job-attributes-group */
+ if (j != NULL) {
+ papi_to_ipp_job_group(response, request, PAPI_ATTR_REPLACE, j);
+ papiJobFree(j);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/purge-jobs.c b/usr/src/lib/print/libipp-listener/common/purge-jobs.c
new file mode 100644
index 0000000000..7128595844
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/purge-jobs.c
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: purge-jobs.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_purge_jobs(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_job_t *jobs = NULL;
+ papi_attribute_t **operational = NULL;
+
+ char *queue = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ if ((status = papiPrinterPurgeJobs(svc, queue, &jobs)) != PAPI_OK) {
+ ipp_set_status(response, status, "purge failed: %s: %s",
+ (queue ? queue : "(null)"),
+ ipp_svc_status_mesg(svc, status));
+ }
+
+ papiJobListFree(jobs);
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/release-job.c b/usr/src/lib/print/libipp-listener/common/release-job.c
new file mode 100644
index 0000000000..0ae16906a6
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/release-job.c
@@ -0,0 +1,95 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: release-job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_release_job(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *message = NULL;
+ char *queue = NULL;
+ int id = -1;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * the operational-attributes-group must contain:
+ * job-uri (or printer-uri/job-id)
+ */
+ get_printer_id(operational, &queue, &id);
+ if (id < 0) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-uri or job-id");
+ return (PAPI_BAD_REQUEST);
+ } else if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * the operational-attributes-group may contain:
+ * message
+ */
+ (void) papiAttributeListGetString(operational, NULL,
+ "message", &message);
+
+ if ((status = papiJobRelease(svc, queue, id)) != PAPI_OK) {
+ ipp_set_status(response, status,
+ "release failed: %s-%d: %s",
+ (queue ? queue : "(null)"), id,
+ ipp_svc_status_mesg(svc, status));
+ } else if (message != NULL) { /* add unsupported attribute group */
+ papi_attribute_t **unsupported = NULL;
+
+ papiAttributeListAddValue(&unsupported, PAPI_ATTR_EXCL,
+ "message", PAPI_COLLECTION, NULL);
+ (void) papiAttributeListAddCollection(response,
+ PAPI_ATTR_REPLACE, "unsupported-attributes-group",
+ unsupported);
+ papiAttributeListFree(unsupported);
+
+ status = PAPI_OK_SUBST;
+ ipp_set_status(response, status,
+ "unsupported attribute in request");
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/restart-job.c b/usr/src/lib/print/libipp-listener/common/restart-job.c
new file mode 100644
index 0000000000..d78967b0f2
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/restart-job.c
@@ -0,0 +1,106 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: restart-job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_restart_job(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *message = NULL;
+ char *hold_until = NULL;
+ char *queue = NULL;
+ int id = -1;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * the operational-attributes-group must contain:
+ * job-uri (or printer-uri/job-id)
+ */
+ get_printer_id(operational, &queue, &id);
+ if (id < 0) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-uri or job-id");
+ return (PAPI_BAD_REQUEST);
+ } else if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * the operational-attributes-group may contain:
+ * message
+ * job-hold-until
+ */
+ (void) papiAttributeListGetString(operational, NULL,
+ "job-hold-until", &hold_until);
+ (void) papiAttributeListGetString(operational, NULL,
+ "message", &message);
+
+ if ((status = papiJobRestart(svc, queue, id)) != PAPI_OK) {
+ ipp_set_status(response, status,
+ "restart failed: %s-%d: %s",
+ (queue ? queue : "(null)"), id,
+ ipp_svc_status_mesg(svc, status));
+ } else if ((message != NULL) || (hold_until != NULL)) {
+ /* add unsupported attribute group */
+ papi_attribute_t **unsupported = NULL;
+
+ if (message != NULL)
+ (void) papiAttributeListAddValue(&unsupported,
+ PAPI_ATTR_EXCL, "message",
+ PAPI_COLLECTION, NULL);
+ if (hold_until != NULL)
+ (void) papiAttributeListAddValue(&unsupported,
+ PAPI_ATTR_EXCL, "hold-until",
+ PAPI_COLLECTION, NULL);
+ (void) papiAttributeListAddCollection(response,
+ PAPI_ATTR_REPLACE, "unsupported-attributes-group",
+ unsupported);
+ papiAttributeListFree(unsupported);
+
+ status = PAPI_OK_SUBST;
+ ipp_set_status(response, status,
+ "unsupported attribute in request");
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/resume-printer.c b/usr/src/lib/print/libipp-listener/common/resume-printer.c
new file mode 100644
index 0000000000..8d48ee9adb
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/resume-printer.c
@@ -0,0 +1,68 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: resume-printer.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_resume_printer(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ papi_status_t status;
+ papi_attribute_t **operational = NULL;
+
+ char *queue = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ if ((status = papiPrinterResume(svc, queue)) != PAPI_OK) {
+ ipp_set_status(response, status, "resume failed: %s: %s",
+ (queue ? queue : "(null)"),
+ ipp_svc_status_mesg(svc, status));
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/send-document.c b/usr/src/lib/print/libipp-listener/common/send-document.c
new file mode 100644
index 0000000000..4a4d3a4314
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/send-document.c
@@ -0,0 +1,143 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: send-document.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+/*
+ * When the PAPI supports papiJobCreate(), papiJobStreamAdd() and
+ * papiJobClose(), this will be much cleaner and more efficient, but in the
+ * meantime, we are using a private, non-standard interface to do this.
+ */
+papi_status_t
+ipp_send_document(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response, ipp_reader_t iread, void *fd)
+{
+ papi_status_t status;
+ papi_stream_t s = NULL;
+ papi_job_t j = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **job_attributes = NULL;
+ char *queue = NULL;
+ ssize_t rc;
+ int id = -1;
+ char buf[BUFSIZ];
+ char last = PAPI_FALSE;
+ char *keys[] = { "attributes-natural-language", "attributes-charset",
+ "printer-uri", "job-id", "job-uri", "last-document",
+ NULL };
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * the operational-attributes-group must contain:
+ * job-uri (or printer-uri/job-id)
+ * last-document
+ */
+ get_printer_id(operational, &queue, &id);
+ if (id < 0) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-uri or job-id");
+ return (PAPI_BAD_REQUEST);
+ } else if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ status = papiAttributeListGetBoolean(operational, NULL,
+ "last-document", &last);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "last-document: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * the operational-attributes-group may contain:
+ * document-name
+ * compression
+ * document-format
+ * document-natural-language
+ * Simply copy the entire contents of the operational-attributes-group
+ * for the PAPI call's possible use.
+ */
+ split_and_copy_attributes(keys, operational, NULL, &job_attributes);
+
+ /* copy any job-attributes-group attributes for the PAPI call */
+ if (papiAttributeListGetCollection(request, NULL,
+ "job-attributes-group", &operational) == PAPI_OK)
+ copy_attributes(&job_attributes, operational);
+
+ /* create a stream to write the document data on */
+ status = papiJobStreamAdd(svc, queue, id, &s);
+ papiAttributeListFree(job_attributes);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "job submission: %s",
+ ipp_svc_status_mesg(svc, status));
+ return (status);
+ }
+
+ /* copy the document data from the IPP connection to the stream */
+ while ((status == PAPI_OK) && ((rc = iread(fd, buf, sizeof (buf))) > 0))
+ status = papiJobStreamWrite(svc, s, buf, rc);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "write job data: %s",
+ ipp_svc_status_mesg(svc, status));
+ return (status);
+ }
+
+ /* close the stream */
+ status = papiJobStreamClose(svc, s, &j);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "close job stream: %s",
+ ipp_svc_status_mesg(svc, status));
+ papiJobFree(j); /* we shouldn't have a job, but just in case */
+ return (status);
+ }
+
+ /* if it's the last document, commit the job */
+ if (last == PAPI_TRUE) {
+ status = papiJobCommit(svc, queue, id);
+ }
+
+ /* add the job attributes to the response in a job-attributes-group */
+ if (j != NULL) {
+ papi_to_ipp_job_group(response, request, PAPI_ATTR_REPLACE, j);
+ papiJobFree(j);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/set-job-attributes.c b/usr/src/lib/print/libipp-listener/common/set-job-attributes.c
new file mode 100644
index 0000000000..57c0b899f3
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/set-job-attributes.c
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: set-job-attributes.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_set_job_attributes(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response, ipp_reader_t iread, void *fd)
+{
+ papi_status_t status;
+ papi_stream_t s = NULL;
+ papi_job_t j = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **job_attributes = NULL;
+
+ char *queue = NULL;
+ int32_t id = -1;
+ ssize_t rc;
+ char buf[BUFSIZ];
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * job-uri
+ */
+ get_printer_id(operational, &queue, &id);
+ if (id < 0) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing job-uri or job-id");
+ return (PAPI_BAD_REQUEST);
+ } else if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /* get the job-attributes-group attributes for the PAPI call */
+ papiAttributeListGetCollection(request, NULL,
+ "job-attributes-group", &job_attributes);
+
+ /* request job modification */
+ status = papiJobModify(svc, queue, id, job_attributes, &j);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "job modification: %s",
+ ipp_svc_status_mesg(svc, status));
+ return (status);
+ }
+
+ /* add the job attributes to the response in a job-attributes-group */
+ if (j != NULL) {
+ papi_to_ipp_job_group(response, request, PAPI_ATTR_REPLACE, j);
+ papiJobFree(j);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/set-printer-attributes.c b/usr/src/lib/print/libipp-listener/common/set-printer-attributes.c
new file mode 100644
index 0000000000..7d80864961
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/set-printer-attributes.c
@@ -0,0 +1,83 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: set-printer-attributes.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_set_printer_attributes(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response, ipp_reader_t iread, void *fd)
+{
+ papi_status_t status;
+ papi_printer_t p = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **printer_attributes = NULL;
+
+ char *queue = NULL;
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, PAPI_BAD_REQUEST,
+ "missing printer-uri or job-uri");
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /* get the printer-attributes-group attributes for the PAPI call */
+ papiAttributeListGetCollection(request, NULL,
+ "printer-attributes-group", &printer_attributes);
+
+ /* request job modification */
+ status = papiPrinterModify(svc, queue, printer_attributes, &p);
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "printer modification: %s",
+ ipp_svc_status_mesg(svc, status));
+ return (status);
+ }
+
+ /* add the job attributes to the response in a job-attributes-group */
+ if (p != NULL) {
+ papi_to_ipp_printer_group(response, request,
+ PAPI_ATTR_REPLACE, p);
+ papiPrinterFree(p);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/common/validate-job.c b/usr/src/lib/print/libipp-listener/common/validate-job.c
new file mode 100644
index 0000000000..8ea72ee38b
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/common/validate-job.c
@@ -0,0 +1,107 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: validate-job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <papi.h>
+#include <ipp.h>
+#include <ipp-listener.h>
+
+papi_status_t
+ipp_validate_job(papi_service_t svc, papi_attribute_t **request,
+ papi_attribute_t ***response, ipp_reader_t iread, void *fd)
+{
+ papi_status_t status;
+ papi_job_t j = NULL;
+ papi_attribute_t **operational = NULL;
+ papi_attribute_t **job_attributes = NULL;
+ char *queue = NULL;
+ char *files[] = { "/etc/syslog.conf", NULL };
+ ssize_t rc;
+ char buf[BUFSIZ];
+ char *keys[] = { "attributes-natural-language", "attributes-charset",
+ "printer-uri", NULL };
+
+ /* Get operational attributes from the request */
+ (void) papiAttributeListGetCollection(request, NULL,
+ "operational-attributes-group", &operational);
+
+ /*
+ * The operational-attributes-group must contain:
+ * printer-uri
+ */
+ get_printer_id(operational, &queue, NULL);
+ if (queue == NULL) {
+ ipp_set_status(response, status, "printer-uri: %s",
+ papiStatusString(status));
+ return (PAPI_BAD_REQUEST);
+ }
+
+ /*
+ * The operational-attributes-group may contain:
+ * job-name
+ * ipp-attribute-fidelity
+ * document-name
+ * compression
+ * document-format
+ * document-natural-language
+ * job-k-octets
+ * job-impressions
+ * job-media-sheets
+ * Simply copy the entire contents of the operational-attributes-group
+ * for the PAPI call's possible use.
+ */
+ split_and_copy_attributes(keys, operational, NULL, &job_attributes);
+
+ /* copy any job-attributes-group attributes for the PAPI call */
+ if (papiAttributeListGetCollection(request, NULL,
+ "job-attributes-group", &operational) == PAPI_OK)
+ copy_attributes(&job_attributes, operational);
+
+ /* request job validation */
+ status = papiJobValidate(svc, queue, job_attributes, NULL, files, &j);
+ papiAttributeListFree(job_attributes);
+
+ if (status != PAPI_OK) {
+ ipp_set_status(response, status, "validating job: %s",
+ ipp_svc_status_mesg(svc, status));
+ papiJobFree(j); /* we shouldn't have a job, but just in case */
+ return (status);
+ }
+
+ /* add the job attributes to the response in a job-attributes-group */
+ if (j != NULL) {
+ papi_to_ipp_job_group(response, request, PAPI_ATTR_REPLACE, j);
+ papiJobFree(j);
+ }
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libipp-listener/i386/Makefile b/usr/src/lib/print/libipp-listener/i386/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libipp-listener/sparc/Makefile b/usr/src/lib/print/libipp-listener/sparc/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libipp-listener/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libpapi-common/Makefile b/usr/src/lib/print/libpapi-common/Makefile
new file mode 100644
index 0000000000..ef7e964b85
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/Makefile
@@ -0,0 +1,57 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+HDRS = papi.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber: .WAIT $(SUBDIRS)
+install: .WAIT $(SUBDIRS) install_h
+
+lint: # $(SUBDIRS)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/libpapi-common/Makefile.com b/usr/src/lib/print/libpapi-common/Makefile.com
new file mode 100644
index 0000000000..7948a2261e
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/Makefile.com
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = libpapi-common.a
+VERS = .0
+OBJECTS = attribute.o common.o library.o list.o misc.o status.o uri.o
+
+include ../../../Makefile.lib
+include ../../../Makefile.rootfs
+
+ROOTLIBDIR= $(ROOT)/usr/lib
+
+SRCDIR = ../common
+
+LIBS = $(DYNLIB)
+
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR)
+
+CERRWARN += -_gcc=-Wno-switch
+
+MAPFILES = $(SRCDIR)/mapfile
+
+LDLIBS += -lc -lsocket -lnsl
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/print/libpapi-common/common/attribute.c b/usr/src/lib/print/libpapi-common/common/attribute.c
new file mode 100644
index 0000000000..76268c7591
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/attribute.c
@@ -0,0 +1,1119 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014 Gary Mills
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: attribute.c 157 2006-04-26 15:07:55Z ktou $ */
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <alloca.h>
+#include <papi.h>
+#include <regex.h>
+
+#define MAX_PAGES 32767
+/*
+ * Assuming the maximum number of pages in
+ * a document to be 32767
+ */
+
+static void papiAttributeFree(papi_attribute_t *attribute);
+
+static void
+papiAttributeValueFree(papi_attribute_value_type_t type,
+ papi_attribute_value_t *value)
+{
+ if (value != NULL) {
+ switch (type) {
+ case PAPI_STRING:
+ if (value->string != NULL)
+ free(value->string);
+ break;
+ case PAPI_COLLECTION:
+ if (value->collection != NULL) {
+ int i;
+
+ for (i = 0; value->collection[i] != NULL; i++)
+ papiAttributeFree(value->collection[i]);
+
+ free(value->collection);
+ }
+ break;
+ default: /* don't need to free anything extra */
+ break;
+ }
+
+ free(value);
+ }
+}
+
+static void
+papiAttributeValuesFree(papi_attribute_value_type_t type,
+ papi_attribute_value_t **values)
+{
+ if (values != NULL) {
+ int i;
+
+ for (i = 0; values[i] != NULL; i++)
+ papiAttributeValueFree(type, values[i]);
+
+ free(values);
+ }
+}
+
+static void
+papiAttributeFree(papi_attribute_t *attribute)
+{
+ if (attribute != NULL) {
+ if (attribute->name != NULL)
+ free(attribute->name);
+ if (attribute->values != NULL)
+ papiAttributeValuesFree(attribute->type,
+ attribute->values);
+ free(attribute);
+ }
+}
+
+void
+papiAttributeListFree(papi_attribute_t **list)
+{
+ if (list != NULL) {
+ int i;
+
+ for (i = 0; list[i] != NULL; i++)
+ papiAttributeFree(list[i]);
+
+ free(list);
+ }
+}
+
+static papi_attribute_t **
+collection_dup(papi_attribute_t **collection)
+{
+ papi_attribute_t **result = NULL;
+
+ /* allows a NULL collection that is "empty" or "no value" */
+ if (collection != NULL) {
+ papi_status_t status = PAPI_OK;
+ int i;
+
+ for (i = 0; ((collection[i] != NULL) && (status == PAPI_OK));
+ i++) {
+ papi_attribute_t *a = collection[i];
+
+ status = papiAttributeListAddValue(&result,
+ PAPI_ATTR_APPEND, a->name, a->type,
+ NULL);
+ if ((status == PAPI_OK) && (a->values != NULL)) {
+ int j;
+
+ for (j = 0; ((a->values[j] != NULL) &&
+ (status == PAPI_OK)); j++)
+ status = papiAttributeListAddValue(
+ &result,
+ PAPI_ATTR_APPEND,
+ a->name, a->type,
+ a->values[j]);
+ }
+ }
+ if (status != PAPI_OK) {
+ papiAttributeListFree(result);
+ result = NULL;
+ }
+ }
+
+ return (result);
+}
+
+static papi_attribute_value_t *
+papiAttributeValueDup(papi_attribute_value_type_t type,
+ papi_attribute_value_t *v)
+{
+ papi_attribute_value_t *result = NULL;
+
+ if ((v != NULL) && ((result = calloc(1, sizeof (*result))) != NULL)) {
+ switch (type) {
+ case PAPI_STRING:
+ if (v->string == NULL) {
+ free(result);
+ result = NULL;
+ } else
+ result->string = strdup(v->string);
+ break;
+ case PAPI_INTEGER:
+ result->integer = v->integer;
+ break;
+ case PAPI_BOOLEAN:
+ result->boolean = v->boolean;
+ break;
+ case PAPI_RANGE:
+ result->range.lower = v->range.lower;
+ result->range.upper = v->range.upper;
+ break;
+ case PAPI_RESOLUTION:
+ result->resolution.xres = v->resolution.xres;
+ result->resolution.yres = v->resolution.yres;
+ result->resolution.units = v->resolution.units;
+ break;
+ case PAPI_DATETIME:
+ result->datetime = v->datetime;
+ break;
+ case PAPI_COLLECTION:
+ result->collection = collection_dup(v->collection);
+ break;
+ case PAPI_METADATA:
+ result->metadata = v->metadata;
+ break;
+ default: /* unknown type, fail to duplicate */
+ free(result);
+ result = NULL;
+ }
+ }
+
+ return (result);
+}
+
+static papi_attribute_t *
+papiAttributeAlloc(char *name, papi_attribute_value_type_t type)
+{
+ papi_attribute_t *result = NULL;
+
+ if ((result = calloc(1, sizeof (*result))) != NULL) {
+ result->name = strdup(name);
+ result->type = type;
+ }
+
+ return (result);
+}
+
+static papi_status_t
+papiAttributeListAppendValue(papi_attribute_value_t ***values,
+ papi_attribute_value_type_t type,
+ papi_attribute_value_t *value)
+{
+
+ if (values == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if (value != NULL) { /* this allows "empty" attributes */
+ papi_attribute_value_t *tmp = NULL;
+
+ if ((tmp = papiAttributeValueDup(type, value)) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ list_append(values, tmp);
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiAttributeListAddValue(papi_attribute_t ***list, int flgs,
+ char *name, papi_attribute_value_type_t type,
+ papi_attribute_value_t *value)
+{
+ papi_status_t result;
+ int flags = flgs;
+ papi_attribute_t *attribute = NULL;
+ papi_attribute_value_t **values = NULL;
+
+ if ((list == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((type == PAPI_RANGE) && (value != NULL) &&
+ (value->range.lower > value->range.upper))
+ return (PAPI_BAD_ARGUMENT); /* RANGE must have min <= max */
+
+ if (flags == 0) /* if it wasn't set, set a default behaviour */
+ flags = PAPI_ATTR_APPEND;
+
+ /* look for an existing one */
+ attribute = papiAttributeListFind(*list, name);
+
+ if (((flags & PAPI_ATTR_EXCL) != 0) && (attribute != NULL))
+ return (PAPI_CONFLICT); /* EXISTS */
+
+ if (((flags & PAPI_ATTR_REPLACE) == 0) && (attribute != NULL) &&
+ (attribute->type != type))
+ return (PAPI_CONFLICT); /* TYPE CONFLICT */
+
+ /* if we don't have one, create it and add it to the list */
+ if ((attribute == NULL) &&
+ ((attribute = papiAttributeAlloc(name, type)) != NULL))
+ list_append(list, attribute);
+
+ /* if we don't have one by now, it's most likely an alloc fail */
+ if (attribute == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ /*
+ * if we are replacing, clear any existing values, but don't free
+ * until after we have replaced the values, in case we are replacing
+ * a collection with a relocated version of the original collection.
+ */
+ if (((flags & PAPI_ATTR_REPLACE) != 0) && (attribute->values != NULL)) {
+ values = attribute->values;
+ attribute->values = NULL;
+ }
+
+ attribute->type = type;
+
+ result = papiAttributeListAppendValue(&attribute->values, type, value);
+
+ /* free old values if we replaced them */
+ if (values != NULL)
+ papiAttributeValuesFree(type, values);
+
+ return (result);
+}
+
+papi_status_t
+papiAttributeListAddString(papi_attribute_t ***list, int flags,
+ char *name, char *string)
+{
+ papi_attribute_value_t v;
+
+ v.string = (char *)string;
+ return (papiAttributeListAddValue(list, flags, name, PAPI_STRING, &v));
+}
+
+papi_status_t
+papiAttributeListAddInteger(papi_attribute_t ***list, int flags,
+ char *name, int integer)
+{
+ papi_attribute_value_t v;
+
+ v.integer = integer;
+ return (papiAttributeListAddValue(list, flags, name, PAPI_INTEGER, &v));
+}
+
+papi_status_t
+papiAttributeListAddBoolean(papi_attribute_t ***list, int flags,
+ char *name, char boolean)
+{
+ papi_attribute_value_t v;
+
+ v.boolean = boolean;
+ return (papiAttributeListAddValue(list, flags, name, PAPI_BOOLEAN, &v));
+}
+
+papi_status_t
+papiAttributeListAddRange(papi_attribute_t ***list, int flags,
+ char *name, int lower, int upper)
+{
+ papi_attribute_value_t v;
+
+ v.range.lower = lower;
+ v.range.upper = upper;
+ return (papiAttributeListAddValue(list, flags, name, PAPI_RANGE, &v));
+}
+
+papi_status_t
+papiAttributeListAddResolution(papi_attribute_t ***list, int flags,
+ char *name, int xres, int yres,
+ papi_resolution_unit_t units)
+{
+ papi_attribute_value_t v;
+
+ v.resolution.xres = xres;
+ v.resolution.yres = yres;
+ v.resolution.units = units;
+ return (papiAttributeListAddValue(list, flags, name,
+ PAPI_RESOLUTION, &v));
+}
+
+papi_status_t
+papiAttributeListAddDatetime(papi_attribute_t ***list, int flags,
+ char *name, time_t datetime)
+{
+ papi_attribute_value_t v;
+
+ v.datetime = datetime;
+ return (papiAttributeListAddValue(list, flags, name,
+ PAPI_DATETIME, &v));
+}
+
+papi_status_t
+papiAttributeListAddCollection(papi_attribute_t ***list, int flags,
+ char *name, papi_attribute_t **collection)
+{
+ papi_attribute_value_t v;
+
+ v.collection = (papi_attribute_t **)collection;
+ return (papiAttributeListAddValue(list, flags, name,
+ PAPI_COLLECTION, &v));
+}
+
+papi_status_t
+papiAttributeListAddMetadata(papi_attribute_t ***list, int flags,
+ char *name, papi_metadata_t metadata)
+{
+ papi_attribute_value_t v;
+
+ v.metadata = metadata;
+ return (papiAttributeListAddValue(list, flags, name,
+ PAPI_METADATA, &v));
+}
+
+papi_status_t
+papiAttributeListDelete(papi_attribute_t ***list, char *name)
+{
+ papi_attribute_t *attribute;
+
+ if ((list == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((attribute = papiAttributeListFind(*list, name)) == NULL)
+ return (PAPI_NOT_FOUND);
+
+ list_remove(list, attribute);
+ papiAttributeFree(attribute);
+
+ return (PAPI_OK);
+}
+
+papi_attribute_t *
+papiAttributeListFind(papi_attribute_t **list, char *name)
+{
+ int i;
+ if ((list == NULL) || (name == NULL))
+ return (NULL);
+
+ for (i = 0; list[i] != NULL; i++)
+ if (strcasecmp(list[i]->name, name) == 0)
+ return ((papi_attribute_t *)list[i]);
+
+ return (NULL);
+}
+
+papi_attribute_t *
+papiAttributeListGetNext(papi_attribute_t **list, void **iter)
+{
+ papi_attribute_t **tmp, *result;
+
+ if ((list == NULL) && (iter == NULL))
+ return (NULL);
+
+ if (*iter == NULL)
+ *iter = list;
+
+ tmp = *iter;
+ result = *tmp;
+ *iter = ++tmp;
+
+ return (result);
+}
+
+papi_status_t
+papiAttributeListGetValue(papi_attribute_t **list, void **iter,
+ char *name, papi_attribute_value_type_t type,
+ papi_attribute_value_t **value)
+{
+ papi_attribute_value_t **tmp;
+ void *fodder = NULL;
+
+ if ((list == NULL) || ((name == NULL) && (iter == NULL)) ||
+ (value == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (iter == NULL)
+ iter = &fodder;
+
+ if ((iter == NULL) || (*iter == NULL)) {
+ papi_attribute_t *attr = papiAttributeListFind(list, name);
+
+ if (attr == NULL)
+ return (PAPI_NOT_FOUND);
+
+ if (attr->type != type)
+ return (PAPI_NOT_POSSIBLE);
+
+ tmp = attr->values;
+ } else
+ tmp = *iter;
+
+ if (tmp == NULL)
+ return (PAPI_NOT_FOUND);
+
+ *value = *tmp;
+ *iter = ++tmp;
+
+ if (*value == NULL)
+ return (PAPI_GONE);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiAttributeListGetString(papi_attribute_t **list, void **iter,
+ char *name, char **vptr)
+{
+ papi_status_t status;
+ papi_attribute_value_t *value = NULL;
+
+ if (vptr == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ status = papiAttributeListGetValue(list, iter, name,
+ PAPI_STRING, &value);
+ if (status == PAPI_OK)
+ *vptr = value->string;
+
+ return (status);
+}
+
+papi_status_t
+papiAttributeListGetInteger(papi_attribute_t **list, void **iter,
+ char *name, int *vptr)
+{
+ papi_status_t status;
+ papi_attribute_value_t *value = NULL;
+
+ if (vptr == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ status = papiAttributeListGetValue(list, iter, name,
+ PAPI_INTEGER, &value);
+ if (status == PAPI_OK)
+ *vptr = value->integer;
+
+ return (status);
+}
+
+papi_status_t
+papiAttributeListGetBoolean(papi_attribute_t **list, void **iter,
+ char *name, char *vptr)
+{
+ papi_status_t status;
+ papi_attribute_value_t *value = NULL;
+
+ if (vptr == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ status = papiAttributeListGetValue(list, iter, name,
+ PAPI_BOOLEAN, &value);
+ if (status == PAPI_OK)
+ *vptr = value->boolean;
+
+ return (status);
+}
+
+papi_status_t
+papiAttributeListGetRange(papi_attribute_t **list, void **iter,
+ char *name, int *min, int *max)
+{
+ papi_status_t status;
+ papi_attribute_value_t *value = NULL;
+
+ if ((min == NULL) || (max == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ status = papiAttributeListGetValue(list, iter, name,
+ PAPI_RANGE, &value);
+ if (status == PAPI_OK) {
+ *min = value->range.lower;
+ *max = value->range.upper;
+ }
+
+ return (status);
+}
+
+papi_status_t
+papiAttributeListGetResolution(papi_attribute_t **list, void **iter,
+ char *name, int *x, int *y,
+ papi_resolution_unit_t *units)
+{
+ papi_status_t status;
+ papi_attribute_value_t *value = NULL;
+
+ if ((x == NULL) || (y == NULL) || (units == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ status = papiAttributeListGetValue(list, iter, name,
+ PAPI_RESOLUTION, &value);
+ if (status == PAPI_OK) {
+ *x = value->resolution.xres;
+ *y = value->resolution.yres;
+ *units = value->resolution.units;
+ }
+
+ return (status);
+}
+
+papi_status_t
+papiAttributeListGetDatetime(papi_attribute_t **list, void **iter,
+ char *name, time_t *dt)
+{
+ papi_status_t status;
+ papi_attribute_value_t *value = NULL;
+
+ if (dt == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ status = papiAttributeListGetValue(list, iter, name,
+ PAPI_DATETIME, &value);
+ if (status == PAPI_OK) {
+ *dt = value->datetime;
+ }
+
+ return (status);
+}
+
+papi_status_t
+papiAttributeListGetCollection(papi_attribute_t **list, void **iter,
+ char *name, papi_attribute_t ***collection)
+{
+ papi_status_t status;
+ papi_attribute_value_t *value = NULL;
+
+ if (collection == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ status = papiAttributeListGetValue(list, iter, name,
+ PAPI_COLLECTION, &value);
+ if (status == PAPI_OK) {
+ *collection = value->collection;
+ }
+
+ return (status);
+}
+
+papi_status_t
+papiAttributeListGetMetadata(papi_attribute_t **list, void **iter,
+ char *name, papi_metadata_t *vptr)
+{
+ papi_status_t status;
+ papi_attribute_value_t *value = NULL;
+
+ if (vptr == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ status = papiAttributeListGetValue(list, iter, name,
+ PAPI_METADATA, &value);
+ if (status == PAPI_OK)
+ *vptr = value->metadata;
+
+ return (status);
+}
+
+
+/* The string is modified by this call */
+static char *
+regvalue(regmatch_t match, char *string)
+{
+ char *result = NULL;
+ if (match.rm_so != match.rm_eo) {
+ result = string + match.rm_so;
+ *(result + (match.rm_eo - match.rm_so)) = '\0';
+ }
+ return (result);
+}
+
+static papi_attribute_value_type_t
+_process_value(char *string, char ***parts)
+{
+ int i;
+ static struct {
+ papi_attribute_value_type_t type;
+ size_t vals;
+ char *expression;
+ int compiled;
+ regex_t re;
+ } types[] = {
+ { PAPI_BOOLEAN, 1, "^(true|false|yes|no)$", 0 },
+ { PAPI_COLLECTION, 1, "^\\{(.+)\\}$", 0 },
+ /* PAPI_DATETIME is unsupported, too much like an integer */
+ { PAPI_INTEGER, 1, "^([+-]{0,1}[[:digit:]]+)$", 0 },
+ { PAPI_RANGE, 3, "^([[:digit:]]*)-([[:digit:]]*)$", 0 },
+ { PAPI_RESOLUTION, 4, "^([[:digit:]]+)x([[:digit:]]+)dp(i|c)$",
+ 0 },
+ NULL
+ };
+ regmatch_t matches[4];
+
+ for (i = 0; i < 5; i++) {
+ int j;
+
+ if (types[i].compiled == 0) {
+ (void) regcomp(&(types[i].re), types[i].expression,
+ REG_EXTENDED|REG_ICASE);
+ types[i].compiled = 1;
+ }
+ if (regexec(&(types[i].re), string, (size_t)types[i].vals,
+ matches, 0) == REG_NOMATCH)
+ continue;
+
+ for (j = 0 ; j < types[i].vals; j++)
+ list_append(parts, regvalue(matches[j], string));
+ return (types[i].type);
+ }
+
+ list_append(parts, string);
+ return (PAPI_STRING);
+}
+
+static void
+_add_attribute_value(papi_attribute_value_t ***list,
+ papi_attribute_value_type_t type,
+ papi_attribute_value_type_t dtype, char **parts)
+{
+ papi_attribute_value_t *value = calloc(1, sizeof (*value));
+
+ switch(type) {
+ case PAPI_STRING:
+ value->string = strdup(parts[0]);
+ list_append(list, value);
+ break;
+ case PAPI_BOOLEAN:
+ value->boolean = PAPI_TRUE;
+ if ((strcasecmp(parts[0], "false") == 0) ||
+ (strcasecmp(parts[0], "no") == 0))
+ value->boolean = PAPI_FALSE;
+ list_append(list, value);
+ break;
+ case PAPI_INTEGER:
+ value->integer = atoi(parts[0]);
+ list_append(list, value);
+ break;
+ case PAPI_RANGE:
+ if (dtype == PAPI_INTEGER) {
+ if (atoi(parts[0]) < 0) {
+ /*
+ * Handles -P -x case
+ * which prints from page number 1
+ * till page number x
+ */
+ value->range.lower = 1;
+ value->range.upper = 0 - (atoi(parts[0]));
+ } else {
+ value->range.lower = value->range.upper
+ = atoi(parts[0]);
+ }
+ } else if (dtype == PAPI_RANGE) {
+ if (parts[2] == NULL) {
+ value->range.lower = atoi(parts[1]);
+ /*
+ * Imposing an artificial limit on
+ * the upper bound for page range.
+ */
+ value->range.upper = MAX_PAGES;
+ } else if ((parts[1] != NULL) && (parts[2] != NULL)) {
+ value->range.lower = atoi(parts[1]);
+ value->range.upper = atoi(parts[2]);
+ }
+ }
+ list_append(list, value);
+ break;
+ case PAPI_RESOLUTION:
+ value->resolution.xres = atoi(parts[1]);
+ value->resolution.yres = atoi(parts[2]);
+ if (parts[3][0] == 'i')
+ value->resolution.units = PAPI_RES_PER_INCH;
+ else
+ value->resolution.units = PAPI_RES_PER_CM;
+ list_append(list, value);
+ break;
+ case PAPI_COLLECTION:
+ papiAttributeListFromString(&(value->collection), 0, parts[0]);
+ list_append(list, value);
+ break;
+ }
+}
+
+static papi_status_t
+_papiAttributeFromStrings(papi_attribute_t ***list, int flags,
+ char *key, char **values)
+{
+ int i;
+ papi_status_t result = PAPI_OK;
+ papi_attribute_t *attr = calloc(1, sizeof (*attr));
+
+ /* these are specified in the papi spec as ranges */
+ char *ranges[] = { "copies-supported", "job-impressions-supported",
+ "job-k-octets-supported",
+ "job-media-sheets-supported", "page-ranges",
+ NULL };
+
+ if ((attr == NULL) || ((attr->name = strdup(key)) == NULL))
+ return (PAPI_TEMPORARY_ERROR);
+
+ attr->type = PAPI_METADATA;
+ /* these are known ranges */
+ for (i = 0; ranges[i] != NULL; i++)
+ if (strcasecmp(attr->name, ranges[i]) == 0) {
+ attr->type = PAPI_RANGE;
+ break;
+ }
+
+ if (values != NULL) {
+ papi_attribute_value_t **vals = NULL;
+
+ for (i = 0; values[i] != NULL; i++) {
+ papi_attribute_value_type_t dtype;
+ char **parts = NULL;
+
+ dtype = _process_value(values[i], &parts);
+ if (attr->type == PAPI_METADATA)
+ attr->type = dtype;
+ _add_attribute_value(&vals, attr->type, dtype, parts);
+ free(parts);
+ }
+ attr->values = vals;
+ }
+
+ list_append(list, attr);
+
+ return (result);
+}
+
+static papi_status_t
+_parse_attribute_list(papi_attribute_t ***list, int flags, char *string)
+{
+ papi_status_t result = PAPI_OK;
+ char *ptr;
+
+ if ((list == NULL) || (string == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((ptr = strdup(string)) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ while ((*ptr != '\0') && (result == PAPI_OK)) {
+ char *key, **values = NULL;
+
+ /* strip any leading whitespace */
+ while (isspace(*ptr) != 0)
+ ptr++;
+
+ /* Get the name: name[=value] */
+ key = ptr;
+ while ((*ptr != '\0') && (*ptr != '=') && (isspace(*ptr) == 0))
+ ptr++;
+
+ if (*ptr == '=') {
+ *ptr++ = '\0';
+
+ while ((*ptr != '\0') && (isspace(*ptr) == 0)) {
+ char *value = ptr;
+
+ if ((*ptr == '\'') || (*ptr == '"')) {
+ char q = *ptr++;
+
+ /* quoted string value */
+ while ((*ptr != '\0') && (*ptr != q))
+ ptr++;
+ if (*ptr == q)
+ ptr++;
+ } else if (*ptr == '{') {
+ /* collection */
+ while ((*ptr != '\0') && (*ptr != '}'))
+ ptr++;
+ if (*ptr == '}')
+ ptr++;
+ } else {
+ /* value */
+ while ((*ptr != '\0') &&
+ (*ptr != ',') &&
+ (isspace(*ptr) == 0))
+ ptr++;
+ }
+ if (*ptr == ',')
+ *ptr++ = '\0';
+ list_append(&values, value);
+ }
+ } else { /* boolean "[no]key" */
+ char *value = "true";
+
+ if (strncasecmp(key, "no", 2) == 0) {
+ key += 2;
+ value = "false";
+ }
+ list_append(&values, value);
+ }
+ if (*ptr != '\0')
+ *ptr++ = '\0';
+
+ result = _papiAttributeFromStrings(list, flags, key, values);
+ free(values);
+ }
+
+ return (result);
+}
+
+papi_status_t
+papiAttributeListFromString(papi_attribute_t ***attrs,
+ int flags, char *string)
+{
+ papi_status_t result = PAPI_OK;
+
+ if ((attrs != NULL) && (string != NULL) &&
+ ((flags & ~(PAPI_ATTR_APPEND+PAPI_ATTR_REPLACE+PAPI_ATTR_EXCL))
+ == 0)) {
+ result = _parse_attribute_list(attrs, flags, string);
+ } else {
+ result = PAPI_BAD_ARGUMENT;
+ }
+
+ return (result);
+}
+
+static papi_status_t
+papiAttributeToString(papi_attribute_t *attribute, char *delim,
+ char *buffer, size_t buflen)
+{
+ papi_attribute_value_t **values = attribute->values;
+ int rc, i;
+
+ if ((attribute->type == PAPI_BOOLEAN) && (values[1] == NULL)) {
+ if (values[0]->boolean == PAPI_FALSE) {
+ if (isupper(attribute->name[0]) == 0)
+ strlcat(buffer, "no", buflen);
+ else
+ strlcat(buffer, "No", buflen);
+ }
+ rc = strlcat(buffer, attribute->name, buflen);
+ } else {
+ strlcat(buffer, attribute->name, buflen);
+ rc = strlcat(buffer, "=", buflen);
+ }
+
+ if (values == NULL)
+ return (PAPI_OK);
+
+ for (i = 0; values[i] != NULL; i++) {
+ switch (attribute->type) {
+ case PAPI_STRING:
+ rc = strlcat(buffer, values[i]->string, buflen);
+ break;
+ case PAPI_INTEGER: {
+ char string[24];
+
+ snprintf(string, sizeof (string), "%d",
+ values[i]->integer);
+ rc = strlcat(buffer, string, buflen);
+ }
+ break;
+ case PAPI_BOOLEAN:
+ if (values[1] != NULL)
+ rc = strlcat(buffer, (values[i]->boolean ?
+ "true" : "false"), buflen);
+ break;
+ case PAPI_RANGE: {
+ char string[24];
+
+ if (values[i]->range.lower == values[i]->range.upper)
+ snprintf(string, sizeof (string), "%d",
+ values[i]->range.lower);
+ else
+ snprintf(string, sizeof (string), "%d-%d",
+ values[i]->range.lower,
+ values[i]->range.upper);
+ rc = strlcat(buffer, string, buflen);
+ }
+ break;
+ case PAPI_RESOLUTION: {
+ char string[24];
+
+ snprintf(string, sizeof (string), "%dx%ddp%c",
+ values[i]->resolution.xres,
+ values[i]->resolution.yres,
+ (values[i]->resolution.units == PAPI_RES_PER_CM
+ ? 'c' : 'i'));
+ rc = strlcat(buffer, string, buflen);
+ }
+ break;
+ case PAPI_DATETIME: {
+ struct tm *tm = localtime(&values[i]->datetime);
+
+ if (tm != NULL) {
+ char string[64];
+
+ strftime(string, sizeof (string), "%c", tm);
+ rc = strlcat(buffer, string, buflen);
+ }}
+ break;
+ case PAPI_COLLECTION: {
+ char *string = alloca(buflen);
+
+ papiAttributeListToString(values[i]->collection,
+ delim, string, buflen);
+ rc = strlcat(buffer, string, buflen);
+ }
+ break;
+ default: {
+ char string[32];
+
+ snprintf(string, sizeof (string), "unknown-type-0x%x",
+ attribute->type);
+ rc = strlcat(buffer, string, buflen);
+ }
+ }
+ if (values[i+1] != NULL)
+ rc = strlcat(buffer, ",", buflen);
+
+ if (rc >= buflen)
+ return (PAPI_NOT_POSSIBLE);
+
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiAttributeListToString(papi_attribute_t **attrs,
+ char *delim, char *buffer, size_t buflen)
+{
+ papi_status_t status = PAPI_OK;
+ int i;
+
+ if ((attrs == NULL) || (buffer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ buffer[0] = '\0';
+ if (!delim)
+ delim = " ";
+
+ for (i = 0; ((attrs[i] != NULL) && (status == PAPI_OK)); i++) {
+ status = papiAttributeToString(attrs[i], delim, buffer, buflen);
+ if (attrs[i+1] != NULL)
+ strlcat(buffer, delim, buflen);
+ }
+
+ return (status);
+}
+
+static int
+is_in_list(char *value, char **list)
+{
+ if ((list != NULL) && (value != NULL)) {
+ int i;
+
+ for (i = 0; list[i] != NULL; i++)
+ if (strcasecmp(value, list[i]) == 0)
+ return (0);
+ }
+
+ return (1);
+}
+
+static papi_status_t
+copy_attribute(papi_attribute_t ***list, papi_attribute_t *attribute)
+{
+ papi_status_t status;
+ int i = 0;
+
+ if ((list == NULL) || (attribute == NULL) ||
+ (attribute->values == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ for (status = papiAttributeListAddValue(list, PAPI_ATTR_EXCL,
+ attribute->name, attribute->type,
+ attribute->values[i]);
+ ((status == PAPI_OK) && (attribute->values[i] != NULL));
+ status = papiAttributeListAddValue(list, PAPI_ATTR_APPEND,
+ attribute->name, attribute->type,
+ attribute->values[i]))
+ i++;
+
+ return (status);
+}
+
+void
+copy_attributes(papi_attribute_t ***result, papi_attribute_t **attributes)
+{
+ int i;
+
+ if ((result == NULL) || (attributes == NULL))
+ return;
+
+ for (i = 0; attributes[i] != NULL; i++)
+ copy_attribute(result, attributes[i]);
+}
+
+void
+split_and_copy_attributes(char **list, papi_attribute_t **attributes,
+ papi_attribute_t ***in, papi_attribute_t ***out)
+{
+ int i;
+
+ if ((list == NULL) || (attributes == NULL))
+ return;
+
+ for (i = 0; attributes[i] != NULL; i++)
+ if (is_in_list(attributes[i]->name, list) == 0)
+ copy_attribute(in, attributes[i]);
+ else
+ copy_attribute(out, attributes[i]);
+}
+
+void
+papiAttributeListPrint(FILE *fp, papi_attribute_t **attributes,
+ char *prefix_fmt, ...)
+{
+ char *prefix = NULL;
+ char *buffer = NULL;
+ char *newfmt = NULL;
+ void *mem;
+ ssize_t size = 0;
+ va_list ap;
+
+ newfmt = malloc(strlen(prefix_fmt) + 2);
+ sprintf(newfmt, "\n%s", prefix_fmt);
+
+ va_start(ap, prefix_fmt);
+ while (vsnprintf(prefix, size, newfmt, ap) > size) {
+ size += 1024;
+ mem = realloc(prefix, size);
+ if (!mem) goto error;
+ prefix = mem;
+ }
+ va_end(ap);
+
+ if (attributes) {
+ size = 0;
+ while (papiAttributeListToString(attributes, prefix, buffer,
+ size) != PAPI_OK) {
+ size += 1024;
+ mem = realloc(buffer, size);
+ if (!mem) goto error;
+ buffer = mem;
+ }
+ }
+
+ fprintf(fp, "%s%s\n", prefix, buffer ? buffer : "");
+ fflush(fp);
+
+ error:
+ free(newfmt);
+ free(prefix);
+ free(buffer);
+}
diff --git a/usr/src/lib/print/libpapi-common/common/common.c b/usr/src/lib/print/libpapi-common/common/common.c
new file mode 100644
index 0000000000..c14515417b
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/common.c
@@ -0,0 +1,135 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: common.c 151 2006-04-25 16:55:34Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Shared "unsupported" function implementations that can be overridden
+ * by libpapi and the various print service modules (psms).
+ */
+
+#include <stdlib.h>
+#include <papi.h>
+
+static papi_status_t
+_unsupported()
+{
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+}
+
+static void *
+_unsupported_null_return()
+{
+ return (NULL);
+}
+
+static void
+_unsupported_no_return()
+{
+}
+
+/*
+ * Service interfaces
+ */
+#pragma weak papiServiceCreate = _unsupported
+#pragma weak papiServiceDestroy = _unsupported_no_return
+#pragma weak papiServiceSetPeer = _unsupported
+#pragma weak papiServiceSetUserName = _unsupported
+#pragma weak papiServiceSetPassword = _unsupported
+#pragma weak papiServiceSetEncryption = _unsupported
+#pragma weak papiServiceSetAuthCB = _unsupported
+#pragma weak papiServiceSetAppData = _unsupported
+
+#pragma weak papiServiceGetServiceName = _unsupported_null_return
+#pragma weak papiServiceGetUserName = _unsupported_null_return
+#pragma weak papiServiceGetPassword = _unsupported_null_return
+#pragma weak papiServiceGetAppData = _unsupported_null_return
+
+papi_encryption_t
+papiServiceGetEncryption(papi_service_t handle)
+{
+ return (PAPI_ENCRYPT_NEVER);
+}
+
+#pragma weak papiServiceGetAttributeList = _unsupported_null_return
+#pragma weak papiServiceGetStatusMessage = _unsupported_null_return
+
+/*
+ * Printer operations
+ */
+#pragma weak papiPrintersList = _unsupported
+#pragma weak papiPrinterQuery = _unsupported
+#pragma weak papiPrinterEnable = _unsupported
+#pragma weak papiPrinterDisable = _unsupported
+#pragma weak papiPrinterPause = _unsupported
+#pragma weak papiPrinterResume = _unsupported
+#pragma weak papiPrinterAdd = _unsupported
+#pragma weak papiPrinterModify = _unsupported
+#pragma weak papiPrinterRemove = _unsupported
+#pragma weak papiPrinterPurgeJobs = _unsupported
+#pragma weak papiPrinterListJobs = _unsupported
+#pragma weak papiPrinterGetAttributeList = _unsupported_null_return
+#pragma weak papiPrinterFree = _unsupported_no_return
+#pragma weak papiPrinterListFree = _unsupported_no_return
+
+/*
+ * Job interfaces
+ */
+#pragma weak papiJobHold = _unsupported
+#pragma weak papiJobRelease = _unsupported
+#pragma weak papiJobRestart = _unsupported
+#pragma weak papiJobPromote = _unsupported
+#pragma weak papiJobModify = _unsupported
+#pragma weak papiJobSubmit = _unsupported
+#pragma weak papiJobSubmitByReference = _unsupported
+#pragma weak papiJobValidate = _unsupported
+#pragma weak papiJobStreamOpen = _unsupported
+#pragma weak papiJobStreamWrite = _unsupported
+#pragma weak papiJobStreamClose = _unsupported
+#pragma weak papiJobQuery = _unsupported
+#pragma weak papiJobMove = _unsupported
+#pragma weak papiJobCancel = _unsupported
+#pragma weak papiJobGetAttributeList = _unsupported_null_return
+#pragma weak papiJobGetPrinterName = _unsupported_null_return
+#pragma weak papiJobCreate = _unsupported
+#pragma weak papiJobStreamAdd = _unsupported
+#pragma weak papiJobCommit = _unsupported
+
+int
+papiJobGetId(papi_job_t job)
+{
+ return (-1);
+}
+
+#pragma weak papiJobGetJobTicket = _unsupported_null_return
+#pragma weak papiJobFree = _unsupported_no_return
+#pragma weak papiJobListFree = _unsupported_no_return
+
+/* private functions */
+#pragma weak getprinterbyname = _unsupported_null_return
diff --git a/usr/src/lib/print/libpapi-common/common/config-site.h b/usr/src/lib/print/libpapi-common/common/config-site.h
new file mode 100644
index 0000000000..2007f4f669
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/config-site.h
@@ -0,0 +1,60 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _CONFIG_SITE_H
+#define _CONFIG_SITE_H
+
+/* $Id: config-site.h.in 171 2006-05-20 06:00:32Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <config.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* the "default" destination for various commands and libraries */
+#define DEFAULT_DEST "_default"
+
+/* the "default" server uri to fallback to */
+#define DEFAULT_SERVICE_URI "lpsched://localhost/printers"
+
+/* the "default" IPP service to fallback to in the IPP psm */
+#define DEFAULT_IPP_SERVICE_URI "ipp://localhost/printers"
+
+/* the name of the SUID lpd-port binary that hands psm-lpd a connected socket */
+#define SUID_LPD_PORT "/usr/lib/print/lpd-port"
+
+/* enable/disable printer-uri in enumeration results */
+#define NEED_BROKEN_PRINTER_URI_SEMANTIC
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CONFIG_SITE_H */
diff --git a/usr/src/lib/print/libpapi-common/common/config.h b/usr/src/lib/print/libpapi-common/common/config.h
new file mode 100644
index 0000000000..280ac6d6b4
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/config.h
@@ -0,0 +1,159 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+/* source/libpapi-common/config.h. Generated by configure. */
+/* source/libpapi-common/config.h.in. Generated from configure.in by autoheader. */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dlopen' function. */
+#define HAVE_DLOPEN 1
+
+/* Define to 1 if you have the `dlsym' function. */
+#define HAVE_DLSYM 1
+
+/* Define to 1 if you have the `fprintf' function. */
+#define HAVE_FPRINTF 1
+
+/* define if you have getipnodbyname */
+#define HAVE_GETIPNODEBYNAME 1
+
+/* Define to 1 if you have the `getpassphrase' function. */
+#define HAVE_GETPASSPHRASE 1
+
+/* Define to 1 if you have the `gettext' function. */
+#define HAVE_GETTEXT 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `is_system_labeled' function. */
+#define HAVE_IS_SYSTEM_LABELED 1
+
+/* Define to 1 if you have the `localtime' function. */
+#define HAVE_LOCALTIME 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <priv.h> header file. */
+#define HAVE_PRIV_H 1
+
+/* define if you have rresvport_af */
+#define HAVE_RRESVPORT_AF 1
+
+/* Define to 1 if you have the <ruby.h> header file. */
+/* #undef HAVE_RUBY_H */
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcmp' function. */
+#define HAVE_STRCMP 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+#define HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Name of package */
+#define PACKAGE "papi"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.0_rc1"
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CONFIG_H */
diff --git a/usr/src/lib/print/libpapi-common/common/library.c b/usr/src/lib/print/libpapi-common/common/library.c
new file mode 100644
index 0000000000..12b1ffb449
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/library.c
@@ -0,0 +1,105 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: library.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <alloca.h>
+#include <libintl.h>
+#include <papi.h>
+
+static char *calls[] = {
+ /* Attribute Calls */
+ "papiAttributeListAddValue",
+ "papiAttributeListAddBoolean", "papiAttributeListAddCollection",
+ "papiAttributeListAddDatetime", "papiAttributeListAddInteger",
+ "papiAttributeListAddMetadata", "papiAttributeListAddRange",
+ "papiAttributeListAddResolution", "papiAttributeListAddString",
+ "papiAttributeListDelete",
+ "papiAttributeListGetValue", "papiAttributeListGetNext",
+ "papiAttributeListFind",
+ "papiAttributeListGetBoolean", "papiAttributeListGetCollection",
+ "papiAttributeListGetDatetime", "papiAttributeListGetInteger",
+ "papiAttributeListGetMetadata", "papiAttributeListGetRange",
+ "papiAttributeListGetResolution", "papiAttributeListGetString",
+ "papiAttributeListFromString", "papiAttributeListToString",
+ "papiAttributeListFree",
+ /* Job Calls */
+ "papiJobSubmit", "papiJobSubmitByReference", "papiJobValidate",
+ "papiJobStreamOpen", "papiJobStreamWrite", "papiJobStreamClose",
+ "papiJobQuery", "papiJobModify", "papiJobCancel", "papiJobPromote",
+ "papiJobGetAttributeList", "papiJobGetId", "papiJobGetPrinterName",
+ "papiJobGetJobTicket",
+ "papiJobFree", "papiJobListFree",
+ "papiJobHold", "papiJobRelease", "papiJobRestart",
+ /* Printer Calls */
+ "papiPrintersList", "papiPrinterQuery", "papiPrinterModify",
+ "papiPrinterAdd", "papiPrinterRemove",
+ "papiPrinterPause", "papiPrinterResume",
+ "papiPrinterDisable", "papiPrinterEnable",
+ "papiPrinterPurgeJobs", "papiPrinterListJobs",
+ "papiPrinterGetAttributeList",
+ "papiPrinterFree", "papiPrinterListFree",
+ /* Service Calls */
+ "papiServiceCreate", "papiServiceDestroy",
+ "papiServiceGetAppData",
+ "papiServiceGetEncryption", "papiServiceGetPassword",
+ "papiServiceGetServiceName", "papiServiceGetUserName",
+ "papiServiceSetAppData", "papiServiceSetAuthCB",
+ "papiServiceSetEncryption", "papiServiceSetPassword",
+ "papiServiceSetUserName",
+ "papiServiceGetAttributeList", "papiServiceGetStatusMessage",
+ /* Misc Calls */
+ "papiStatusString",
+ "papiLibrarySupportedCall", "papiLibrarySupportedCalls",
+ NULL
+};
+
+char **
+papiLibrarySupportedCalls()
+{
+ return (calls);
+}
+
+char
+papiLibrarySupportedCall(const char *name)
+{
+ int i;
+
+ for (i = 0; calls[i] != NULL; i++)
+ if (strcmp(name, calls[i]) == 0)
+ return (PAPI_TRUE);
+
+ return (PAPI_FALSE);
+}
diff --git a/usr/src/lib/print/libpapi-common/common/list.c b/usr/src/lib/print/libpapi-common/common/list.c
new file mode 100644
index 0000000000..b2560c5059
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/list.c
@@ -0,0 +1,177 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: list.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+static int __list_increment = 16;
+
+#define LIST_SIZE(x) ((((x) / __list_increment) + 1) * __list_increment)
+
+int
+list_append(void ***list, void *item)
+{
+ int count;
+
+ if ((list == NULL) || (item == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (item != NULL) {
+ if (*list == NULL)
+ *list = (void **)calloc(__list_increment,
+ sizeof (void *));
+
+ for (count = 0; (*list)[count] != NULL; count++)
+ ;
+
+ if ((count + 1) % __list_increment == 0) { /* expand the list */
+ void **new_list = NULL;
+ int new_size = LIST_SIZE(count + 1);
+
+ new_list = (void **)calloc(new_size, sizeof (void *));
+ if (new_list == NULL)
+ return (-1);
+
+ for (count = 0; (*list)[count] != NULL; count++)
+ new_list[count] = (*list)[count];
+ free(*list);
+ *list = new_list;
+ }
+
+ (*list)[count] = item;
+ }
+
+ return (0);
+}
+
+/*
+ * list_concatenate() takes in two NULL terminated lists of items (type **)
+ * and creates a new list with items from list2 appended on the end of
+ * the list of items from list1. The result is a list (type **). If
+ * there is a failure, -1 is returned.
+ */
+int
+list_concatenate(void ***result, void **list2)
+{
+ void **list1;
+ int size1 = 0;
+ int size2 = 0;
+ int new_size = 0;
+
+ if ((result == NULL) || ((*result == NULL) && (list2 == NULL))) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ list1 = *result;
+
+ if (list1 != NULL)
+ for (size1 = 0; list1[size1] != NULL; size1++)
+ ;
+ if (list2 != NULL)
+ for (size2 = 0; list2[size2] != NULL; size2++)
+ ;
+
+ /* list1 + list2 padded to a multiple of _list_increment */
+ new_size = LIST_SIZE(size1 + size2);
+
+ if ((*result = (void **)calloc((new_size), sizeof (void *))) != NULL) {
+ int count = 0;
+
+ if (list1 != NULL)
+ for (size1 = 0; list1[size1] != NULL; size1++)
+ (*result)[count++] = list1[size1];
+ if (list2 != NULL)
+ for (size2 = 0; list2[size2] != NULL; size2++)
+ (*result)[count++] = list2[size2];
+ free(list1);
+ }
+
+ return (0);
+}
+
+/*
+ * list_locate() iterates through the list passed in and uses the comparison
+ * routine and element passed in to find an element in the list. It
+ * returns the first element matched, or NULL if none exists
+ */
+void *
+list_locate(void **list, int (*compare)(void *, void *), void *element)
+{
+ int current = 0;
+
+ if ((list != NULL) && (element != NULL))
+ for (current = 0; list[current] != NULL; current++)
+ if ((compare)(list[current], element) == 0)
+ return (list[current]);
+ return (NULL);
+}
+
+void
+list_remove(void ***list, void *item)
+{
+ int i = 0, count;
+
+ if ((list == NULL) || (*list == NULL) || (item == NULL))
+ return;
+
+ /* size the original list */
+ for (count = 0; (*list)[count] != NULL; count++)
+ if ((*list)[count] == item) { /* mark the location of item */
+ i = count;
+ item = NULL;
+ }
+
+ /* if found, remove it */
+ if (item == NULL) {
+ /* shift the list over the item */
+ for (++i; ((*list)[i] != NULL); i++)
+ (*list)[i-1] = (*list)[i];
+ (*list)[i-1] = NULL;
+ }
+
+ /* if found, removed, and list should shrink, shrink it */
+ if ((item == NULL) && (LIST_SIZE(i) < LIST_SIZE(count))) {
+ void **tmp = (void **)calloc(LIST_SIZE(i), sizeof (void *));
+
+ if (tmp != NULL) {
+ for (i = 0; (*list)[i] != NULL; i++)
+ tmp[i] = (*list)[i];
+ free(*list);
+ *list = tmp;
+ }
+ }
+}
diff --git a/usr/src/lib/print/libpapi-common/common/mapfile b/usr/src/lib/print/libpapi-common/common/mapfile
new file mode 100644
index 0000000000..c1f9e3f1ab
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/mapfile
@@ -0,0 +1,168 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# $Id: mapfile.in,v 1.2 2006/03/02 06:31:36 njacobs Exp $
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+#
+# Common interfaces that are most likely to be shared amongst the various
+# PAPI implementations.
+#
+
+SYMBOL_VERSION SUNW_1.0 {
+ global:
+ # PAPI Attribute Calls
+ papiAttributeListAddValue;
+ papiAttributeListAddBoolean;
+ papiAttributeListAddCollection;
+ papiAttributeListAddDatetime;
+ papiAttributeListAddInteger;
+ papiAttributeListAddMetadata;
+ papiAttributeListAddRange;
+ papiAttributeListAddResolution;
+ papiAttributeListAddString;
+ papiAttributeListDelete;
+ papiAttributeListGetValue;
+ papiAttributeListGetNext;
+ papiAttributeListFind;
+ papiAttributeListGetBoolean;
+ papiAttributeListGetCollection;
+ papiAttributeListGetDatetime;
+ papiAttributeListGetInteger;
+ papiAttributeListGetMetadata;
+ papiAttributeListGetRange;
+ papiAttributeListGetResolution;
+ papiAttributeListGetString;
+ papiAttributeListFromString;
+ papiAttributeListToString;
+ papiAttributeListFree;
+
+ # PAPI Service Calls
+ papiServiceCreate { FLAGS = NODYNSORT };
+ papiServiceDestroy { FLAGS = NODYNSORT };
+ papiServiceSetUserName { FLAGS = NODYNSORT };
+ papiServiceSetPassword { FLAGS = NODYNSORT };
+ papiServiceSetEncryption { FLAGS = NODYNSORT };
+ papiServiceSetAuthCB { FLAGS = NODYNSORT };
+ papiServiceSetAppData { FLAGS = NODYNSORT };
+ papiServiceGetUserName { FLAGS = NODYNSORT };
+ papiServiceGetPassword { FLAGS = NODYNSORT };
+ papiServiceGetEncryption;
+ papiServiceGetAppData { FLAGS = NODYNSORT };
+ papiServiceGetServiceName { FLAGS = NODYNSORT };
+ papiServiceGetAttributeList { FLAGS = NODYNSORT };
+ papiServiceGetStatusMessage { FLAGS = NODYNSORT };
+
+ # PAPI Printer Calls
+ papiPrintersList { FLAGS = NODYNSORT };
+ papiPrinterQuery { FLAGS = NODYNSORT };
+ papiPrinterAdd { FLAGS = NODYNSORT };
+ papiPrinterModify { FLAGS = NODYNSORT };
+ papiPrinterRemove { FLAGS = NODYNSORT };
+ papiPrinterDisable { FLAGS = NODYNSORT };
+ papiPrinterEnable { FLAGS = NODYNSORT };
+ papiPrinterPause { FLAGS = NODYNSORT };
+ papiPrinterResume { FLAGS = NODYNSORT };
+ papiPrinterPurgeJobs { FLAGS = NODYNSORT };
+ papiPrinterListJobs { FLAGS = NODYNSORT };
+ papiPrinterGetAttributeList { FLAGS = NODYNSORT };
+ papiPrinterFree { FLAGS = NODYNSORT };
+ papiPrinterListFree { FLAGS = NODYNSORT };
+
+ # PAPI Job Calls
+ papiJobSubmit { FLAGS = NODYNSORT };
+ papiJobSubmitByReference { FLAGS = NODYNSORT };
+ papiJobValidate { FLAGS = NODYNSORT };
+ papiJobStreamOpen { FLAGS = NODYNSORT };
+ papiJobStreamWrite { FLAGS = NODYNSORT };
+ papiJobStreamClose { FLAGS = NODYNSORT };
+ papiJobQuery { FLAGS = NODYNSORT };
+ papiJobModify { FLAGS = NODYNSORT };
+ papiJobMove { FLAGS = NODYNSORT };
+ papiJobCancel { FLAGS = NODYNSORT };
+ papiJobHold { FLAGS = NODYNSORT };
+ papiJobRelease { FLAGS = NODYNSORT };
+ papiJobRestart { FLAGS = NODYNSORT };
+ papiJobPromote { FLAGS = NODYNSORT };
+ papiJobGetAttributeList { FLAGS = NODYNSORT };
+ papiJobGetPrinterName { FLAGS = NODYNSORT };
+ papiJobGetId;
+ papiJobGetJobTicket { FLAGS = NODYNSORT };
+ papiJobFree { FLAGS = NODYNSORT };
+ papiJobListFree { FLAGS = NODYNSORT };
+
+ # Misc. PAPI Calls
+ papiStatusString;
+ papiLibrarySupportedCall;
+ papiLibrarySupportedCalls;
+};
+
+SYMBOL_VERSION SUNWprivate_1.0 { # Misc. semi-private supporting calls
+ global:
+ papiServiceSetPeer { FLAGS = NODYNSORT };
+ papiJobCreate { FLAGS = NODYNSORT };
+ papiJobStreamAdd { FLAGS = NODYNSORT };
+ papiJobCommit { FLAGS = NODYNSORT };
+
+ # URI
+ uri_from_string;
+ uri_to_string;
+ uri_free;
+
+ # list
+ list_remove;
+ list_append;
+ list_concatenate;
+
+ # NS
+ getprinterbyname { FLAGS = NODYNSORT };
+
+ # extra Attribute Calls
+ copy_attributes;
+ split_and_copy_attributes;
+ papiAttributeListPrint;
+
+ is_localhost;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/print/libpapi-common/common/misc.c b/usr/src/lib/print/libpapi-common/common/misc.c
new file mode 100644
index 0000000000..2688fd0ec0
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/misc.c
@@ -0,0 +1,224 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: misc.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <papi.h>
+#include <uri.h>
+#include <config-site.h>
+
+/*
+ * The implementations of strlcpy() and strlcat() have been taken directly
+ * from OpenSolaris. The contents of this file originated from
+ * usr/src/lib/libc/port/gen/strlcpy.c
+ * usr/src/lib/libc/port/gen/strcat.c
+ */
+
+#ifndef HAVE_STRLCPY
+size_t
+strlcpy(char *dst, const char *src, size_t len)
+{
+ size_t slen = strlen(src);
+ size_t copied;
+
+ if (len == 0)
+ return (slen);
+
+ if (slen >= len)
+ copied = len - 1;
+ else
+ copied = slen;
+ (void) memcpy(dst, src, copied);
+ dst[copied] = '\0';
+ return (slen);
+}
+#endif
+
+#ifndef HAVE_STRLCAT
+size_t
+strlcat(char *dst, const char *src, size_t dstsize)
+{
+ char *df = dst;
+ size_t left = dstsize;
+ size_t l1;
+ size_t l2 = strlen(src);
+ size_t copied;
+
+ while (left-- != 0 && *df != '\0')
+ df++;
+ l1 = df - dst;
+ if (dstsize == l1)
+ return (l1 + l2);
+
+ copied = l1 + l2 >= dstsize ? dstsize - l1 - 1 : l2;
+ (void) memcpy(dst + l1, src, copied);
+ dst[l1+copied] = '\0';
+ return (l1 + l2);
+}
+#endif
+
+#if defined(__sun) && defined(__SVR4)
+#include <sys/systeminfo.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+static struct in6_addr **
+local_interfaces()
+{
+ struct in6_addr **result = NULL;
+ int s;
+ struct lifnum n;
+ struct lifconf c;
+ struct lifreq *r;
+ int count;
+
+ /* we need a socket to get the interfaces */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return (0);
+
+ /* get the number of interfaces */
+ memset(&n, 0, sizeof (n));
+ n.lifn_family = AF_UNSPEC;
+ if (ioctl(s, SIOCGLIFNUM, (char *)&n) < 0) {
+ close(s);
+ return (0); /* no interfaces */
+ }
+
+ /* get the interface(s) configuration */
+ memset(&c, 0, sizeof (c));
+ c.lifc_family = AF_UNSPEC;
+ c.lifc_buf = calloc(n.lifn_count, sizeof (struct lifreq));
+ c.lifc_len = (n.lifn_count * sizeof (struct lifreq));
+ if (ioctl(s, SIOCGLIFCONF, (char *)&c) < 0) {
+ free(c.lifc_buf);
+ close(s);
+ return (0); /* can't get interface(s) configuration */
+ }
+ close(s);
+
+ r = c.lifc_req;
+ for (count = c.lifc_len / sizeof (struct lifreq);
+ count > 0; count--, r++) {
+ struct in6_addr v6[1], *addr = NULL;
+
+ switch (r->lifr_addr.ss_family) {
+ case AF_INET: {
+ struct sockaddr_in *s =
+ (struct sockaddr_in *)&r->lifr_addr;
+ IN6_INADDR_TO_V4MAPPED(&s->sin_addr, v6);
+ addr = v6;
+ }
+ break;
+ case AF_INET6: {
+ struct sockaddr_in6 *s =
+ (struct sockaddr_in6 *)&r->lifr_addr;
+ addr = &s->sin6_addr;
+ }
+ break;
+ }
+
+ if (addr != NULL) {
+ struct in6_addr *a = malloc(sizeof (*a));
+
+ memcpy(a, addr, sizeof (*a));
+ list_append(&result, a);
+ }
+ }
+ free(c.lifc_buf);
+
+ return (result);
+}
+
+static int
+match_interfaces(char *host)
+{
+ struct in6_addr **lif = local_interfaces();
+ struct hostent *hp;
+ int rc = 0;
+ int errnum;
+
+ /* are there any local interfaces */
+ if (lif == NULL)
+ return (0);
+
+ /* cycle through the host db addresses */
+ hp = getipnodebyname(host, AF_INET6, AI_ALL|AI_V4MAPPED, &errnum);
+ if (hp != NULL) {
+ struct in6_addr **tmp = (struct in6_addr **)hp->h_addr_list;
+ int i;
+
+ for (i = 0; ((rc == 0) && (tmp[i] != NULL)); i++) {
+ int j;
+
+ for (j = 0; ((rc == 0) && (lif[j] != NULL)); j++)
+ if (memcmp(tmp[i], lif[j],
+ sizeof (struct in6_addr)) == 0)
+ rc = 1;
+ }
+ }
+ free(lif);
+
+ return (rc);
+}
+#endif
+
+int
+is_localhost(char *host)
+{
+ char hostname[BUFSIZ];
+
+ /* is it "localhost" */
+ if (strncasecmp(host, "localhost", 10) == 0)
+ return (1);
+
+ /* is it the {nodename} */
+ sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
+ if (strncasecmp(host, hostname, strlen(hostname)) == 0)
+ return (1);
+
+#if defined(__sun) && defined(__SVR4)
+ /* does it match one of the host's configured interfaces */
+ if (match_interfaces(host) != 0)
+ return (1);
+#endif
+ return (0);
+}
diff --git a/usr/src/lib/print/libpapi-common/common/papi.h b/usr/src/lib/print/libpapi-common/common/papi.h
new file mode 100644
index 0000000000..5fcaccc584
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/papi.h
@@ -0,0 +1,452 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _PAPI_H
+#define _PAPI_H
+
+/* $Id: papi.h 161 2006-05-03 04:32:59Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <time.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Types
+ */
+
+/* service related types */
+typedef void *papi_service_t;
+typedef void *papi_printer_t;
+typedef void *papi_job_t;
+typedef void *papi_stream_t;
+
+typedef enum {
+ PAPI_ENCRYPT_IF_REQUESTED, /* Encrypt if requested (TLS upgrade) */
+ PAPI_ENCRYPT_NEVER, /* Never encrypt */
+ PAPI_ENCRYPT_REQUIRED, /* Encryption required (TLS upgrade) */
+ PAPI_ENCRYPT_ALWAYS /* Always encrypt (SSL) */
+} papi_encryption_t;
+
+/* attribute related types */
+typedef enum {
+ PAPI_STRING,
+ PAPI_INTEGER,
+ PAPI_BOOLEAN,
+ PAPI_RANGE,
+ PAPI_RESOLUTION,
+ PAPI_DATETIME,
+ PAPI_COLLECTION,
+ PAPI_METADATA
+} papi_attribute_value_type_t;
+
+typedef enum {
+ PAPI_RES_PER_INCH = 3,
+ PAPI_RES_PER_CM
+} papi_resolution_unit_t;
+
+enum { /* for boolean values */
+ PAPI_FALSE = 0,
+ PAPI_TRUE = 1
+};
+
+typedef enum {
+ PAPI_UNSUPPORTED = 0x10,
+ PAPI_DEFAULT = 0x11,
+ PAPI_UNKNOWN,
+ PAPI_NO_VALUE,
+ PAPI_NOT_SETTABLE = 0x15,
+ PAPI_DELETE = 0x16
+} papi_metadata_t;
+
+#define PAPI_LIST_JOBS_OTHERS 0x0001
+#define PAPI_LIST_JOBS_COMPLETED 0x0002
+#define PAPI_LIST_JOBS_NOT_COMPLETED 0x0004
+#define PAPI_LIST_JOBS_ALL 0xFFFF
+
+typedef struct papi_attribute_s papi_attribute_t;
+
+typedef union {
+ char *string; /* PAPI_STRING value */
+ int integer; /* PAPI_INTEGER value */
+ char boolean; /* PAPI_BOOLEAN value */
+ struct { /* PAPI_RANGE value */
+ int lower;
+ int upper;
+ } range;
+ struct { /* PAPI_RESOLUTION value */
+ int xres;
+ int yres;
+ papi_resolution_unit_t units;
+ } resolution;
+ time_t datetime; /* PAPI_DATETIME value */
+ papi_attribute_t **collection; /* PAPI_COLLECTION value */
+ papi_metadata_t metadata; /* PAPI_METADATA value */
+} papi_attribute_value_t;
+
+struct papi_attribute_s {
+ char *name; /* attribute name */
+ papi_attribute_value_type_t type; /* type of values */
+ papi_attribute_value_t **values; /* list of values */
+};
+
+#define PAPI_ATTR_APPEND 0x0001 /* Add values to attr */
+#define PAPI_ATTR_REPLACE 0x0002 /* Delete existing values, then add */
+#define PAPI_ATTR_EXCL 0x0004 /* Fail if attr exists */
+
+/* job related types */
+typedef enum {
+ PAPI_JT_FORMAT_JDF = 0,
+ PAPI_JT_FORMAT_PWG = 1
+} papi_jt_format_t;
+
+typedef struct {
+ papi_jt_format_t format;
+ char *ticket_data;
+ char *file_name;
+} papi_job_ticket_t;
+
+/* status related types */
+typedef enum {
+ PAPI_OK = 0x0000,
+ PAPI_OK_SUBST,
+ PAPI_OK_CONFLICT,
+ PAPI_OK_IGNORED_SUBSCRIPTIONS,
+ PAPI_OK_IGNORED_NOTIFICATIONS,
+ PAPI_OK_TOO_MANY_EVENTS,
+ PAPI_OK_BUT_CANCEL_SUBSCRIPTION,
+ PAPI_REDIRECTION_OTHER_SITE = 0x0300,
+ PAPI_BAD_REQUEST = 0x0400,
+ PAPI_FORBIDDEN,
+ PAPI_NOT_AUTHENTICATED,
+ PAPI_NOT_AUTHORIZED,
+ PAPI_NOT_POSSIBLE,
+ PAPI_TIMEOUT,
+ PAPI_NOT_FOUND,
+ PAPI_GONE,
+ PAPI_REQUEST_ENTITY,
+ PAPI_REQUEST_VALUE,
+ PAPI_DOCUMENT_FORMAT,
+ PAPI_ATTRIBUTES,
+ PAPI_URI_SCHEME,
+ PAPI_CHARSET,
+ PAPI_CONFLICT,
+ PAPI_COMPRESSION_NOT_SUPPORTED,
+ PAPI_COMPRESSION_ERROR,
+ PAPI_DOCUMENT_FORMAT_ERROR,
+ PAPI_DOCUMENT_ACCESS_ERROR,
+ PAPI_ATTRIBUTES_NOT_SETTABLE,
+ PAPI_IGNORED_ALL_SUBSCRIPTIONS,
+ PAPI_TOO_MANY_SUBSCRIPTIONS,
+ PAPI_IGNORED_ALL_NOTIFICATIONS,
+ PAPI_PRINT_SUPPORT_FILE_NOT_FOUND,
+ PAPI_INTERNAL_ERROR = 0x0500,
+ PAPI_OPERATION_NOT_SUPPORTED,
+ PAPI_SERVICE_UNAVAILABLE,
+ PAPI_VERSION_NOT_SUPPORTED,
+ PAPI_DEVICE_ERROR,
+ PAPI_TEMPORARY_ERROR,
+ PAPI_NOT_ACCEPTING,
+ PAPI_PRINTER_BUSY,
+ PAPI_ERROR_JOB_CANCELLED,
+ PAPI_MULTIPLE_JOBS_NOT_SUPPORTED,
+ PAPI_PRINTER_IS_DEACTIVATED,
+ PAPI_BAD_ARGUMENT,
+ PAPI_JOB_TICKET_NOT_SUPPORTED
+} papi_status_t;
+
+/* list filter related */
+typedef enum {
+ PAPI_FILTER_BITMASK = 0
+} papi_filter_type_t;
+
+typedef struct {
+ papi_filter_type_t type;
+ union {
+ struct { /* PAPI_FILTER_BITMASK */
+ unsigned int mask;
+ unsigned int value;
+ } bitmask;
+ } filter;
+} papi_filter_t;
+
+enum {
+ PAPI_PRINTER_LOCAL = 0x0000, /* Local destination */
+ PAPI_PRINTER_CLASS = 0x0001, /* Printer class */
+ PAPI_PRINTER_REMOTE = 0x0002, /* Remote destination */
+ PAPI_PRINTER_BW = 0x0004, /* Can do B&W printing */
+ PAPI_PRINTER_COLOR = 0x0008, /* Can do color printing */
+ PAPI_PRINTER_DUPLEX = 0x0010, /* Can do duplex printing */
+ PAPI_PRINTER_STAPLE = 0x0020, /* Can do stapling */
+ PAPI_PRINTER_COPIES = 0x0040, /* Can do copies */
+ PAPI_PRINTER_COLLATE = 0x0080, /* Can collate copies */
+ PAPI_PRINTER_PUNCH = 0x0100, /* Can punch output */
+ PAPI_PRINTER_COVER = 0x0200, /* Can cover output */
+ PAPI_PRINTER_BIND = 0x0400, /* Can bind output */
+ PAPI_PRINTER_SORT = 0x0800, /* Can sort output */
+ PAPI_PRINTER_SMALL = 0x1000, /* Can do letter/legal/a4 */
+ PAPI_PRINTER_MEDIUM = 0x2000, /* Can do tabloid/B/C/A3/A2 */
+ PAPI_PRINTER_LARGE = 0x4000, /* Can do D/E/A1/A0 */
+ PAPI_PRINTER_VARIABLE = 0x8000, /* Can do variable sizes */
+ PAPI_PRINTER_IMPLICIT = 0x10000, /* implicit class */
+ PAPI_PRINTER_DEFAULT = 0x20000, /* Default printer on network */
+ PAPI_PRINTER_OPTIONS = 0xfffc /* ~ (CLASS | REMOTE | IMPLICIT) */
+};
+
+/*
+ * Functions
+ */
+
+/* Service related */
+extern papi_status_t papiServiceCreate(papi_service_t *handle,
+ char *service_name, char *user_name,
+ char *password,
+ int (*authCB)(papi_service_t svc,
+ void *app_data),
+ papi_encryption_t encryption,
+ void *app_data);
+extern void papiServiceDestroy(papi_service_t handle);
+extern papi_status_t papiServiceSetUserName(papi_service_t handle,
+ char *user_name);
+extern papi_status_t papiServiceSetPassword(papi_service_t handle,
+ char *password);
+extern papi_status_t papiServiceSetEncryption(papi_service_t handle,
+ papi_encryption_t encryption);
+extern papi_status_t papiServiceSetAuthCB(papi_service_t handle,
+ int (*authCB)(papi_service_t s,
+ void *app_data));
+extern papi_status_t papiServiceSetAppData(papi_service_t handle,
+ void *app_data);
+extern char *papiServiceGetServiceName(papi_service_t handle);
+extern char *papiServiceGetUserName(papi_service_t handle);
+extern char *papiServiceGetPassword(papi_service_t handle);
+extern papi_encryption_t papiServiceGetEncryption(papi_service_t handle);
+extern void *papiServiceGetAppData(papi_service_t handle);
+extern papi_attribute_t **papiServiceGetAttributeList(papi_service_t handle);
+extern char *papiServiceGetStatusMessage(papi_service_t handle);
+
+/* Attribute related */
+extern papi_status_t papiAttributeListAddValue(papi_attribute_t ***attrs,
+ int flags, char *name,
+ papi_attribute_value_type_t type,
+ papi_attribute_value_t *value);
+extern papi_status_t papiAttributeListAddString(papi_attribute_t ***attrs,
+ int flags, char *name, char *string);
+extern papi_status_t papiAttributeListAddInteger(papi_attribute_t ***attrs,
+ int flags, char *name, int integer);
+extern papi_status_t papiAttributeListAddBoolean(papi_attribute_t ***attrs,
+ int flags, char *name, char boolean);
+extern papi_status_t papiAttributeListAddRange(papi_attribute_t ***attrs,
+ int flags, char *name,
+ int lower, int upper);
+extern papi_status_t papiAttributeListAddResolution(papi_attribute_t ***attrs,
+ int flags, char *name,
+ int xres, int yres,
+ papi_resolution_unit_t units);
+extern papi_status_t papiAttributeListAddDatetime(papi_attribute_t ***attrs,
+ int flags, char *name, time_t datetime);
+extern papi_status_t papiAttributeListAddCollection(papi_attribute_t ***attrs,
+ int flags, char *name,
+ papi_attribute_t **collection);
+extern papi_status_t papiAttributeListAddMetadata(papi_attribute_t ***attrs,
+ int flags, char *name,
+ papi_metadata_t metadata);
+extern papi_status_t papiAttributeListDelete(papi_attribute_t ***attributes,
+ char *name);
+extern papi_status_t papiAttributeListGetValue(papi_attribute_t **list,
+ void **iterator, char *name,
+ papi_attribute_value_type_t type,
+ papi_attribute_value_t **value);
+extern papi_status_t papiAttributeListGetString(papi_attribute_t **list,
+ void **iterator, char *name,
+ char **vptr);
+extern papi_status_t papiAttributeListGetInteger(papi_attribute_t **list,
+ void **iterator, char *name, int *vptr);
+extern papi_status_t papiAttributeListGetBoolean(papi_attribute_t **list,
+ void **iterator, char *name,
+ char *vptr);
+extern papi_status_t papiAttributeListGetRange(papi_attribute_t **list,
+ void **iterator, char *name,
+ int *min, int *max);
+extern papi_status_t papiAttributeListGetResolution(papi_attribute_t **list,
+ void **iterator, char *name,
+ int *x, int *y,
+ papi_resolution_unit_t *units);
+extern papi_status_t papiAttributeListGetDatetime(papi_attribute_t **list,
+ void **iterator, char *name,
+ time_t *dt);
+extern papi_status_t papiAttributeListGetCollection(papi_attribute_t **list,
+ void **iterator, char *name,
+ papi_attribute_t ***collection);
+extern papi_status_t papiAttributeListGetMetadata(papi_attribute_t **list,
+ void **iterator, char *name,
+ papi_metadata_t *vptr);
+extern papi_attribute_t *papiAttributeListFind(papi_attribute_t **list,
+ char *name);
+extern papi_attribute_t *papiAttributeListGetNext(papi_attribute_t **list,
+ void **iterator);
+extern void papiAttributeListFree(papi_attribute_t **attributes);
+
+extern papi_status_t papiAttributeListFromString(papi_attribute_t ***attrs,
+ int flags, char *string);
+extern papi_status_t papiAttributeListToString(papi_attribute_t **attrs,
+ char *delim,
+ char *buffer, size_t buflen);
+extern void papiAttributeListPrint(FILE *fp, papi_attribute_t **list,
+ char *prefix_fmt, ...);
+
+/* Printer related */
+extern papi_status_t papiPrintersList(papi_service_t handle,
+ char **requested_attrs,
+ papi_filter_t *filter,
+ papi_printer_t **printers);
+extern papi_status_t papiPrinterQuery(papi_service_t handle, char *name,
+ char **requested_attrs,
+ papi_attribute_t **job_attributes,
+ papi_printer_t *printer);
+extern papi_status_t papiPrinterAdd(papi_service_t handle, char *name,
+ papi_attribute_t **attributes,
+ papi_printer_t *printer);
+extern papi_status_t papiPrinterModify(papi_service_t handle, char *name,
+ papi_attribute_t **attributes,
+ papi_printer_t *printer);
+extern papi_status_t papiPrinterRemove(papi_service_t handle, char *name);
+extern papi_status_t papiPrinterDisable(papi_service_t handle, char *name,
+ char *message);
+extern papi_status_t papiPrinterEnable(papi_service_t handle, char *name);
+extern papi_status_t papiPrinterPause(papi_service_t handle, char *name,
+ char *message);
+extern papi_status_t papiPrinterResume(papi_service_t handle, char *name);
+extern papi_status_t papiPrinterPurgeJobs(papi_service_t handle,
+ char *name, papi_job_t **jobs);
+extern papi_status_t papiPrinterListJobs(papi_service_t handle,
+ char *name, char **requested_attrs,
+ int type_mask, int max_num_jobs,
+ papi_job_t **jobs);
+extern papi_attribute_t **papiPrinterGetAttributeList(papi_printer_t printer);
+extern void papiPrinterFree(papi_printer_t printer);
+extern void papiPrinterListFree(papi_printer_t *printers);
+
+/* Job related */
+extern papi_status_t papiJobSubmit(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ char **files, papi_job_t *job);
+extern papi_status_t papiJobSubmitByReference(papi_service_t handle,
+ char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ char **files, papi_job_t *job);
+extern papi_status_t papiJobValidate(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ char **files, papi_job_t *job);
+extern papi_status_t papiJobStreamOpen(papi_service_t handle,
+ char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ papi_stream_t *stream);
+extern papi_status_t papiJobStreamWrite(papi_service_t handle,
+ papi_stream_t stream,
+ void *buffer, size_t buflen);
+extern papi_status_t papiJobStreamClose(papi_service_t handle,
+ papi_stream_t stream,
+ papi_job_t *job);
+extern papi_status_t papiJobQuery(papi_service_t handle, char *printer,
+ int32_t job_id, char **requested_attrs,
+ papi_job_t *job);
+extern papi_status_t papiJobModify(papi_service_t handle, char *printer,
+ int32_t job_id,
+ papi_attribute_t **attributes,
+ papi_job_t *job);
+extern papi_status_t papiJobMove(papi_service_t handle, char *printer,
+ int32_t job_id, char *destination);
+extern papi_status_t papiJobCancel(papi_service_t handle, char *printer,
+ int32_t job_id);
+extern papi_status_t papiJobHold(papi_service_t handle, char *printer,
+ int32_t job_id);
+extern papi_status_t papiJobRelease(papi_service_t handle, char *printer,
+ int32_t job_id);
+extern papi_status_t papiJobRestart(papi_service_t handle, char *printer,
+ int32_t job_id);
+extern papi_status_t papiJobPromote(papi_service_t handle, char *printer,
+ int32_t job_id);
+extern papi_attribute_t **papiJobGetAttributeList(papi_job_t printer);
+extern char *papiJobGetPrinterName(papi_job_t printer);
+extern int32_t papiJobGetId(papi_job_t printer);
+extern papi_job_ticket_t *papiJobGetJobTicket(papi_job_t printer);
+extern void papiJobFree(papi_job_t job);
+extern void papiJobListFree(papi_job_t *jobs);
+
+#ifdef SOLARIS_PRIVATE_POST_0_9
+/*
+ * These have been added to support IPP create-job/send-document with PAPI v0.9
+ * in an IPP listener using PAPI as it's spooler interface. A future version
+ * of the API is expected to support this type of functionality
+ */
+extern papi_status_t papiJobCreate(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ papi_job_t *job);
+extern papi_status_t papiJobStreamAdd(papi_service_t handle, char *printer,
+ int32_t id, papi_stream_t *stream);
+extern papi_status_t papiJobCommit(papi_service_t handle, char *printer,
+ int32_t id);
+extern papi_status_t papiServiceSetPeer(papi_service_t handle, int peerfd);
+#endif /* SOLARIS_PRIVATE_POST_0_9 */
+
+extern char *papiStatusString(papi_status_t status);
+
+/*
+ * Internal functions that aren't in the API, but are shared across
+ * protocol support implementations(psms) and the tightly bound
+ * listener library. Do not use these in your applications.
+ */
+extern void list_append();
+extern void list_concatenate();
+extern void list_remove();
+extern void copy_attributes(papi_attribute_t ***result,
+ papi_attribute_t **list);
+extern void split_and_copy_attributes(char **list,
+ papi_attribute_t **attributes,
+ papi_attribute_t ***in,
+ papi_attribute_t ***out);
+
+extern papi_attribute_t **getprinterbyname(char *name, char *ns);
+
+extern int is_localhost(char *hostname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PAPI_H */
diff --git a/usr/src/lib/print/libpapi-common/common/status.c b/usr/src/lib/print/libpapi-common/common/status.c
new file mode 100644
index 0000000000..897aa1322d
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/status.c
@@ -0,0 +1,133 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: status.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <papi.h>
+#include <libintl.h>
+
+char *
+papiStatusString(const papi_status_t status)
+{
+ switch (status) {
+ case PAPI_OK:
+ return (gettext("ok"));
+ case PAPI_OK_SUBST:
+ return (gettext("ok-substitution"));
+ case PAPI_OK_CONFLICT:
+ return (gettext("ok-conflict"));
+ case PAPI_OK_IGNORED_SUBSCRIPTIONS:
+ return (gettext("ok-ignored-subscriptions"));
+ case PAPI_OK_IGNORED_NOTIFICATIONS:
+ return (gettext("ok-ignored-notifications"));
+ case PAPI_OK_TOO_MANY_EVENTS:
+ return (gettext("ok-too-many-events"));
+ case PAPI_OK_BUT_CANCEL_SUBSCRIPTION:
+ return (gettext("ok-but-cancel-subscription"));
+ case PAPI_REDIRECTION_OTHER_SITE:
+ return (gettext("redirection-to-other-site"));
+ case PAPI_BAD_REQUEST:
+ return (gettext("bad-request"));
+ case PAPI_FORBIDDEN:
+ return (gettext("forbidden"));
+ case PAPI_NOT_AUTHENTICATED:
+ return (gettext("not-authenticated"));
+ case PAPI_NOT_AUTHORIZED:
+ return (gettext("not-authorized"));
+ case PAPI_NOT_POSSIBLE:
+ return (gettext("not-possible"));
+ case PAPI_TIMEOUT:
+ return (gettext("timeout"));
+ case PAPI_NOT_FOUND:
+ return (gettext("not-found"));
+ case PAPI_GONE:
+ return (gettext("gone"));
+ case PAPI_REQUEST_ENTITY:
+ return (gettext("request-entity"));
+ case PAPI_REQUEST_VALUE:
+ return (gettext("request-value"));
+ case PAPI_DOCUMENT_FORMAT:
+ return (gettext("document-format"));
+ case PAPI_ATTRIBUTES:
+ return (gettext("attributes"));
+ case PAPI_URI_SCHEME:
+ return (gettext("uri-scheme"));
+ case PAPI_CHARSET:
+ return (gettext("charset"));
+ case PAPI_CONFLICT:
+ return (gettext("conflict"));
+ case PAPI_COMPRESSION_NOT_SUPPORTED:
+ return (gettext("compression-not-supported"));
+ case PAPI_COMPRESSION_ERROR:
+ return (gettext("compression-error"));
+ case PAPI_DOCUMENT_FORMAT_ERROR:
+ return (gettext("document-format-error"));
+ case PAPI_DOCUMENT_ACCESS_ERROR:
+ return (gettext("document-access-error"));
+ case PAPI_ATTRIBUTES_NOT_SETTABLE:
+ return (gettext("attributes-not-settable"));
+ case PAPI_IGNORED_ALL_SUBSCRIPTIONS:
+ return (gettext("ignored-all-subscriptions"));
+ case PAPI_TOO_MANY_SUBSCRIPTIONS:
+ return (gettext("too-many-subscriptions"));
+ case PAPI_IGNORED_ALL_NOTIFICATIONS:
+ return (gettext("ignored-all-notifications"));
+ case PAPI_PRINT_SUPPORT_FILE_NOT_FOUND:
+ return (gettext("print-support-file-not-found"));
+ case PAPI_INTERNAL_ERROR:
+ return (gettext("internal-error"));
+ case PAPI_OPERATION_NOT_SUPPORTED:
+ return (gettext("operation-not-supported"));
+ case PAPI_SERVICE_UNAVAILABLE:
+ return (gettext("service-unavailable"));
+ case PAPI_VERSION_NOT_SUPPORTED:
+ return (gettext("version-not-supported"));
+ case PAPI_DEVICE_ERROR:
+ return (gettext("device-error"));
+ case PAPI_TEMPORARY_ERROR:
+ return (gettext("temporary-error"));
+ case PAPI_NOT_ACCEPTING:
+ return (gettext("not-accepting"));
+ case PAPI_PRINTER_BUSY:
+ return (gettext("printer-busy"));
+ case PAPI_ERROR_JOB_CANCELLED:
+ return (gettext("error-job-cancelled"));
+ case PAPI_MULTIPLE_JOBS_NOT_SUPPORTED:
+ return (gettext("multiple-jobs-not-supported"));
+ case PAPI_PRINTER_IS_DEACTIVATED:
+ return (gettext("printer-is-deactivated"));
+ case PAPI_BAD_ARGUMENT:
+ return (gettext("bad-argument"));
+ case PAPI_JOB_TICKET_NOT_SUPPORTED:
+ return (gettext("job-ticket-not-supported"));
+ default:
+ return (gettext("unknown-error"));
+ }
+}
diff --git a/usr/src/lib/print/libpapi-common/common/uri.c b/usr/src/lib/print/libpapi-common/common/uri.c
new file mode 100644
index 0000000000..31f6ce4eff
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/uri.c
@@ -0,0 +1,300 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/* $Id: uri.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#include "uri.h"
+
+/*
+ * This will handle the following forms:
+ * scheme:scheme_data
+ * scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]]
+ */
+int
+uri_from_string(char *string, uri_t **uri)
+{
+ char *ptr;
+ uri_t *u;
+
+ if ((string == NULL) || (uri == NULL)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* find the scheme:scheme_part split */
+ if ((ptr = strchr(string, ':')) == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((*uri = u = calloc(1, sizeof (*u))) == NULL)
+ return (-1);
+
+ u->scheme = strndup(string, ptr - string);
+
+ if ((ptr[1] == '/') && (ptr[2] == '/')) {
+ /*
+ * CSTYLED
+ * scheme://[host_part]/[path_part]
+ */
+ char *end = NULL, *user = NULL, *host = NULL, *path = NULL;
+
+ string = ptr + 3; /* skip the :// */
+
+ if ((path = end = strchr(string, '/')) == NULL)
+ for (end = string; *end != '\0'; end++)
+ continue;
+
+ u->host_part = strndup(string, end - string);
+
+ for (host = string; host < end; host ++)
+ if (*host == '@') {
+ /* string to host is the user part */
+ u->user_part = strndup(string, host-string);
+ /* host+1 to end is the host part */
+ u->host_part = strndup(host + 1,
+ end - (host+1));
+ user = string;
+ host++;
+ break;
+ }
+
+ if (user != NULL) {
+ char *password = NULL;
+
+ for (password = user; (password < host - 1); password++)
+ if (*password == ':') {
+ u->password = strndup(password + 1,
+ host - password - 2);
+ break;
+ }
+ u->user = strndup(user, password - user);
+ } else
+ host = string;
+
+ if (host != NULL) {
+ char *port = NULL;
+
+ for (port = host; (port < path); port++)
+ if ((*port == ':') || (*port == '/'))
+ break;
+
+ if (port < path) {
+ u->port = strndup(port + 1, path - port - 1);
+ }
+
+ u->host = strndup(host, port - host);
+ }
+
+ if (path != NULL) {
+ char *name = strrchr(path, '/');
+
+ u->path_part = strdup(path);
+
+ if (name != NULL) {
+ char *query, *fragment;
+
+ query = strrchr(name, '?');
+ if ((query != NULL) && (*query != '\0')) {
+ u->query = strdup(query + 1);
+ end = query;
+ } else {
+ for (end = path; *end != '\0'; end++)
+ continue;
+ }
+
+ fragment = strrchr(name, '#');
+ if ((fragment != NULL) && (*fragment != '\0')) {
+ u->fragment = strndup(fragment + 1,
+ end - fragment - 1);
+ end = fragment;
+ }
+
+ u->path = strndup(path, end - path);
+ }
+ }
+ } else { /* scheme:scheme_part */
+ u->scheme_part = strdup(&ptr[1]);
+ }
+
+ if ((u->host_part == NULL) && (u->path_part == NULL) &&
+ (u->scheme_part == NULL)) {
+ errno = EINVAL;
+ uri_free(u);
+ *uri = NULL;
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+uri_to_string(uri_t *uri, char *buffer, size_t buflen)
+{
+ char *uri_ppfix;
+
+ if ((uri == NULL) || (buffer == NULL) || (buflen == 0) ||
+ (uri->scheme == NULL) ||
+ ((uri->password != NULL) && (uri->user == NULL)) ||
+ ((uri->user != NULL) && (uri->host == NULL)) ||
+ ((uri->port != NULL) && (uri->host == NULL)) ||
+ ((uri->fragment != NULL) && (uri->path == NULL)) ||
+ ((uri->query != NULL) && (uri->path == NULL))) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if (uri->path == NULL || uri->path[0] == '/')
+ uri_ppfix = "";
+ else
+ uri_ppfix = "/";
+
+ (void) memset(buffer, 0, buflen);
+
+ if (uri->scheme_part == NULL) {
+ (void) snprintf(buffer, buflen,
+ "%s://%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ uri->scheme,
+ (uri->user ? uri->user : ""),
+ (uri->password ? ":" : ""),
+ (uri->password ? uri->password : ""),
+ (uri->user ? "@": ""),
+ (uri->host ? uri->host : ""),
+ (uri->port ? ":" : ""),
+ (uri->port ? uri->port : ""),
+ uri_ppfix,
+ (uri->path ? uri->path : ""),
+ (uri->fragment ? "#" : ""),
+ (uri->fragment ? uri->fragment : ""),
+ (uri->query ? "?" : ""),
+ (uri->query ? uri->query : ""));
+ } else {
+ (void) snprintf(buffer, buflen, "%s:%s", uri->scheme,
+ uri->scheme_part);
+ }
+
+ return (0);
+}
+
+void
+uri_free(uri_t *uri)
+{
+ if (uri != NULL) {
+ if (uri->scheme != NULL)
+ free(uri->scheme);
+ if (uri->scheme_part != NULL)
+ free(uri->scheme_part);
+ if (uri->user != NULL)
+ free(uri->user);
+ if (uri->password != NULL)
+ free(uri->password);
+ if (uri->host != NULL)
+ free(uri->host);
+ if (uri->port != NULL)
+ free(uri->port);
+ if (uri->path != NULL)
+ free(uri->path);
+ if (uri->fragment != NULL)
+ free(uri->fragment);
+ if (uri->query != NULL)
+ free(uri->query);
+ /* help me debug */
+ if (uri->user_part != NULL)
+ free(uri->user_part);
+ if (uri->host_part != NULL)
+ free(uri->host_part);
+ if (uri->path_part != NULL)
+ free(uri->path_part);
+ free(uri);
+ }
+}
+
+#ifdef DEADBEEF
+static void
+uri_dump(FILE *fp, uri_t *uri)
+{
+ if (uri != NULL) {
+ fprintf(fp, "URI:\n");
+ if (uri->scheme != NULL)
+ fprintf(fp, "scheme: %s\n", uri->scheme);
+ if (uri->scheme_part != NULL)
+ fprintf(fp, "scheme_part: %s\n", uri->scheme_part);
+ if (uri->user != NULL)
+ fprintf(fp, "user: %s\n", uri->user);
+ if (uri->password != NULL)
+ fprintf(fp, "password: %s\n", uri->password);
+ if (uri->host != NULL)
+ fprintf(fp, "host: %s\n", uri->host);
+ if (uri->port != NULL)
+ fprintf(fp, "port: %s\n", uri->port);
+ if (uri->path != NULL)
+ fprintf(fp, "path: %s\n", uri->path);
+ if (uri->fragment != NULL)
+ fprintf(fp, "fragment: %s\n", uri->fragment);
+ if (uri->query != NULL)
+ fprintf(fp, "query: %s\n", uri->query);
+ /* help me debug */
+ if (uri->user_part != NULL)
+ fprintf(fp, "user_part: %s\n", uri->user_part);
+ if (uri->host_part != NULL)
+ fprintf(fp, "host_part: %s\n", uri->host_part);
+ if (uri->path_part != NULL)
+ fprintf(fp, "path_part: %s\n", uri->path_part);
+ fflush(fp);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ uri_t *u = NULL;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s uri\n", argv[0]);
+ exit(1);
+ }
+
+ if (uri_from_string(argv[1], &u) == 0) {
+ char buf[BUFSIZ];
+
+ uri_dump(stdout, u);
+ uri_to_string(u, buf, sizeof (buf));
+ fprintf(stdout, "reconstituted: %s\n", buf);
+
+ uri_to_string(u, buf, 12);
+ fprintf(stdout, "reconstituted(12): %s\n", buf);
+ } else
+ printf(" failed for %s (%s)\n", argv[1], strerror(errno));
+
+ exit(0);
+}
+#endif /* DEADBEEF */
diff --git a/usr/src/lib/print/libpapi-common/common/uri.h b/usr/src/lib/print/libpapi-common/common/uri.h
new file mode 100644
index 0000000000..5dd714a199
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/common/uri.h
@@ -0,0 +1,66 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _URI_H
+#define _URI_H
+
+/* $Id: uri.h 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * scheme://[[user[:password]@]host[:port]]/path[[#fragment]|[?query]]
+ */
+typedef struct {
+ char *scheme;
+ char *scheme_part;
+ char *user;
+ char *password;
+ char *host;
+ char *port;
+ char *path;
+ char *fragment;
+ char *query;
+ /* really for testing, but left in */
+ char *user_part;
+ char *host_part;
+ char *path_part;
+} uri_t;
+
+extern int uri_from_string(char *string, uri_t **uri);
+extern int uri_to_string(uri_t *uri, char *buffer, size_t buflen);
+extern void uri_free(uri_t *uri);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _URI_H */
diff --git a/usr/src/lib/print/libpapi-common/i386/Makefile b/usr/src/lib/print/libpapi-common/i386/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libpapi-common/sparc/Makefile b/usr/src/lib/print/libpapi-common/sparc/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libpapi-common/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libpapi-dynamic/Makefile b/usr/src/lib/print/libpapi-dynamic/Makefile
new file mode 100644
index 0000000000..b92d620b10
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+#HDRS = papi.h
+#HDRDIR = common
+SUBDIRS = $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install: .WAIT $(SUBDIRS)
+
+lint: # $(SUBDIRS)
+
+install_h: # $(ROOTHDRS)
+
+check: # $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/libpapi-dynamic/Makefile.com b/usr/src/lib/print/libpapi-dynamic/Makefile.com
new file mode 100644
index 0000000000..8a51154c48
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/Makefile.com
@@ -0,0 +1,57 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = libpapi.a
+VERS = .0
+OBJECTS = job.o nss.o printer.o psm.o service.o
+
+include ../../../Makefile.lib
+include ../../../Makefile.rootfs
+
+SRCDIR = ../common
+
+ROOTLIBDIR= $(ROOT)/usr/lib
+
+LIBS = $(DYNLIB)
+
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+MAPFILES = $(SRCDIR)/mapfile
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR)
+CPPFLAGS += -I../../libpapi-common/common
+CPPFLAGS += -DNSS_SOLARIS
+LDLIBS += -lc
+
+CERRWARN += -_gcc=-Wno-unused-variable
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/print/libpapi-dynamic/common/job.c b/usr/src/lib/print/libpapi-dynamic/common/job.c
new file mode 100644
index 0000000000..e7bca751a0
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/common/job.c
@@ -0,0 +1,457 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: job.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <papi_impl.h>
+
+void
+papiJobFree(papi_job_t job)
+{
+ job_t *tmp = (job_t *)job;
+
+ if (tmp != NULL) {
+ void (*f)();
+
+ f = (void (*)())psm_sym(tmp->svc, "papiJobFree");
+ if (f != NULL)
+ f(tmp->job);
+ free(tmp);
+ }
+}
+
+void
+papiJobListFree(papi_job_t *jobs)
+{
+ if (jobs != NULL) {
+ int i;
+
+ for (i = 0; jobs[i] != NULL; i++)
+ papiJobFree(jobs[i]);
+ free(jobs);
+ }
+}
+
+papi_attribute_t **
+papiJobGetAttributeList(papi_job_t job)
+{
+ papi_attribute_t **result = NULL;
+ job_t *j = job;
+
+ if (job != NULL) {
+ papi_attribute_t **(*f)();
+
+ f = (papi_attribute_t **(*)())psm_sym(j->svc,
+ "papiJobGetAttributeList");
+ if (f != NULL)
+ result = f(j->job);
+ }
+
+ return (result);
+}
+
+char *
+papiJobGetPrinterName(papi_job_t job)
+{
+ char *result = NULL;
+ job_t *j = job;
+
+ if (job != NULL) {
+ char *(*f)();
+
+ f = (char *(*)())psm_sym(j->svc, "papiJobGetPrinterName");
+ if (f != NULL)
+ result = f(j->job);
+ }
+
+ return (result);
+}
+
+int32_t
+papiJobGetId(papi_job_t job)
+{
+ int32_t result = -1;
+ job_t *j = job;
+
+ if (job != NULL) {
+ int32_t (*f)();
+
+ f = (int32_t (*)())psm_sym(j->svc, "papiJobGetId");
+ if (f != NULL)
+ result = f(j->job);
+ }
+
+ return (result);
+}
+
+papi_job_ticket_t *
+papiJobGetJobTicket(papi_job_t job)
+{
+ papi_job_ticket_t *result = NULL;
+ job_t *j = job;
+
+ if (job != NULL) {
+ papi_job_ticket_t *(*f)();
+
+ f = (papi_job_ticket_t *(*)())psm_sym(j->svc,
+ "papiJobGetJobTicket");
+ if (f != NULL)
+ result = f(j->job);
+ }
+
+ return (result);
+}
+
+/* common support for papiJob{Submit|SubmitByReference|Validate} */
+static papi_status_t
+_papi_job_submit_reference_or_validate(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job,
+ char *function)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
+ (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ j->svc = svc;
+ f = (papi_status_t (*)())psm_sym(j->svc, function);
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, job_attributes,
+ job_ticket, files, &j->job);
+
+ return (result);
+}
+
+papi_status_t
+papiJobSubmit(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
+{
+ return (_papi_job_submit_reference_or_validate(handle, printer,
+ job_attributes, job_ticket, files, job,
+ "papiJobSubmit"));
+}
+
+papi_status_t
+papiJobSubmitByReference(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
+{
+ return (_papi_job_submit_reference_or_validate(handle, printer,
+ job_attributes, job_ticket, files, job,
+ "papiJobSubmitByReference"));
+}
+
+papi_status_t
+papiJobValidate(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
+{
+ return (_papi_job_submit_reference_or_validate(handle, printer,
+ job_attributes, job_ticket, files, job,
+ "papiJobValidate"));
+}
+
+papi_status_t
+papiJobStreamOpen(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, papi_stream_t *stream)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printer == NULL) || (stream == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiJobStreamOpen");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, job_attributes,
+ job_ticket, stream);
+
+ return (result);
+}
+
+papi_status_t
+papiJobStreamWrite(papi_service_t handle,
+ papi_stream_t stream, void *buffer, size_t buflen)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (stream == NULL) || (buffer == NULL) ||
+ (buflen == 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiJobStreamWrite");
+ if (f != NULL)
+ result = f(svc->svc_handle, stream, buffer, buflen);
+
+ return (result);
+}
+
+papi_status_t
+papiJobStreamClose(papi_service_t handle, papi_stream_t stream, papi_job_t *job)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (stream == NULL) || (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ j->svc = svc;
+ f = (papi_status_t (*)())psm_sym(j->svc, "papiJobStreamClose");
+ if (f != NULL)
+ result = f(svc->svc_handle, stream, &j->job);
+
+ return (result);
+}
+
+papi_status_t
+papiJobQuery(papi_service_t handle, char *printer, int32_t job_id,
+ char **requested_attrs, papi_job_t *job)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ j->svc = svc;
+ f = (papi_status_t (*)())psm_sym(j->svc, "papiJobQuery");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, job_id,
+ requested_attrs, &j->job);
+
+ return (result);
+}
+
+papi_status_t
+papiJobMove(papi_service_t handle, char *printer, int32_t job_id,
+ char *destination)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiJobMove");
+ if (f != NULL) {
+ papi_attribute_t **attrs = getprinterbyname(destination, NULL);
+
+ papiAttributeListGetString(attrs, NULL,
+ "printer-uri-supported", &destination);
+ result = f(svc->svc_handle, svc->name, job_id, destination);
+ papiAttributeListFree(attrs);
+ }
+
+ return (result);
+}
+
+/* common support for papiJob{Cancel|Release|Restart|Promote} */
+static papi_status_t
+_papi_job_handle_printer_id(papi_service_t handle,
+ char *printer, int32_t job_id, char *function)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, function);
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, job_id);
+
+ return (result);
+}
+
+papi_status_t
+papiJobCancel(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_papi_job_handle_printer_id(handle, printer, job_id,
+ "papiJobCancel"));
+}
+
+papi_status_t
+papiJobRelease(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_papi_job_handle_printer_id(handle, printer, job_id,
+ "papiJobRelease"));
+}
+
+papi_status_t
+papiJobRestart(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_papi_job_handle_printer_id(handle, printer, job_id,
+ "papiJobRestart"));
+}
+
+papi_status_t
+papiJobPromote(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_papi_job_handle_printer_id(handle, printer, job_id,
+ "papiJobPromote"));
+}
+
+papi_status_t
+papiJobCommit(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_papi_job_handle_printer_id(handle, printer, job_id,
+ "papiJobCommit"));
+}
+
+papi_status_t
+papiJobHold(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_papi_job_handle_printer_id(handle, printer, job_id,
+ "papiJobHold"));
+}
+
+papi_status_t
+papiJobModify(papi_service_t handle, char *printer, int32_t job_id,
+ papi_attribute_t **attributes, papi_job_t *job)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
+ (attributes == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ j->svc = svc;
+ f = (papi_status_t (*)())psm_sym(j->svc, "papiJobModify");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, job_id, attributes,
+ &j->job);
+
+ return (result);
+}
+
+/*
+ * The functions defined below are private to Solaris. They are here
+ * temporarily, until equivalent functionality makes it's way into the PAPI
+ * spec. This is expected in the next minor version after v1.0.
+ */
+papi_status_t
+papiJobCreate(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, papi_job_t *job)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printer == NULL) || (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ j->svc = svc;
+ f = (papi_status_t (*)())psm_sym(j->svc, "papiJobCreate");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, job_attributes,
+ job_ticket, &j->job);
+
+ return (result);
+}
+
+papi_status_t
+papiJobStreamAdd(papi_service_t handle, char *printer, int32_t id,
+ papi_stream_t *stream)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiJobStreamAdd");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, id, stream);
+
+ return (result);
+}
diff --git a/usr/src/lib/print/libpapi-dynamic/common/mapfile b/usr/src/lib/print/libpapi-dynamic/common/mapfile
new file mode 100644
index 0000000000..cc8cb45239
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/common/mapfile
@@ -0,0 +1,279 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# $Id: mapfile.in,v 1.2 2006/03/02 06:31:36 njacobs Exp $
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+#
+# Common interfaces that are most likely to be shared amongst the various
+# PAPI implementations.
+#
+
+SYMBOL_VERSION SUNW_1.0 {
+ global:
+ # PAPI Attribute Calls
+ papiAttributeListAddValue {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddBoolean {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddCollection {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddDatetime {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddInteger {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddMetadata {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddRange {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddResolution {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListDelete {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetValue {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetNext {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFind {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetBoolean {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetCollection {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetDatetime {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetInteger {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetMetadata {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetRange {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetResolution {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFromString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListToString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFree {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ # PAPI Service Calls
+ papiServiceCreate ;
+ papiServiceDestroy ;
+ papiServiceSetUserName ;
+ papiServiceSetPassword ;
+ papiServiceSetEncryption ;
+ papiServiceSetAuthCB ;
+ papiServiceSetAppData ;
+ papiServiceGetUserName ;
+ papiServiceGetPassword ;
+ papiServiceGetEncryption ;
+ papiServiceGetAppData ;
+ papiServiceGetServiceName ;
+ papiServiceGetAttributeList ;
+ papiServiceGetStatusMessage ;
+
+ # PAPI Printer Calls
+ papiPrintersList ;
+ papiPrinterQuery ;
+ papiPrinterAdd ;
+ papiPrinterModify ;
+ papiPrinterRemove ;
+ papiPrinterDisable ;
+ papiPrinterEnable ;
+ papiPrinterPause ;
+ papiPrinterResume ;
+ papiPrinterPurgeJobs ;
+ papiPrinterListJobs ;
+ papiPrinterGetAttributeList ;
+ papiPrinterFree ;
+ papiPrinterListFree ;
+
+ # PAPI Job Calls
+ papiJobSubmit ;
+ papiJobSubmitByReference ;
+ papiJobValidate ;
+ papiJobStreamOpen ;
+ papiJobStreamWrite ;
+ papiJobStreamClose ;
+ papiJobQuery ;
+ papiJobModify ;
+ papiJobMove ;
+ papiJobCancel ;
+ papiJobHold ;
+ papiJobRelease ;
+ papiJobRestart ;
+ papiJobPromote ;
+ papiJobGetAttributeList ;
+ papiJobGetPrinterName ;
+ papiJobGetId ;
+ papiJobGetJobTicket ;
+ papiJobFree ;
+ papiJobListFree ;
+
+ # Misc. PAPI Calls
+ papiStatusString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiLibrarySupportedCall {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiLibrarySupportedCalls {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+};
+
+SYMBOL_VERSION SUNWprivate_1.0 {
+ global:
+ papiServiceSetPeer ; # extension
+ papiJobCreate ;
+ papiJobStreamAdd ;
+ papiJobCommit ;
+
+ # Misc. supporting calls
+ # URI
+ uri_from_string {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ uri_to_string {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ uri_free {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ # list
+ list_remove {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ list_append {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ list_concatenate {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ # NS
+ getprinterbyname ;
+ is_localhost {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ # extra Attribute Calls
+ copy_attributes {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ split_and_copy_attributes {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListPrint {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ local:
+ * ;
+} ;
+
+SYMBOL_VERSION FSG_1.0 {} SUNW_1.0;
diff --git a/usr/src/lib/print/libpapi-dynamic/common/nss.c b/usr/src/lib/print/libpapi-dynamic/common/nss.c
new file mode 100644
index 0000000000..5ab245e936
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/common/nss.c
@@ -0,0 +1,532 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ */
+
+/* Id: nss.c 180 2006-07-20 17:33:02Z njacobs $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <papi.h>
+#include <uri.h>
+#include <papi_impl.h>
+#ifdef NSS_EMULATION
+#include <nss-emulation.h>
+#elif NSS_SOLARIS
+#include <nss_dbdefs.h>
+#endif
+#include <config-site.h>
+#if defined(__sun) && defined(__SVR4)
+#include <sys/systeminfo.h>
+#endif
+
+
+static char *
+bsdaddr_to_uri(papi_attribute_t **list, char *bsdaddr)
+{
+ char *result = NULL;
+
+ if (bsdaddr != NULL) {
+ char *bsd[3], *tmp, *iter = NULL;
+ char buf[512];
+
+ tmp = strdup(bsdaddr);
+
+ bsd[0] = strtok_r(tmp, ":,", &iter);
+ if ((bsd[1] = strtok_r(NULL, ":,", &iter)) == NULL)
+ papiAttributeListGetString(list, NULL,
+ "printer-name", &bsd[1]);
+ bsd[2] = strtok_r(NULL, ":,", &iter);
+
+ snprintf(buf, sizeof (buf), "lpd://%s/printers/%s%s%s", bsd[0],
+ (bsd[1] != NULL) ? bsd[1] : "",
+ (bsd[2] != NULL) ? "#" : "",
+ (bsd[2] != NULL) ? bsd[2] : "");
+
+ free(tmp);
+
+ result = strdup(buf);
+ }
+
+ return (result);
+}
+
+#if defined(__sun) && defined(__SVR4)
+/*
+ * This is an awful HACK to force the dynamic PAPI library to use the
+ * lpsched support when the destination apears to be a local lpsched
+ * queue on Solaris.
+ */
+static void
+solaris_lpsched_shortcircuit_hack(papi_attribute_t ***list)
+{
+ papi_attribute_t *attribute;
+ uri_t *uri = NULL;
+ char *printer = NULL;
+ char buf[128], buf2[128];
+
+ /* setting this in the calling env can be useful for debugging */
+ if (getenv("DISABLE_LPSCHED_SHORTCIRCUIT") != NULL)
+ return;
+
+ papiAttributeListGetString(*list, NULL,
+ "printer-uri-supported", &printer);
+ /* if there is no printer-uri-supported, there is nothing to do */
+ if (printer == NULL) {
+ return;
+ }
+
+ if (uri_from_string(printer, &uri) < 0) {
+ papiAttributeListFree(*list);
+ *list = NULL;
+ uri_free(uri);
+ return;
+ }
+
+ /* already an lpsched URI ? */
+ if (strcasecmp(uri->scheme, "lpsched") == 0) {
+ uri_free(uri);
+ return;
+ }
+
+ if (uri->path == NULL) {
+ printer = "";
+ } else {
+ if ((printer = strrchr(uri->path, '/')) == NULL)
+ printer = uri->path;
+ else
+ printer++;
+ }
+
+ /* is there an lpsched queue (printer/class) */
+ snprintf(buf, sizeof (buf), "/etc/lp/interfaces/%s", printer);
+ snprintf(buf2, sizeof (buf2), "/etc/lp/classes/%s", printer);
+ if ((access(buf, F_OK) < 0) && (access(buf2, F_OK) < 0)) {
+ uri_free(uri);
+ return;
+ }
+
+ /* is this the "local" host */
+ if ((uri->host != NULL) && (is_localhost(uri->host) == 0)) {
+ uri_free(uri);
+ return;
+ }
+
+ snprintf(buf, sizeof (buf), "lpsched://%s/printers/%s",
+ (uri->host ? uri->host : "localhost"), printer);
+ papiAttributeListAddString(list, PAPI_ATTR_REPLACE,
+ "printer-uri-supported", buf);
+ uri_free(uri);
+}
+#endif
+
+static void
+fill_printer_uri_supported(papi_attribute_t ***list)
+{
+ papi_attribute_t *attribute;
+ char *string = NULL;
+
+ /* do we have a printer-uri-supported */
+ attribute = papiAttributeListFind(*list, "printer-uri-supported");
+ if (attribute != NULL) /* we have what we need, return */
+ return;
+
+ /* do we have a printer-uri (in URI form) to rename */
+ attribute = papiAttributeListFind(*list, "printer-uri");
+ if ((attribute != NULL) &&
+ (attribute->type == PAPI_STRING) &&
+ (attribute->values != NULL) &&
+ (attribute->values[0]->string != NULL) &&
+ (strstr(attribute->values[0]->string, "://") != NULL)) {
+ /* rename it in place and return */
+ free(attribute->name);
+ attribute->name = strdup("printer-uri-supported");
+ return;
+ }
+
+ /* do we have a printers.conf(4) "bsdaddr" to convert */
+ papiAttributeListGetString(*list, NULL, "bsdaddr", &string);
+ if (string != NULL) { /* parse it, convert it, add it */
+ char *uri = bsdaddr_to_uri(*list, string);
+
+ if (uri != NULL) {
+ papiAttributeListAddString(list, PAPI_ATTR_APPEND,
+ "printer-uri-supported", uri);
+ papiAttributeListDelete(list, "bsdaddr");
+ free(uri);
+ return;
+ }
+ }
+
+ /* do we have a printers.conf(4) "rm" (and "rp") to convert */
+ papiAttributeListGetString(*list, NULL, "rm", &string);
+ if (string != NULL) {
+ char *rp = NULL;
+
+ /* default to "printer-name", but use "rp" if we have it */
+ papiAttributeListGetString(*list, NULL, "printer-name", &rp);
+ papiAttributeListGetString(*list, NULL, "rp", &rp);
+
+ if (rp != NULL) { /* fill in the uri if we have the data */
+ char buf[BUFSIZ];
+
+ snprintf(buf, sizeof (buf), "lpd://%s/printers/%s",
+ string, rp);
+ papiAttributeListAddString(list, PAPI_ATTR_APPEND,
+ "printer-uri-supported", strdup(buf));
+ return;
+ }
+ }
+
+ /* if were are here, we don't have a printer-uri-supported */
+}
+
+#ifdef NEED_BROKEN_PRINTER_URI_SEMANTIC
+static void
+fill_printer_uri(papi_attribute_t ***list)
+{
+ papi_attribute_t *attribute;
+ char *uri = NULL;
+
+ if ((list == NULL) || (*list == NULL))
+ return;
+
+ /* do we have a printer-uri */
+ attribute = papiAttributeListFind(*list, "printer-uri");
+ if (attribute != NULL) /* we have what we need, return */
+ return;
+
+ /*
+ * this is sufficient to fool libgnomeprintpapi, but not promote it's
+ * use in the future.
+ */
+ papiAttributeListAddString(list, PAPI_ATTR_EXCL, "printer-uri",
+ "broken printer-uri semantic");
+}
+#endif /* NEED_BROKEN_PRINTER_URI_SEMANTIC */
+
+static void
+cvt_all_to_member_names(papi_attribute_t ***list)
+{
+ papi_status_t status;
+ void *iter = NULL;
+ char *string = NULL;
+
+ papiAttributeListGetString(*list, NULL, "member-names", &string);
+ if (string != NULL) /* already have a member-names */
+ return;
+
+ for (status = papiAttributeListGetString(*list, &iter, "all", &string);
+ status == PAPI_OK;
+ status = papiAttributeListGetString(*list, &iter, NULL, &string)) {
+ char *s_iter = NULL, *value, *tmp = strdup(string);
+
+ for (value = strtok_r(tmp, ", \t", &s_iter);
+ value != NULL;
+ value = strtok_r(NULL, ", \t", &s_iter))
+ papiAttributeListAddString(list, PAPI_ATTR_APPEND,
+ "member-names", value);
+ free(tmp);
+ }
+}
+
+static papi_attribute_t **
+_cvt_nss_entry_to_printer(char *entry)
+{
+ char *key = NULL;
+ char *cp;
+ char buf[BUFSIZ];
+ int in_namelist = 1, buf_pos = 0;
+ papi_attribute_t **list = NULL;
+
+ if (entry == NULL)
+ return (NULL);
+
+ memset(buf, 0, sizeof (buf));
+ for (cp = entry; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case ':': /* end of kvp */
+ if (in_namelist != 0) {
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_APPEND, "printer-name", buf);
+ in_namelist = 0;
+ } else if (key != NULL) {
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_APPEND, key, buf);
+ free(key);
+ }
+ memset(buf, 0, sizeof (buf));
+ buf_pos = 0;
+ key = NULL;
+ break;
+ case '=': /* kvp seperator */
+ if (key == NULL) {
+ key = strdup(buf);
+ memset(buf, 0, sizeof (buf));
+ buf_pos = 0;
+ } else
+ buf[buf_pos++] = *cp;
+ break;
+ case '|': /* namelist seperator */
+ if (in_namelist != 0) {
+ papiAttributeListAddString(&list,
+ PAPI_ATTR_APPEND, "printer-name", buf);
+ memset(buf, 0, sizeof (buf));
+ buf_pos = 0;
+ } else /* add it to the buffer */
+ buf[buf_pos++] = *cp;
+ break;
+ case '\\': /* escape char */
+ buf[buf_pos++] = *(++cp);
+ break;
+ default:
+ buf[buf_pos++] = *cp;
+ }
+
+ }
+
+ if (key != NULL) {
+ papiAttributeListAddString(&list, PAPI_ATTR_APPEND, key, buf);
+ free(key);
+ }
+
+ /* resolve any "use" references in the configuration DB */
+ key = NULL;
+ papiAttributeListGetString(list, NULL, "use", &key);
+ if (key != NULL) {
+ papi_attribute_t **use_attrs = getprinterbyname(key, NULL);
+
+ list_concatenate(&list, use_attrs);
+ }
+
+ fill_printer_uri_supported(&list);
+ cvt_all_to_member_names(&list); /* convert "all" to "member-names" */
+
+ return (list);
+}
+
+#if defined(NSS_SOLARIS) && !defined(NSS_EMULATION)
+
+#ifndef NSS_DBNAM__PRINTERS /* not in nss_dbdefs.h because it's private */
+#define NSS_DBNAM__PRINTERS "_printers"
+#endif
+
+static DEFINE_NSS_DB_ROOT(db_root);
+static DEFINE_NSS_GETENT(context);
+
+static char *private_ns = NULL;
+
+static void
+_nss_initf_printers(p)
+ nss_db_params_t *p;
+{
+ if (private_ns != NULL) {
+ /*
+ * because we need to support a legacy interface that allows
+ * us to select a specific name service, we need to dummy up
+ * the parameters to use a private nsswitch database and set
+ * the * default_config entry to the name service we are
+ * looking into.
+ */
+ p->name = NSS_DBNAM__PRINTERS; /* "_printers" */
+ p->default_config = private_ns;
+ } else {
+ /* regular behaviour */
+ p->name = NSS_DBNAM_PRINTERS; /* "printers" */
+ p->default_config = NSS_DEFCONF_PRINTERS;
+ }
+ syslog(LOG_DEBUG, "database: %s, default: %s",
+ (p->name ? p->name : "NULL"),
+ (p->default_config ? p->default_config : "NULL"));
+}
+
+/*
+ * Return values: 0 = success, 1 = parse error, 2 = erange ...
+ * The structure pointer passed in is a structure in the caller's space
+ * wherein the field pointers would be set to areas in the buffer if
+ * need be. instring and buffer should be separate areas.
+ */
+/* ARGSUSED */
+static int
+str2printer(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
+{
+ if (lenstr + 1 > buflen)
+ return (NSS_STR_PARSE_ERANGE);
+
+ /* skip entries that begin with '#' */
+ if (instr[0] == '#')
+ return (NSS_STR_PARSE_PARSE);
+
+ /*
+ * We copy the input string into the output buffer
+ */
+ (void) memcpy(buffer, instr, lenstr);
+ buffer[lenstr] = '\0';
+
+ return (NSS_STR_PARSE_SUCCESS);
+}
+#endif /* NSS_SOLARIS */
+
+int
+setprinterentry(int stayopen, char *ns)
+{
+#ifdef NSS_EMULATION
+ emul_setprinterentry(stayopen);
+#elif NSS_SOLARIS
+ private_ns = ns;
+ nss_setent(&db_root, _nss_initf_printers, &context);
+ private_ns = NULL;
+#endif
+ return (0);
+}
+
+
+int
+endprinterentry(int i)
+{
+#ifdef NSS_EMULATION
+ emul_endprinterentry();
+#elif NSS_SOLARIS
+ nss_endent(&db_root, _nss_initf_printers, &context);
+ nss_delete(&db_root);
+ private_ns = NULL;
+#endif
+ return (0);
+}
+
+/* ARGSUSED2 */
+papi_attribute_t **
+getprinterentry(char *ns)
+{
+ papi_attribute_t **result = NULL;
+
+#if defined(NSS_EMULATION) || defined(NSS_SOLARIS)
+ char buf[10240];
+ nss_status_t res = NSS_NOTFOUND;
+
+#ifdef NSS_EMULATION
+ res = emul_getprinterentry_r(buf, sizeof (buf));
+#elif NSS_SOLARIS
+ nss_XbyY_args_t arg;
+
+ private_ns = ns;
+ buf[0] = '\0';
+ NSS_XbyY_INIT(&arg, buf, buf, sizeof (buf), str2printer);
+ res = nss_getent(&db_root, _nss_initf_printers, &context, &arg);
+ (void) NSS_XbyY_FINI(&arg);
+ private_ns = NULL;
+#endif
+
+ if (res != NSS_SUCCESS)
+ buf[0] = '\0';
+
+ result = _cvt_nss_entry_to_printer(buf);
+#if defined(__sun) && defined(__SVR4)
+ solaris_lpsched_shortcircuit_hack(&result);
+#endif
+#ifdef NEED_BROKEN_PRINTER_URI_SEMANTIC
+ fill_printer_uri(&result);
+#endif /* NEED_BROKEN_PRINTER_URI_SEMANTIC */
+#endif
+
+#ifdef DEBUG
+ printf("getprinterentry(%s): 0x%8.8x\n", (ns ? ns : "NULL"), result);
+ if (result != NULL) {
+ char buf[4096];
+
+ papiAttributeListToString(result, "\n\t", buf, sizeof (buf));
+ printf("\t%s\n", buf);
+ }
+#endif /* DEBUG */
+
+ return (result);
+}
+
+
+papi_attribute_t **
+getprinterbyname(char *name, char *ns)
+{
+ papi_attribute_t **result = NULL;
+
+ if (strstr(name, "://") != NULL) { /* shortcut for URI form */
+ papiAttributeListAddString(&result, PAPI_ATTR_APPEND,
+ "printer-name", name);
+ papiAttributeListAddString(&result, PAPI_ATTR_APPEND,
+ "printer-uri-supported", name);
+ } else if (strchr(name, ':') != NULL) { /* shortcut for POSIX form */
+ char *uri = bsdaddr_to_uri(result, name);
+
+ papiAttributeListAddString(&result, PAPI_ATTR_APPEND,
+ "printer-name", name);
+ if (uri != NULL) {
+ papiAttributeListAddString(&result, PAPI_ATTR_APPEND,
+ "printer-uri-supported", uri);
+ free(uri);
+ }
+ } else { /* anything else */
+#if defined(NSS_EMULATION) || defined(NSS_SOLARIS)
+ char buf[10240];
+ nss_status_t res = NSS_NOTFOUND;
+
+#ifdef NSS_EMULATION
+ res = emul_getprinterbyname_r(name, buf, sizeof (buf));
+#elif NSS_SOLARIS
+ nss_XbyY_args_t arg;
+
+ private_ns = ns;
+ NSS_XbyY_INIT(&arg, buf, buf, sizeof (buf), str2printer);
+ arg.key.name = name;
+ res = nss_search(&db_root, _nss_initf_printers,
+ NSS_DBOP_PRINTERS_BYNAME, &arg);
+ (void) NSS_XbyY_FINI(&arg);
+ private_ns = NULL;
+
+ if (res != NSS_SUCCESS)
+ buf[0] = '\0';
+#endif
+
+ result = _cvt_nss_entry_to_printer(buf);
+#endif
+ }
+#if defined(__sun) && defined(__SVR4)
+ solaris_lpsched_shortcircuit_hack(&result);
+#endif
+#ifdef DEBUG
+ printf("getprinterbyname(%s): %s = 0x%8.8x\n", (ns ? ns : "NULL"),
+ name, result);
+ if (result != NULL) {
+ char buf[4096];
+
+ papiAttributeListToString(result, "\n\t", buf, sizeof (buf));
+ printf("\t%s\n", buf);
+ }
+#endif /* DEBUG */
+
+ return (result);
+}
diff --git a/usr/src/lib/print/libpapi-dynamic/common/papi_impl.h b/usr/src/lib/print/libpapi-dynamic/common/papi_impl.h
new file mode 100644
index 0000000000..be28a9de0c
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/common/papi_impl.h
@@ -0,0 +1,97 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _PAPI_IMPL_H
+#define _PAPI_IMPL_H
+
+/* $Id: papi_impl.h 161 2006-05-03 04:32:59Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <papi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <uri.h>
+
+/*
+ * Implementation specific types/prototypes/definitions follow
+ *
+ *
+ * Ex:
+ */
+
+typedef struct {
+ papi_attribute_t **attributes;
+ void *so_handle;
+ void *svc_handle;
+ char *name;
+ char *user;
+ char *password;
+ int (*authCB)(papi_service_t svc, void *app_data);
+ papi_encryption_t encryption;
+ void *app_data;
+ uri_t *uri;
+ int peer_fd;
+} service_t;
+
+typedef struct job {
+ service_t *svc;
+ papi_job_t *job;
+} job_t;
+
+typedef struct {
+ service_t *svc;
+ papi_printer_t *printer;
+ papi_attribute_t **attributes;
+ char svc_is_internal;
+} printer_t;
+
+extern papi_status_t psm_open(service_t *svc, char *name);
+extern void *psm_sym(service_t *svc, char *name);
+extern void psm_close(void *handle);
+extern void detailed_error(service_t *svc, char *fmt, ...);
+extern papi_status_t service_connect(service_t *svc, char *uri);
+extern papi_attribute_t **getprinterentry(char *ns);
+extern papi_attribute_t **getprinterbyname(char *name, char *ns);
+extern int setprinterentry(int stayopen, char *ns);
+extern int endprinterentry(int stayopen);
+
+
+
+extern void list_remove();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PAPI_IMPL_H */
diff --git a/usr/src/lib/print/libpapi-dynamic/common/printer.c b/usr/src/lib/print/libpapi-dynamic/common/printer.c
new file mode 100644
index 0000000000..e02a325ebd
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/common/printer.c
@@ -0,0 +1,513 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: printer.c 151 2006-04-25 16:55:34Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <papi_impl.h>
+
+void
+papiPrinterFree(papi_printer_t printer)
+{
+ printer_t *tmp = printer;
+
+ if (tmp != NULL) {
+ void (*f)();
+
+ f = (void (*)())psm_sym(tmp->svc, "papiPrinterFree");
+ if (f != NULL)
+ f(tmp->printer);
+ if (tmp->attributes != NULL)
+ papiAttributeListFree(tmp->attributes);
+ if (tmp->svc_is_internal != 0)
+ papiServiceDestroy(tmp->svc);
+ free(tmp);
+ }
+}
+
+void
+papiPrinterListFree(papi_printer_t *printers)
+{
+ if (printers != NULL) {
+ int i;
+
+ for (i = 0; printers[i] != NULL; i++)
+ papiPrinterFree(printers[i]);
+ free(printers);
+ }
+}
+
+/* Enumerate a list of printers from the loaded print service. */
+static papi_status_t
+printers_from_service(service_t *svc, char **requested_attrs,
+ papi_filter_t *filter, papi_printer_t **printers)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ papi_printer_t *svc_printers = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printers == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* connect to the service if we are not connected */
+ if ((result = service_connect(svc, svc->name)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiPrintersList");
+ if (f != NULL)
+ result = f(svc->svc_handle, requested_attrs, filter,
+ &svc_printers);
+
+ /*
+ * copy the resulting printer object pointers into our own
+ * representation of a printer object because we need the
+ * service context to operate against the individual printer
+ * objects. We free the list now because we no longer need
+ * it and would have no way of freeing it later.
+ */
+ if ((result == PAPI_OK) && (svc_printers != NULL)) {
+ int i;
+
+ *printers = NULL;
+ for (i = 0; svc_printers[i] != NULL; i++) {
+ printer_t *p = NULL;
+
+ if ((p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ p->svc = svc;
+ p->printer = svc_printers[i];
+ list_append(printers, p);
+ }
+ free(svc_printers);
+ }
+
+ return (result);
+}
+
+/* Get printer attributes from it's print service */
+static papi_status_t
+printer_from_service(service_t *svc, printer_t *p, char **requested_attrs)
+{
+ papi_status_t result;
+ papi_service_t p_svc = NULL;
+ papi_printer_t printer = NULL;
+ char *psm = NULL;
+ char *uri = NULL;
+
+ /* get the psm and uri from the attributes */
+ papiAttributeListGetString(p->attributes, NULL,
+ "print-service-module", &psm);
+ papiAttributeListGetString(p->attributes, NULL, "printer-name", &uri);
+ papiAttributeListGetString(p->attributes, NULL, "printer-uri-supported",
+ &uri);
+
+ /* contact the service for the printer */
+ result = papiServiceCreate((papi_service_t *)&p_svc, psm, svc->user,
+ svc->password, svc->authCB, svc->encryption,
+ svc->app_data);
+ if (result != PAPI_OK)
+ return (result);
+
+ /* get the printer from the service */
+ result = papiPrinterQuery(p_svc, uri, requested_attrs, NULL, &printer);
+ if (result == PAPI_OK) {
+ papi_attribute_t **attributes;
+
+ attributes = papiPrinterGetAttributeList(printer);
+ copy_attributes(&p->attributes, attributes);
+ }
+ papiPrinterFree(printer);
+ papiServiceDestroy(p_svc);
+
+ return (result);
+}
+
+/* are the requested attributes contained in the list */
+static int
+contained(char **requested, papi_attribute_t **list)
+{
+ int i;
+
+ if (requested == NULL) /* we want every possible attribute */
+ return (0);
+
+ for (i = 0; requested[i] != NULL; i++)
+ if (papiAttributeListFind(list, requested[i]) == NULL)
+ return (0);
+
+ return (1);
+}
+
+/* Enumerate a list of printers from the Name Service */
+static papi_status_t
+printers_from_name_service(service_t *svc, char **requested_attrs,
+ papi_filter_t *filter, papi_printer_t **printers)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ papi_attribute_t **attrs;
+
+ if ((svc == NULL) || (printers == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* retrieve printers from the nameservice */
+ setprinterentry(0, NULL);
+ while ((attrs = getprinterentry(NULL)) != NULL) {
+ printer_t *p = NULL;
+
+ if ((p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ p->attributes = attrs;
+ list_append(printers, p);
+ }
+
+ /* if we have printers, check if our request has been satisfied */
+ if ((printers != NULL) && (*printers != NULL)) {
+ int i;
+
+ /* walk through the list */
+ for (i = 0; (*printers)[i] != NULL; i++) {
+ printer_t *p = (*printers)[i];
+
+ /* see if the name service satisfied the request */
+ if (contained(requested_attrs, p->attributes) == 0)
+ printer_from_service(svc, p, requested_attrs);
+ }
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiPrintersList(papi_service_t handle, char **requested_attrs,
+ papi_filter_t *filter, papi_printer_t **printers)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_printer_t *svc_printers = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (printers == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (svc->so_handle != NULL) /* connected, use the print svc */
+ result = printers_from_service(svc, requested_attrs,
+ filter, printers);
+ else /* not connected, use the name svc */
+ result = printers_from_name_service(svc, requested_attrs,
+ filter, printers);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterQuery(papi_service_t handle, char *name, char **requested_attrs,
+ papi_attribute_t **job_attributes, papi_printer_t *printer)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ printer_t *p = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (name == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ if ((svc->name != NULL) && (svc->svc_handle != NULL) &&
+ (svc->uri != NULL)) {
+ p->svc = svc;
+ f = (papi_status_t (*)())psm_sym(p->svc, "papiPrinterQuery");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, requested_attrs,
+ job_attributes, &p->printer);
+ } else {
+ setprinterentry(0, NULL);
+ p->attributes = getprinterbyname(name, NULL);
+ if (p->attributes == NULL)
+ result = PAPI_NOT_FOUND;
+ else
+ result = PAPI_OK;
+ }
+
+ return (result);
+}
+
+static papi_status_t
+_papi_printer_disable_or_pause(papi_service_t handle, char *name, char *message,
+ char *function)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, function);
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, message);
+
+ return (result);
+}
+
+static papi_status_t
+_papi_printer_enable_or_resume(papi_service_t handle, char *name,
+ char *function)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, function);
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterDisable(papi_service_t handle, char *name, char *message)
+{
+ return (_papi_printer_disable_or_pause(handle, name, message,
+ "papiPrinterDisable"));
+}
+
+papi_status_t
+papiPrinterPause(papi_service_t handle, char *name, char *message)
+{
+ return (_papi_printer_disable_or_pause(handle, name, message,
+ "papiPrinterPause"));
+}
+
+papi_status_t
+papiPrinterEnable(papi_service_t handle, char *name)
+{
+ return (_papi_printer_enable_or_resume(handle, name,
+ "papiPrinterEnable"));
+}
+
+papi_status_t
+papiPrinterResume(papi_service_t handle, char *name)
+{
+ return (_papi_printer_enable_or_resume(handle, name,
+ "papiPrinterResume"));
+}
+
+static papi_status_t
+_papi_printer_add_or_modify(papi_service_t handle, char *name,
+ papi_attribute_t **attributes, papi_printer_t *printer,
+ char *function)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ printer_t *p = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (name == NULL) || (attributes == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ p->svc = svc;
+ f = (papi_status_t (*)())psm_sym(p->svc, function);
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, attributes,
+ &p->printer);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterAdd(papi_service_t handle, char *name,
+ papi_attribute_t **attributes, papi_printer_t *printer)
+{
+ return (_papi_printer_add_or_modify(handle, name, attributes, printer,
+ "papiPrinterAdd"));
+}
+
+papi_status_t
+papiPrinterModify(papi_service_t handle, char *name,
+ papi_attribute_t **attributes, papi_printer_t *printer)
+{
+ return (_papi_printer_add_or_modify(handle, name, attributes, printer,
+ "papiPrinterModify"));
+}
+
+
+papi_status_t
+papiPrinterRemove(papi_service_t handle, char *name)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiPrinterRemove");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterPurgeJobs(papi_service_t handle, char *name, papi_job_t **jobs)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_job_t *svc_jobs = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiPrinterPurgeJobs");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, &svc_jobs);
+
+ /*
+ * copy the resulting job object pointers into our own
+ * representation of a job object because we need the
+ * service context to operate against the individual job
+ * objects. We free the list now because we no longer need
+ * it and would have no way of freeing it later.
+ */
+ if ((result == PAPI_OK) && (svc_jobs != NULL) && (jobs != NULL)) {
+ int i;
+
+ *jobs = NULL;
+ for (i = 0; svc_jobs[i] != NULL; i++) {
+ job_t *j = NULL;
+
+ if ((j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ j->svc = svc;
+ j->job = svc_jobs[i];
+ list_append(jobs, j);
+ }
+ free(svc_jobs);
+ }
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterListJobs(papi_service_t handle, char *name, char **requested_attrs,
+ int type_mask, int max_num_jobs, papi_job_t **jobs)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_job_t *svc_jobs = NULL;
+ papi_status_t (*f)();
+
+ if ((svc == NULL) || (name == NULL) || (jobs == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiPrinterListJobs");
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->name, requested_attrs,
+ type_mask, max_num_jobs, &svc_jobs);
+
+ /*
+ * copy the resulting job object pointers into our own
+ * representation of a job object because we need the
+ * service context to operate against the individual job
+ * objects. We free the list now because we no longer need
+ * it and would have no way of freeing it later.
+ */
+ if ((result == PAPI_OK) && (svc_jobs != NULL)) {
+ int i;
+
+ *jobs = NULL;
+ for (i = 0; svc_jobs[i] != NULL; i++) {
+ job_t *j = NULL;
+
+ if ((j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ j->svc = svc;
+ j->job = svc_jobs[i];
+ list_append(jobs, j);
+ }
+ free(svc_jobs);
+ }
+
+ return (result);
+}
+
+papi_attribute_t **
+papiPrinterGetAttributeList(papi_printer_t printer)
+{
+ papi_attribute_t **result = NULL;
+ printer_t *p = printer;
+
+ if ((p != NULL) && (p->printer != NULL)) {
+ papi_attribute_t **(*f)();
+
+ f = (papi_attribute_t **(*)())psm_sym(p->svc,
+ "papiPrinterGetAttributeList");
+ if (f != NULL)
+ result = f(p->printer);
+ } else
+ result = p->attributes;
+
+ return (result);
+}
diff --git a/usr/src/lib/print/libpapi-dynamic/common/psm.c b/usr/src/lib/print/libpapi-dynamic/common/psm.c
new file mode 100644
index 0000000000..af31f24b4e
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/common/psm.c
@@ -0,0 +1,95 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: psm.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <papi_impl.h>
+
+#ifndef RTLD_GROUP
+#define RTLD_GROUP 0
+#endif /* RTLD_GROUP */
+
+#ifndef PSM_DIR
+#define PSM_DIR "/usr/lib/print"
+#endif
+
+papi_status_t
+psm_open(service_t *svc, char *scheme)
+{
+ papi_status_t result = PAPI_OK;
+ char path[BUFSIZ];
+
+ if ((scheme == NULL) || (strchr(scheme, '/') != NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ snprintf(path, sizeof (path), PSM_DIR "/psm-%s.so", scheme);
+
+ svc->so_handle = dlopen(path, RTLD_LAZY|RTLD_LOCAL|RTLD_GROUP);
+ if (svc->so_handle == NULL) { /* failed, set the result/message */
+ if ((access(path, F_OK) < 0) && (errno == ENOENT))
+ result = PAPI_URI_SCHEME;
+ else
+ result = PAPI_NOT_POSSIBLE;
+#ifdef DEBUG
+ detailed_error(svc, "psm_open(%s): %s: %s", scheme, path,
+ dlerror());
+#endif
+ }
+
+ return (result);
+}
+
+void
+psm_close(void *handle)
+{
+ dlclose(handle);
+}
+
+void *
+psm_sym(service_t *svc, char *name)
+{
+ char *error = "invalid input";
+ void *func = NULL;
+
+ if ((svc != NULL) && (svc->so_handle != NULL) && (name != NULL)) {
+ if ((func = dlsym(svc->so_handle, name)) == NULL)
+ error = dlerror();
+ }
+#ifdef DEBUG
+ if (func == NULL)
+ detailed_error(svc, "psm_sym(%s): %s", name, error);
+#endif
+
+ return (func);
+}
diff --git a/usr/src/lib/print/libpapi-dynamic/common/service.c b/usr/src/lib/print/libpapi-dynamic/common/service.c
new file mode 100644
index 0000000000..55f1732a65
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/common/service.c
@@ -0,0 +1,572 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: service.c 172 2006-05-24 20:54:00Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <alloca.h>
+#include <libintl.h>
+#include <papi_impl.h>
+#include <config-site.h>
+
+static int
+interposed_auth_callback(papi_service_t handle, void *app_data)
+{
+ int result = -1;
+ service_t *svc = app_data;
+
+ if (svc != NULL)
+ result = svc->authCB(svc, svc->app_data);
+
+ return (result);
+}
+
+static char *
+default_service_uri(char *fallback)
+{
+ char *result = NULL;
+
+ if (getuid() == geteuid())
+ result = getenv("PAPI_SERVICE_URI");
+
+ if (result == NULL) {
+ char *cups;
+
+ if ((cups = getenv("CUPS_SERVER")) != NULL) {
+ char buf[BUFSIZ];
+
+ snprintf(buf, sizeof (buf), "ipp://%s/printers/", cups);
+ result = strdup(buf);
+ }
+ }
+
+ if (result == NULL)
+ result = fallback;
+
+ return (result);
+}
+
+static char *
+default_print_service()
+{
+ static char *result = NULL;
+
+ if (result == NULL) {
+ char *service_uri = default_service_uri(DEFAULT_SERVICE_URI);
+ uri_t *uri = NULL;
+
+ if (uri_from_string(service_uri, &uri) != -1)
+ result = strdup(uri->scheme);
+
+ if (uri != NULL)
+ uri_free(uri);
+ }
+
+ return (result);
+}
+
+static papi_status_t
+service_load(service_t *svc, char *name)
+{
+ papi_status_t result;
+ char *scheme = default_print_service();
+
+ if (svc->so_handle != NULL) /* already loaded */
+ return (PAPI_OK);
+
+ if (name == NULL) /* no info, can't load yet */
+ return (PAPI_OK);
+
+ /* Lookup the printer in the configuration DB */
+ svc->attributes = getprinterbyname((char *)name, NULL);
+
+ if (svc->attributes != NULL) {
+ char *tmp = NULL;
+
+ /* Printer found (or was a URI), use the attribute data */
+ papiAttributeListGetString(svc->attributes, NULL,
+ "printer-uri-supported", &tmp);
+ if (tmp != NULL)
+ svc->name = strdup(tmp);
+
+ /* parse the URI and set the scheme(print service) */
+ if (uri_from_string(svc->name, &svc->uri) != -1)
+ scheme = (svc->uri)->scheme;
+
+ /* override the scheme if it was in the attributes */
+ papiAttributeListGetString(svc->attributes, NULL,
+ "print-service-module", &scheme);
+
+ } else /* not found, assume it is the actual print service name */
+ scheme = name;
+
+ result = psm_open(svc, scheme);
+ switch (result) {
+ case PAPI_OK:
+ break; /* no error */
+ case PAPI_URI_SCHEME:
+ result = PAPI_NOT_FOUND;
+#ifdef DEBUG
+ detailed_error(svc, "Unable to load service for: %s", name);
+#endif
+ break;
+ default: /* set the detailed message */
+ detailed_error(svc, "Unable to load service (%s) for: %s",
+ scheme, name);
+ }
+
+ return (result);
+}
+
+static papi_status_t
+service_send_peer(service_t *svc)
+{
+ papi_status_t result = PAPI_OK;
+
+ if ((svc->peer_fd != -1) && (svc->so_handle != NULL) &&
+ (svc->svc_handle != NULL)) {
+ papi_status_t (*f)();
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetPeer");
+
+ if (f != NULL)
+ result = f(svc->svc_handle, svc->peer_fd);
+ }
+
+ return (result);
+}
+
+papi_status_t
+service_connect(service_t *svc, char *name)
+{
+ papi_status_t result = PAPI_NOT_POSSIBLE;
+
+ /* if there is no print service module loaded, try and load one. */
+ if (svc->so_handle == NULL)
+ result = service_load(svc, name);
+ else if ((svc->name == NULL) && (name != NULL))
+ svc->name = strdup(name);
+
+ /*
+ * the print service module is loaded, but we don't have a service
+ * handle.
+ */
+ if (svc->so_handle != NULL) {
+ papi_status_t (*f)();
+
+ if (svc->svc_handle != NULL) /* already connected? */
+ return (PAPI_OK);
+
+ f = (papi_status_t (*)())psm_sym(svc, "papiServiceCreate");
+
+ if (f != NULL) {
+ char *user = svc->user;
+ char *password = svc->password;
+
+ /* if no API user, try the URI user */
+ if ((user == NULL) && (svc->uri != NULL))
+ user = (svc->uri)->user;
+ /* if no API password, try the URI password */
+ if ((password == NULL) && (svc->uri != NULL))
+ password = (svc->uri)->password;
+
+ result = f(&svc->svc_handle, svc->name, user, password,
+ (svc->authCB ? interposed_auth_callback
+ : NULL),
+ svc->encryption, svc);
+ (void) service_send_peer(svc);
+ }
+ }
+
+ return (result);
+}
+
+papi_status_t
+papiServiceCreate(papi_service_t *handle, char *service_name, char *user_name,
+ char *password,
+ int (*authCB)(papi_service_t svc, void *app_data),
+ papi_encryption_t encryption, void *app_data)
+{
+ papi_status_t result = PAPI_NOT_POSSIBLE;
+ service_t *svc = NULL;
+ uri_t *u = NULL;
+
+ if (handle == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*handle = svc = calloc(1, sizeof (*svc))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ svc->peer_fd = -1;
+
+ if (user_name != NULL)
+ svc->user = strdup(user_name);
+
+ if (password != NULL)
+ svc->password = strdup(password);
+
+ svc->encryption = encryption;
+
+ if (authCB != NULL)
+ svc->authCB = authCB;
+
+ if (app_data != NULL)
+ svc->app_data = app_data;
+
+ /* If not specified, get a "default" service from the environment */
+ if (service_name == NULL)
+ service_name = default_service_uri(NULL);
+
+ if (service_name != NULL) {
+ result = service_load(svc, service_name);
+ /* if the psm loaded and the svc contains a URI, connect */
+ if ((result == PAPI_OK) && (svc->uri != NULL))
+ result = service_connect(svc, service_name);
+ } else
+ result = PAPI_OK;
+
+ return (result);
+}
+
+void
+papiServiceDestroy(papi_service_t handle)
+{
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ if (svc->so_handle != NULL) {
+ if (svc->svc_handle != NULL) {
+ void (*f)();
+
+ f = (void (*)())psm_sym(svc,
+ "papiServiceDestroy");
+ f(svc->svc_handle);
+ }
+ psm_close(svc->so_handle);
+ }
+ if (svc->attributes != NULL)
+ papiAttributeListFree(svc->attributes);
+ if (svc->name != NULL)
+ free(svc->name);
+ if (svc->user != NULL)
+ free(svc->user);
+ if (svc->password != NULL)
+ free(svc->password);
+ if (svc->uri != NULL)
+ uri_free(svc->uri);
+
+ free(handle);
+ }
+}
+
+papi_status_t
+papiServiceSetPeer(papi_service_t handle, int fd)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ svc->peer_fd = fd;
+ result = service_send_peer(svc);
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+papi_status_t
+papiServiceSetUserName(papi_service_t handle, char *user_name)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if (svc->user != NULL)
+ free(svc->user);
+ if (user_name != NULL)
+ svc->user = strdup(user_name);
+ f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetUserName");
+ if (f != NULL)
+ result = f(svc->svc_handle, user_name);
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+papi_status_t
+papiServiceSetPassword(papi_service_t handle, char *password)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ if (svc->password != NULL)
+ free(svc->password);
+ if (password != NULL)
+ svc->password = strdup(password);
+ f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetPassword");
+ if (f != NULL)
+ result = f(svc->svc_handle, password);
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+papi_status_t
+papiServiceSetEncryption(papi_service_t handle, papi_encryption_t encryption)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ svc->encryption = encryption;
+ f = (papi_status_t (*)())psm_sym(svc,
+ "papiServiceSetEncryption");
+ if (f != NULL)
+ result = f(svc->svc_handle, encryption);
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+papi_status_t
+papiServiceSetAuthCB(papi_service_t handle,
+ int (*authCB)(papi_service_t svc, void *app_data))
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ svc->authCB = authCB;
+ f = (papi_status_t (*)())psm_sym(svc, "papiServiceSetAuthCB");
+ if (f != NULL)
+ result = f(svc->svc_handle, interposed_auth_callback);
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+
+papi_status_t
+papiServiceSetAppData(papi_service_t handle, void *app_data)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ papi_status_t (*f)();
+
+ svc->app_data = (void *)app_data;
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+char *
+papiServiceGetServiceName(papi_service_t handle)
+{
+ char *result = NULL;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ char *(*f)();
+
+ f = (char *(*)())psm_sym(svc, "papiServiceGetServiceName");
+ if (f != NULL)
+ result = f(svc->svc_handle);
+ if (result == NULL)
+ result = svc->name;
+ }
+
+ return (result);
+}
+
+char *
+papiServiceGetUserName(papi_service_t handle)
+{
+ char *result = NULL;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ char *(*f)();
+
+ f = (char *(*)())psm_sym(svc, "papiServiceGetUserName");
+ if (f != NULL)
+ result = f(svc->svc_handle);
+ if (result == NULL)
+ result = svc->user;
+ }
+
+ return (result);
+}
+
+char *
+papiServiceGetPassword(papi_service_t handle)
+{
+ char *result = NULL;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ char *(*f)();
+
+ f = (char *(*)())psm_sym(svc, "papiServiceGetPassword");
+ if (f != NULL)
+ result = f(svc->svc_handle);
+ if (result == NULL)
+ result = svc->password;
+ }
+
+ return (result);
+}
+
+papi_encryption_t
+papiServiceGetEncryption(papi_service_t handle)
+{
+ papi_encryption_t result = PAPI_ENCRYPT_NEVER;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+ papi_encryption_t (*f)();
+
+ f = (papi_encryption_t (*)())psm_sym(svc,
+ "papiServiceGetEncryption");
+ if (f != NULL)
+ result = f(svc->svc_handle);
+ if (result == PAPI_ENCRYPT_NEVER)
+ result = svc->encryption;
+ }
+
+ return (result);
+}
+
+void *
+papiServiceGetAppData(papi_service_t handle)
+{
+ void *result = NULL;
+ service_t *svc = handle;
+
+ if (handle != NULL)
+ result = svc->app_data;
+
+ return (result);
+}
+
+papi_attribute_t **
+papiServiceGetAttributeList(papi_service_t handle)
+{
+ papi_attribute_t **result = NULL;
+ service_t *svc = handle;
+
+ if (handle != NULL) {
+ papi_attribute_t **(*f)();
+
+ if (svc->so_handle == NULL) {
+ char *uri = default_service_uri(DEFAULT_SERVICE_URI);
+
+ if (service_connect(svc, uri) != PAPI_OK)
+ return (NULL);
+ }
+
+ f = (papi_attribute_t **(*)())psm_sym(svc,
+ "papiServiceGetAttributeList");
+ if (f != NULL)
+ result = f(svc->svc_handle);
+ } else
+ result = svc->attributes;
+
+ return (result);
+}
+
+char *
+papiServiceGetStatusMessage(papi_service_t handle)
+{
+ char *result = NULL;
+ service_t *svc = handle;
+
+ if (handle != NULL) {
+ char *(*f)();
+
+ f = (char *(*)())psm_sym(svc, "papiServiceGetStatusMessage");
+ if (f != NULL)
+ result = f(svc->svc_handle);
+ }
+ if (result == NULL) {
+ papiAttributeListGetString(svc->attributes, NULL,
+ "detailed-status-message", &result);
+ }
+
+ return (result);
+}
+
+void
+detailed_error(service_t *svc, char *fmt, ...)
+{
+ if ((svc != NULL) && (fmt != NULL)) {
+ va_list ap;
+ size_t size;
+ char *message = alloca(BUFSIZ);
+
+ va_start(ap, fmt);
+ /*
+ * fill in the message. If the buffer is too small, allocate
+ * one that is large enough and fill it in.
+ */
+ if ((size = vsnprintf(message, BUFSIZ, fmt, ap)) >= BUFSIZ)
+ if ((message = alloca(size)) != NULL)
+ vsnprintf(message, size, fmt, ap);
+ va_end(ap);
+
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_APPEND,
+ "detailed-status-message", message);
+#ifdef DEBUG
+ fprintf(stderr, "detailed_error(%s)\n", message);
+#endif
+ }
+}
diff --git a/usr/src/lib/print/libpapi-dynamic/i386/Makefile b/usr/src/lib/print/libpapi-dynamic/i386/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libpapi-dynamic/sparc/Makefile b/usr/src/lib/print/libpapi-dynamic/sparc/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libpapi-dynamic/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libpapi-ipp/Makefile b/usr/src/lib/print/libpapi-ipp/Makefile
new file mode 100644
index 0000000000..b92d620b10
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+#HDRS = papi.h
+#HDRDIR = common
+SUBDIRS = $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install: .WAIT $(SUBDIRS)
+
+lint: # $(SUBDIRS)
+
+install_h: # $(ROOTHDRS)
+
+check: # $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/libpapi-ipp/Makefile.com b/usr/src/lib/print/libpapi-ipp/Makefile.com
new file mode 100644
index 0000000000..f5abebce00
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/Makefile.com
@@ -0,0 +1,71 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = psm-ipp.a
+VERS = .1
+OBJECTS = ipp-support.o job.o printer.o service.o
+ROOTLIBDIR = $(ROOT)/usr/lib/print
+
+include ../../../Makefile.lib
+include ../../../Makefile.rootfs
+
+SRCDIR = ../common
+
+ROOTLIBDIR= $(ROOT)/usr/lib/print
+ROOTLIBDIR64= $(ROOT)/usr/lib/print/$(MACH)
+
+EXTRALINKS= $(ROOTLIBDIR)/psm-http.so
+$(EXTRALINKS): $(ROOTLINKS)
+ $(RM) $@; $(SYMLINK) $(LIBLINKS) $@
+
+LIBS = $(DYNLIB)
+
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR)
+CPPFLAGS += -I../../libpapi-common/common
+CPPFLAGS += -I../../libipp-core/common
+CPPFLAGS += -I../../libhttp-core/common
+
+CERRWARN += -_gcc=-Wno-type-limits
+CERRWARN += -_gcc=-Wno-unused-variable
+CERRWARN += -_gcc=-Wno-uninitialized
+
+MAPFILES = $(SRCDIR)/mapfile
+
+LDLIBS += -L$(ROOTLIBDIR) -R/usr/lib/print -lhttp-core -lmd5
+LDLIBS += -lipp-core -lc
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+$(ROOTLIBDIR):
+ $(INS.dir)
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/print/libpapi-ipp/common/ipp-support.c b/usr/src/lib/print/libpapi-ipp/common/ipp-support.c
new file mode 100644
index 0000000000..b2caff84ac
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/common/ipp-support.c
@@ -0,0 +1,631 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: ipp-support.c 148 2006-04-25 16:54:17Z njacobs $ */
+
+
+#include <papi_impl.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <locale.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <md5.h>
+
+#include <config-site.h>
+
+#include <ipp.h>
+
+static void ipp_add_printer_uri(service_t *svc, char *name,
+ papi_attribute_t ***op);
+
+papi_status_t
+http_to_papi_status(http_status_t status)
+{
+ switch (status) {
+ case HTTP_OK:
+ return (PAPI_OK);
+ case HTTP_BAD_REQUEST:
+ return (PAPI_BAD_REQUEST);
+ case HTTP_UNAUTHORIZED:
+ case HTTP_FORBIDDEN:
+ return (PAPI_NOT_AUTHORIZED);
+ case HTTP_NOT_FOUND:
+ return (PAPI_NOT_FOUND);
+ case HTTP_GONE:
+ return (PAPI_GONE);
+ case HTTP_SERVICE_UNAVAILABLE:
+ return (PAPI_SERVICE_UNAVAILABLE);
+ default:
+ return ((papi_status_t)status);
+ }
+}
+
+papi_status_t
+ipp_to_papi_status(uint16_t status)
+{
+ switch (status) {
+ case IPP_OK:
+ return (PAPI_OK);
+ case IPP_OK_IGNORED_ATTRIBUTES:
+ return (PAPI_OK);
+ case IPP_OK_CONFLICTING_ATTRIBUTES:
+ return (PAPI_OK);
+ case IPP_OK_IGNORED_SUBSCRIPTIONS:
+ return (PAPI_OK_IGNORED_SUBSCRIPTIONS);
+ case IPP_OK_IGNORED_NOTIFICATIONS:
+ return (PAPI_OK_IGNORED_NOTIFICATIONS);
+ case IPP_CERR_BAD_REQUEST:
+ return (PAPI_BAD_REQUEST);
+ case IPP_CERR_FORBIDDEN:
+ return (PAPI_FORBIDDEN);
+ case IPP_CERR_NOT_AUTHENTICATED:
+ return (PAPI_NOT_AUTHENTICATED);
+ case IPP_CERR_NOT_AUTHORIZED:
+ return (PAPI_NOT_AUTHORIZED);
+ case IPP_CERR_NOT_POSSIBLE:
+ return (PAPI_NOT_POSSIBLE);
+ case IPP_CERR_TIMEOUT:
+ return (PAPI_TIMEOUT);
+ case IPP_CERR_NOT_FOUND:
+ return (PAPI_NOT_FOUND);
+ case IPP_CERR_GONE:
+ return (PAPI_GONE);
+ case IPP_CERR_REQUEST_ENTITY:
+ return (PAPI_REQUEST_ENTITY);
+ case IPP_CERR_REQUEST_VALUE:
+ return (PAPI_REQUEST_VALUE);
+ case IPP_CERR_DOCUMENT_FORMAT:
+ return (PAPI_DOCUMENT_FORMAT);
+ case IPP_CERR_ATTRIBUTES:
+ return (PAPI_ATTRIBUTES);
+ case IPP_CERR_URI_SCHEME:
+ return (PAPI_URI_SCHEME);
+ case IPP_CERR_CHARSET:
+ return (PAPI_CHARSET);
+ case IPP_CERR_CONFLICT:
+ return (PAPI_CONFLICT);
+ case IPP_CERR_COMPRESSION_NOT_SUPPORTED:
+ return (PAPI_COMPRESSION_NOT_SUPPORTED);
+ case IPP_CERR_COMPRESSION_ERROR:
+ return (PAPI_COMPRESSION_ERROR);
+ case IPP_CERR_DOCUMENT_FORMAT_ERROR:
+ return (PAPI_DOCUMENT_FORMAT_ERROR);
+ case IPP_CERR_DOCUMENT_ACCESS_ERROR:
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ case IPP_CERR_ATTRIBUTES_NOT_SETTABLE:
+ return (PAPI_ATTRIBUTES_NOT_SETTABLE);
+ case IPP_CERR_IGNORED_ALL_SUBSCRIPTIONS:
+ return (PAPI_IGNORED_ALL_SUBSCRIPTIONS);
+ case IPP_CERR_TOO_MANY_SUBSCRIPTIONS:
+ return (PAPI_TOO_MANY_SUBSCRIPTIONS);
+ case IPP_CERR_IGNORED_ALL_NOTIFICATIONS:
+ return (PAPI_IGNORED_ALL_NOTIFICATIONS);
+ case IPP_CERR_PRINT_SUPPORT_FILE_NOT_FOUND:
+ return (PAPI_PRINT_SUPPORT_FILE_NOT_FOUND);
+ case IPP_SERR_INTERNAL:
+ return (PAPI_INTERNAL_ERROR);
+ case IPP_SERR_OPERATION_NOT_SUPPORTED:
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+ case IPP_SERR_SERVICE_UNAVAILABLE:
+ return (PAPI_SERVICE_UNAVAILABLE);
+ case IPP_SERR_VERSION_NOT_SUPPORTED:
+ return (PAPI_VERSION_NOT_SUPPORTED);
+ case IPP_SERR_DEVICE_ERROR:
+ return (PAPI_DEVICE_ERROR);
+ case IPP_SERR_TEMPORARY_ERROR:
+ return (PAPI_TEMPORARY_ERROR);
+ case IPP_SERR_NOT_ACCEPTING:
+ return (PAPI_NOT_ACCEPTING);
+ case IPP_SERR_BUSY:
+ case IPP_SERR_CANCELLED:
+ default:
+ return (PAPI_TEMPORARY_ERROR);
+ }
+}
+
+void
+ipp_initialize_request(service_t *svc, papi_attribute_t ***request,
+ uint16_t operation)
+{
+ papiAttributeListAddInteger(request, PAPI_ATTR_EXCL,
+ "version-major", 1);
+ papiAttributeListAddInteger(request, PAPI_ATTR_EXCL,
+ "version-minor", 1);
+ papiAttributeListAddInteger(request, PAPI_ATTR_EXCL,
+ "request-id", (short)lrand48());
+ papiAttributeListAddInteger(request, PAPI_ATTR_EXCL,
+ "operation-id", operation);
+}
+
+void
+ipp_initialize_operational_attributes(service_t *svc, papi_attribute_t ***op,
+ char *printer, int job_id)
+{
+ char *charset = "utf-8"; /* default to UTF-8 encoding */
+ char *language = setlocale(LC_ALL, "");
+ char *user = "nobody";
+ struct passwd *pw = NULL;
+
+ /*
+ * All IPP requests must contain the following:
+ * attributes-charset (UTF-8)
+ * attributes-natural-language (our current locale)
+ * (object identifier) printer-uri/job-id or job-uri
+ * requesting-user-name (process user or none)
+ */
+ papiAttributeListAddString(op, PAPI_ATTR_EXCL,
+ "attributes-charset", charset);
+
+ papiAttributeListAddString(op, PAPI_ATTR_EXCL,
+ "attributes-natural-language", language);
+
+ if (printer != NULL)
+ ipp_add_printer_uri(svc, printer, op);
+
+ if ((printer != NULL) && (job_id >= 0))
+ papiAttributeListAddInteger(op, PAPI_ATTR_EXCL,
+ "job-id", job_id);
+
+ if ((pw = getpwuid(getuid())) != NULL)
+ user = pw->pw_name;
+ /*
+ * if our euid is 0 "super user", we will allow the system supplied
+ * user name to be overridden, if the requestor wants to.
+ */
+ if (geteuid() == 0) {
+ if (svc->user != NULL)
+ user = svc->user;
+ }
+ papiAttributeListAddString(op, PAPI_ATTR_REPLACE,
+ "requesting-user-name", user);
+}
+
+#ifndef OPID_CUPS_GET_DEFAULT /* for servers that will enumerate */
+#define OPID_CUPS_GET_DEFAULT 0x4001
+#endif /* OPID_CUPS_GET_DEFAULT */
+
+static papi_status_t
+_default_destination(service_t *svc, char **uri)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ printer_t *p = NULL;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+ char *tmp = NULL;
+
+ if ((svc == NULL) || (uri == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* we must be connected to find the default destination */
+ if (svc->connection == NULL)
+ return (PAPI_NOT_POSSIBLE);
+
+ if ((p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ ipp_initialize_request(svc, &request, OPID_CUPS_GET_DEFAULT);
+ ipp_initialize_operational_attributes(svc, &op, NULL, -1);
+ papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
+ "requested-attributes", "printer-uri-supported");
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+
+ op = NULL;
+ papiAttributeListGetCollection(response, NULL,
+ "printer-attributes-group", &op);
+
+ if (uri != NULL) {
+ char *tmp = NULL;
+
+ papiAttributeListGetString(op, NULL, "printer-uri", &tmp);
+ papiAttributeListGetString(op, NULL,
+ "printer-uri-supported", &tmp);
+ if (tmp != NULL)
+ *uri = strdup(tmp);
+ }
+
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+static void
+ipp_add_printer_uri(service_t *svc, char *name, papi_attribute_t ***op)
+{
+ char *uri = name;
+ char buf[BUFSIZ];
+ uri_t *tmp = NULL;
+
+ if (strstr(name, "://") == NULL) { /* not in URI form */
+ if (strcmp(name, DEFAULT_DEST) != 0) {
+ /* not the "default" */
+ snprintf(buf, sizeof (buf), "%s/%s", svc->name, name);
+ uri = buf;
+ } else
+ _default_destination(svc, &uri);
+ }
+
+ papiAttributeListAddString(op, PAPI_ATTR_EXCL, "printer-uri", uri);
+
+ /* save the printer-uri's path to be used by http POST request */
+ if ((uri_from_string(uri, &tmp) == 0) && (tmp != NULL)) {
+ if (svc->post != NULL)
+ free(svc->post);
+ svc->post = strdup(tmp->path);
+ uri_free(tmp);
+ }
+}
+
+
+/*
+ * don't actually write anything, just add to the total size and return the
+ * size of what would be written, so we can figure out how big the request
+ * is going to be.
+ */
+static ssize_t
+size_calculate(void *fd, void *buffer, size_t length)
+{
+ ssize_t *size = (ssize_t *)fd;
+
+ *size += length;
+ return (length);
+}
+
+
+static ssize_t
+build_chunk(void *fd, void *buffer, size_t length)
+{
+ char **s1 = fd;
+
+ memcpy(*s1, buffer, length);
+ *s1 = *s1 + length;
+
+ return (length);
+}
+
+ssize_t
+ipp_request_write(void *fd, void *buffer, size_t length)
+{
+ service_t *svc = (service_t *)fd;
+
+#ifdef DEBUG
+ printf("ipp_request_write(0x%8.8x, 0x%8.8x, %d)\n", fd, buffer, length);
+ httpDumpData(stdout, "ipp_request_write:", buffer, length);
+#endif
+ return (httpWrite(svc->connection, buffer, length));
+}
+
+ssize_t
+ipp_request_read(void *fd, void *buffer, size_t length)
+{
+ service_t *svc = (service_t *)fd;
+ ssize_t rc, i = length;
+ char *p = buffer;
+
+ while ((rc = httpRead(svc->connection, p, i)) != i) {
+ if (rc == 0)
+ return (rc);
+ if (rc < 0)
+ return (rc);
+ i -= rc;
+ p += rc;
+ }
+#ifdef DEBUG
+ printf("ipp_request_read(0x%8.8x, 0x%8.8x, %d) = %d\n",
+ fd, buffer, length, rc);
+ httpDumpData(stdout, "ipp_request_read:", buffer, length);
+#endif
+
+ return (length);
+}
+
+papi_status_t
+ipp_send_initial_request_block(service_t *svc, papi_attribute_t **request,
+ ssize_t file_size)
+{
+ papi_status_t result = PAPI_OK;
+ ssize_t chunk_size = 0;
+ char length[32];
+ void *chunk, *ptr;
+ http_status_t status;
+
+ /* calculate the request size */
+ (void) ipp_write_message(&size_calculate, &chunk_size, request);
+
+ /* Fill in the HTTP Header information */
+ httpClearFields(svc->connection);
+ if (svc->transfer_encoding == TRANSFER_ENCODING_CHUNKED)
+ httpSetField(svc->connection, HTTP_FIELD_TRANSFER_ENCODING,
+ "chunked");
+ else {
+ sprintf(length, "%lu", (unsigned long)(file_size + chunk_size));
+ httpSetField(svc->connection, HTTP_FIELD_CONTENT_LENGTH,
+ length);
+ }
+ httpSetField(svc->connection, HTTP_FIELD_CONTENT_TYPE,
+ "application/ipp");
+ httpSetField(svc->connection, HTTP_FIELD_AUTHORIZATION,
+ svc->connection->authstring);
+
+ /* flush any state information about this connection */
+ httpFlush(svc->connection);
+
+ /* if we have don't have a POST path, use the service uri path */
+ if ((svc->post == NULL) && (svc->uri->path))
+ svc->post = strdup(svc->uri->path);
+ /* send the HTTP POST message for the IPP request */
+ /* if the POST fails, return the error */
+ status = httpPost(svc->connection, svc->post);
+ if (status != 0)
+ return (http_to_papi_status(status));
+
+ if (httpCheck(svc->connection) != 0) {
+ status = httpUpdate(svc->connection);
+ if (status != HTTP_OK)
+ return (http_to_papi_status(status));
+ }
+
+ /* build the request chunk */
+ chunk = ptr = calloc(1, chunk_size);
+ result = ipp_write_message(&build_chunk, &ptr, request);
+#ifdef DEBUG
+ printf("request: %d (0x%x) bytes\n", chunk_size, chunk_size);
+ httpDumpData(stdout, "request:", chunk, chunk_size);
+#endif
+
+ /* send the actual IPP request */
+ if (ipp_request_write(svc, chunk, chunk_size) != chunk_size)
+ result = PAPI_TEMPORARY_ERROR;
+ free(chunk);
+
+ if (httpCheck(svc->connection) != 0) {
+ status = httpUpdate(svc->connection);
+ if (status != HTTP_OK)
+ return (http_to_papi_status(status));
+ }
+
+ return (result);
+}
+
+static int
+setAuthString(service_t *svc)
+{
+ http_t *http;
+ char *user, *passphrase;
+ char encoded[BUFSIZ];
+
+ if ((svc == NULL) || (svc->connection == NULL) || (svc->name == NULL))
+ return (-1);
+
+ http = svc->connection;
+
+ if (svc->user == NULL) {
+ struct passwd *p;
+
+ if ((p = getpwuid(getuid())) != NULL) {
+ user = p->pw_name;
+ } else if ((user = getenv("LOGNAME")) == NULL)
+ user = getenv("USER");
+ if (user == NULL)
+ user = "nobody";
+ } else
+ user = svc->user;
+
+ /* if the passphrase is not set, use the Authentication Callback */
+ if (((svc->password == NULL) || (svc->password[0] == '\0')) &&
+ (svc->authCB != NULL))
+ (svc->authCB)(svc, svc->app_data);
+ passphrase = svc->password;
+
+ /* if there is still no passphrase, we have to fail */
+ if ((passphrase == NULL) || (passphrase[0] == '\0'))
+ return (-1);
+
+ if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE],
+ "Basic", 5) == 0) {
+ char plain[BUFSIZ];
+
+ snprintf(plain, sizeof (plain), "%s:%s", user, passphrase);
+ httpEncode64(encoded, plain);
+ snprintf(http->authstring, sizeof (http->authstring),
+ "Basic %s", encoded);
+ } else if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE],
+ "Digest", 6) == 0) {
+ char realm[HTTP_MAX_VALUE];
+ char nonce[HTTP_MAX_VALUE];
+ char line [BUFSIZ];
+ char urp[128];
+ char mr[128];
+ char *uri = svc->post;
+
+ httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE,
+ "realm", realm);
+ httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE,
+ "nonce", nonce);
+
+ snprintf(line, sizeof (line), "%s:%s:%s", user, realm,
+ passphrase);
+ md5_calc(urp, line, strlen(line));
+
+ snprintf(line, sizeof (line), "POST:%s", uri);
+ md5_calc(mr, line, strlen(line));
+
+ snprintf(line, sizeof (line), "%s:%s:%s", urp, mr, nonce);
+ md5_calc(encoded, line, strlen(line));
+
+ snprintf(http->authstring, sizeof (http->authstring),
+ "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", "
+ "uri=\"%s\", response=\"%s\"", user, realm, nonce, uri,
+ encoded);
+ }
+
+ return (0);
+}
+
+papi_status_t
+ipp_status_info(service_t *svc, papi_attribute_t **response)
+{
+ papi_attribute_t **operational = NULL;
+ int32_t status = 0;
+
+ papiAttributeListGetCollection(response, NULL,
+ "operational-attributes-group", &operational);
+ if (operational != NULL) {
+ char *message = NULL;
+
+ papiAttributeListGetString(response, NULL,
+ "status-message", &message);
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_REPLACE,
+ "detailed-status-message", message);
+ }
+ papiAttributeListGetInteger(response, NULL, "status-code", &status);
+
+ return (ipp_to_papi_status(status));
+}
+
+papi_status_t
+ipp_send_request_with_file(service_t *svc, papi_attribute_t **request,
+ papi_attribute_t ***response, char *file)
+{
+ papi_status_t result = PAPI_OK;
+ ssize_t size = 0;
+ struct stat statbuf;
+ int fd;
+
+#ifdef DEBUG
+ fprintf(stderr, "\nIPP-REQUEST: (%s)", (file ? file : ""));
+ papiAttributeListPrint(stderr, request, " ");
+ putc('\n', stderr);
+ fflush(stderr);
+#endif
+
+ /*
+ * if we are sending a file, open it and include it's size in the
+ * message size.
+ */
+ if (file != NULL) {
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ detailed_error(svc, "%s: %s", file, strerror(errno));
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ } else if (strcmp("standard input", file) != 0) {
+ if (stat(file, &statbuf) < 0) {
+ detailed_error(svc,
+ gettext("Cannot access file: %s: %s"),
+ file, strerror(errno));
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+ if (statbuf.st_size == 0) {
+ detailed_error(svc,
+ "Zero byte (empty) file: %s", file);
+ return (PAPI_BAD_ARGUMENT);
+ }
+ } else if (svc->transfer_encoding !=
+ TRANSFER_ENCODING_CHUNKED) {
+ struct stat st;
+
+ if (fstat(fd, &st) >= 0)
+ size = st.st_size;
+ }
+ }
+
+ *response = NULL;
+ while (*response == NULL) {
+ http_status_t status = HTTP_CONTINUE;
+
+ result = ipp_send_initial_request_block(svc, request, size);
+
+ if (result == PAPI_OK) {
+ if (file != NULL) {
+ /* send the file contents if we have it */
+ int rc;
+ char buf[BUFSIZ];
+
+ lseek(fd, 0L, SEEK_SET);
+ while ((rc = read(fd, buf, sizeof (buf))) > 0) {
+ if (ipp_request_write(svc, buf, rc)
+ < rc) {
+ break;
+ }
+ }
+ }
+
+ (void) ipp_request_write(svc, "", 0);
+ }
+
+ /* update our connection info */
+ while (status == HTTP_CONTINUE)
+ status = httpUpdate(svc->connection);
+
+ if (status == HTTP_UNAUTHORIZED) {
+ httpFlush(svc->connection);
+ if ((svc->connection->authstring[0] == '\0') &&
+ (setAuthString(svc) == 0)) {
+ httpReconnect(svc->connection);
+ continue;
+ }
+ } else if (status == HTTP_UPGRADE_REQUIRED) {
+ /*
+ * If the transport was built with TLS support, we can
+ * try to use it.
+ */
+ httpFlush(svc->connection);
+ httpReconnect(svc->connection);
+ httpEncryption(svc->connection, HTTP_ENCRYPT_REQUIRED);
+ continue;
+ }
+
+ if (status != HTTP_OK)
+ return (http_to_papi_status(status));
+
+ /* read the IPP response */
+ result = ipp_read_message(&ipp_request_read, svc, response,
+ IPP_TYPE_RESPONSE);
+
+ if (result == PAPI_OK)
+ result = ipp_status_info(svc, *response);
+#ifdef DEBUG
+ fprintf(stderr, "\nIPP-RESPONSE: (%s) (%s)", (file ? file : ""),
+ papiStatusString(result));
+ papiAttributeListPrint(stderr, *response, " ");
+ putc('\n', stderr);
+ fflush(stderr);
+#endif
+ }
+
+ return (result);
+}
+
+papi_status_t
+ipp_send_request(service_t *svc, papi_attribute_t **request,
+ papi_attribute_t ***response)
+{
+ return (ipp_send_request_with_file(svc, request, response, NULL));
+}
diff --git a/usr/src/lib/print/libpapi-ipp/common/job.c b/usr/src/lib/print/libpapi-ipp/common/job.c
new file mode 100644
index 0000000000..65575d44db
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/common/job.c
@@ -0,0 +1,666 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: job.c 148 2006-04-25 16:54:17Z njacobs $ */
+
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <papi_impl.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libintl.h>
+
+#ifndef OPID_CUPS_MOVE_JOB
+#define OPID_CUPS_MOVE_JOB 0x400D
+#endif
+
+void
+papiJobFree(papi_job_t job)
+{
+ job_t *tmp = (job_t *)job;
+
+ if (tmp != NULL) {
+ if (tmp->attributes != NULL)
+ papiAttributeListFree(tmp->attributes);
+ free(tmp);
+ }
+}
+
+void
+papiJobListFree(papi_job_t *jobs)
+{
+ if (jobs != NULL) {
+ int i;
+
+ for (i = 0; jobs[i] != NULL; i++)
+ papiJobFree(jobs[i]);
+ free(jobs);
+ }
+}
+
+papi_attribute_t **
+papiJobGetAttributeList(papi_job_t job)
+{
+ papi_attribute_t **result = NULL;
+ job_t *j = job;
+
+ if (j != NULL)
+ result = j->attributes;
+
+ return (result);
+}
+
+char *
+papiJobGetPrinterName(papi_job_t job)
+{
+ char *result = NULL;
+ job_t *j = job;
+
+ if (j != NULL)
+ (void) papiAttributeListGetString(j->attributes, NULL,
+ "printer-name", &result);
+
+ return (result);
+}
+
+int32_t
+papiJobGetId(papi_job_t job)
+{
+ int32_t result = -1;
+ job_t *j = job;
+
+ if (j != NULL)
+ (void) papiAttributeListGetInteger(j->attributes, NULL,
+ "job-id", &result);
+
+ return (result);
+}
+
+papi_job_ticket_t *
+papiJobGetJobTicket(papi_job_t job)
+{
+ papi_job_ticket_t *result = NULL;
+
+ return (result);
+}
+
+static void
+populate_job_request(service_t *svc, papi_attribute_t ***request,
+ papi_attribute_t **attributes, char *printer, uint16_t type)
+{
+ papi_attribute_t **operational = NULL, **job = NULL;
+ static char *operational_names[] = {
+ "job-name", "ipp-attribute-fidelity", "document-name",
+ "compression", "document-format", "document-natural-language",
+ "job-k-octets", "job-impressions", "job-media-sheets", NULL
+ };
+
+ /* create the base IPP request */
+ ipp_initialize_request(svc, request, type);
+
+ /* create an operational attributes group */
+ ipp_initialize_operational_attributes(svc, &operational, printer, -1);
+
+ /* split up the attributes into operational and job attributes */
+ split_and_copy_attributes(operational_names, attributes,
+ &operational, &job);
+
+ /* add the operational attributes group to the request */
+ papiAttributeListAddCollection(request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", operational);
+ papiAttributeListFree(operational);
+
+ /* add the job attributes group to the request */
+ if (job != NULL) {
+ /*
+ * Add job-originating-host-name to attributes
+ * if not already set.
+ */
+ char *hostname = NULL;
+
+ papiAttributeListGetString(job, NULL,
+ "job-originating-host-name", &hostname);
+
+ if (hostname == NULL) {
+ char host[BUFSIZ];
+
+ if (gethostname(host, sizeof (host)) == 0)
+ papiAttributeListAddString(&job, PAPI_ATTR_EXCL,
+ "job-originating-host-name", host);
+ }
+
+ papiAttributeListAddCollection(request, PAPI_ATTR_REPLACE,
+ "job-attributes-group", job);
+ papiAttributeListFree(job);
+ }
+}
+
+static papi_status_t
+send_document_uri(service_t *svc, char *file, papi_attribute_t **attributes,
+ char *printer, int32_t id, char last, uint16_t type)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+
+ /* create the base IPP request */
+ ipp_initialize_request(svc, &request, type);
+
+ /* create an operational attributes group */
+ ipp_initialize_operational_attributes(svc, &op, printer, id);
+
+ papiAttributeListAddString(&op, PAPI_ATTR_REPLACE, "document-name",
+ file);
+ papiAttributeListAddBoolean(&op, PAPI_ATTR_REPLACE, "last-document",
+ (last ? PAPI_TRUE : PAPI_FALSE));
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+
+ /* send the IPP request to the server */
+ result = ipp_send_request_with_file(svc, request, &response, file);
+ papiAttributeListFree(request);
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+typedef enum {_WITH_DATA, _BY_REFERENCE, _VALIDATE} call_type_t;
+
+papi_status_t
+internal_job_submit(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket,
+ char **files, papi_job_t *job,
+ call_type_t call_type)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ struct stat statbuf;
+ job_t *j = NULL;
+ int i;
+ uint16_t req_type = OPID_PRINT_JOB;
+ uint16_t data_type = OPID_SEND_DOCUMENT;
+ papi_attribute_t **request = NULL, **response = NULL;
+
+ if ((svc == NULL) || (printer == NULL) || (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ switch (call_type) {
+ case _BY_REFERENCE:
+#ifdef SOME_DAY_WE_WILL_BE_ABLE_TO_USE_URIS_FOR_JOB_DATA
+ /*
+ * For the time being, this is disabled. There are a number
+ * of issues to be dealt with before we can send a URI
+ * across the network to the server. For example, the file
+ * name(s) passed in are most likely relative to the current
+ * hosts filesystem. They also most likely will require some
+ * form of authentication information to be passed with the
+ * URI.
+ */
+ req_type = OPID_PRINT_URI;
+ req_type = OPID_SEND_URI;
+#endif
+ /* fall-through */
+ case _WITH_DATA:
+ if ((files == NULL) || (files[0] == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (files[1] != NULL) /* more than 1 file */
+ req_type = OPID_CREATE_JOB;
+
+ break;
+ case _VALIDATE:
+ req_type = OPID_VALIDATE_JOB;
+ /* if we have files, validate access to them */
+ if (files != NULL) {
+ for (i = 0; files[i] != NULL; i++) {
+ if (access(files[i], R_OK) < 0) {
+ detailed_error(svc, "%s: %s", files[i],
+ strerror(errno));
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+
+ if (strcmp("standard input", files[i]) != 0) {
+ if (stat(files[i], &statbuf) < 0) {
+ detailed_error(svc, gettext(
+ "Cannot access file: %s:"
+ " %s"), files[i],
+ strerror(errno));
+ return (
+ PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+ if (statbuf.st_size == 0) {
+ detailed_error(svc,
+ "Zero byte (empty) file: "
+ "%s",
+ files[i]);
+ return (PAPI_BAD_ARGUMENT);
+ }
+ }
+ }
+ files = NULL;
+ }
+ break;
+ }
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ /*
+ * before creating IPP request
+ * add the job-name
+ */
+ if ((files != NULL) && (files[0] != NULL))
+ papiAttributeListAddString(&job_attributes, PAPI_ATTR_EXCL,
+ "job-name", files[0]);
+
+ /* create IPP request */
+ populate_job_request(svc, &request, job_attributes, printer, req_type);
+
+ switch (req_type) {
+ case OPID_PRINT_JOB:
+ result = ipp_send_request_with_file(svc, request, &response,
+ files[0]);
+ break;
+ case OPID_CREATE_JOB:
+ case OPID_VALIDATE_JOB:
+ case OPID_PRINT_URI:
+ result = ipp_send_request(svc, request, &response);
+ break;
+ }
+ papiAttributeListFree(request);
+
+ if (result == PAPI_OK) {
+ papi_attribute_t **op = NULL;
+
+ /* retrieve the job attributes */
+ papiAttributeListGetCollection(response, NULL,
+ "job-attributes-group", &op);
+ copy_attributes(&j->attributes, op);
+
+ if (req_type == OPID_CREATE_JOB) {
+ int32_t id = 0;
+
+ papiAttributeListGetInteger(j->attributes, NULL,
+ "job-id", &id);
+ /* send each document */
+ for (i = 0; ((result == PAPI_OK) && (files[i] != NULL));
+ i++)
+ result = send_document_uri(svc, files[i],
+ job_attributes,
+ printer, id, (files[i+1]?0:1),
+ data_type);
+ }
+ }
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_status_t
+papiJobSubmit(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
+{
+ return (internal_job_submit(handle, printer, job_attributes,
+ job_ticket, files, job, _WITH_DATA));
+}
+
+papi_status_t
+papiJobSubmitByReference(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
+{
+ return (internal_job_submit(handle, printer, job_attributes,
+ job_ticket, files, job, _BY_REFERENCE));
+}
+
+papi_status_t
+papiJobValidate(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
+{
+ return (internal_job_submit(handle, printer, job_attributes,
+ job_ticket, files, job, _VALIDATE));
+}
+
+papi_status_t
+papiJobStreamOpen(papi_service_t handle, char *printer,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, papi_stream_t *stream)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ papi_attribute_t **request = NULL;
+ service_t *svc = handle;
+
+ if ((svc == NULL) || (printer == NULL) || (stream == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ papiAttributeListAddString(&job_attributes, PAPI_ATTR_EXCL,
+ "job-name", "standard input");
+
+ /* create job request */
+ populate_job_request(svc, &request, job_attributes, printer,
+ OPID_PRINT_JOB);
+
+ *stream = svc->connection;
+
+ result = ipp_send_initial_request_block(svc, request, 0);
+ papiAttributeListFree(request);
+
+ return (result);
+}
+
+papi_status_t
+papiJobStreamWrite(papi_service_t handle,
+ papi_stream_t stream, void *buffer, size_t buflen)
+{
+ papi_status_t result = PAPI_OK;
+ service_t *svc = handle;
+ size_t rc;
+
+#ifdef DEBUG
+ printf("papiJobStreamWrite(0x%8.8x, 0x%8.8x, 0x%8.8x, %d)\n",
+ handle, stream, buffer, buflen);
+ httpDumpData(stdout, "papiJobStreamWrite:", buffer, buflen);
+#endif
+
+ if ((svc == NULL) || (stream == NULL) || (buffer == NULL) ||
+ (buflen == 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ while ((result == PAPI_OK) && (buflen > 0)) {
+ rc = ipp_request_write(svc, buffer, buflen);
+ if (rc < 0)
+ result = PAPI_TEMPORARY_ERROR;
+ else {
+ buffer = (char *)buffer + rc;
+ buflen -= rc;
+ }
+ }
+
+#ifdef DEBUG
+ printf("papiJobStreamWrite(): %s\n", papiStatusString(result));
+#endif
+
+ return (result);
+}
+
+papi_status_t
+papiJobStreamClose(papi_service_t handle,
+ papi_stream_t stream, papi_job_t *job)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ http_status_t status = HTTP_CONTINUE;
+ service_t *svc = handle;
+ papi_attribute_t **response = NULL;
+ job_t *j = NULL;
+
+ if ((svc == NULL) || (stream == NULL) || (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ (void) ipp_request_write(svc, "", 0);
+
+ /* update our connection info */
+ while (status == HTTP_CONTINUE)
+ status = httpUpdate(svc->connection);
+
+ if (status != HTTP_OK)
+ return (http_to_papi_status(status));
+ httpWait(svc->connection, 1000);
+
+ /* read the IPP response */
+ result = ipp_read_message(&ipp_request_read, svc, &response,
+ IPP_TYPE_RESPONSE);
+ if (result == PAPI_OK)
+ result = ipp_status_info(svc, response);
+
+ if (result == PAPI_OK) {
+ papi_attribute_t **op = NULL;
+
+ papiAttributeListGetCollection(response, NULL,
+ "job-attributes-group", &op);
+ copy_attributes(&j->attributes, op);
+ }
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_status_t
+papiJobQuery(papi_service_t handle, char *printer, int32_t job_id,
+ char **requested_attrs,
+ papi_job_t *job)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ ipp_initialize_request(svc, &request, OPID_GET_JOB_ATTRIBUTES);
+
+ ipp_initialize_operational_attributes(svc, &op, printer, job_id);
+
+ if (requested_attrs != NULL) {
+ int i;
+
+ for (i = 0; requested_attrs[i] != NULL; i++)
+ papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
+ "requested-attributes", requested_attrs[i]);
+ }
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+
+ op = NULL;
+ papiAttributeListGetCollection(response, NULL,
+ "job-attributes-group", &op);
+ copy_attributes(&j->attributes, op);
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+/* papiJob{Cancel|Hold|Release|Restart|Promote} are all the same */
+static papi_status_t
+_job_cancel_hold_release_restart_promote(papi_service_t handle,
+ char *printer, int32_t job_id, uint16_t type)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ ipp_initialize_request(svc, &request, type);
+
+ ipp_initialize_operational_attributes(svc, &op, printer, job_id);
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_status_t
+papiJobCancel(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_job_cancel_hold_release_restart_promote(handle, printer,
+ job_id, OPID_CANCEL_JOB));
+}
+
+
+papi_status_t
+papiJobHold(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_job_cancel_hold_release_restart_promote(handle, printer,
+ job_id, OPID_HOLD_JOB));
+}
+
+papi_status_t
+papiJobRelease(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_job_cancel_hold_release_restart_promote(handle, printer,
+ job_id, OPID_RELEASE_JOB));
+}
+
+papi_status_t
+papiJobRestart(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_job_cancel_hold_release_restart_promote(handle, printer,
+ job_id, OPID_RESTART_JOB));
+}
+
+papi_status_t
+papiJobPromote(papi_service_t handle, char *printer, int32_t job_id)
+{
+ return (_job_cancel_hold_release_restart_promote(handle, printer,
+ job_id, OPID_PROMOTE_JOB));
+}
+
+papi_status_t
+papiJobMove(papi_service_t handle, char *printer, int32_t job_id,
+ char *destination)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
+ (destination == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ ipp_initialize_request(svc, &request, OPID_CUPS_MOVE_JOB);
+
+ ipp_initialize_operational_attributes(svc, &op, printer, job_id);
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+
+ op = NULL;
+ papiAttributeListAddString(&op, PAPI_ATTR_EXCL,
+ "job-printer-uri", destination);
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "job-attributes-group", op);
+ papiAttributeListFree(op);
+
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_status_t
+papiJobModify(papi_service_t handle, char *printer, int32_t job_id,
+ papi_attribute_t **attributes, papi_job_t *job)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+ job_t *j = NULL;
+
+ if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
+ (attributes == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*job = j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, printer)) != PAPI_OK)
+ return (result);
+
+ ipp_initialize_request(svc, &request, OPID_SET_JOB_ATTRIBUTES);
+
+ ipp_initialize_operational_attributes(svc, &op, printer, job_id);
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "job-attributes-group", attributes);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+
+ op = NULL;
+ papiAttributeListGetCollection(response, NULL,
+ "job-attributes-group", &op);
+ copy_attributes(&j->attributes, op);
+ papiAttributeListFree(response);
+
+ return (result);
+}
diff --git a/usr/src/lib/print/libpapi-ipp/common/mapfile b/usr/src/lib/print/libpapi-ipp/common/mapfile
new file mode 100644
index 0000000000..847a5bb76f
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/common/mapfile
@@ -0,0 +1,292 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# $Id: mapfile.in,v 1.2 2006/03/02 06:31:36 njacobs Exp $
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+#
+# Common interfaces that are most likely to be shared amongst the various
+# PAPI implementations.
+#
+
+SYMBOL_VERSION SUNW_1.0 {
+ global:
+ # PAPI Attribute Calls
+ papiAttributeListAddValue {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddBoolean {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddCollection {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddDatetime {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddInteger {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddMetadata {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddRange {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddResolution {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListDelete {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetValue {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetNext {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFind {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetBoolean {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetCollection {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetDatetime {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetInteger {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetMetadata {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetRange {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetResolution {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFromString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListToString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFree {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ # PAPI Service Calls
+ papiServiceCreate ;
+ papiServiceDestroy ;
+ papiServiceSetUserName ;
+ papiServiceSetPassword ;
+ papiServiceSetEncryption ;
+ papiServiceSetAuthCB ;
+ papiServiceSetAppData ;
+ papiServiceGetUserName ;
+ papiServiceGetPassword ;
+ papiServiceGetEncryption ;
+ papiServiceGetAppData ;
+ papiServiceGetServiceName ;
+ papiServiceGetAttributeList ;
+ papiServiceGetStatusMessage ;
+
+ # PAPI Printer Calls
+ papiPrintersList ;
+ papiPrinterQuery ;
+ papiPrinterAdd ;
+ papiPrinterModify ;
+ papiPrinterRemove ;
+ papiPrinterDisable ;
+ papiPrinterEnable ;
+ papiPrinterPause ;
+ papiPrinterResume ;
+ papiPrinterPurgeJobs ;
+ papiPrinterListJobs ;
+ papiPrinterGetAttributeList ;
+ papiPrinterFree ;
+ papiPrinterListFree ;
+
+ # PAPI Job Calls
+ papiJobSubmit ;
+ papiJobSubmitByReference ;
+ papiJobValidate ;
+ papiJobStreamOpen ;
+ papiJobStreamWrite ;
+ papiJobStreamClose ;
+ papiJobQuery ;
+ papiJobModify ;
+ papiJobMove ;
+ papiJobCancel ;
+ papiJobHold ;
+ papiJobRelease ;
+ papiJobRestart ;
+ papiJobPromote ;
+ papiJobGetAttributeList ;
+ papiJobGetPrinterName ;
+ papiJobGetId ;
+ papiJobGetJobTicket ;
+ papiJobFree ;
+ papiJobListFree ;
+
+ # Misc. PAPI Calls
+ papiStatusString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiLibrarySupportedCall {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiLibrarySupportedCalls {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+} ;
+
+SYMBOL_VERSION SUNWprivate_1.0 {
+ global:
+ papiServiceSetPeer {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobCreate {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobStreamAdd {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobCommit {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ # Misc. supporting calls
+ # URI
+ uri_from_string {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ uri_to_string {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ uri_free {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ # list
+ list_remove {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ list_append {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ list_concatenate {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ # NS
+ getprinterbyname {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ is_localhost {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ # extra Attribute Calls
+ copy_attributes {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ split_and_copy_attributes {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListPrint {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ local:
+ * ;
+} ;
diff --git a/usr/src/lib/print/libpapi-ipp/common/papi_impl.h b/usr/src/lib/print/libpapi-ipp/common/papi_impl.h
new file mode 100644
index 0000000000..c7048665a8
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/common/papi_impl.h
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _PAPI_IMPL_H
+#define _PAPI_IMPL_H
+
+/* $Id: papi_impl.h 161 2006-05-03 04:32:59Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <papi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <uri.h>
+
+#include <http.h>
+#include <ipp.h>
+
+/*
+ * Implementation specific types/prototypes/definitions follow
+ *
+ *
+ * Ex:
+ */
+typedef enum {
+ TRANSFER_ENCODING_CHUNKED,
+ TRANSFER_ENCODING_LENGTH
+} http_transfer_encoding_t;
+
+typedef struct {
+ papi_attribute_t **attributes;
+ char *name;
+ char *user;
+ char *password;
+ int (*authCB)(papi_service_t svc, void *app_data);
+ papi_encryption_t encryption;
+ void *app_data;
+ uri_t *uri;
+ char *post;
+ http_t *connection;
+ http_transfer_encoding_t transfer_encoding;
+} service_t;
+
+typedef struct job {
+ papi_attribute_t **attributes;
+} job_t;
+
+typedef struct {
+ papi_attribute_t **attributes;
+} printer_t;
+
+/* IPP glue interfaces */
+extern ssize_t ipp_request_read(void *fd, void *buffer, size_t length);
+extern ssize_t ipp_request_write(void *fd, void *buffer, size_t length);
+extern papi_status_t ipp_send_request(service_t *svc,
+ papi_attribute_t **request,
+ papi_attribute_t ***response);
+extern papi_status_t ipp_send_request_with_file(service_t *svc,
+ papi_attribute_t **request,
+ papi_attribute_t ***response, char *file);
+extern papi_status_t ipp_send_initial_request_block(service_t *svc,
+ papi_attribute_t **request, ssize_t file_size);
+extern papi_status_t ipp_status_info(service_t *svc,
+ papi_attribute_t **response);
+extern void ipp_initialize_request(service_t *svc,
+ papi_attribute_t ***request, uint16_t type);
+extern void ipp_initialize_operational_attributes(service_t *svc,
+ papi_attribute_t ***op,
+ char *printer, int job_id);
+extern papi_status_t ipp_to_papi_status(uint16_t status);
+extern papi_status_t http_to_papi_status(http_status_t status);
+
+/* service related interfaces */
+extern void detailed_error(service_t *svc, char *fmt, ...);
+extern papi_status_t service_connect(service_t *svc, char *service_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PAPI_IMPL_H */
diff --git a/usr/src/lib/print/libpapi-ipp/common/printer.c b/usr/src/lib/print/libpapi-ipp/common/printer.c
new file mode 100644
index 0000000000..c49c4adb03
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/common/printer.c
@@ -0,0 +1,430 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: printer.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <papi_impl.h>
+
+#include <config-site.h>
+
+void
+papiPrinterFree(papi_printer_t printer)
+{
+ printer_t *tmp = printer;
+
+ if (tmp != NULL) {
+ if (tmp->attributes != NULL)
+ papiAttributeListFree(tmp->attributes);
+ free(tmp);
+ }
+}
+
+void
+papiPrinterListFree(papi_printer_t *printers)
+{
+ if (printers != NULL) {
+ int i;
+
+ for (i = 0; printers[i] != NULL; i++)
+ papiPrinterFree(printers[i]);
+ free(printers);
+ }
+}
+
+/*
+ * Enumeration of printers is not part of the IPP specification, so many
+ * servers will probably not respond back with a list of printers, but
+ * CUPS has implemented an extension to IPP to enumerate printers and
+ * classes. the Apache/mod_ipp IPP listener module available in Solaris
+ * implements this IPP extension, so CUPS and Solaris can provide this
+ * to IPP clients.
+ */
+#ifndef OPID_CUPS_GET_PRINTERS /* for servers that will enumerate */
+#define OPID_CUPS_GET_PRINTERS 0x4002
+#endif /* OPID_CUPS_GET_PRINTERS */
+#ifndef OPID_CUPS_DELETE_PRINTER /* for servers that can delete */
+#define OPID_CUPS_DELETE_PRINTER 0x4004
+#endif /* OPID_CUPS_DELETE_PRINTER */
+#ifndef OPID_CUPS_GET_CLASSES /* for servers that will enumerate */
+#define OPID_CUPS_GET_CLASSES 0x4005
+#endif /* OPID_CUPS_GET_CLASSES */
+
+papi_status_t
+papiPrintersList(papi_service_t handle, char **requested_attrs,
+ papi_filter_t *filter, papi_printer_t **printers)
+{
+ papi_status_t status, result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+ void *iter = NULL;
+
+ if ((svc == NULL) || (printers == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, DEFAULT_DEST)) != PAPI_OK)
+ return (result);
+ ipp_initialize_request(svc, &request, OPID_CUPS_GET_PRINTERS);
+
+ ipp_initialize_operational_attributes(svc, &op, NULL, -1);
+
+ if (requested_attrs != NULL) {
+ int i;
+
+ for (i = 0; requested_attrs[i] != NULL; i++)
+ papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
+ "requested-attributes", requested_attrs[i]);
+ }
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+
+ op = NULL;
+ for (status = papiAttributeListGetCollection(response, &iter,
+ "printer-attributes-group", &op);
+ status == PAPI_OK;
+ status = papiAttributeListGetCollection(response, &iter,
+ NULL, &op)) {
+ printer_t *p = NULL;
+
+ if ((p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ copy_attributes(&p->attributes, op);
+ op = NULL;
+ list_append(printers, p);
+ }
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterQuery(papi_service_t handle, char *name,
+ char **requested_attrs,
+ papi_attribute_t **job_attributes,
+ papi_printer_t *printer)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ printer_t *p = NULL;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+
+ if ((svc == NULL) || (name == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ ipp_initialize_request(svc, &request, OPID_GET_PRINTER_ATTRIBUTES);
+
+ ipp_initialize_operational_attributes(svc, &op, name, -1);
+
+ if (requested_attrs != NULL) {
+ int i;
+
+ for (i = 0; requested_attrs[i] != NULL; i++)
+ papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
+ "requested-attributes", requested_attrs[i]);
+ }
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+
+ op = NULL;
+ papiAttributeListGetCollection(response, NULL,
+ "printer-attributes-group", &op);
+ copy_attributes(&p->attributes, op);
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+static papi_status_t
+_printer_enable_disable_pause_resume_delete(papi_service_t handle, char *name,
+ char *message, uint16_t type)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+
+ if ((svc == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ ipp_initialize_request(svc, &request, type);
+
+ ipp_initialize_operational_attributes(svc, &op, name, -1);
+
+ switch (type) {
+ case OPID_DISABLE_PRINTER:
+ papiAttributeListAddString(&op, PAPI_ATTR_REPLACE,
+ "printer-message-from-operator", message);
+ break;
+ case OPID_PAUSE_PRINTER:
+ papiAttributeListAddString(&op, PAPI_ATTR_REPLACE,
+ "printer-state-message", message);
+ break;
+ default: /* a message value is of no use */
+ break;
+ }
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterEnable(papi_service_t handle, char *name)
+{
+ return (_printer_enable_disable_pause_resume_delete(handle, name,
+ NULL, OPID_ENABLE_PRINTER));
+}
+
+papi_status_t
+papiPrinterResume(papi_service_t handle, char *name)
+{
+ return (_printer_enable_disable_pause_resume_delete(handle, name,
+ NULL, OPID_RESUME_PRINTER));
+}
+
+papi_status_t
+papiPrinterPause(papi_service_t handle, char *name, char *message)
+{
+ return (_printer_enable_disable_pause_resume_delete(handle, name,
+ message, OPID_PAUSE_PRINTER));
+}
+
+papi_status_t
+papiPrinterDisable(papi_service_t handle, char *name, char *message)
+{
+ return (_printer_enable_disable_pause_resume_delete(handle, name,
+ message, OPID_PAUSE_PRINTER));
+}
+
+/*
+ * there is no IPP create operation, the set-printer-attibutes operation
+ * is the closest we have, so we will assume that the server will create
+ * a printer and set attributes if there is none.
+ */
+papi_status_t
+papiPrinterAdd(papi_service_t handle, char *name,
+ papi_attribute_t **attributes, papi_printer_t *printer)
+{
+ return (papiPrinterModify(handle, name, attributes, printer));
+}
+
+papi_status_t
+papiPrinterModify(papi_service_t handle, char *name,
+ papi_attribute_t **attributes, papi_printer_t *printer)
+{
+ papi_status_t result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ printer_t *p = NULL;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+
+ if ((svc == NULL) || (name == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ ipp_initialize_request(svc, &request, OPID_SET_PRINTER_ATTRIBUTES);
+
+ ipp_initialize_operational_attributes(svc, &op, name, -1);
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "printer-attributes-group", attributes);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+
+ op = NULL;
+ papiAttributeListGetCollection(response, NULL,
+ "printer-attributes-group", &op);
+ copy_attributes(&p->attributes, op);
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterRemove(papi_service_t handle, char *name)
+{
+ return (_printer_enable_disable_pause_resume_delete(handle, name,
+ NULL, OPID_CUPS_DELETE_PRINTER));
+}
+
+papi_status_t
+papiPrinterPurgeJobs(papi_service_t handle, char *name,
+ papi_job_t **jobs)
+{
+ papi_status_t status, result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+ void *iter = NULL;
+
+
+ if ((svc == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ ipp_initialize_request(svc, &request, OPID_PURGE_JOBS);
+
+ ipp_initialize_operational_attributes(svc, &op, name, -1);
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+
+ op = NULL;
+ for (status = papiAttributeListGetCollection(response, &iter,
+ "job-attributes-group", &op);
+ status == PAPI_OK;
+ status = papiAttributeListGetCollection(response, &iter,
+ NULL, &op)) {
+ job_t *j = NULL;
+
+ if ((j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ copy_attributes(&j->attributes, op);
+ op = NULL;
+ list_append(jobs, j);
+ }
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_status_t
+papiPrinterListJobs(papi_service_t handle, char *name,
+ char **requested_attrs, int type_mask,
+ int max_num_jobs, papi_job_t **jobs)
+{
+ papi_status_t status, result = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
+ void *iter = NULL;
+
+ if ((svc == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ /* if we are already connected, use that connection. */
+ if (svc->connection == NULL)
+ if ((result = service_connect(svc, name)) != PAPI_OK)
+ return (result);
+
+ ipp_initialize_request(svc, &request, OPID_GET_JOBS);
+
+ ipp_initialize_operational_attributes(svc, &op, name, -1);
+
+ if (requested_attrs != NULL) {
+ int i;
+
+ for (i = 0; requested_attrs[i] != NULL; i++)
+ papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
+ "requested-attributes", requested_attrs[i]);
+ }
+
+ papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
+ "operational-attributes-group", op);
+ papiAttributeListFree(op);
+ result = ipp_send_request(svc, request, &response);
+ papiAttributeListFree(request);
+
+ op = NULL;
+ for (status = papiAttributeListGetCollection(response, &iter,
+ "job-attributes-group", &op);
+ status == PAPI_OK;
+ status = papiAttributeListGetCollection(response, &iter,
+ NULL, &op)) {
+ job_t *j = NULL;
+
+ if ((j = calloc(1, sizeof (*j))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ copy_attributes(&j->attributes, op);
+ op = NULL;
+ list_append(jobs, j);
+ }
+ papiAttributeListFree(response);
+
+ return (result);
+}
+
+papi_attribute_t **
+papiPrinterGetAttributeList(papi_printer_t printer)
+{
+ papi_attribute_t **result = NULL;
+ printer_t *p = printer;
+
+ if (p != NULL)
+ result = p->attributes;
+
+ return (result);
+}
diff --git a/usr/src/lib/print/libpapi-ipp/common/service.c b/usr/src/lib/print/libpapi-ipp/common/service.c
new file mode 100644
index 0000000000..e5531f1422
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/common/service.c
@@ -0,0 +1,394 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: service.c 171 2006-05-20 06:00:32Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <alloca.h>
+#include <libintl.h>
+#include <papi_impl.h>
+
+#include <config-site.h>
+
+http_encryption_t
+http_encryption_type(papi_encryption_t encryption)
+{
+ switch (encryption) {
+ case PAPI_ENCRYPT_IF_REQUESTED:
+ return (HTTP_ENCRYPT_IF_REQUESTED);
+ case PAPI_ENCRYPT_REQUIRED:
+ return (HTTP_ENCRYPT_REQUIRED);
+ case PAPI_ENCRYPT_ALWAYS:
+ return (HTTP_ENCRYPT_ALWAYS);
+ case PAPI_ENCRYPT_NEVER:
+ return (HTTP_ENCRYPT_NEVER);
+ default:
+ ; /* this should log an error */
+ }
+
+ return (HTTP_ENCRYPT_NEVER); /* should never get here */
+}
+
+papi_status_t
+service_connect(service_t *svc, char *service_name)
+{
+ papi_status_t result = PAPI_OK;
+ int port = 631;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if (svc->connection != NULL) /* alread connected ? */
+ return (PAPI_OK);
+
+ if (svc->uri == NULL)
+ uri_from_string(service_name, &svc->uri);
+
+ if ((service_name != NULL) && (svc->uri == NULL)) {
+ /*
+ * a name was supplied and it's not in URI form, we will
+ * try to use a "default" IPP service under the assumption
+ * that this is most likely a short-form printer name from
+ * from a papiPrinter*() or papiJob*() call and not from a
+ * papiServiceCreate() call.
+ */
+ if ((service_name = getenv("PAPI_SERVICE_URI")) == NULL) {
+ char *cups;
+
+ if ((cups = getenv("CUPS_SERVER")) != NULL) {
+ char buf[BUFSIZ];
+
+ snprintf(buf, sizeof (buf),
+ "ipp://%s/printers/", cups);
+ service_name = strdup(buf);
+ }
+ }
+ if (service_name == NULL)
+ service_name = DEFAULT_IPP_SERVICE_URI;
+
+ uri_from_string(service_name, &svc->uri);
+ }
+
+ if (svc->uri == NULL)
+ return (PAPI_NOT_POSSIBLE);
+
+ if (svc->uri->port != NULL)
+ port = strtol(svc->uri->port, NULL, 10);
+
+ svc->connection = httpConnectEncrypt(svc->uri->host, port,
+ http_encryption_type(svc->encryption));
+ if (svc->connection == NULL) {
+ if (svc->uri != NULL) {
+ uri_free(svc->uri);
+ svc->uri = NULL;
+ }
+ result = PAPI_SERVICE_UNAVAILABLE;
+ } else if (service_name != NULL)
+ svc->name = strdup(service_name);
+
+ return (result);
+}
+
+papi_status_t
+papiServiceCreate(papi_service_t *handle, char *service_name,
+ char *user_name, char *password,
+ int (*authCB)(papi_service_t svc, void *app_data),
+ papi_encryption_t encryption, void *app_data)
+{
+ papi_status_t result = PAPI_NOT_POSSIBLE;
+ service_t *svc = NULL;
+ char *encoding = getenv("HTTP_TRANSFER_ENCODING");
+
+ if (handle == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*handle = svc = calloc(1, sizeof (*svc))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ if (user_name != NULL)
+ svc->user = strdup(user_name);
+
+ if (password != NULL)
+ svc->password = strdup(password);
+
+ svc->encryption = encryption;
+
+ if (authCB != NULL)
+ svc->authCB = authCB;
+
+ if (app_data != NULL)
+ svc->app_data = app_data;
+
+ if ((encoding != NULL) && (strcasecmp(encoding, "content-length") == 0))
+ svc->transfer_encoding = TRANSFER_ENCODING_LENGTH;
+ else
+ svc->transfer_encoding = TRANSFER_ENCODING_CHUNKED;
+
+ if (service_name != NULL) {
+ result = service_connect(svc, service_name);
+ } else
+ result = PAPI_OK;
+
+ return (result);
+}
+
+void
+papiServiceDestroy(papi_service_t handle)
+{
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ if (svc->attributes != NULL)
+ papiAttributeListFree(svc->attributes);
+ if (svc->name != NULL)
+ free(svc->name);
+ if (svc->user != NULL)
+ free(svc->user);
+ if (svc->password != NULL)
+ free(svc->password);
+ if (svc->uri != NULL)
+ uri_free(svc->uri);
+ if (svc->post != NULL)
+ free(svc->post);
+ if (svc->connection != NULL)
+ httpClose(svc->connection);
+
+ free(handle);
+ }
+}
+
+papi_status_t
+papiServiceSetUserName(papi_service_t handle, char *user_name)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ if (svc->user != NULL)
+ free(svc->user);
+ svc->user = NULL;
+ if (user_name != NULL)
+ svc->user = strdup(user_name);
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+papi_status_t
+papiServiceSetPassword(papi_service_t handle, char *password)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ if (svc->password != NULL)
+ free(svc->password);
+ svc->password = NULL;
+ if (password != NULL)
+ svc->password = strdup(password);
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+papi_status_t
+papiServiceSetEncryption(papi_service_t handle,
+ papi_encryption_t encryption)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ svc->encryption = encryption;
+ httpEncryption(svc->connection,
+ (http_encryption_t)svc->encryption);
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+papi_status_t
+papiServiceSetAuthCB(papi_service_t handle,
+ int (*authCB)(papi_service_t svc, void *app_data))
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ svc->authCB = authCB;
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+
+papi_status_t
+papiServiceSetAppData(papi_service_t handle, void *app_data)
+{
+ papi_status_t result = PAPI_OK;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ svc->app_data = (void *)app_data;
+ } else
+ result = PAPI_BAD_ARGUMENT;
+
+ return (result);
+}
+
+char *
+papiServiceGetServiceName(papi_service_t handle)
+{
+ char *result = NULL;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ result = svc->name;
+ }
+
+ return (result);
+}
+
+char *
+papiServiceGetUserName(papi_service_t handle)
+{
+ char *result = NULL;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ result = svc->user;
+ }
+
+ return (result);
+}
+
+char *
+papiServiceGetPassword(papi_service_t handle)
+{
+ char *result = NULL;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ result = svc->password;
+ }
+
+ return (result);
+}
+
+papi_encryption_t
+papiServiceGetEncryption(papi_service_t handle)
+{
+ papi_encryption_t result = PAPI_ENCRYPT_NEVER;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ result = svc->encryption;
+ }
+
+ return (result);
+}
+
+void *
+papiServiceGetAppData(papi_service_t handle)
+{
+ void *result = NULL;
+
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+ result = svc->app_data;
+ }
+
+ return (result);
+}
+
+papi_attribute_t **
+papiServiceGetAttributeList(papi_service_t handle)
+{
+ papi_attribute_t **result = NULL;
+ service_t *svc = handle;
+
+ if (handle != NULL)
+ result = svc->attributes;
+
+ return (result);
+}
+
+char *
+papiServiceGetStatusMessage(papi_service_t handle)
+{
+ char *result = NULL;
+ service_t *svc = handle;
+
+ papiAttributeListGetString(svc->attributes, NULL,
+ "detailed-status-message", &result);
+
+ return (result);
+}
+
+void
+detailed_error(service_t *svc, char *fmt, ...)
+{
+ if ((svc != NULL) && (fmt != NULL)) {
+ va_list ap;
+ size_t size;
+ char *message = alloca(BUFSIZ);
+
+ va_start(ap, fmt);
+ /*
+ * fill in the message. If the buffer is too small, allocate
+ * one that is large enough and fill it in.
+ */
+ if ((size = vsnprintf(message, BUFSIZ, fmt, ap)) >= BUFSIZ)
+ if ((message = alloca(size)) != NULL)
+ vsnprintf(message, size, fmt, ap);
+ va_end(ap);
+
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_APPEND,
+ "detailed-status-message", message);
+ }
+}
diff --git a/usr/src/lib/print/libpapi-ipp/i386/Makefile b/usr/src/lib/print/libpapi-ipp/i386/Makefile
new file mode 100644
index 0000000000..39b4a998ec
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS) $(EXTRALINKS)
diff --git a/usr/src/lib/print/libpapi-ipp/sparc/Makefile b/usr/src/lib/print/libpapi-ipp/sparc/Makefile
new file mode 100644
index 0000000000..39b4a998ec
--- /dev/null
+++ b/usr/src/lib/print/libpapi-ipp/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS) $(EXTRALINKS)
diff --git a/usr/src/lib/print/libpapi-lpd/Makefile b/usr/src/lib/print/libpapi-lpd/Makefile
new file mode 100644
index 0000000000..b92d620b10
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+#HDRS = papi.h
+#HDRDIR = common
+SUBDIRS = $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install: .WAIT $(SUBDIRS)
+
+lint: # $(SUBDIRS)
+
+install_h: # $(ROOTHDRS)
+
+check: # $(CHECKHDRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/libpapi-lpd/Makefile.com b/usr/src/lib/print/libpapi-lpd/Makefile.com
new file mode 100644
index 0000000000..9c0a8af8df
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/Makefile.com
@@ -0,0 +1,94 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = psm-lpd.a
+VERS = .1
+COMMON_OBJS = lpd-misc.o
+OBJECTS = job.o library.o lpd-cancel.o lpd-job.o lpd-query.o printer.o \
+ service.o $(COMMON_OBJS)
+
+include ../../../Makefile.lib
+include ../../../Makefile.rootfs
+
+SRCDIR = ../common
+
+ROOTLIBDIR= $(ROOT)/usr/lib/print
+ROOTLIBDIR64= $(ROOT)/usr/lib/print/$(MACH)
+
+EXTRALINKS= $(ROOTLIBDIR)/psm-rfc-1179.so
+$(EXTRALINKS): $(ROOTLINKS)
+ $(RM) $@; $(SYMLINK) $(LIBLINKS) $@
+
+LIBS = $(DYNLIB)
+
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR)
+CPPFLAGS += -I../../libpapi-common/common
+
+CERRWARN += -_gcc=-Wno-unused-variable
+
+MAPFILES = $(SRCDIR)/mapfile
+
+LDLIBS += -lc
+
+CLOBBERFILES += $(PROG)
+
+.KEEP_STATE:
+
+all: $(LIBS) $(PROG)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
+
+#
+# NEEDED to build lpd-port
+#
+PROG = lpd-port
+LPD_PORT_OBJS = lpd-port.o $(COMMON_OBJS)
+
+$(PROG) := LDLIBS += -lsocket -lnsl -lsendfile
+
+PROG_OBJS = $(LPD_PORT_OBJS:%=pics/%)
+OBJS += $(PROG_OBJS)
+
+LDFLAGS.cmd = \
+ $(ENVLDFLAGS1) $(ENVLDFLAGS2) $(ENVLDFLAGS3) $(BDIRECT) \
+ $(MAPFILE.NES:%=-M%) $(MAPFILE.PGA:%=-M%) $(MAPFILE.NED:%=-M%)
+
+$(PROG): $(PROG_OBJS)
+ $(LINK.c) -o $@ $(PROG_OBJS) $(LDFLAGS.cmd) $(LDLIBS)
+ $(POST_PROCESS)
+
+# needed for the 'install' phase
+ROOTLIBPRINTPROG = $(PROG:%=$(ROOTLIBDIR)/%)
+$(ROOTLIBPRINTPROG) := FILEMODE = 04511
+
+$(ROOTLIBDIR)/%: $(ROOTLIBDIR) %
+ $(INS.file)
+$(ROOTLIBDIR):
+ $(INS.dir)
diff --git a/usr/src/lib/print/libpapi-lpd/common/job.c b/usr/src/lib/print/libpapi-lpd/common/job.c
new file mode 100644
index 0000000000..8663816337
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/job.c
@@ -0,0 +1,312 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* $Id: job.c 179 2006-07-17 18:24:07Z njacobs $ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <libintl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <papi_impl.h>
+#include <uri.h>
+
+/*
+ * must copy files before leaving routine
+ */
+papi_status_t
+papiJobSubmit(papi_service_t handle, char *name, papi_attribute_t **attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
+{
+ papi_status_t status = PAPI_OK;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ char *metadata = NULL;
+
+ if ((svc == NULL) || (name == NULL) || (files == NULL) ||
+ (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (job_ticket != NULL) {
+ detailed_error(svc,
+ gettext("papiJobSubmit: job ticket not supported"));
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+ }
+
+ if ((status = service_fill_in(svc, name)) != PAPI_OK)
+ return (status);
+
+ if ((*job = j = (job_t *)calloc(1, sizeof (*j))) == NULL) {
+ detailed_error(svc,
+ gettext("calloc() failed"));
+ return (PAPI_TEMPORARY_ERROR);
+ }
+
+ /* before creating a control file add the job-name */
+ if ((files != NULL) && (files[0] != NULL))
+ papiAttributeListAddString(&attributes, PAPI_ATTR_EXCL,
+ "job-name", files[0]);
+
+ /* create a control file */
+ (void) lpd_job_add_attributes(svc, attributes, &metadata,
+ &j->attributes);
+
+ if ((status = lpd_job_add_files(svc, attributes, files, &metadata,
+ &j->attributes)) != PAPI_OK) {
+ return (status);
+ }
+
+ /* send the job to the server */
+ status = lpd_submit_job(svc, metadata, &j->attributes, NULL);
+ free(metadata);
+
+ return (status);
+
+}
+
+
+papi_status_t
+papiJobSubmitByReference(papi_service_t handle, char *name,
+ papi_attribute_t **job_attributes,
+ papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
+{
+ return (papiJobSubmit(handle, name, job_attributes,
+ job_ticket, files, job));
+}
+
+papi_status_t
+papiJobStreamOpen(papi_service_t handle, char *name,
+ papi_attribute_t **attributes,
+ papi_job_ticket_t *job_ticket, papi_stream_t *stream)
+{
+ papi_status_t status = PAPI_OK;
+ service_t *svc = handle;
+ char *metadata = NULL;
+ stream_t *s = NULL;
+
+ if ((svc == NULL) || (name == NULL) || (stream == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (job_ticket != NULL)
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+
+ if ((status = service_fill_in(svc, name)) != PAPI_OK)
+ return (status);
+
+ /* create the stream container */
+ if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ /* create the job */
+ if ((s->job = calloc(1, sizeof (*(s->job)))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ papiAttributeListAddString(&attributes, PAPI_ATTR_EXCL,
+ "job-name", "standard input");
+
+ /* process the attribute list */
+ lpd_job_add_attributes(svc, attributes, &metadata, &s->job->attributes);
+
+ /* if we can stream, do it */
+ if ((svc->uri->fragment != NULL) &&
+ (strcasecmp(svc->uri->fragment, "streaming") == 0)) {
+ char *files[] = { "standard input", NULL };
+
+ lpd_job_add_files(svc, attributes, files, &metadata,
+ &(s->job->attributes));
+ status = lpd_submit_job(svc, metadata, &(s->job->attributes),
+ &s->fd);
+ } else {
+ char dfname[18];
+ char buf[256];
+
+ strcpy(dfname, "/tmp/stdin-XXXXX");
+
+ if ((s->fd = mkstemp(dfname)) >= 0)
+ s->dfname = strdup(dfname);
+ if (s->job->attributes)
+ papiAttributeListFree(s->job->attributes);
+ s->job->attributes = NULL;
+ papiAttributeListToString(attributes, " ", buf, sizeof (buf));
+ papiAttributeListFromString(&(s->job->attributes),
+ PAPI_ATTR_APPEND, buf);
+ }
+ s->metadata = metadata;
+
+ return (status);
+}
+
+
+papi_status_t
+papiJobStreamWrite(papi_service_t handle, papi_stream_t stream,
+ void *buffer, size_t buflen)
+{
+ service_t *svc = handle;
+ stream_t *s = stream;
+
+ if ((svc == NULL) || (stream == NULL) || (buffer == NULL) ||
+ (buflen == 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ if (write(s->fd, buffer, buflen) != buflen)
+ return (PAPI_DEVICE_ERROR);
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiJobStreamClose(papi_service_t handle, papi_stream_t stream, papi_job_t *job)
+{
+ papi_status_t status = PAPI_INTERNAL_ERROR;
+ service_t *svc = handle;
+ job_t *j = NULL;
+ stream_t *s = stream;
+ int ret;
+
+ if ((svc == NULL) || (stream == NULL) || (job == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ close(s->fd); /* close the stream */
+
+ if (s->dfname != NULL) { /* if it is a tmpfile, print it */
+ char *files[2];
+
+ files[0] = s->dfname;
+ files[1] = NULL;
+
+ lpd_job_add_files(svc, s->job->attributes, files, &s->metadata,
+ &(s->job->attributes));
+ status = lpd_submit_job(svc, s->metadata,
+ &(s->job->attributes), NULL);
+ unlink(s->dfname);
+ free(s->dfname);
+ } else
+ status = PAPI_OK;
+
+ if (s->metadata != NULL)
+ free(s->metadata);
+
+ *job = s->job;
+
+ return (status);
+}
+
+papi_status_t
+papiJobQuery(papi_service_t handle, char *name, int32_t job_id,
+ char **job_attributes, papi_job_t *job)
+{
+ papi_status_t status = PAPI_OK;
+ service_t *svc = handle;
+
+ if ((svc == NULL) || (name == NULL) || job_id < 0)
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK)
+ status = lpd_find_job_info(svc, job_id, (job_t **)job);
+
+ return (status);
+}
+
+papi_status_t
+papiJobCancel(papi_service_t handle, char *name, int32_t job_id)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+
+ if ((svc == NULL) || (name == NULL) || (job_id < 0))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK)
+ status = lpd_cancel_job(svc, job_id);
+
+ return (status);
+}
+
+papi_attribute_t **
+papiJobGetAttributeList(papi_job_t job)
+{
+ job_t *j = (job_t *)job;
+
+ if (j != NULL)
+ return ((papi_attribute_t **)j->attributes);
+
+ return (NULL);
+}
+
+char *
+papiJobGetPrinterName(papi_job_t job)
+{
+ char *result = NULL;
+ job_t *j = (job_t *)job;
+
+ if (j != NULL)
+ papiAttributeListGetString(j->attributes, NULL,
+ "printer-name", &result);
+
+ return (result);
+}
+
+int
+papiJobGetId(papi_job_t job)
+{
+ int result = -1;
+ job_t *j = (job_t *)job;
+
+ if (j != NULL)
+ papiAttributeListGetInteger(j->attributes, NULL,
+ "job-id", &result);
+
+ return (result);
+}
+
+void
+papiJobFree(papi_job_t job)
+{
+ job_t *j = (job_t *)job;
+
+
+ if (j != NULL) {
+ papiAttributeListFree(j->attributes);
+ free(j);
+ }
+}
+
+void
+papiJobListFree(papi_job_t *jobs)
+{
+ if (jobs != NULL) {
+ int i;
+
+ for (i = 0; jobs[i] != NULL; i++)
+ papiJobFree(jobs[i]);
+ free(jobs);
+ }
+}
diff --git a/usr/src/lib/print/libpapi-lpd/common/library.c b/usr/src/lib/print/libpapi-lpd/common/library.c
new file mode 100644
index 0000000000..de38c2bbfa
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/library.c
@@ -0,0 +1,90 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: library.c 146 2006-03-24 00:26:54Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <alloca.h>
+#include <libintl.h>
+#include <papi_impl.h>
+
+static char *calls[] = {
+ /* Attribute Calls */
+ "papiAttributeListAdd",
+ "papiAttributeListAddBoolean", "papiAttributeListAddCollection",
+ "papiAttributeListAddDatetime", "papiAttributeListAddInteger",
+ "papiAttributeListAddMetadata", "papiAttributeListAddRange",
+ "papiAttributeListAddResolution", "papiAttributeListAddString",
+ "papiAttributeListDelete",
+ "papiAttributeListGetValue", "papiAttributeListGetNext",
+ "papiAttributeListFind",
+ "papiAttributeListGetBoolean", "papiAttributeListGetCollection",
+ "papiAttributeListGetDatetime", "papiAttributeListGetInteger",
+ "papiAttributeListGetMetadata", "papiAttributeListGetRange",
+ "papiAttributeListGetResolution", "papiAttributeListGetString",
+ "papiAttributeListFromString", "papiAttributeListToString",
+ "papiAttributeListFree",
+ /* Job Calls */
+ "papiJobSubmit", "papiJobSubmitByReference",
+ "papiJobStreamOpen", "papiJobStreamWrite", "papiJobStreamClose",
+ "papiJobQuery", "papiJobCancel",
+ "papiJobGetAttributeList", "papiJobGetId", "papiJobGetPrinterName",
+ "papiJobFree", "papiJobListFree",
+ /* Printer Calls */
+ "papiPrinterQuery", "papiPrinterPurgeJobs", "papiPrinterListJobs",
+ "papiPrinterGetAttributeList", "papiPrinterFree",
+ /* Service Calls */
+ "papiServiceCreate", "papiServiceDestroy",
+ "papiServiceGetStatusMessage",
+ /* Misc Calls */
+ "papiStatusString",
+ "papiLibrarySupportedCall", "papiLibrarySupportedCalls",
+ NULL
+};
+
+char **
+papiLibrarySupportedCalls()
+{
+ return (calls);
+}
+
+char
+papiLibrarySupportedCall(char *name)
+{
+ int i;
+
+ for (i = 0; calls[i] != NULL; i++)
+ if (strcmp(name, calls[i]) == 0)
+ return (PAPI_TRUE);
+
+ return (PAPI_FALSE);
+}
diff --git a/usr/src/lib/print/libpapi-lpd/common/lpd-cancel.c b/usr/src/lib/print/libpapi-lpd/common/lpd-cancel.c
new file mode 100644
index 0000000000..d5a8fd30fd
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/lpd-cancel.c
@@ -0,0 +1,121 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lpd-cancel.c 155 2006-04-26 02:34:54Z ktou $ */
+
+#define __EXTENSIONS__ /* for strtok_r() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <papi_impl.h>
+
+papi_status_t
+lpd_cancel_job(service_t *svc, int id)
+{
+ papi_status_t status = PAPI_INTERNAL_ERROR;
+ int fd;
+ char *list[2];
+ char buf[128]; /* this should be overkill */
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ snprintf(buf, sizeof (buf), "%d", id);
+ list[0] = buf;
+ list[1] = NULL;
+
+ if ((fd = lpd_open(svc, 'c', list, 15)) < 0)
+ return (PAPI_INTERNAL_ERROR);
+
+ memset(buf, 0, sizeof (buf));
+ if (fdgets(buf, sizeof (buf), fd) != NULL) {
+ if (buf[0] == '\0')
+ status = PAPI_NOT_FOUND;
+ else if ((strstr(buf, "permission denied") != NULL) ||
+ (strstr(buf, "not-authorized") != NULL))
+ status = PAPI_NOT_AUTHORIZED;
+ else if ((strstr(buf, "cancelled") != NULL) ||
+ (strstr(buf, "removed") != NULL))
+ status = PAPI_OK;
+ } else
+ status = PAPI_NOT_FOUND;
+
+ close(fd);
+
+ return (status);
+}
+
+papi_status_t
+lpd_purge_jobs(service_t *svc, job_t ***jobs)
+{
+ papi_status_t status = PAPI_INTERNAL_ERROR;
+ int fd;
+ char *queue;
+ char buf[256];
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((fd = lpd_open(svc, 'c', NULL, 15)) < 0)
+ return (PAPI_INTERNAL_ERROR);
+
+ queue = queue_name_from_uri(svc->uri);
+
+ status = PAPI_OK;
+ memset(buf, 0, sizeof (buf));
+ while (fdgets(buf, sizeof (buf), fd) != NULL) {
+ /* if we canceled it, add it to the list */
+ if ((strstr(buf, "cancelled") != NULL) ||
+ (strstr(buf, "removed") != NULL)) {
+ job_t *job;
+ papi_attribute_t **attributes = NULL;
+ char *ptr, *iter = NULL;
+ int id;
+
+ ptr = strtok_r(buf, ":", &iter);
+ papiAttributeListAddString(&attributes, PAPI_ATTR_EXCL,
+ "job-name", ptr);
+ id = atoi(ptr);
+ papiAttributeListAddInteger(&attributes, PAPI_ATTR_EXCL,
+ "job-id", id);
+ papiAttributeListAddString(&attributes, PAPI_ATTR_EXCL,
+ "job-printer", queue);
+
+ if ((job = (job_t *)calloc(1, (sizeof (*job))))
+ != NULL) {
+ job->attributes = attributes;
+ list_append(jobs, job);
+ } else
+ papiAttributeListFree(attributes);
+ } else if (strstr(buf, "permission denied") != NULL)
+ status = PAPI_NOT_AUTHORIZED;
+ }
+ close(fd);
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libpapi-lpd/common/lpd-job.c b/usr/src/lib/print/libpapi-lpd/common/lpd-job.c
new file mode 100644
index 0000000000..c958a51e06
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/lpd-job.c
@@ -0,0 +1,626 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lpd-job.c 157 2006-04-26 15:07:55Z ktou $ */
+
+
+#define __EXTENSIONS__ /* for strtok_r() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <pwd.h>
+#include <libintl.h>
+#include <papi_impl.h>
+
+enum { LPD_RFC, LPD_SVR4 };
+
+static char
+mime_type_to_rfc1179_type(char *mime)
+{
+ static struct { char *mime; char rfc; } cvt[] = {
+ { "text/plain", 'f' },
+ { "application/octet-stream", 'l' },
+ { "application/postscript", 'f' }, /* rfc incorrectly has 'o' */
+ { "application/x-pr", 'p' },
+ { "application/x-cif", 'c' },
+ { "application/x-dvi", 'd' },
+ { "application/x-fortran", 'r' },
+ { "application/x-plot", 'g' },
+ { "application/x-ditroff", 'n' },
+ { "application/x-troff", 't' },
+ { "application/x-raster", 'v' },
+ { NULL, 0}
+ };
+ char result = '\0';
+
+ if (mime != NULL) {
+ int i;
+
+ for (i = 0; cvt[i].mime != NULL; i++)
+ if (strcasecmp(cvt[i].mime, mime) == 0) {
+ result = cvt[i].rfc;
+ break;
+ }
+ }
+
+ return (result);
+}
+
+static papi_status_t
+add_lpd_control_line(char **metadata, char code, char *value)
+{
+ size_t size = 0;
+ char line[BUFSIZ];
+
+ if ((metadata == NULL) || (value == NULL))
+ return (PAPI_BAD_REQUEST);
+
+ if (*metadata != NULL)
+ size = strlen(*metadata);
+ size += strlen(value) + 3;
+
+ if (*metadata == NULL) {
+ *metadata = (char *)calloc(1, size);
+ } else {
+ void *tmp;
+ tmp = calloc(1, size);
+ if (tmp) {
+ strlcpy(tmp, *metadata, size);
+ free(*metadata);
+ *metadata = (char *)tmp;
+ } else
+ return (PAPI_TEMPORARY_ERROR);
+ }
+
+ snprintf(line, sizeof (line), "%c%s\n", code, value);
+ strlcat(*metadata, line, size);
+
+ return (PAPI_OK);
+}
+
+static papi_status_t
+add_svr4_control_line(char **metadata, char code, char *value)
+{
+
+ char line[BUFSIZ];
+
+ if ((metadata == NULL) || (value == NULL))
+ return (PAPI_BAD_REQUEST);
+
+ snprintf(line, sizeof (line), "%c%s", code, value);
+
+ return (add_lpd_control_line(metadata, '5', line));
+}
+
+static papi_status_t
+add_hpux_control_line(char **metadata, char *value)
+{
+
+ char line[BUFSIZ];
+
+ if ((metadata == NULL) || (value == NULL))
+ return (PAPI_BAD_REQUEST);
+
+ snprintf(line, sizeof (line), " O%s", value);
+
+ return (add_lpd_control_line(metadata, 'N', line));
+}
+
+static papi_status_t
+add_int_control_line(char **metadata, char code, int value, int flag)
+{
+ char buf[16];
+
+ snprintf(buf, sizeof (buf), "%d", value);
+
+ if (flag == LPD_SVR4)
+ return (add_svr4_control_line(metadata, code, buf));
+ else
+ return (add_lpd_control_line(metadata, code, buf));
+}
+
+static papi_status_t
+lpd_add_rfc1179_attributes(service_t *svc, papi_attribute_t **attributes,
+ char **metadata, papi_attribute_t ***used)
+{
+ papi_status_t status = PAPI_OK;
+ char *s;
+ int integer;
+ char bool;
+ char host[BUFSIZ];
+ char *user = "nobody";
+ uid_t uid = getuid();
+ struct passwd *pw;
+ char *h1;
+
+ if (svc == NULL)
+ return (PAPI_BAD_REQUEST);
+
+ /* There is nothing to do */
+ if (attributes == NULL)
+ return (PAPI_OK);
+
+ gethostname(host, sizeof (host));
+ if (papiAttributeListGetString(attributes, NULL,
+ "job-originating-host-name", &h1) == PAPI_OK) {
+ papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
+ "job-host", h1);
+ }
+ add_lpd_control_line(metadata, 'H', host);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "job-originating-host-name", host);
+
+ if ((pw = getpwuid(uid)) != NULL)
+ user = pw->pw_name;
+ if (uid == 0)
+ papiAttributeListGetString(svc->attributes, NULL, "username",
+ &user);
+ add_lpd_control_line(metadata, 'P', user);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "job-originating-user-name", user);
+
+ /* Class for Banner Page */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "rfc-1179-class", &s);
+ if (s != NULL) {
+ add_lpd_control_line(metadata, 'C', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "rfc-1179-class", s);
+ }
+
+ /* Print Banner Page */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "job-sheets", &s);
+ if ((s != NULL) && (strcmp(s, "standard") == 0)) {
+ add_lpd_control_line(metadata, 'L', user);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "job-sheets", s);
+ }
+
+ /* Jobname */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "job-name", &s);
+ if (s != NULL) {
+ add_lpd_control_line(metadata, 'J', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "job-name", s);
+ }
+
+ /* User to mail when job is done - lpr -m */
+ bool = PAPI_FALSE;
+ papiAttributeListGetBoolean(attributes, NULL, "rfc-1179-mail", &bool);
+ if (bool == PAPI_TRUE) {
+ add_lpd_control_line(metadata, 'M', user);
+ papiAttributeListAddBoolean(used, PAPI_ATTR_EXCL,
+ "rfc-1179-mail", bool);
+ }
+
+ /* Title for pr */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "pr-title", &s);
+ if (s != NULL) {
+ add_lpd_control_line(metadata, 'T', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "pr-title", s);
+ }
+
+ /* Indent - used with pr filter */
+ integer = 0;
+ papiAttributeListGetInteger(attributes, NULL, "pr-indent", &integer);
+ if (integer >= 1) {
+ add_int_control_line(metadata, 'I', integer, LPD_RFC);
+ papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
+ "pr-indent", integer);
+ }
+
+ /* Width - used with pr filter */
+ integer = 0;
+ papiAttributeListGetInteger(attributes, NULL, "pr-width", &integer);
+ if (integer >= 1) {
+ add_int_control_line(metadata, 'W', integer, LPD_RFC);
+ papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
+ "pr-width", integer);
+ }
+
+ /* file with Times Roman font lpr -1 */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "rfc-1179-font-r", &s);
+ if (s != NULL) {
+ add_lpd_control_line(metadata, '1', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "rfc-1179-font-r", s);
+ }
+
+ /* file with Times Roman font lpr -2 */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "rfc-1179-font-i", &s);
+ if (s != NULL) {
+ add_lpd_control_line(metadata, '2', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "rfc-1179-font-i", s);
+ }
+
+ /* file with Times Roman font lpr -3 */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "rfc-1179-font-b", &s);
+ if (s != NULL) {
+ add_lpd_control_line(metadata, '3', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "rfc-1179-font-b", s);
+ }
+
+ /* file with Times Roman font lpr -4 */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "rfc-1179-font-s", &s);
+ if (s != NULL) {
+ add_lpd_control_line(metadata, '4', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "rfc-1179-font-s", s);
+ }
+
+ /*
+ * The document format needs to be added, but the control line
+ * should be added when the filenames are figured out.
+ */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "document-format", &s);
+ if (s != NULL) {
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "document-format", s);
+ }
+
+ return (status);
+}
+
+static char *
+unused_attributes(papi_attribute_t **list, papi_attribute_t **used)
+{
+ char *result = NULL;
+ char **names = NULL;
+ int i;
+
+ if ((list == NULL) || (used == NULL))
+ return (NULL);
+
+ for (i = 0; used[i] != NULL; i++)
+ list_append(&names, used[i]->name);
+
+ if (names != NULL) {
+ papi_attribute_t **unused = NULL;
+
+ /* add these to the list of things to ignore */
+ list_append(&names, "document-format");
+ list_append(&names, "copies");
+
+ split_and_copy_attributes(names, list, NULL, &unused);
+ if (unused != NULL) {
+ size_t size = 0;
+
+ do {
+ size += 1024;
+ if (result != NULL)
+ free(result);
+ result = calloc(1, size);
+ } while (papiAttributeListToString(unused, " ",
+ result, size) != PAPI_OK);
+ papiAttributeListFree(unused);
+ }
+ free(names);
+ }
+
+ return (result);
+}
+
+/*
+ * lpd_add_svr4_attributes
+ * Solaris 2.x LP - BSD protocol extensions
+ */
+static papi_status_t
+lpd_add_svr4_attributes(service_t *svc, papi_attribute_t **attributes,
+ char **metadata, papi_attribute_t ***used)
+{
+ papi_attribute_t *tmp[2];
+ char *s;
+ int integer;
+
+ if (svc == NULL)
+ return (PAPI_BAD_REQUEST);
+
+ /* media */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "media", &s);
+ if (s != NULL) {
+ add_svr4_control_line(metadata, 'f', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "media", s);
+ }
+
+ /* Handling */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "job-hold-until", &s);
+ if ((s != NULL) && (strcmp(s, "indefinite") == 0)) {
+ add_svr4_control_line(metadata, 'H', "hold");
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "job-hold-until", "indefinite");
+ } else if ((s != NULL) && (strcmp(s, "no-hold") == 0)) {
+ add_svr4_control_line(metadata, 'H', "immediate");
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "job-hold-until", "no-hold");
+ } else if (s != NULL) {
+ add_svr4_control_line(metadata, 'H', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "job-hold-until", s);
+ }
+
+ /* Pages */
+ s = NULL;
+ memset(tmp, NULL, sizeof (tmp));
+ tmp[0] = papiAttributeListFind(attributes, "page-ranges");
+ if (tmp[0] != NULL) {
+ char buf[BUFSIZ];
+
+ papiAttributeListToString(tmp, " ", buf, sizeof (buf));
+ if ((s = strchr(buf, '=')) != NULL) {
+ add_svr4_control_line(metadata, 'P', ++s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "page-ranges", s);
+ }
+ }
+
+ /* Priority : lp -q */
+ integer = -1;
+ papiAttributeListGetInteger(attributes, NULL, "job-priority", &integer);
+ if (integer != -1) {
+ integer = 40 - (integer / 2.5);
+ add_int_control_line(metadata, 'q', integer, LPD_SVR4);
+ papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
+ "job-priority", integer);
+ }
+
+ /* Charset : lp -S */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "lp-charset", &s);
+ if (s != NULL) {
+ add_svr4_control_line(metadata, 'S', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "lp-charset", s);
+ }
+
+ /* Type : done when adding file */
+
+ /* Mode : lp -y */
+ s = NULL;
+ papiAttributeListGetString(attributes, NULL, "lp-modes", &s);
+ if (s != NULL) {
+ add_svr4_control_line(metadata, 'y', s);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "lp-modes", s);
+ }
+
+ /* Options lp -o are handled elsewhere */
+ if ((s = unused_attributes(attributes, *used)) != NULL) {
+ add_lpd_control_line(metadata, 'O', s);
+ free(s);
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+lpd_add_hpux_attributes(service_t *svc, papi_attribute_t **attributes,
+ char **metadata, papi_attribute_t ***used)
+{
+ char *s = NULL;
+
+ /* Options lp -o */
+ if ((s = unused_attributes(attributes, *used)) != NULL) {
+ add_hpux_control_line(metadata, s);
+ free(s);
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+lpd_job_add_attributes(service_t *svc, papi_attribute_t **attributes,
+ char **metadata, papi_attribute_t ***used)
+{
+ if ((svc == NULL) || (metadata == NULL))
+ return (PAPI_BAD_REQUEST);
+
+ lpd_add_rfc1179_attributes(svc, attributes, metadata, used);
+
+ /* add protocol extensions if applicable */
+ if (svc->uri->fragment != NULL) {
+ if ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
+ (strcasecmp(svc->uri->fragment, "svr4") == 0))
+ lpd_add_svr4_attributes(svc, attributes, metadata,
+ used);
+ else if (strcasecmp(svc->uri->fragment, "hpux") == 0)
+ lpd_add_hpux_attributes(svc, attributes, metadata,
+ used);
+ /*
+ * others could be added here:
+ * lprng, sco, aix, digital unix, xerox, ...
+ */
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+lpd_job_add_files(service_t *svc, papi_attribute_t **attributes,
+ char **files, char **metadata, papi_attribute_t ***used)
+{
+ char *format = "text/plain";
+ char rfc_fmt = 'l';
+ int copies = 1;
+ char host[BUFSIZ];
+ int i;
+
+ if ((svc == NULL) || (attributes == NULL) || (files == NULL) ||
+ (metadata == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ papiAttributeListGetString(attributes, NULL, "document-format",
+ &format);
+ papiAttributeListAddString(used, PAPI_ATTR_EXCL,
+ "document-format", format);
+ if ((rfc_fmt = mime_type_to_rfc1179_type(format)) == '\0') {
+ if ((svc->uri->fragment != NULL) &&
+ ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
+ (strcasecmp(svc->uri->fragment, "svr4") == 0)))
+ add_svr4_control_line(metadata, 'T', format);
+ rfc_fmt = 'l';
+ }
+
+ papiAttributeListGetInteger(attributes, NULL, "copies", &copies);
+ if (copies < 1)
+ copies = 1;
+ papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, "copies", copies);
+
+ gethostname(host, sizeof (host));
+
+ for (i = 0; files[i] != NULL; i++) {
+ char name[BUFSIZ];
+ struct stat statbuf;
+ char key;
+ int j;
+
+ if ((strcmp("standard input", files[i]) != 0) &&
+ (access(files[i], R_OK) < 0)) {
+ detailed_error(svc, gettext("aborting request, %s: %s"),
+ files[i], strerror(errno));
+ return (PAPI_NOT_AUTHORIZED);
+ }
+ if (strcmp("standard input", files[i]) != 0) {
+ if (stat(files[i], &statbuf) < 0) {
+ detailed_error(svc,
+ gettext("Cannot access file: %s: %s"),
+ files[i], strerror(errno));
+ return (PAPI_DOCUMENT_ACCESS_ERROR);
+ }
+ if (statbuf.st_size == 0) {
+ detailed_error(svc,
+ gettext("Zero byte (empty) file: %s"),
+ files[i]);
+ return (PAPI_BAD_ARGUMENT);
+ }
+ }
+
+ if (i < 26)
+ key = 'A' + i;
+ else if (i < 52)
+ key = 'a' + (i - 26);
+ else if (i < 62)
+ key = '0' + (i - 52);
+ else {
+ detailed_error(svc,
+ gettext("too many files, truncated at 62"));
+ return (PAPI_OK_SUBST);
+ }
+
+ snprintf(name, sizeof (name), "df%cXXX%s", key, host);
+
+ for (j = 0; j < copies; j++)
+ add_lpd_control_line(metadata, rfc_fmt, name);
+ add_lpd_control_line(metadata, 'U', name);
+ add_lpd_control_line(metadata, 'N', (char *)files[i]);
+ }
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+lpd_submit_job(service_t *svc, char *metadata, papi_attribute_t ***attributes,
+ int *ofd)
+{
+ papi_status_t status = PAPI_INTERNAL_ERROR;
+ int fd;
+ char path[32];
+ char *list[2];
+
+ if ((svc == NULL) || (metadata == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ strcpy(path, "/tmp/lpd-job-XXXXXX");
+ fd = mkstemp(path);
+ write(fd, metadata, strlen(metadata));
+ close(fd);
+
+ list[0] = path;
+ list[1] = NULL;
+
+ if (((fd = lpd_open(svc, 's', list, 15)) < 0) && (errno != EBADMSG)) {
+ switch (errno) {
+ case ENOSPC:
+ status = PAPI_TEMPORARY_ERROR;
+ break;
+ case EIO:
+ status = PAPI_TEMPORARY_ERROR;
+ break;
+ case ECONNREFUSED:
+ status = PAPI_SERVICE_UNAVAILABLE;
+ break;
+ case ENOENT:
+ status = PAPI_NOT_ACCEPTING;
+ break;
+ case EBADMSG:
+ case EBADF:
+ status = PAPI_OK;
+ break;
+ default:
+ status = PAPI_TIMEOUT;
+ break;
+ }
+ } else
+ status = PAPI_OK;
+
+ if (ofd != NULL)
+ *ofd = fd;
+ else
+ close(fd);
+
+ /* read the ID and add it to to the job */
+ if ((fd = open(path, O_RDONLY)) >= 0) {
+ int job_id = 0;
+ read(fd, &job_id, sizeof (job_id));
+ papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
+ "job-id", job_id);
+ close(fd);
+ }
+
+ unlink(path);
+
+ return (status);
+}
diff --git a/usr/src/lib/print/libpapi-lpd/common/lpd-misc.c b/usr/src/lib/print/libpapi-lpd/common/lpd-misc.c
new file mode 100644
index 0000000000..1dc9589d25
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/lpd-misc.c
@@ -0,0 +1,206 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lpd-misc.c 155 2006-04-26 02:34:54Z ktou $ */
+
+#define __EXTENSIONS__ /* for strtok_r() */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <wait.h>
+#include <stropts.h>
+#include <papi_impl.h>
+
+#include <config-site.h>
+
+char *
+fdgets(char *buf, size_t len, int fd)
+{
+ char tmp;
+ int count = 0;
+
+ memset(buf, 0, len);
+ while ((count < len) && (read(fd, &tmp, 1) > 0))
+ if ((buf[count++] = tmp) == '\n') break;
+
+ if (count != 0)
+ return (buf);
+ return (NULL);
+}
+
+char *
+queue_name_from_uri(uri_t *uri)
+{
+ char *result = NULL;
+
+ if ((uri != NULL) && (uri->path != NULL)) {
+ char *ptr = strrchr(uri->path, '/');
+
+ if (ptr == NULL)
+ result = uri->path;
+ else
+ result = ++ptr;
+ }
+
+ return (result);
+}
+
+static int
+recvfd(int sockfd)
+{
+ int fd = -1;
+#if defined(sun) && defined(unix) && defined(I_RECVFD)
+ struct strrecvfd recv_fd;
+
+ memset(&recv_fd, NULL, sizeof (recv_fd));
+ if (ioctl(sockfd, I_RECVFD, &recv_fd) == 0)
+ fd = recv_fd.fd;
+#else
+ struct iovec iov[1];
+ struct msghdr msg;
+
+#ifdef CMSG_DATA
+ struct cmsghdr cmp[1];
+ char buf[24]; /* send/recv 2 byte protocol */
+
+ memset(buf, 0, sizeof (buf));
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = sizeof (buf);
+
+ msg.msg_control = cmp;
+ msg.msg_controllen = sizeof (struct cmsghdr) + sizeof (int);
+#else
+ iov[0].iov_base = NULL;
+ iov[0].iov_len = 0;
+ msg.msg_accrights = (caddr_t)&fd;
+ msg.msg_accrights = sizeof (fd);
+#endif
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ if (recvmsg(sockfd, &msg, 0) < 0)
+ fd = -1;
+#ifdef CMSG_DATA
+ else
+ fd = * (int *)CMSG_DATA(cmp);
+#endif
+#endif
+ return (fd);
+}
+
+int
+lpd_open(service_t *svc, char type, char **args, int timeout)
+{
+ int ac, rc = -1, fds[2];
+ pid_t pid;
+ char *av[64], *tmp, buf[BUFSIZ];
+
+ if ((svc == NULL) || (svc->uri == NULL))
+ return (-1);
+
+#ifndef SUID_LPD_PORT
+#define SUID_LPD_PORT "/usr/lib/print/lpd-port"
+#endif
+
+ av[0] = SUID_LPD_PORT; ac = 1;
+
+ /* server */
+ av[ac++] = "-H";
+ av[ac++] = svc->uri->host;
+
+ /* timeout */
+ if (timeout > 0) {
+ snprintf(buf, sizeof (buf), "%d", timeout);
+ av[ac++] = "-t";
+ av[ac++] = strdup(buf);
+ }
+
+ /* operation */
+ snprintf(buf, sizeof (buf), "-%c", type);
+ av[ac++] = buf;
+
+ /* queue */
+ if (svc->uri->path == NULL) {
+ tmp = "";
+ } else {
+ if ((tmp = strrchr(svc->uri->path, '/')) == NULL)
+ tmp = svc->uri->path;
+ else
+ tmp++;
+ }
+ av[ac++] = tmp;
+
+ /* args */
+ if (args != NULL)
+ while ((*args != NULL) && (ac < 62))
+ av[ac++] = *args++;
+
+ av[ac++] = NULL;
+
+#if defined(sun) && defined(unix) && defined(I_RECVFD)
+ pipe(fds);
+#else
+ socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+#endif
+
+ switch (pid = fork()) {
+ case -1: /* failed */
+ break;
+ case 0: /* child */
+ dup2(fds[1], 1);
+ execv(av[0], &av[0]);
+ perror("exec");
+ exit(1);
+ break;
+ default: { /* parent */
+ int err, status = 0;
+
+ while ((waitpid(pid, &status, 0) < 0) && (errno == EINTR));
+ errno = WEXITSTATUS(status);
+
+ if (errno == 0)
+ rc = recvfd(fds[0]);
+
+ err = errno;
+ close(fds[0]);
+ close(fds[1]);
+ errno = err;
+ }
+ }
+
+ return (rc);
+}
diff --git a/usr/src/lib/print/libpapi-lpd/common/lpd-port.c b/usr/src/lib/print/libpapi-lpd/common/lpd-port.c
new file mode 100644
index 0000000000..5c6c2e3ff8
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/lpd-port.c
@@ -0,0 +1,823 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: lpd-port.c 155 2006-04-26 02:34:54Z ktou $ */
+
+#include <config-site.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <syslog.h>
+#include <values.h>
+#include <stropts.h> /* for sendfd */
+#include <sys/uio.h> /* for sendmsg stuff */
+#include <pwd.h>
+#include <sys/sendfile.h>
+#include <ctype.h>
+#ifdef HAVE_PRIV_H
+#include <priv.h>
+#endif
+
+#ifndef JOB_ID_FILE
+#define JOB_ID_FILE "/var/run/rfc-1179.seq"
+#endif /* JOB_ID_FILE */
+
+static int
+sendfd(int sockfd, int fd)
+{
+ syslog(LOG_DEBUG, "sendfd(%d, %d)", sockfd, fd);
+
+#if defined(sun) && defined(unix) && defined(I_SENDFD)
+ return (ioctl(sockfd, I_SENDFD, fd));
+#else
+ struct iovec iov[1];
+ struct msghdr msg;
+#ifdef CMSG_DATA
+ struct cmsghdr cmp[1];
+ char buf[2]; /* send/recv 2 byte protocol */
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 2;
+
+ cmp[0].cmsg_level = SOL_SOCKET;
+ cmp[0].cmsg_type = SCM_RIGHTS;
+ cmp[0].cmsg_len = sizeof (struct cmsghdr) + sizeof (int);
+ * (int *)CMSG_DATA(cmp) = fd;
+
+ buf[1] = 0;
+ buf[0] = 0;
+ msg.msg_control = cmp;
+ msg.msg_controllen = sizeof (struct cmsghdr) + sizeof (int);
+#else
+ iov[0].iov_base = NULL;
+ iov[0].iov_len = 0;
+ msg.msg_accrights = (caddr_t)&fd;
+ msg.msg_accrights = sizeof (fd);
+#endif
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ return (sendmsg(sockfd, &msg, 0));
+#endif
+}
+
+static void
+null(int i)
+{
+}
+
+static int
+sock_connect(int sock, char *host, int timeout)
+{
+ struct hostent *hp;
+ struct servent *sp;
+#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_RRESVPORT_AF)
+ struct sockaddr_in6 sin;
+#else
+ struct sockaddr_in sin;
+#endif
+ static void (*old_handler)();
+ int err, error_num;
+ unsigned timo = 1;
+
+ /*
+ * Get the host address and port number to connect to.
+ */
+ if (host == NULL) {
+ return (-1);
+ }
+
+ /* linux style NULL usage */
+ (void) memset((char *)&sin, (int)NULL, sizeof (sin));
+
+#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_RRESVPORT_AF)
+ if ((hp = getipnodebyname(host, AF_INET6, AI_DEFAULT,
+ &error_num)) == NULL) {
+ errno = ENOENT;
+ return (-1);
+ }
+ (void) memcpy((caddr_t)&sin.sin6_addr, hp->h_addr, hp->h_length);
+ sin.sin6_family = hp->h_addrtype;
+#else
+ if ((hp = gethostbyname(host)) == NULL) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+ (void) memcpy((caddr_t)&sin.sin_addr, hp->h_addr, hp->h_length);
+ sin.sin_family = hp->h_addrtype;
+#endif
+
+ if ((sp = getservbyname("printer", "tcp")) == NULL) {
+ errno = ENOENT;
+ return (-1);
+ }
+
+#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_RRESVPORT_AF)
+ sin.sin6_port = sp->s_port;
+#else
+ sin.sin_port = sp->s_port;
+#endif
+
+retry:
+ old_handler = signal(SIGALRM, null);
+ (void) alarm(timeout);
+
+ if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+ (void) alarm(0);
+ (void) signal(SIGALRM, old_handler);
+
+ if (errno == ECONNREFUSED && timo <= 16) {
+ (void) sleep(timo);
+ timo *= 2;
+ goto retry;
+ }
+
+ return (-1);
+ }
+
+ (void) alarm(0);
+ (void) signal(SIGALRM, old_handler);
+ return (sock);
+}
+
+static int
+next_job_id()
+{
+ int fd, result = getpid() % 1000;
+
+ /* gain back enough privilege to open the id file */
+#ifdef PRIV_ALLSETS
+ if ((priv_set(PRIV_ON, PRIV_EFFECTIVE,
+ PRIV_FILE_DAC_READ, PRIV_FILE_DAC_WRITE, NULL)) < 0) {
+ syslog(LOG_ERR, "lpd_port:next_job_id:priv_set fails: : %m");
+ return (-1);
+ }
+#else
+ seteuid(0);
+#endif
+
+ /* open the sequence file */
+ if (((fd = open(JOB_ID_FILE, O_RDWR)) < 0) && (errno == ENOENT))
+ fd = open(JOB_ID_FILE, O_CREAT|O_EXCL|O_RDWR, 0644);
+
+ syslog(LOG_DEBUG, "sequence file fd: %d", fd);
+
+ /* drop our privilege again */
+#ifdef PRIV_ALLSETS
+ /* drop file access privilege */
+ priv_set(PRIV_OFF, PRIV_PERMITTED,
+ PRIV_FILE_DAC_READ, PRIV_FILE_DAC_WRITE, NULL);
+#else
+ seteuid(getuid());
+#endif
+
+ if (fd >= 0) {
+ /* wait for a lock on the file */
+ if (lockf(fd, F_LOCK, 0) == 0) {
+ char buf[8];
+ int next;
+
+ /* get the current id */
+ (void) memset(buf, 0, sizeof (buf));
+ if (read(fd, buf, sizeof (buf)) > 0)
+ result = atoi(buf);
+
+ next = ((result < 999) ? (result + 1) : 0);
+
+ /* store the next id in the file */
+ snprintf(buf, sizeof (buf), "%.3d", next);
+ if ((lseek(fd, 0, SEEK_SET) == 0) &&
+ (ftruncate(fd, 0) == 0))
+ write(fd, buf, strlen(buf));
+ }
+ close(fd);
+ }
+ syslog(LOG_DEBUG, "next_job_id() is %d", result);
+
+ return (result);
+}
+
+static int
+reserved_port()
+{
+ int result = -1;
+ int port;
+
+ /* gain back enough privilege to open a reserved port */
+#ifdef PRIV_ALLSETS
+ if ((priv_set(
+ PRIV_ON, PRIV_EFFECTIVE, PRIV_NET_PRIVADDR, NULL)) != 0) {
+ syslog(LOG_ERR, "priv_set fails for net_privaddr %m");
+ return (-1);
+ }
+#else
+ seteuid(0);
+#endif
+
+#if defined(HAVE_GETIPNODEBYNAME) && defined(HAVE_RRESVPORT_AF)
+ port = 0; /* set to 0, rresvport_af() will find us one. */
+ result = rresvport_af(&port, AF_INET6);
+#else
+ port = IPPORT_RESERVED - 1;
+ while (((result = rresvport(&port)) < 0) && (port >= 0))
+ port--;
+#endif
+
+ /* drop our privilege again */
+#ifdef PRIV_ALLSETS
+ priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_NET_PRIVADDR, NULL);
+#else
+ seteuid(getuid());
+#endif
+
+ return (result);
+}
+
+static char *
+get_user_name()
+{
+ static struct passwd *p = NULL;
+
+ if ((p = getpwuid(getuid())) != NULL)
+ return (p->pw_name);
+ else
+ return ("unknown");
+}
+
+static void
+add_args(int ac, char **av, char *buf, size_t len)
+{
+ while (ac--) {
+ strlcat(buf, " ", len);
+ strlcat(buf, *(av++), len);
+ }
+}
+
+static int
+massage_control_data(char *data, int id)
+{
+ char *line, *iter = NULL;
+ char *ptr, *mod_ptr, *datacpy;
+ char host[BUFSIZ];
+ int host_present = 0;
+
+ if (gethostname(host, sizeof (host)) != 0)
+ return (-1);
+
+ if ((datacpy = strdup(data)) == NULL) {
+ return (-1);
+ }
+
+ for (ptr = strtok_r(datacpy, "\n", &iter); ptr != NULL;
+ ptr = strtok_r(NULL, "\n", &iter)) {
+
+ if (ptr[0] == 'H') {
+ if (strncmp(++ptr, host, strlen(host)) != 0) {
+ free(datacpy);
+ return (-1);
+ }
+ host_present = 1;
+ } else if ((ptr[0] == 'P') || (ptr[0] == 'L')) {
+ /* check the user name */
+ uid_t uid = getuid();
+ struct passwd *pw;
+ int len;
+
+ if (uid == 0) { /* let root do what they want */
+ continue;
+ }
+ if ((pw = getpwuid(uid)) == NULL) {
+ free(datacpy);
+ return (-1); /* failed */
+ }
+ len = strlen(pw->pw_name);
+ if ((strncmp(++ptr, pw->pw_name, len) != 0)) {
+ free(datacpy);
+ return (-1); /* failed */
+ }
+ } else if ((islower(ptr[0]) != 0) || (ptr[0] == 'U')) {
+ /* check/fix df?XXXhostname */
+ ptr++;
+
+ if (strlen(ptr) < 6) {
+ free(datacpy);
+ return (-1);
+ }
+
+ /*
+ * As ptr is a copy of the string (df?XXX...) the code
+ * needs to work on the original, hence the need for
+ * mod_ptr. No need to check for a NULL mod_ptr
+ * because the required string must already exist as
+ * ptr is a copy of the original data.
+ */
+
+ mod_ptr = strstr(data, ptr);
+
+ if ((mod_ptr[0] == 'd') && (mod_ptr[1] == 'f') &&
+ (mod_ptr[3] == 'X') && (mod_ptr[4] == 'X') &&
+ (mod_ptr[5] == 'X')) {
+ mod_ptr[3] = '0' + (id / 100) % 10;
+ mod_ptr[4] = '0' + (id / 10) % 10;
+ mod_ptr[5] = '0' + id % 10;
+
+ if (strncmp(&mod_ptr[6], host, strlen(host))
+ != 0) {
+ free(datacpy);
+ return (-1);
+ }
+ } else {
+ free(datacpy);
+ return (-1);
+ }
+ }
+
+ }
+ free(datacpy);
+
+ if (!host_present) {
+ return (-1);
+ }
+
+ return (1);
+}
+
+static int
+send_lpd_message(int fd, char *fmt, ...)
+{
+ char buf[BUFSIZ];
+ size_t size;
+ va_list ap;
+
+ va_start(ap, fmt);
+ size = vsnprintf(buf, sizeof (buf), fmt, ap);
+ va_end(ap);
+ if (size == 0)
+ size = 1;
+
+ syslog(LOG_DEBUG, "lpd_messsage(%d, %s)", fd, buf);
+
+ if (write(fd, buf, size) != size) {
+ errno = EIO;
+ return (-1);
+ }
+
+ if ((read(fd, buf, 1) != 1) || (buf[0] != 0))
+ return (-1);
+
+ return (0);
+}
+
+static int
+send_data_file(int sock, char *dfname, char *name)
+{
+ size_t len;
+ off_t off = 0;
+ struct stat st;
+ char buf[32];
+ int fd = -1;
+
+ if (strcmp(name, "standard input") != 0) {
+ if ((fd = open(name, O_RDONLY)) < 0)
+ return (-1);
+
+ if (fstat(fd, &st) < 0)
+ return (-1);
+ } else
+ st.st_size = MAXINT; /* should be 0 */
+
+ /* request data file transfer, read ack/nack */
+ errno = ENOSPC;
+ if (send_lpd_message(sock, "\003%d %s\n", st.st_size, dfname) < 0)
+ return (-1);
+
+ if (fd != -1) {
+ /* write the data */
+ if (sendfile(sock, fd, &off, st.st_size) != st.st_size)
+ return (-1);
+ close(fd);
+
+ /* request ack/nack after the data transfer */
+ errno = EIO;
+ if (send_lpd_message(sock, "") < 0)
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+send_control_file(int sock, char *data, int id)
+{
+ int len;
+ char buf[BUFSIZ];
+ char *ptr, *iter = NULL;
+ char *datacpy = NULL;
+ char *host = NULL;
+
+ len = strlen(data);
+
+ if ((datacpy = strdup(data)) == NULL)
+ return (-1);
+
+ syslog(LOG_DEBUG, "cfA: %s\n", datacpy);
+
+ for (ptr = strtok_r(datacpy, "\n", &iter); ptr != NULL;
+ ptr = strtok_r(NULL, "\n", &iter)) {
+
+ if (ptr[0] != 'H')
+ continue;
+
+ ptr++;
+ host = ptr;
+ syslog(LOG_DEBUG, "hostname: %s\n", host);
+ }
+
+ free(datacpy);
+
+ /* request data file transfer, read ack/nack */
+ errno = ENOSPC;
+ if (send_lpd_message(sock, "\002%d cfA%.3d%s\n", len, id, host) < 0)
+ return (-1);
+
+ /* write the data */
+ if (write(sock, data, len) != len)
+ return (-1);
+
+ /* request ack/nack after the data transfer */
+ errno = EIO;
+ if (send_lpd_message(sock, "") < 0)
+ return (-1);
+
+ return (0);
+}
+
+
+static int
+submit_job(int sock, char *printer, int job_id, char *path)
+{
+ struct stat st;
+ int current = 0;
+ off_t off = 0;
+ char *metadata = NULL;
+ char *ptr, *iter = NULL;
+ int fd, err;
+ int sent_files = 0;
+ char buf[BUFSIZ];
+ size_t len;
+
+ /* open the control file */
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ syslog(LOG_ERR, "submit_job(%d, %s, %d, %s): open(): %m",
+ sock, printer, job_id, path);
+ return (-1);
+ }
+
+ /* get the size of the control file */
+ if (fstat(fd, &st) < 0) {
+ syslog(LOG_ERR, "submit_job(%d, %s, %d, %s): fstat(): %m",
+ sock, printer, job_id, path);
+ close(fd);
+ return (-1);
+ }
+
+ /* allocate memory for the control file */
+ if ((metadata = calloc(1, st.st_size + 1)) == NULL) {
+ syslog(LOG_ERR, "submit_job(%d, %s, %d, %s): calloc(): %m",
+ sock, printer, job_id, path);
+ close(fd);
+ return (-1);
+ }
+
+ /* read in the control file */
+ if (read(fd, metadata, st.st_size) != st.st_size) {
+ syslog(LOG_ERR, "submit_job(%d, %s, %d, %s): read(): %m",
+ sock, printer, job_id, path);
+ free(metadata);
+ close(fd);
+ return (-1);
+ }
+
+ /* massage the control file */
+ if (massage_control_data(metadata, job_id) < 0) {
+ /* bad control data, dump the job */
+ syslog(LOG_ALERT,
+ "bad control file, possible subversion attempt");
+ free(metadata);
+ errno = EINVAL;
+ close(fd);
+ return (-1);
+ }
+
+ /* request to transfer the job */
+ if (send_lpd_message(sock, "\002%s\n", printer) < 0) {
+ /* no such (or disabled) queue, got to love rfc-1179 */
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /* send the control data */
+ if (send_control_file(sock, metadata, job_id) < 0) {
+ err = errno;
+ write(sock, "\001\n", 2); /* abort */
+ errno = err;
+ return (-1);
+ }
+
+ /* walk the control file sending the data files */
+ for (ptr = strtok_r(metadata, "\n", &iter); ptr != NULL;
+ ptr = strtok_r(NULL, "\n", &iter)) {
+ char *name = NULL;
+
+ if (ptr[0] != 'U')
+ continue;
+
+ name = strtok_r(NULL, "\n", &iter);
+ if (name[0] != 'N')
+ continue;
+
+ ptr++;
+ name++;
+
+ if (send_data_file(sock, ptr, name) < 0) {
+ err = errno;
+ write(sock, "\001\n", 2); /* abort */
+ errno = err;
+ return (-1);
+ }
+ if (strcmp(name, "standard input") != 0)
+ sent_files++;
+ }
+
+ /* write back the job-id */
+ err = errno;
+ if ((fd = open(path, O_WRONLY)) >= 0) {
+ ftruncate(fd, 0);
+ write(fd, &job_id, sizeof (job_id));
+ close(fd);
+ }
+ errno = err;
+
+ if (sent_files != 0) {
+ err = errno;
+ close(sock);
+ errno = err;
+ }
+
+ return (0);
+}
+static int
+query(int fd, char *printer, int ac, char **av)
+{
+ char buf[BUFSIZ];
+ int rc, len;
+
+ /* build the request */
+ snprintf(buf, sizeof (buf), "\04%s", printer);
+ add_args(ac, av, buf, sizeof (buf));
+ strlcat(buf, "\n", sizeof (buf));
+ len = strlen(buf);
+
+ if (((rc = write(fd, buf, len)) >= 0) && (rc != len)) {
+ errno = EMSGSIZE;
+ rc = -1;
+ } else
+ rc = 0;
+
+ return (rc);
+}
+
+static int
+cancel(int fd, char *printer, int ac, char **av)
+{
+ char buf[BUFSIZ];
+ int rc, len;
+
+ /* build the request */
+ snprintf(buf, sizeof (buf), "\05%s %s", printer, get_user_name());
+ add_args(ac, av, buf, sizeof (buf));
+ strlcat(buf, "\n", sizeof (buf));
+ len = strlen(buf);
+
+ if (((rc = write(fd, buf, len)) >= 0) && (rc != len)) {
+ errno = EMSGSIZE;
+ rc = -1;
+ } else
+ rc = 0;
+
+ return (rc);
+}
+
+static void
+usage(char *program)
+{
+ char *name;
+
+ setreuid(getuid(), getuid());
+
+ if ((name = strrchr(program, '/')) == NULL)
+ name = program;
+ else
+ name++;
+
+ fprintf(stderr, "usage:\t%s -H host [-t timeout] -s queue control ]\n",
+ name);
+ fprintf(stderr, "\t%s -H host [-t timeout] -c queue [user|job ...]\n",
+ name);
+ fprintf(stderr, "\t%s -H host [-t timeout] -q queue [user|job ...]\n",
+ name);
+ exit(EINVAL);
+}
+
+/*
+ * The main program temporarily loses privilege while searching the command
+ * line arguments. It then allocates any resources it need privilege for
+ * job-id, reserved port. Once it has the resources it needs, it perminently
+ * drops all elevated privilege. It ghen connects to the remote print service
+ * based on destination hostname. Doing it this way reduces the potenential
+ * opportunity for a breakout with elevated privilege, breakout with an
+ * unconnected reserved port, and exploitation of the remote print service
+ * by a calling program.
+ */
+int
+main(int ac, char *av[])
+{
+ enum { OP_NONE, OP_SUBMIT, OP_QUERY, OP_CANCEL } operation = OP_NONE;
+ int fd, c, timeout = 0, exit_code = 0;
+ char *host = NULL, *queue = NULL;
+ uid_t uid = getuid();
+#ifdef PRIV_ALLSETS
+ priv_set_t *saveset;
+#endif
+
+ openlog("lpd-port", LOG_PID, LOG_LPR);
+
+#ifdef PRIV_ALLSETS
+
+ /* lose as much as we can perminently and temporarily drop the rest. */
+
+ if ((saveset = priv_allocset()) == NULL) {
+ syslog(LOG_ERR, "lpd_port: priv_allocset saveset failed: %m\n");
+ return (-1);
+ }
+
+ priv_basicset(saveset);
+ (void) priv_addset(saveset, PRIV_NET_PRIVADDR);
+ (void) priv_addset(saveset, PRIV_FILE_DAC_READ);
+ (void) priv_addset(saveset, PRIV_FILE_DAC_WRITE);
+
+ if ((setppriv(PRIV_SET, PRIV_PERMITTED, saveset)) < 0) {
+ syslog(LOG_ERR, "lpd_port:setppriv:priv_set failed: %m");
+ return (-1);
+ }
+
+ priv_freeset(saveset);
+
+ /*
+ * These privileges permanently dropped in next_job_id() and
+ * reserved_port()
+ */
+
+ if (priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_NET_PRIVADDR,
+ PRIV_FILE_DAC_READ, PRIV_FILE_DAC_WRITE, (char *)NULL) < 0) {
+ syslog(LOG_ERR, "lpd_port:priv_set:priv_off failed: %m");
+ return (-1);
+ }
+
+ syslog(LOG_DEBUG, "using privs");
+#else
+
+ syslog(LOG_DEBUG, "no privs");
+ seteuid(uid);
+#endif
+
+ while ((c = getopt(ac, av, "H:t:c:q:s:")) != EOF) {
+ switch (c) {
+ case 'H':
+ host = optarg;
+ break;
+ case 't':
+ timeout = atoi(optarg);
+ break;
+ case 'c':
+ if (operation != OP_NONE)
+ usage(av[0]);
+ operation = OP_CANCEL;
+ queue = optarg;
+ break;
+ case 'q':
+ if (operation != OP_NONE)
+ usage(av[0]);
+ operation = OP_QUERY;
+ queue = optarg;
+ break;
+ case 's':
+ if (operation != OP_NONE)
+ usage(av[0]);
+ operation = OP_SUBMIT;
+ queue = optarg;
+ break;
+ default:
+ usage(av[0]);
+ /* does not return */
+ }
+ }
+
+ if ((host == NULL) || (queue == NULL) || (timeout < 0) ||
+ (operation == OP_NONE))
+ usage(av[0]);
+
+ if (operation == OP_SUBMIT) /* get a job-id if we need it */
+ if ((c = next_job_id()) < 0) {
+ syslog(LOG_ERR, "lpd_port:main:next_job_id fails");
+ return (-1);
+ }
+
+ if ((fd = reserved_port()) < 0) {
+ syslog(LOG_ERR, "reserved_port() failed %m");
+ return (errno);
+ }
+
+ /*
+ * we no longer want or need any elevated privilege, lose it all
+ * permanently.
+ */
+
+ setreuid(uid, uid);
+
+ /* connect to the print service */
+ if ((fd = sock_connect(fd, host, timeout)) < 0)
+ return (errno);
+
+ /* perform the requested operation */
+ switch (operation) {
+ case OP_SUBMIT: /* transfer the job, close the fd */
+ if (submit_job(fd, queue, c, av[optind]) < 0)
+ exit_code = errno;
+ break;
+ case OP_QUERY: /* send the query string, return the fd */
+ if (query(fd, queue, ac - optind, &av[optind]) < 0)
+ exit_code = errno;
+ break;
+ case OP_CANCEL: /* send the cancel string, return the fd */
+ if (cancel(fd, queue, ac - optind, &av[optind]) < 0)
+ exit_code = errno;
+ break;
+ default: /* This should never happen */
+ exit_code = EINVAL;
+ }
+
+
+ /* if the operation succeeded, send the fd to our parent */
+ if ((exit_code == 0) && (sendfd(1, fd) < 0)) {
+ char buf[BUFSIZ];
+
+ exit_code = errno;
+
+ /* sendfd() failed, dump the socket data for the heck of it */
+ while ((c = read(fd, buf, sizeof (buf))) > 0)
+ write(1, buf, c);
+ }
+
+ syslog(LOG_DEBUG, "exit code: %d", exit_code);
+ return (exit_code);
+}
diff --git a/usr/src/lib/print/libpapi-lpd/common/lpd-query.c b/usr/src/lib/print/libpapi-lpd/common/lpd-query.c
new file mode 100644
index 0000000000..964023c919
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/lpd-query.c
@@ -0,0 +1,507 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/* $Id: lpd-query.c 155 2006-04-26 02:34:54Z ktou $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/fcntl.h>
+#include <time.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <regex.h>
+
+#include <papi_impl.h>
+
+/* The string is modified by this call */
+static char *
+regvalue(regmatch_t match, char *string)
+{
+ char *result = NULL;
+
+ if (match.rm_so != match.rm_eo) {
+ result = string + match.rm_so;
+ *(result + (match.rm_eo - match.rm_so)) = '\0';
+ }
+
+ return (result);
+}
+
+/*
+ * Print job entries start with:
+ * (user): (rank) [job (number) (...)]
+ * (user) is the job-owner's user name
+ * (rank) is the rank in queue. (active, 1st, 2nd, ...)
+ * (number) is the job number
+ * (...) is an optional hostname
+ * some servers will use whitespace a little differently than is displayed
+ * above. The regular expression below makes whitespace optional in some
+ * places.
+ */
+static char *job_expr = "^(.*[[:alnum:]]):[[:space:]]+([[:alnum:]]+)"\
+ "[[:space:]]+[[][[:space:]]*job[[:space:]]*([[:digit:]]+)"\
+ "[[:space:]]*(.*)]";
+static regex_t job_re;
+
+/*
+ * Print job entries for remote windows printer start with:
+ * Owner Status Jobname Job-Id Size Pages Priority
+ * e.g:
+ * Owner Status Jobname Job-Id Size Pages Priority
+ * ------------------------------------------------------------
+ * root (10.3. Waiting /etc/release 2 240 1 4
+ *
+ * Owner is the job-owner's user name
+ * Status is the job-status (printing, waiting, error)
+ * Jobname is the name of the job to be printed
+ * Job-Id is the id of the job queued to be printed
+ * Size is the size of the job in bytes
+ * Pages is the number of pages of the job
+ * Priority is the job-priority
+ */
+static char *wjob_expr = "^([[:alnum:]]+)[[:space:]]*[(](.*)[)]*[[:space:]]"\
+ "+([[:alnum:]]+)[[:space:]]+(.*)([[:alnum:]]+)(.*)[[:space:]]+"\
+ "([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)"\
+ "[[:space:]]+([[:digit:]]+)";
+static regex_t wjob_re;
+
+/*
+ * Windows job header is in the following format
+ * Owner Status Jobname Job-Id Size Pages Priority
+ * --------------------------------------------------------------
+ */
+static char *whjob_expr = "Owner Status Jobname Job-Id"\
+ " Size Pages Priority";
+static regex_t whjob_re;
+
+static char *wline_expr = "----------";
+static regex_t wline_re;
+
+/*
+ * status line(s) for "processing" printers will contain one of the following:
+ * ready and printing
+ * Printing
+ * processing
+ */
+static char *proc_expr = "(ready and printing|printing|processing)";
+static regex_t proc_re;
+
+/*
+ * status line(s) for "idle" printers will contain one of the following:
+ * no entries
+ * (printer) is ready
+ * idle
+ */
+static char *idle_expr = "(no entries|is ready| idle)";
+static regex_t idle_re;
+
+/*
+ * Printer state reason (For Windows remote printers)
+ * Paused
+ */
+static char *state_reason_expr = "(Paused)";
+static regex_t state_reason_re;
+
+/*
+ * document line(s)
+ * (copies) copies of (name) (size) bytes
+ * (name) (size) bytes
+ * document lines can be in either format above.
+ * (copies) is the number of copies of the document to print
+ * (name) is the name of the document: /etc/motd, ...
+ * (size) is the number of bytes in the document data
+ */
+static char *doc1_expr = "[[:space:]]+(([[:digit:]]+) copies of )"\
+ "([^[:space:]]+)[[:space:]]*([[:digit:]]+) bytes";
+static char *doc2_expr = "[[:space:]]+()([^[:space:]]+)[[:space:]]*"\
+ "([[:digit:]]+) bytes";
+static regex_t doc1_re;
+static regex_t doc2_re;
+
+/* Printer-state for Windows */
+static int win_state = 0x03; /* Idle */
+
+static void
+parse_lpd_job(service_t *svc, job_t **job, int fd, char *line, int len)
+{
+ papi_attribute_t **attributes = NULL;
+ regmatch_t matches[10];
+ char *s;
+ int octets = 0;
+ int flag = 0;
+
+ /*
+ * job_re and wjob_re were compiled in the calling function
+ * first check for solaris jobs
+ * if there is no-match check for windows jobs
+ */
+
+ if (regexec(&job_re, line, (size_t)5, matches, 0) == REG_NOMATCH) {
+ if (regexec(&wjob_re, line, (size_t)10, matches, 0)
+ == REG_NOMATCH)
+ return;
+ else
+ flag = 1;
+ }
+
+ if (flag == 1) {
+ /* Windows job */
+ /* first match is job-id */
+
+ if ((s = regvalue(matches[1], line)) == NULL)
+ s = "nobody";
+ papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
+ "job-originating-user-name", s);
+
+ if ((s = regvalue(matches[4], line)) == NULL)
+ s = "unknown";
+ papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
+ "job-name", s);
+ papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
+ "job-file-names", s);
+
+ if ((s = regvalue(matches[7], line)) == NULL)
+ s = "0";
+ papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE,
+ "job-id", atoi(s));
+
+ if ((s = regvalue(matches[8], line)) == NULL)
+ s = "0";
+ octets = atoi(s);
+ papiAttributeListAddInteger(&attributes,
+ PAPI_ATTR_APPEND, "job-file-sizes", atoi(s));
+
+ /*
+ * Since a job has been found so the printer state is either
+ * 'stopped' or 'processing'
+ * By default it is "processing"
+ */
+ win_state = 0x04;
+ } else {
+ /* Solaris job */
+ if ((s = regvalue(matches[1], line)) == NULL)
+ s = "nobody";
+ papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
+ "job-originating-user-name", s);
+
+ if ((s = regvalue(matches[2], line)) == NULL)
+ s = "0";
+ papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE,
+ "number-of-intervening-jobs", atoi(s) - 1);
+
+ if ((s = regvalue(matches[3], line)) == NULL)
+ s = "0";
+ papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE,
+ "job-id", atoi(s));
+
+ if ((s = regvalue(matches[4], line)) == NULL)
+ s = svc->uri->host;
+ papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
+ "job-originating-host-name", s);
+ }
+
+ while ((fdgets(line, len, fd) != NULL) &&
+ (regexec(&job_re, line, (size_t)0, NULL, 0) == REG_NOMATCH) &&
+ (regexec(&wjob_re, line, (size_t)0, NULL, 0) == REG_NOMATCH)) {
+ int size = 0, copies = 1;
+ /* process copies/documents */
+
+ /* doc1_re and doc2_re were compiled in the calling function */
+ if ((regexec(&doc1_re, line, (size_t)4, matches, 0) != 0) &&
+ (regexec(&doc2_re, line, (size_t)4, matches, 0) != 0))
+ continue;
+
+ if ((s = regvalue(matches[1], line)) == NULL)
+ s = "1";
+ if ((copies = atoi(s)) < 1)
+ copies = 1;
+
+ if ((s = regvalue(matches[2], line)) == NULL)
+ s = "unknown";
+ papiAttributeListAddString(&attributes,
+ PAPI_ATTR_APPEND, "job-name", s);
+ papiAttributeListAddString(&attributes,
+ PAPI_ATTR_APPEND, "job-file-names", s);
+
+ if ((s = regvalue(matches[3], line)) == NULL)
+ s = "0";
+ size = atoi(s);
+
+ papiAttributeListAddInteger(&attributes,
+ PAPI_ATTR_APPEND, "job-file-sizes", size);
+
+ octets += (size * copies);
+ }
+
+ papiAttributeListAddInteger(&attributes, PAPI_ATTR_APPEND,
+ "job-k-octets", octets/1024);
+ papiAttributeListAddInteger(&attributes, PAPI_ATTR_APPEND,
+ "job-octets", octets);
+ papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
+ "printer-name", queue_name_from_uri(svc->uri));
+
+ if ((*job = (job_t *)calloc(1, sizeof (**job))) != NULL)
+ (*job)->attributes = attributes;
+}
+
+void
+parse_lpd_query(service_t *svc, int fd)
+{
+ papi_attribute_t **attributes = NULL;
+ cache_t *cache = NULL;
+ int state = 0x03; /* idle */
+ char line[128];
+ char status[1024];
+ char *s;
+ int win_flag = 0;
+
+ papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
+ "printer-name", queue_name_from_uri(svc->uri));
+
+ if (uri_to_string(svc->uri, status, sizeof (status)) == 0)
+ papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND,
+ "printer-uri-supported", status);
+
+ /*
+ * on most systems, status is a single line, but some appear to
+ * return multi-line status messages. To get the "best" possible
+ * printer-state-reason, we accumulate the text until we hit the
+ * first print job entry.
+ *
+ * Print job entries start with:
+ * user: rank [job number ...]
+ */
+ (void) regcomp(&job_re, job_expr, REG_EXTENDED|REG_ICASE);
+
+ /*
+ * For remote windows printers
+ * Print job entries start with:
+ * Owner Status Jobname Job-Id Size Pages Priority
+ */
+ (void) regcomp(&wjob_re, wjob_expr, REG_EXTENDED|REG_ICASE);
+ (void) regcomp(&whjob_re, whjob_expr, REG_EXTENDED|REG_ICASE);
+ (void) regcomp(&wline_re, wline_expr, REG_EXTENDED|REG_ICASE);
+
+ status[0] = '\0';
+
+ while ((fdgets(line, sizeof (line), fd) != NULL) &&
+ (regexec(&job_re, line, (size_t)0, NULL, 0) == REG_NOMATCH) &&
+ (regexec(&wjob_re, line, (size_t)0, NULL, 0) == REG_NOMATCH)) {
+ /*
+ * When windows job queue gets queried following header
+ * should not get printed
+ * Owner Status Jobname Job-Id Size Pages Priority
+ * -----------------------------------------------
+ */
+ if ((regexec(&whjob_re, line, (size_t)0, NULL, 0)
+ == REG_NOMATCH) &&
+ (regexec(&wline_re, line, (size_t)0, NULL, 0)
+ == REG_NOMATCH))
+ strlcat(status, line, sizeof (status));
+ }
+
+ /* chop off trailing whitespace */
+ s = status + strlen(status) - 1;
+ while ((s > status) && (isspace(*s) != 0))
+ *s-- = '\0';
+
+ papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
+ "printer-state-reasons", status);
+
+ /* Check if this is for Windows remote printers */
+ if (strstr(status, "Windows")) {
+ /*
+ * It is a remote windows printer
+ * By default set the status as idle
+ * Set the printer-state after call to "parse_lpd_job"
+ */
+ win_flag = 1;
+ (void) regcomp(&state_reason_re, state_reason_expr,
+ REG_EXTENDED|REG_ICASE);
+
+ if (regexec(&state_reason_re, status, (size_t)0, NULL, 0) == 0)
+ state = 0x05; /* stopped */
+ } else {
+ (void) regcomp(&proc_re, proc_expr, REG_EXTENDED|REG_ICASE);
+ (void) regcomp(&idle_re, idle_expr, REG_EXTENDED|REG_ICASE);
+
+ if (regexec(&proc_re, status, (size_t)0, NULL, 0) == 0)
+ state = 0x04; /* processing */
+ else if (regexec(&idle_re, status, (size_t)0, NULL, 0) == 0)
+ state = 0x03; /* idle */
+ else
+ state = 0x05; /* stopped */
+ papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE,
+ "printer-state", state);
+ }
+
+ if ((cache = (cache_t *)calloc(1, sizeof (*cache))) == NULL)
+ return;
+
+ if ((cache->printer = (printer_t *)calloc(1, sizeof (*cache->printer)))
+ == NULL)
+ return;
+
+ cache->printer->attributes = attributes;
+ svc->cache = cache;
+
+ (void) regcomp(&doc1_re, doc1_expr, REG_EXTENDED|REG_ICASE);
+ (void) regcomp(&doc2_re, doc2_expr, REG_EXTENDED|REG_ICASE);
+ /* process job related entries */
+ while (line[0] != '\0') {
+ job_t *job = NULL;
+
+ parse_lpd_job(svc, &job, fd, line, sizeof (line));
+ if (job == NULL)
+ break;
+ list_append(&cache->jobs, job);
+ }
+
+ /*
+ * For remote windows printer set the printer-state
+ * after parse_lpd_job
+ */
+ if (win_flag) {
+ if (state == 0x05)
+ win_state = state;
+
+ papiAttributeListAddInteger(&attributes, PAPI_ATTR_REPLACE,
+ "printer-state", win_state);
+ }
+ time(&cache->timestamp);
+}
+
+void
+cache_update(service_t *svc)
+{
+ int fd;
+
+ if (svc == NULL)
+ return;
+
+ if (svc->cache != NULL) { /* this should be time based */
+ if (svc->cache->jobs == NULL) {
+ free(svc->cache);
+ svc->cache = NULL;
+ } else
+ return;
+ }
+
+ if ((fd = lpd_open(svc, 'q', NULL, 15)) < 0)
+ return;
+
+ parse_lpd_query(svc, fd);
+
+ close(fd);
+}
+
+papi_status_t
+lpd_find_printer_info(service_t *svc, printer_t **printer)
+{
+ papi_status_t result = PAPI_BAD_ARGUMENT;
+
+ if ((svc == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ cache_update(svc);
+
+ if (svc->cache != NULL) {
+ *printer = svc->cache->printer;
+ result = PAPI_OK;
+ } else
+ result = PAPI_NOT_FOUND;
+
+ return (result);
+}
+
+papi_status_t
+lpd_find_jobs_info(service_t *svc, job_t ***jobs)
+{
+ papi_status_t result = PAPI_BAD_ARGUMENT;
+
+ if (svc != NULL) {
+ cache_update(svc);
+
+ if (svc->cache != NULL) {
+ *jobs = svc->cache->jobs;
+ result = PAPI_OK;
+ }
+ }
+
+ /*
+ * cache jobs is free()-ed in
+ * libpapi-dynamic/common/printer.c -
+ * papiPrinterListJobs() cache printer is
+ * free()-ed by the caller of
+ * lpd_find_printer_info Invalidate the
+ * cache by freeing the cache.
+ */
+ free(svc->cache);
+ svc->cache = NULL;
+
+ return (result);
+}
+
+papi_status_t
+lpd_find_job_info(service_t *svc, int job_id, job_t **job)
+{
+ papi_status_t result = PAPI_BAD_ARGUMENT;
+ job_t **jobs;
+
+ if ((lpd_find_jobs_info(svc, &jobs) == PAPI_OK) && (jobs != NULL)) {
+ int i;
+
+ *job = NULL;
+ for (i = 0; ((*job == NULL) && (jobs[i] != NULL)); i++) {
+ int id = -1;
+
+ papiAttributeListGetInteger(jobs[i]->attributes, NULL,
+ "job-id", &id);
+ if (id == job_id)
+ *job = jobs[i];
+ }
+
+ if (*job != NULL)
+ result = PAPI_OK;
+ }
+
+ return (result);
+}
+
+void
+cache_free(cache_t *item)
+{
+ if (item != NULL) {
+ if (item->printer != NULL)
+ papiPrinterFree((papi_printer_t *)item->printer);
+ if (item->jobs != NULL)
+ papiJobListFree((papi_job_t *)item->jobs);
+ free(item);
+ }
+}
diff --git a/usr/src/lib/print/libpapi-lpd/common/mapfile b/usr/src/lib/print/libpapi-lpd/common/mapfile
new file mode 100644
index 0000000000..2ad5020f15
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/mapfile
@@ -0,0 +1,322 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# $Id: mapfile.in,v 1.2 2006/03/02 06:31:36 njacobs Exp $
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+#
+# Common interfaces that are most likely to be shared amongst the various
+# PAPI implementations.
+#
+
+SYMBOL_VERSION SUNW_1.0 {
+ global:
+ # PAPI Attribute Calls
+ papiAttributeListAddValue {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddBoolean {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddCollection {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddDatetime {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddInteger {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddMetadata {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddRange {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddResolution {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListAddString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListDelete {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetValue {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetNext {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFind {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetBoolean {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetCollection {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetDatetime {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetInteger {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetMetadata {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetRange {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetResolution {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListGetString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFromString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListToString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListFree {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ # PAPI Service Calls
+ papiServiceCreate ;
+ papiServiceDestroy ;
+ papiServiceSetUserName ;
+ papiServiceSetPassword ;
+ papiServiceSetEncryption ;
+ papiServiceSetAuthCB ;
+ papiServiceSetAppData ;
+ papiServiceGetUserName ;
+ papiServiceGetPassword ;
+ papiServiceGetEncryption ;
+ papiServiceGetAppData ;
+ papiServiceGetServiceName ;
+ papiServiceGetAttributeList ;
+ papiServiceGetStatusMessage ;
+
+ # PAPI Printer Calls
+ papiPrintersList {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiPrinterQuery ;
+ papiPrinterAdd {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiPrinterModify {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiPrinterRemove {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiPrinterDisable ;
+ papiPrinterEnable ;
+ papiPrinterPause ;
+ papiPrinterResume ;
+ papiPrinterPurgeJobs ;
+ papiPrinterListJobs ;
+ papiPrinterGetAttributeList ;
+ papiPrinterFree ;
+ papiPrinterListFree ;
+
+ # PAPI Job Calls
+ papiJobSubmit ;
+ papiJobSubmitByReference ;
+ papiJobValidate {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobStreamOpen ;
+ papiJobStreamWrite ;
+ papiJobStreamClose ;
+ papiJobQuery ;
+ papiJobModify {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobMove {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobCancel ;
+ papiJobHold {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobRelease {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobRestart {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobPromote {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobGetAttributeList ;
+ papiJobGetPrinterName ;
+ papiJobGetId ;
+ papiJobGetJobTicket {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobFree ;
+ papiJobListFree ;
+
+ # Misc. PAPI Calls
+ papiStatusString {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiLibrarySupportedCall ;
+ papiLibrarySupportedCalls ;
+} ;
+
+SYMBOL_VERSION SUNWprivate_1.0 {
+ global:
+ papiServiceSetPeer {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobCreate {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobStreamAdd {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiJobCommit {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ # Misc. supporting calls
+ # URI
+ uri_from_string {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ uri_to_string {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ uri_free {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ # list
+ list_remove {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ list_append {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ list_concatenate {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ # NS
+ getprinterbyname {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ is_localhost {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ # extra Attribute Calls
+ copy_attributes {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ split_and_copy_attributes {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+ papiAttributeListPrint {
+ TYPE = FUNCTION;
+ FILTER = libpapi-common.so;
+ } ;
+
+ local:
+ * ;
+} ;
diff --git a/usr/src/lib/print/libpapi-lpd/common/papi_impl.h b/usr/src/lib/print/libpapi-lpd/common/papi_impl.h
new file mode 100644
index 0000000000..82d955b3cb
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/papi_impl.h
@@ -0,0 +1,111 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+#ifndef _PAPI_IMPL_H
+#define _PAPI_IMPL_H
+
+/* $Id: papi_impl.h 161 2006-05-03 04:32:59Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <papi.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <uri.h>
+
+typedef struct {
+ papi_attribute_t **attributes;
+} printer_t;
+
+typedef struct job {
+ papi_attribute_t **attributes;
+} job_t;
+
+typedef struct stream {
+ job_t *job; /* describes current job */
+ int fd; /* the fd to write to */
+ char *metadata; /* the converted metadata */
+ char *dfname; /* the stream data (if we can't stream) */
+
+} stream_t;
+
+typedef struct { /* used for query operations only */
+ time_t timestamp;
+ printer_t *printer;
+ job_t **jobs;
+} cache_t;
+
+typedef struct {
+ papi_attribute_t **attributes; /* extra info */
+ uri_t *uri; /* printer uri */
+ cache_t *cache; /* printer/job cache */
+ int (*authCB)(papi_service_t svc, void *app_data); /* unused */
+ void *app_data; /* unused */
+} service_t;
+
+
+extern papi_status_t service_fill_in(service_t *svc, char *name);
+extern void detailed_error(service_t *svc, char *fmt, ...);
+extern char *queue_name_from_uri(uri_t *uri);
+extern char *fdgets(char *buf, size_t len, int fd);
+
+
+/* lpd operations */
+ /* open a connection to remote print service */
+extern int lpd_open(service_t *svc, char type, char **args,
+ int timeout);
+ /* job cancelation */
+extern papi_status_t lpd_purge_jobs(service_t *svc, job_t ***jobs);
+extern papi_status_t lpd_cancel_job(service_t *svc, int job_id);
+ /* job submission */
+extern papi_status_t lpd_submit_job(service_t *svc, char *metadata,
+ papi_attribute_t ***attributes, int *fd);
+extern papi_status_t lpd_job_add_attributes(service_t *svc,
+ papi_attribute_t **attributes,
+ char **metadata,
+ papi_attribute_t ***used_attributes);
+extern papi_status_t lpd_job_add_files(service_t *svc,
+ papi_attribute_t **attributes, char **files,
+ char **metadata,
+ papi_attribute_t ***used_attributes);
+ /* query cache lookup routines */
+extern papi_status_t lpd_find_printer_info(service_t *svc, printer_t **result);
+extern papi_status_t lpd_find_job_info(service_t *svc, int job_id, job_t **job);
+extern papi_status_t lpd_find_jobs_info(service_t *svc, job_t ***jobs);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PAPI_IMPL_H */
diff --git a/usr/src/lib/print/libpapi-lpd/common/printer.c b/usr/src/lib/print/libpapi-lpd/common/printer.c
new file mode 100644
index 0000000000..308d9c9443
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/printer.c
@@ -0,0 +1,220 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: printer.c 149 2006-04-25 16:55:01Z njacobs $ */
+
+#include <stdlib.h>
+#include <strings.h>
+#include <papi_impl.h>
+#include <libintl.h>
+
+static int
+contains(char *value, char **list)
+{
+ int i;
+
+ if ((value == NULL) || (list == NULL))
+ return (1);
+
+ for (i = 0; list[i] != NULL; i++)
+ if (strcasecmp(value, list[i]) == 0)
+ return (1);
+
+ return (0);
+}
+
+papi_status_t
+papiPrinterQuery(papi_service_t handle, char *name,
+ char **requested_attrs,
+ papi_attribute_t **job_attributes,
+ papi_printer_t *printer)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+ printer_t *p = NULL;
+
+ if ((svc == NULL) || (name == NULL) || (printer == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK) {
+ *printer = NULL;
+
+ if ((contains("printer-state", requested_attrs) == 1) ||
+ (contains("printer-state-reasons", requested_attrs) == 1))
+ status = lpd_find_printer_info(svc,
+ (printer_t **)printer);
+
+ if ((status == PAPI_OK) && (*printer == NULL)) {
+ char buf[BUFSIZ];
+
+ *printer = p = calloc(1, sizeof (*p));
+
+ papiAttributeListAddString(&(p->attributes),
+ PAPI_ATTR_APPEND, "printer-name",
+ queue_name_from_uri(svc->uri));
+
+ if (uri_to_string(svc->uri, buf, sizeof (buf)) == 0)
+ papiAttributeListAddString(&(p->attributes),
+ PAPI_ATTR_APPEND,
+ "printer-uri-supported", buf);
+ }
+ /* Set printer accepting: mimic prepapi behavior */
+ if ((p = *printer) != NULL)
+ papiAttributeListAddBoolean(&(p->attributes),
+ PAPI_ATTR_REPLACE,
+ "printer-is-accepting-jobs", PAPI_TRUE);
+
+ }
+
+ return (status);
+}
+
+papi_status_t
+papiPrinterPurgeJobs(papi_service_t handle, char *name, papi_job_t **jobs)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+
+ if ((svc == NULL) || (name == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK)
+ status = lpd_purge_jobs(svc, (job_t ***)jobs);
+
+ return (status);
+}
+
+papi_status_t
+papiPrinterListJobs(papi_service_t handle, char *name,
+ char **requested_attrs, int type_mask,
+ int max_num_jobs, papi_job_t **jobs)
+{
+ papi_status_t status;
+ service_t *svc = handle;
+
+ if ((svc == NULL) || (name == NULL) || (jobs == NULL))
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK)
+ status = lpd_find_jobs_info(svc, (job_t ***)jobs);
+
+ return (status);
+}
+
+papi_attribute_t **
+papiPrinterGetAttributeList(papi_printer_t printer)
+{
+ printer_t *p = printer;
+
+ if (p == NULL)
+ return (NULL);
+
+ return (p->attributes);
+}
+
+void
+papiPrinterFree(papi_printer_t printer)
+{
+ printer_t *p = printer;
+
+ if (p != NULL) {
+ if (p->attributes != NULL)
+ papiAttributeListFree(p->attributes);
+ free(p);
+ }
+}
+
+void
+papiPrinterListFree(papi_printer_t *printers)
+{
+ if (printers != NULL) {
+ int i;
+
+ for (i = 0; printers[i] != NULL; i++)
+ papiPrinterFree(printers[i]);
+ free(printers);
+ }
+}
+
+
+papi_status_t
+papiPrinterDisable(papi_service_t handle, char *name, char *message)
+{
+ service_t *svc = handle;
+ papi_status_t status;
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK) {
+ detailed_error(svc,
+ gettext("Warning: %s is remote, disable has no meaning."),
+ queue_name_from_uri(svc->uri));
+ }
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+}
+
+papi_status_t
+papiPrinterEnable(papi_service_t handle, char *name)
+{
+ service_t *svc = handle;
+ papi_status_t status;
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK) {
+ detailed_error(svc,
+ gettext("Warning: %s is remote, enable has no meaning."),
+ queue_name_from_uri(svc->uri));
+ }
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+}
+
+
+papi_status_t
+papiPrinterResume(papi_service_t handle, char *name)
+{
+ service_t *svc = handle;
+ papi_status_t status;
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK) {
+ detailed_error(svc,
+ gettext("Warning: %s is remote, accept has no meaning."),
+ queue_name_from_uri(svc->uri));
+ }
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+}
+
+
+papi_status_t
+papiPrinterPause(papi_service_t handle, char *name, char *message)
+{
+ service_t *svc = handle;
+ papi_status_t status;
+
+ if ((status = service_fill_in(svc, name)) == PAPI_OK) {
+ detailed_error(svc,
+ gettext("Warning: %s is remote, reject has no meaning."),
+ queue_name_from_uri(svc->uri));
+ }
+ return (PAPI_OPERATION_NOT_SUPPORTED);
+}
diff --git a/usr/src/lib/print/libpapi-lpd/common/service.c b/usr/src/lib/print/libpapi-lpd/common/service.c
new file mode 100644
index 0000000000..c39ea0cbb5
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/common/service.c
@@ -0,0 +1,299 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: service.c 163 2006-05-09 15:07:45Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <alloca.h>
+#include <uri.h>
+#include <papi_impl.h>
+
+papi_status_t
+service_fill_in(service_t *svc, char *name)
+{
+ papi_status_t status = PAPI_OK;
+ uri_t *uri = NULL;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if (name == NULL)
+ return (PAPI_OK);
+
+ /*
+ * valid URIs are in the form:
+ * lpd://server[:port]/.../queue[#extensions]
+ * rfc-1179://server[:port]/.../queue[#extensions]
+ * any authentication information supplied the URI is ignored.
+ */
+ if (uri_from_string((char *)name, &uri) != -1) {
+ if ((strcasecmp(uri->scheme, "lpd") == 0) ||
+ (strcasecmp(uri->scheme, "rfc-1179") == 0)) {
+ if (svc->uri != NULL)
+ uri_free(svc->uri);
+ svc->uri = uri;
+ } else {
+ uri_free(uri);
+ status = PAPI_URI_SCHEME;
+ }
+ }
+
+ return (status);
+}
+
+papi_status_t
+papiServiceCreate(papi_service_t *handle, char *service_name,
+ char *user_name, char *password,
+ int (*authCB)(papi_service_t svc, void *app_data),
+ papi_encryption_t encryption, void *app_data)
+{
+ papi_status_t status;
+ service_t *svc = NULL;
+
+ if (handle == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ if ((*handle = svc = (service_t *)calloc(1, sizeof (*svc))) == NULL)
+ return (PAPI_TEMPORARY_ERROR);
+
+ if (service_name != NULL)
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_EXCL,
+ "service-name", service_name);
+
+ (void) papiServiceSetUserName(svc, user_name);
+ (void) papiServiceSetPassword(svc, password);
+ (void) papiServiceSetAuthCB(svc, authCB);
+ (void) papiServiceSetAppData(svc, app_data);
+ (void) papiServiceSetEncryption(svc, encryption);
+
+ status = service_fill_in(svc, service_name);
+
+ return (status);
+}
+
+void
+papiServiceDestroy(papi_service_t handle)
+{
+ if (handle != NULL) {
+ service_t *svc = handle;
+
+#ifdef DEADBEEF
+ if (svc->cache != NULL)
+ cache_free(svc->cache);
+#endif
+ if (svc->uri != NULL)
+ uri_free(svc->uri);
+ if (svc->attributes != NULL)
+ papiAttributeListFree(svc->attributes);
+ free(svc);
+ }
+}
+
+papi_status_t
+papiServiceSetUserName(papi_service_t handle, char *user_name)
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ return (papiAttributeListAddString(&svc->attributes, PAPI_ATTR_REPLACE,
+ "user-name", user_name));
+}
+
+papi_status_t
+papiServiceSetPassword(papi_service_t handle, char *password)
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ return (papiAttributeListAddString(&svc->attributes,
+ PAPI_ATTR_REPLACE, "password", password));
+}
+
+papi_status_t
+papiServiceSetEncryption(papi_service_t handle,
+ papi_encryption_t encryption)
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ return (papiAttributeListAddInteger(&svc->attributes, PAPI_ATTR_REPLACE,
+ "encryption", (int)encryption));
+}
+
+papi_status_t
+papiServiceSetAuthCB(papi_service_t handle,
+ int (*authCB)(papi_service_t svc, void *app_data))
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ svc->authCB = (int (*)(papi_service_t svc, void *))authCB;
+
+ return (PAPI_OK);
+}
+
+papi_status_t
+papiServiceSetAppData(papi_service_t handle, void *app_data)
+{
+ service_t *svc = handle;
+
+ if (svc == NULL)
+ return (PAPI_BAD_ARGUMENT);
+
+ svc->app_data = (void *)app_data;
+
+ return (PAPI_OK);
+}
+
+char *
+papiServiceGetServiceName(papi_service_t handle)
+{
+ service_t *svc = handle;
+ char *result = NULL;
+
+ if (svc != NULL)
+ papiAttributeListGetString(svc->attributes, NULL,
+ "service-name", &result);
+
+ return (result);
+}
+
+char *
+papiServiceGetUserName(papi_service_t handle)
+{
+ service_t *svc = handle;
+ char *result = NULL;
+
+ if (svc != NULL)
+ papiAttributeListGetString(svc->attributes, NULL,
+ "user-name", &result);
+
+ return (result);
+
+}
+
+char *
+papiServiceGetPassword(papi_service_t handle)
+{
+ service_t *svc = handle;
+ char *result = NULL;
+
+ if (svc != NULL)
+ papiAttributeListGetString(svc->attributes, NULL,
+ "password", &result);
+
+ return (result);
+}
+
+papi_encryption_t
+papiServiceGetEncryption(papi_service_t handle)
+{
+ service_t *svc = handle;
+ papi_encryption_t result = PAPI_ENCRYPT_NEVER;
+
+ if (svc != NULL)
+ papiAttributeListGetInteger(svc->attributes, NULL,
+ "encryption", (int *)&result);
+
+ return (result);
+}
+
+void *
+papiServiceGetAppData(papi_service_t handle)
+{
+ service_t *svc = handle;
+ void *result = NULL;
+
+ if (svc != NULL) {
+ result = svc->app_data;
+ }
+
+ return (result);
+
+}
+
+papi_attribute_t **
+papiServiceGetAttributeList(papi_service_t handle)
+{
+ service_t *svc = handle;
+ papi_attribute_t **result = NULL;
+
+ if (svc != NULL)
+ result = svc->attributes;
+
+ return (result);
+}
+
+char *
+papiServiceGetStatusMessage(papi_service_t handle)
+{
+ service_t *svc = handle;
+ char *result = NULL;
+
+ if (svc != NULL) {
+ papiAttributeListGetString(svc->attributes, NULL,
+ "detailed-status-message", &result);
+ }
+
+ return (result);
+}
+
+void
+detailed_error(service_t *svc, char *fmt, ...)
+{
+ if ((svc != NULL) && (fmt != NULL)) {
+ va_list ap;
+ size_t size;
+ char *message = alloca(BUFSIZ);
+
+ va_start(ap, fmt);
+ /*
+ * fill in the message. If the buffer is too small, allocate
+ * one that is large enough and fill it in.
+ */
+ if ((size = vsnprintf(message, BUFSIZ, fmt, ap)) >= BUFSIZ)
+ if ((message = alloca(size)) != NULL)
+ vsnprintf(message, size, fmt, ap);
+ va_end(ap);
+
+ papiAttributeListAddString(&svc->attributes, PAPI_ATTR_APPEND,
+ "detailed-status-message", message);
+ }
+}
diff --git a/usr/src/lib/print/libpapi-lpd/i386/Makefile b/usr/src/lib/print/libpapi-lpd/i386/Makefile
new file mode 100644
index 0000000000..362f811e03
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/i386/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS) $(EXTRALINKS) \
+ $(ROOTLIBPRINTPROG)
diff --git a/usr/src/lib/print/libpapi-lpd/sparc/Makefile b/usr/src/lib/print/libpapi-lpd/sparc/Makefile
new file mode 100644
index 0000000000..362f811e03
--- /dev/null
+++ b/usr/src/lib/print/libpapi-lpd/sparc/Makefile
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBDIR) $(ROOTLIBS) $(ROOTLINKS) $(EXTRALINKS) \
+ $(ROOTLIBPRINTPROG)
diff --git a/usr/src/lib/print/libprint/Makefile b/usr/src/lib/print/libprint/Makefile
new file mode 100644
index 0000000000..55847e0be0
--- /dev/null
+++ b/usr/src/lib/print/libprint/Makefile
@@ -0,0 +1,54 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../../Makefile.lib
+
+SUBDIRS = $(MACH)
+#$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET = all
+clean := TARGET = clean
+clobber := TARGET = clobber
+install := TARGET = install
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all clean clobber install: .WAIT $(SUBDIRS)
+
+lint: # $(SUBDIRS)
+
+install_h:
+
+check:
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/libprint/Makefile.com b/usr/src/lib/print/libprint/Makefile.com
new file mode 100644
index 0000000000..88fbb532b0
--- /dev/null
+++ b/usr/src/lib/print/libprint/Makefile.com
@@ -0,0 +1,58 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+LIBRARY = libprint.a
+VERS = .2
+OBJECTS = \
+ list.o ns.o ns_bsd_addr.o ns_cmn_kvp.o \
+ ns_cmn_printer.o nss_convert.o nss_ldap.o nss_printer.o nss_write.o
+
+include ../../../Makefile.lib
+include ../../../Makefile.rootfs
+
+SRCDIR = ../common
+
+ROOTLIBDIR= $(ROOT)/usr/lib
+
+LIBS = $(DYNLIB)
+
+$(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR)
+CPPFLAGS += -I../../head -D_REENTRANT
+
+LDLIBS += -lnsl -lsocket -lc -lldap
+
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include ../../../Makefile.targ
diff --git a/usr/src/lib/print/libprint/common/list.c b/usr/src/lib/print/libprint/common/list.c
new file mode 100644
index 0000000000..fd90e58130
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/list.c
@@ -0,0 +1,189 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <list.h>
+
+
+static int _list_increment = 64; /* just so It can be tuned with adb(1) */
+/*
+ * list_append() takes in a list (type **) and a pointer to an item to add
+ * to the list and returns a new list with the new item appended on the
+ * end. The list is NULL terminated. If there was an error, NULL is
+ * returned. For reasonable efficiency, the list will be allocated
+ * in blocks of size _list_increment.
+ */
+void **
+list_append(void **list, void *item)
+{
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "list_append(0x%x, 0x%x)", list, item);
+#endif
+ if (item == NULL)
+ return (list);
+
+ if (list == NULL) {
+ list = (void **)calloc(_list_increment, sizeof (void *));
+ (void) memset(list, NULL, (_list_increment * sizeof (void *)));
+ list[0] = item;
+ } else {
+ int count;
+
+ for (count = 0; list[count] != NULL; count++);
+
+ if ((count + 1) % _list_increment == 0) { /* increase size */
+ void **new_list = NULL;
+ int new_size = (((count + 1) / _list_increment) + 1) *
+ _list_increment;
+
+ new_list = (void **)calloc(new_size,
+ sizeof (void *));
+ (void) memset(new_list, NULL,
+ (new_size * sizeof (void *)));
+ for (count = 0; list[count] != NULL; count++)
+ new_list[count] = list[count];
+ free(list);
+ list = new_list;
+ }
+ list[count] = item;
+ }
+ return (list);
+}
+
+
+void **
+list_append_unique(void **list, void *item, int (*cmp)(void *, void*))
+{
+ if (list_locate(list, cmp, item))
+ return (list);
+
+ list = list_append(list, item);
+ return (list);
+}
+
+
+/*
+ * list_locate() iterates through the list passed in and uses the comparison
+ * routine and element passed in to find an element in the list. It
+ * returns the first element matched, or NULL if none exists
+ */
+void *
+list_locate(void **list, int (*compair)(void *, void *), void *element)
+{
+ int current = 0;
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "list_locate()");
+#endif
+ if (list != NULL)
+ for (current = 0; list[current] != NULL; current++)
+ if ((compair)(list[current], element) == 0)
+ return (list[current]);
+ return (NULL);
+}
+
+
+/*
+ * list_concatenate() takes in two NULL terminated lists of items (type **)
+ * and creates a new list with items from list2 appended on the end of
+ * the list of items from list1. The result is a list (type **). If
+ * there is a failure, NULL is returned.
+ */
+void **
+list_concatenate(void **list1, void **list2)
+{
+ void **list = NULL;
+ int size1 = 0,
+ size2 = 0,
+ new_size = 0;
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "list_concatenate(0x%x, 0x%x)", list1, list2);
+#endif
+ if ((list1 == NULL) || (list2 == NULL))
+ return ((list1 != NULL) ? list1 : list2);
+
+ for (size1 = 0; list1[size1] != NULL; size1++);
+ for (size2 = 0; list2[size2] != NULL; size2++);
+
+ /* list1 + list2 padded to a multiple of _list_increment */
+ new_size = ((size1 + size2)/_list_increment + 2) * _list_increment;
+
+ if ((list = (void **)calloc((new_size), sizeof (void *)))
+ != NULL) {
+ int count = 0;
+
+ (void) memset(list, NULL, (new_size * sizeof (void *)));
+
+ for (size1 = 0; list1[size1] != NULL; size1++)
+ list[count++] = list1[size1];
+ for (size2 = 0; list2[size2] != NULL; size2++)
+ list[count++] = list2[size2];
+ free(list1);
+ }
+ return (list);
+}
+
+
+/*
+ * list_iterate() take in a list, pointer to a function, and variable number
+ * of arguements following. list_iterate() will iterate through the list
+ * calling the functions passed in with the first argument being a pointer
+ * to the current item in the list and the second argument being a va_list
+ * containing the rest of arguments used to call list_iterate(). The
+ * calling fuction should be declared: int func(type *, va_list). The
+ * return results are all added together and the sum is returned from
+ * list_iterate().
+ */
+int
+list_iterate(void **list, int (*vfunc)(void *, va_list), ...)
+{
+ int current = 0,
+ rc = 0;
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "list_iterate(0x%x, 0x%x)", list, vfunc);
+#endif
+ if (list != NULL)
+ while (list[current] != NULL) {
+ va_list ap;
+
+ va_start(ap, (vfunc));
+ rc += (vfunc)(list[current++], ap);
+ va_end(ap);
+ }
+ return (rc);
+}
diff --git a/usr/src/lib/print/libprint/common/list.h b/usr/src/lib/print/libprint/common/list.h
new file mode 100644
index 0000000000..cb9b62df78
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/list.h
@@ -0,0 +1,50 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _LIST_H
+#define _LIST_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/va_list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VFUNC_T int (*)(void *, __va_list) /* for casting */
+#define COMP_T int (*)(void *, void *) /* for casting */
+
+extern void **list_append(void **, void *);
+extern void **list_append_unique(void **, void *, int (*)(void *, void*));
+extern void **list_concatenate(void **, void **);
+extern void * list_locate(void **, int (*)(void *, void *), void *);
+extern int list_iterate(void **, int (*)(void *, __va_list), ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIST_H */
diff --git a/usr/src/lib/print/libprint/common/llib-lprint b/usr/src/lib/print/libprint/common/llib-lprint
new file mode 100644
index 0000000000..c52143e527
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/llib-lprint
@@ -0,0 +1,141 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libintl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <pwd.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/systeminfo.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+void **list_append(void **, void *);
+void **list_append_unique(void **, void *, int (*)(void *, void*));
+void **list_concatenate(void **, void **);
+void * list_locate(void **, int (*)(void *, void *), void *);
+int list_iterate(void **, int (*)(void *, __va_list), ...);
+
+void *dynamic_function(const char *, const char *);
+
+struct ns_bsd_addr {
+ char *server; /* server name */
+ char *printer; /* printer name or NULL */
+ char *extension; /* RFC-1179 conformance */
+ char *pname; /* Local printer name */
+};
+typedef struct ns_bsd_addr ns_bsd_addr_t;
+
+/* Key/Value pair structure */
+struct ns_kvp {
+ char *key; /* key */
+ char *value; /* value string */
+};
+typedef struct ns_kvp ns_kvp_t;
+
+/* Printer Object structure */
+struct ns_printer {
+ char *name; /* primary name of printer */
+ char **aliases; /* aliases for printer */
+ char *source; /* name service derived from */
+ ns_kvp_t **attributes; /* key/value pairs. */
+};
+typedef struct ns_printer ns_printer_t;
+
+/* functions to get/put printer objects */
+ns_printer_t *ns_printer_create(char *, char **, char *, ns_kvp_t **);
+ns_printer_t *ns_printer_get_name(const char *, const char *);
+ns_printer_t **ns_printer_get_list(const char *);
+int ns_printer_put(const ns_printer_t *);
+void ns_printer_destroy(ns_printer_t *);
+
+/* functions to manipulate key/value pairs */
+void *ns_get_value(const char *, const ns_printer_t *);
+char *ns_get_value_string(const char *, const ns_printer_t *);
+int ns_set_value(const char *, const void *, ns_printer_t *);
+int ns_set_value_from_string(const char *, const char *,
+ ns_printer_t *);
+ns_kvp_t *ns_kvp_create(const char *, const char *);
+
+/* for BSD bindings only */
+ns_bsd_addr_t *ns_bsd_addr_get_default(void);
+ns_bsd_addr_t *ns_bsd_addr_get_name(char *name);
+ns_bsd_addr_t **ns_bsd_addr_get_all(int);
+ns_bsd_addr_t **ns_bsd_addr_get_list(int);
+
+/* others */
+ns_printer_t *posix_name(const char *);
+int ns_printer_match_name(ns_printer_t *, const char *);
+char *ns_printer_name_list(const ns_printer_t *);
+char *value_to_string(const char *, void *);
+void *string_to_value(const char *, char *);
+
+
+ns_printer_t *_cvt_pconf_entry_to_printer(char *, char *);
+char *_cvt_printer_to_pconf_entry(ns_printer_t *);
+
+ns_printer_t *_cvt_user_string_to_printer(char *, char *);
+char *_cvt_printer_to_user_string(ns_printer_t *);
+
+
+ns_printer_t *_file_get_name(const char *, const char *,
+ ns_printer_t *(*)(char *, char *), char *);
+
+ns_printer_t **_file_get_list(const char *,
+ ns_printer_t *(*)(char *, char *), char *);
+
+int _file_put_printer(const char *, const ns_printer_t *,
+ ns_printer_t *(*)(char *, char *), char *, char *(*)(ns_printer_t *));
+
+
+ns_printer_t *_nis_get_name(const char *, const char *,
+ ns_printer_t *(*)(char *, char *), char *);
+
+ns_printer_t **_nis_get_list(const char *,
+ ns_printer_t *(*)(char *, char *), char *);
+
+int _nis_put_printer(const char *, const ns_printer_t *,
+ ns_printer_t *(*)(char *, char *), char *, char *(*)(ns_printer_t *));
diff --git a/usr/src/lib/print/libprint/common/mapfile-vers b/usr/src/lib/print/libprint/common/mapfile-vers
new file mode 100644
index 0000000000..776e97beca
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/mapfile-vers
@@ -0,0 +1,86 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+#
+# Generic interface definition for usr/src/lib/print.
+#
+
+SYMBOL_VERSION SUNWprivate_2.1 {
+ global:
+ getprinterbyname; # NSS support
+ getprinterentry;
+ setprinterentry;
+ endprinterentry;
+
+ ns_printer_create; # Old NS support
+ ns_printer_get_name;
+ ns_printer_get_list;
+ ns_printer_put;
+ ns_printer_destroy;
+ ns_get_value;
+ ns_get_value_string;
+ ns_set_value;
+ ns_set_value_from_string;
+ ns_kvp_create;
+ ns_bsd_addr_get_default;
+ ns_bsd_addr_get_name;
+ ns_bsd_addr_get_all;
+ ns_bsd_addr_get_list;
+ string_to_bsd_addr;
+ bsd_addr_create;
+ ns_printer_match_name;
+ ns_printer_name_list;
+ value_to_string;
+ string_to_value;
+ normalize_ns_name;
+
+ list_append; # list support
+ list_append_unique;
+ list_concatenate;
+ list_locate;
+ list_iterate;
+
+ files_put_printer; # required for ns_put_printer()
+ nis_put_printer;
+ ldap_put_printer;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/print/libprint/common/ns.c b/usr/src/lib/print/libprint/common/ns.c
new file mode 100644
index 0000000000..943be31e95
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/ns.c
@@ -0,0 +1,187 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdarg.h>
+#include <dlfcn.h>
+#include <nss_dbdefs.h>
+#include <syslog.h>
+
+#include <ns.h>
+#include <list.h>
+
+
+/*
+ * because legacy code can use a variety of values for various name
+ * services, this routine is needed to "normalize" them.
+ */
+char *
+normalize_ns_name(char *ns)
+{
+ if (ns == NULL)
+ return (NULL);
+ else if ((strcasecmp(ns, "files") == 0) ||
+ (strcasecmp(ns, "system") == 0) ||
+ (strcasecmp(ns, "etc") == 0))
+ return ("files");
+ else if (strcasecmp(ns, "nis") == 0)
+ return ("nis");
+ else if (strcasecmp(ns, "ldap") == 0)
+ return ("ldap");
+ else
+ return (ns);
+}
+
+
+/*
+ * FUNCTION:
+ * void ns_printer_destroy(ns_printer_t *printer)
+ * INPUT:
+ * ns_printer_t *printer - a pointer to the printer "object" to destroy
+ * DESCRIPTION:
+ * This function will free all of the memory associated with a printer
+ * object. It does this by walking the structure ad freeing everything
+ * underneath it, with the exception of the object source field. This
+ * field is not filled in with newly allocated space when it is
+ * generated
+ */
+void
+ns_printer_destroy(ns_printer_t *printer)
+{
+ if (printer != NULL) {
+ if (printer->attributes != NULL) { /* attributes */
+ extern void ns_kvp_destroy(ns_kvp_t *);
+
+ list_iterate((void **)printer->attributes,
+ (VFUNC_T)ns_kvp_destroy);
+ free(printer->attributes);
+ }
+ if (printer->aliases != NULL) { /* aliases */
+ free(printer->aliases);
+ }
+ if (printer->name != NULL) /* primary name */
+ free(printer->name);
+ free(printer);
+ }
+}
+
+
+/*
+ * FUNCTION:
+ * ns_printer_t **ns_printer_get_list()
+ * OUTPUT:
+ * ns_printer_t ** (return value) - an array of pointers to printer
+ * objects.
+ * DESCRIPTION:
+ * This function will return a list of all printer objects found in every
+ * configuration interface.
+ */
+ns_printer_t **
+ns_printer_get_list(const char *ns)
+{
+ char buf[NSS_LINELEN_PRINTERS];
+ ns_printer_t **printer_list = NULL;
+
+ (void) setprinterentry(0, (char *)ns);
+
+ ns = normalize_ns_name((char *)ns);
+ while (getprinterentry(buf, sizeof (buf), (char *)ns) == 0) {
+ ns_printer_t *printer =
+ (ns_printer_t *)_cvt_nss_entry_to_printer(buf, NULL);
+
+ printer_list = (ns_printer_t **)list_append(
+ (void **)printer_list,
+ (void *)printer);
+ }
+
+ (void) endprinterentry();
+
+ return (printer_list);
+}
+
+
+/*
+ * This function looks for the named printer in the supplied
+ * name service (ns), or the name services configured under
+ * the nsswitch.
+ */
+ns_printer_t *
+ns_printer_get_name(const char *name, const char *ns)
+{
+ ns_printer_t *result = NULL;
+ char buf[NSS_LINELEN_PRINTERS];
+
+ /*
+ * Reset printer entries to the start so we know we will always
+ * pick up the correct entry
+ */
+ endprinterentry();
+
+ if ((result = (ns_printer_t *)posix_name(name)) != NULL)
+ return (result);
+
+ ns = normalize_ns_name((char *)ns);
+ if (getprinterbyname((char *)name, buf, sizeof (buf), (char *)ns) == 0)
+ result = (ns_printer_t *)_cvt_nss_entry_to_printer(buf, NULL);
+
+ return (result);
+}
+
+
+/*
+ * FUNCTION:
+ * int ns_printer_put(const ns_printer_t *printer)
+ * INPUT:
+ * const ns_printer_t *printer - a printer object
+ * DESCRIPTION:
+ * This function attempts to put the data in the printer object back
+ * to the "name service" specified in the source field of the object.
+ */
+int
+ns_printer_put(const ns_printer_t *printer)
+{
+ char func[32];
+ int (*fpt)();
+
+ if ((printer == NULL) || (printer->source == NULL))
+ return (-1);
+
+ if (snprintf(func, sizeof (func), "%s_put_printer",
+ normalize_ns_name(printer->source)) >= sizeof (func)) {
+ syslog(LOG_ERR, "ns_printer_put: buffer overflow");
+ return (-1);
+ }
+
+ if ((fpt = (int (*)())dlsym(RTLD_DEFAULT, func)) != NULL)
+ return ((*fpt)(printer));
+
+ return (-1);
+}
diff --git a/usr/src/lib/print/libprint/common/ns.h b/usr/src/lib/print/libprint/common/ns.h
new file mode 100644
index 0000000000..84d16f7ceb
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/ns.h
@@ -0,0 +1,202 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NS_H
+#define _NS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Name Service Common Keys/types for lookup
+ */
+#define NS_KEY_BSDADDR "bsdaddr"
+#define NS_KEY_USE "use"
+#define NS_KEY_ALL "all"
+#define NS_KEY_GROUP "group"
+#define NS_KEY_LIST "list"
+
+#define NS_KEY_PRINTER_TYPE "printer-type"
+#define NS_KEY_DESCRIPTION "description"
+
+/*
+ * Name Service reserved names for lookup
+ */
+#define NS_NAME_DEFAULT "_default"
+#define NS_NAME_ALL "_all"
+
+/*
+ * Name Services supported
+ */
+#define NS_SVC_USER "user"
+#define NS_SVC_PRINTCAP "printcap"
+#define NS_SVC_ETC "etc"
+#define NS_SVC_NIS "nis"
+#define NS_SVC_LDAP "ldap"
+
+/*
+ * Known Protocol Extensions
+ */
+#define NS_EXT_SOLARIS "solaris"
+#define NS_EXT_GENERIC "extensions" /* same as SOLARIS */
+#define NS_EXT_HPUX "hpux"
+#define NS_EXT_DEC "dec"
+
+/*
+ * get unique or full list of printer bindings
+ */
+#define NOTUNIQUE 0
+#define UNIQUE 1
+#define LOCAL_UNIQUE 2 /* include alias names */
+
+/* BSD binding address structure */
+struct ns_bsd_addr {
+ char *server; /* server name */
+ char *printer; /* printer name or NULL */
+ char *extension; /* RFC-1179 conformance */
+ char *pname; /* Local printer name */
+};
+typedef struct ns_bsd_addr ns_bsd_addr_t;
+
+/* Key/Value pair structure */
+struct ns_kvp {
+ char *key; /* key */
+ char *value; /* value string */
+};
+typedef struct ns_kvp ns_kvp_t;
+
+
+/* LDAP specific result codes */
+
+typedef enum NSL_RESULT
+{
+ NSL_OK = 0, /* Operation successful */
+ NSL_ERR_INTERNAL = 1, /* Internal coding Error */
+ NSL_ERR_ADD_FAILED = 2, /* LDAP add failed */
+ NSL_ERR_MOD_FAILED = 3, /* LDAP modify failed */
+ NSL_ERR_DEL_FAILED = 4, /* LDAP delete failed */
+ NSL_ERR_UNKNOWN_PRINTER = 5, /* Unknown Printer object */
+ NSL_ERR_CREDENTIALS = 6, /* LDAP credentials invalid */
+ NSL_ERR_CONNECT = 7, /* LDAP server connect failed */
+ NSL_ERR_BIND = 8, /* LDAP bind failed */
+ NSL_ERR_RENAME = 9, /* Object rename is not allowed */
+ NSL_ERR_KVP = 10, /* sun-printer-kvp not allowed */
+ NSL_ERR_BSDADDR = 11, /* sun-printer-bsdaddr not allowed */
+ NSL_ERR_PNAME = 12, /* printer-name not allowed */
+ NSL_ERR_MEMORY = 13, /* memory allocation failed */
+ NSL_ERR_MULTIOP = 14, /* Replace and delete operation */
+ NSL_ERR_NOTALLOWED = 15, /* KVP attribute not allowed */
+ NSL_ERROR = -1 /* General error */
+} NSL_RESULT;
+
+
+/* LDAP bind password security type */
+
+typedef enum NS_PASSWD_TYPE {
+ NS_PW_INSECURE = 0,
+ NS_PW_SECURE = 1
+} NS_PASSWD_TYPE;
+
+
+/*
+ * Information needed to update a name service.
+ * Currently only used for ldap.
+ */
+struct ns_cred {
+ char *binddn;
+ char *passwd;
+ char *host;
+ int port; /* LDAP port, 0 = default */
+ NS_PASSWD_TYPE passwdType; /* password security type */
+ uchar_t *domainDN; /* NS domain DN */
+};
+typedef struct ns_cred ns_cred_t;
+
+/* LDAP specific NS Data */
+
+typedef struct NS_LDAPDATA {
+ char **attrList; /* list of user defined Key Value Pairs */
+} NS_LDAPDATA;
+
+/* Printer Object structure */
+struct ns_printer {
+ char *name; /* primary name of printer */
+ char **aliases; /* aliases for printer */
+ char *source; /* name service derived from */
+ ns_kvp_t **attributes; /* key/value pairs. */
+ ns_cred_t *cred; /* info to update name service */
+ void *nsdata; /* name service specific data */
+};
+typedef struct ns_printer ns_printer_t;
+
+/* functions to get/put printer objects */
+extern ns_printer_t *ns_printer_create(char *, char **, char *, ns_kvp_t **);
+extern ns_printer_t *ns_printer_get_name(const char *, const char *);
+extern ns_printer_t **ns_printer_get_list(const char *);
+extern int ns_printer_put(const ns_printer_t *);
+extern void ns_printer_destroy(ns_printer_t *);
+
+extern int setprinterentry(int, char *);
+extern int endprinterentry();
+extern int getprinterentry(char *, int, char *);
+extern int getprinterbyname(char *, char *, int, char *);
+
+extern char *_cvt_printer_to_entry(ns_printer_t *, char *, int);
+
+extern ns_printer_t *_cvt_nss_entry_to_printer(char *, char *);
+extern ns_printer_t *posix_name(const char *);
+
+
+
+/* functions to manipulate key/value pairs */
+extern void *ns_get_value(const char *, const ns_printer_t *);
+extern char *ns_get_value_string(const char *, const ns_printer_t *);
+extern int ns_set_value(const char *, const void *, ns_printer_t *);
+extern int ns_set_value_from_string(const char *, const char *,
+ ns_printer_t *);
+extern ns_kvp_t *ns_kvp_create(const char *, const char *);
+
+/* for BSD bindings only */
+extern ns_bsd_addr_t *ns_bsd_addr_get_default();
+extern ns_bsd_addr_t *ns_bsd_addr_get_name(char *name);
+extern ns_bsd_addr_t **ns_bsd_addr_get_all(int);
+extern ns_bsd_addr_t **ns_bsd_addr_get_list(int);
+
+/* others */
+extern int ns_printer_match_name(ns_printer_t *, const char *);
+extern char *ns_printer_name_list(const ns_printer_t *);
+extern char *value_to_string(const char *, void *);
+extern void *string_to_value(const char *, char *);
+extern char *normalize_ns_name(char *);
+extern char *strncat_escaped(char *, char *, int, char *);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NS_H */
diff --git a/usr/src/lib/print/libprint/common/ns_bsd_addr.c b/usr/src/lib/print/libprint/common/ns_bsd_addr.c
new file mode 100644
index 0000000000..ba142bb8a1
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/ns_bsd_addr.c
@@ -0,0 +1,571 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <ns.h>
+#include <list.h>
+
+static char **
+strsplit(char *string, char *seperators)
+{
+ char **list = NULL;
+ char *where = NULL;
+ char *element;
+
+ for (element = strtok_r(string, seperators, &where); element != NULL;
+ element = strtok_r(NULL, seperators, &where))
+ list = (char **)list_append((void **)list, element);
+
+ return (list);
+}
+
+/*
+ * Manipulate bsd_addr structures
+ */
+ns_bsd_addr_t *
+bsd_addr_create(const char *server, const char *printer, const char *extension)
+{
+ ns_bsd_addr_t *addr = NULL;
+
+ if ((server != NULL) &&
+ ((addr = calloc(1, sizeof (*addr))) != NULL)) {
+ addr->printer = (char *)printer;
+ addr->server = (char *)server;
+ addr->extension = (char *)extension;
+ }
+
+ return (addr);
+}
+
+static char *
+bsd_addr_to_string(const ns_bsd_addr_t *addr)
+{
+ char buf[BUFSIZ];
+
+ if ((addr == NULL) || (addr->server == NULL))
+ return (NULL);
+
+ if (snprintf(buf, sizeof (buf), "%s", addr->server) >= sizeof (buf)) {
+ syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
+ return (NULL);
+ }
+
+ if ((addr->printer != NULL) || (addr->extension != NULL))
+ (void) strlcat(buf, ",", sizeof (buf));
+ if (addr->printer != NULL)
+ if (strlcat(buf, addr->printer, sizeof (buf)) >= sizeof (buf)) {
+ syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
+ return (NULL);
+ }
+ if (addr->extension != NULL) {
+ (void) strlcat(buf, ",", sizeof (buf));
+ if (strlcat(buf, addr->extension, sizeof (buf))
+ >= sizeof (buf)) {
+ syslog(LOG_ERR, "bsd_addr_to_string: buffer overflow");
+ return (NULL);
+ }
+ }
+
+ return (strdup(buf));
+}
+
+ns_bsd_addr_t *
+string_to_bsd_addr(const char *string)
+{
+ char **list, *tmp, *printer = NULL, *extension = NULL;
+
+ if (string == NULL)
+ return (NULL);
+
+ tmp = strdup(string);
+ list = strsplit(tmp, ",");
+
+ if (list[1] != NULL) {
+ printer = list[1];
+ if (list[2] != NULL)
+ extension = list[2];
+ }
+
+ return (bsd_addr_create(list[0], printer, extension));
+}
+
+static char *
+list_to_string(const char **list)
+{
+ char buf[BUFSIZ];
+
+ if ((list == NULL) || (*list == NULL))
+ return (NULL);
+
+ if (snprintf(buf, sizeof (buf), "%s", *list) >= sizeof (buf)) {
+ syslog(LOG_ERR, "list_to_string: buffer overflow");
+ return (NULL);
+ }
+
+ while (*++list != NULL) {
+ (void) strlcat(buf, ",", sizeof (buf));
+ if (strlcat(buf, *list, sizeof (buf)) >= sizeof (buf)) {
+ syslog(LOG_ERR, "list_to_string: buffer overflow");
+ return (NULL);
+ }
+ }
+
+ return (strdup(buf));
+}
+
+static char *
+internal_list_to_string(const ns_printer_t **list)
+{
+ char buf[BUFSIZ];
+
+ if ((list == NULL) || (*list == NULL))
+ return (NULL);
+
+ if (snprintf(buf, sizeof (buf), "%s", (*list)->name) >= sizeof (buf)) {
+ syslog(LOG_ERR, "internal_list_to_string:buffer overflow");
+ return (NULL);
+ }
+
+ while (*++list != NULL) {
+ (void) strlcat(buf, ",", sizeof (buf));
+ if (strlcat(buf, (*list)->name, sizeof (buf)) >= sizeof (buf)) {
+ syslog(LOG_ERR,
+ "internal_list_to_string:buffer overflow");
+ return (NULL);
+ }
+ }
+
+ return (strdup(buf));
+}
+
+
+char *
+value_to_string(const char *key, void *value)
+{
+ char *string = NULL;
+
+ if ((key != NULL) && (value != NULL)) {
+ if (strcmp(key, NS_KEY_BSDADDR) == 0) {
+ string = bsd_addr_to_string(value);
+ } else if ((strcmp(key, NS_KEY_ALL) == 0) ||
+ (strcmp(key, NS_KEY_GROUP) == 0)) {
+ string = list_to_string(value);
+ } else if (strcmp(key, NS_KEY_LIST) == 0) {
+ string = internal_list_to_string(value);
+ } else {
+ string = strdup((char *)value);
+ }
+ }
+
+ return (string);
+}
+
+
+void *
+string_to_value(const char *key, char *string)
+{
+ void *value = NULL;
+
+ if ((key != NULL) && (string != NULL) && (string[0] != NULL)) {
+ if (strcmp(key, NS_KEY_BSDADDR) == 0) {
+ value = (void *)string_to_bsd_addr(string);
+ } else if ((strcmp(key, NS_KEY_ALL) == 0) ||
+ (strcmp(key, NS_KEY_GROUP) == 0)) {
+ value = (void *)strsplit(string, ",");
+ } else {
+ value = (void *)string;
+ }
+ }
+
+ return (value);
+}
+
+static void
+split_name(char *name, const char *delimiter, char **p1, char **p2, char **p3)
+{
+ char *tmp, *junk = NULL;
+
+ if (p1 != NULL)
+ *p1 = NULL;
+ if (p2 != NULL)
+ *p2 = NULL;
+ if (p3 != NULL)
+ *p3 = NULL;
+
+ if ((name == NULL) || (delimiter == NULL)) {
+ syslog(LOG_DEBUG, "split_name(): name/delimter invalid\n");
+ return;
+ }
+
+ for (tmp = (char *)strtok_r(name, delimiter, &junk); tmp != NULL;
+ tmp = (char *)strtok_r(NULL, delimiter, &junk))
+ if ((p1 != NULL) && (*p1 == NULL))
+ *p1 = tmp;
+ else if ((p2 != NULL) && (*p2 == NULL)) {
+ *p2 = tmp;
+ if (p3 == NULL)
+ break;
+ } else if ((p3 != NULL) && (*p3 == NULL)) {
+ *p3 = tmp;
+ break;
+ }
+}
+
+/*
+ * This implements support for printer names that are fully resolvable
+ * on their own. These "complete" names are converted into a ns_printer_t
+ * structure containing an appropriate "bsdaddr" attribute. The supported
+ * formats are as follows:
+ * POSIX style (server:printer[:conformance]).
+ * This format is an adaptation of the format originally
+ * described in POSIX 1387.4. The POSIX draft has since been
+ * squashed, but this particular component lives on. The
+ * conformace field has been added to allow further identification
+ * of the the server.
+ */
+ns_printer_t *
+posix_name(const char *name)
+{
+ ns_printer_t *printer = NULL;
+ char *tmp = NULL;
+
+ if ((name != NULL) && ((tmp = strpbrk(name, ":")) != NULL)) {
+ char *server = NULL;
+ char *queue = NULL;
+ char *extension = NULL;
+ char *addr = strdup(name);
+ char buf[BUFSIZ];
+
+ if (*tmp == ':')
+ split_name(addr, ": \t", &server, &queue, &extension);
+
+ memset(buf, 0, sizeof (buf));
+ if ((server != NULL) && (queue != NULL))
+ snprintf(buf, sizeof (buf), "%s,%s%s%s", server,
+ queue, (extension != NULL ? "," : ""),
+ (extension != NULL ? extension : ""));
+
+ /* build the structure here */
+ if (buf[0] != NULL) {
+ ns_kvp_t **list, *kvp;
+
+ kvp = ns_kvp_create(NS_KEY_BSDADDR, buf);
+ list = (ns_kvp_t **)list_append(NULL, kvp);
+ if (list != NULL)
+ printer = ns_printer_create(strdup(name), NULL,
+ "posix", list);
+ }
+ }
+
+ return (printer);
+}
+
+/*
+ * FUNCTION:
+ * int ns_bsd_addr_cmp(ns_bsd_addr_t *at, ns_bsd_addr_t *a2)
+ * INPUTS:
+ * ns_bsd_addr_t *a1 - a bsd addr
+ * ns_bsd_addr_t *21 - another bsd addr
+ * DESCRIPTION:
+ * This functions compare 2 bsd_addr structures to determine if the
+ * information in them is the same.
+ */
+static int
+ns_bsd_addr_cmp(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2)
+{
+ int rc;
+
+ if ((a1 == NULL) || (a2 == NULL))
+ return (1);
+
+ if ((rc = strcmp(a1->server, a2->server)) != 0)
+ return (rc);
+
+ if ((a1->printer == NULL) || (a2->printer == NULL))
+ return (a1->printer != a2->printer);
+
+ return (strcmp(a1->printer, a2->printer));
+}
+
+
+
+
+/*
+ * FUNCTION: ns_bsd_addr_cmp_local()
+ *
+ * DESCRIPTION: This function compares 2 bsd_addr structures to determine if
+ * the information in them is the same. It destinquishes between
+ * real printer names and alias names while doing the compare.
+ *
+ * INPUTS: ns_bsd_addr_t *a1 - a bsd addr
+ * ns_bsd_addr_t *21 - another bsd addr
+ */
+
+static int
+ns_bsd_addr_cmp_local(ns_bsd_addr_t *a1, ns_bsd_addr_t *a2)
+
+{
+ int rc;
+
+ if ((a1 == NULL) || (a2 == NULL))
+ {
+ return (1);
+ }
+
+ if ((rc = strcmp(a1->server, a2->server)) != 0)
+ {
+ return (rc);
+ }
+
+ if ((a1->printer == NULL) || (a2->printer == NULL))
+ {
+ return (a1->printer != a2->printer);
+ }
+
+ rc = strcmp(a1->printer, a2->printer);
+ if (rc == 0)
+ {
+ /*
+ * The printer's real names are the same, but now check if
+ * their local names (alias) are the same.
+ */
+ rc = strcmp(a1->pname, a2->pname);
+ }
+
+ return (rc);
+} /* ns_bsd_addr_cmp_local */
+
+
+
+/*
+ * FUNCTION:
+ * ns_bsd_addr_t *ns_bsd_addr_get_name(char *name)
+ * INPUTS:
+ * char *name - name of printer to get address for
+ * OUTPUTS:
+ * ns_bsd_addr_t *(return) - the address of the printer
+ * DESCRIPTION:
+ * This function will get the BSD address of the printer specified.
+ * it fills in the printer name if none is specified in the "name service"
+ * as a convenience to calling functions.
+ */
+ns_bsd_addr_t *
+ns_bsd_addr_get_name(char *name)
+{
+ ns_printer_t *printer;
+ ns_bsd_addr_t *addr = NULL;
+
+ endprinterentry();
+ if ((printer = ns_printer_get_name(name, NULL)) != NULL) {
+ addr = ns_get_value(NS_KEY_BSDADDR, printer);
+
+ if (addr != NULL && addr->printer == NULL)
+ addr->printer = strdup(printer->name);
+ if (addr != NULL) {
+ /*
+ * if the name given is not the same as that in the
+ * this is an alias/remote name so put that into the
+ * pname field otherwise duplicate the real printer
+ * name
+ */
+ if (strcmp(name, printer->name) != 0) {
+ addr->pname = strdup(name);
+ } else {
+ addr->pname = strdup(printer->name);
+ }
+ }
+ }
+
+ return (addr);
+}
+
+
+/*
+ * FUNCTION:
+ * ns_bsd_addr_t **ns_bsd_addr_get_list()
+ * OUTPUT:
+ * ns_bsd_addr_t **(return) - a list of bsd addresses for all printers
+ * in all "name services"
+ * DESCRIPTION:
+ * This function will gather a list of all printer addresses in all
+ * of the "name services". All redundancy is removed.
+ */
+ns_bsd_addr_t **
+ns_bsd_addr_get_list(int unique)
+
+{
+ ns_printer_t **printers;
+ ns_bsd_addr_t **list = NULL;
+ char **aliases = NULL;
+
+ for (printers = ns_printer_get_list(NULL);
+ printers != NULL && *printers != NULL; printers++) {
+ ns_bsd_addr_t *addr;
+
+ if (strcmp(NS_NAME_ALL, (*printers)->name) == 0)
+ continue;
+
+ if ((addr = ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL) {
+ if (addr->printer == NULL)
+ addr->printer = strdup((*printers)->name);
+ addr->pname = strdup((*printers)->name);
+ }
+
+ if (unique == UNIQUE)
+ list =
+ (ns_bsd_addr_t **)list_append_unique((void **)list,
+ (void *)addr, (COMP_T)ns_bsd_addr_cmp);
+ else
+ if (unique == LOCAL_UNIQUE)
+ list =
+ (ns_bsd_addr_t **)list_append_unique((void **)list,
+ (void *)addr, (COMP_T)ns_bsd_addr_cmp_local);
+ else
+ list = (ns_bsd_addr_t **)list_append((void **)list,
+ (void *)addr);
+
+ for (aliases = (*printers)->aliases;
+ (aliases != NULL) && (*aliases != NULL); aliases++)
+ {
+ /*
+ * Include any alias names that belong to the printer
+ */
+
+ if ((addr =
+ ns_get_value(NS_KEY_BSDADDR, *printers)) != NULL)
+ {
+ if (addr->printer == NULL)
+ {
+ addr->printer = strdup(*aliases);
+ }
+ addr->pname = strdup(*aliases);
+ }
+
+ if (unique == UNIQUE)
+ {
+ list = (ns_bsd_addr_t **)
+ list_append_unique((void **)list,
+ (void *)addr, (COMP_T)ns_bsd_addr_cmp);
+ }
+ else
+ if (unique == LOCAL_UNIQUE)
+ {
+ list = (ns_bsd_addr_t **)
+ list_append_unique((void **)list,
+ (void *)addr,
+ (COMP_T)ns_bsd_addr_cmp_local);
+ }
+ else
+ {
+ list = (ns_bsd_addr_t **)
+ list_append((void **)list, (void *)addr);
+ }
+ }
+ }
+
+ return (list);
+}
+
+
+
+
+/*
+ * FUNCTION:
+ * ns_bsd_addr_t **ns_bsd_addr_get_list()
+ * OUTPUT:
+ * ns_bsd_addr_t **(return) - a list of bsd addresses for "_all" printers
+ * in the "name service"
+ * DESCRIPTION:
+ * This function will use the "_all" entry to find a list of printers and
+ * addresses. The "default" printer is also added to the list.
+ * All redundancy is removed.
+ */
+ns_bsd_addr_t **
+ns_bsd_addr_get_all(int unique)
+{
+ ns_printer_t *printer;
+ ns_bsd_addr_t **list = NULL;
+ char **printers;
+ char *def = NULL;
+
+ if (((def = (char *)getenv("PRINTER")) == NULL) &&
+ ((def = (char *)getenv("LPDEST")) == NULL))
+ def = NS_NAME_DEFAULT;
+
+ list = (ns_bsd_addr_t **)list_append((void **)list,
+ (void *)ns_bsd_addr_get_name(def));
+
+ endprinterentry();
+ if ((printer = ns_printer_get_name(NS_NAME_ALL, NULL)) == NULL)
+ return (ns_bsd_addr_get_list(unique));
+
+ for (printers = (char **)ns_get_value(NS_KEY_ALL, printer);
+ printers != NULL && *printers != NULL; printers++) {
+ ns_bsd_addr_t *addr;
+
+ addr = ns_bsd_addr_get_name(*printers);
+ if (addr != NULL)
+ addr->pname = *printers;
+ if (unique == UNIQUE)
+ list =
+ (ns_bsd_addr_t **)list_append_unique((void **)list,
+ (void *)addr, (COMP_T)ns_bsd_addr_cmp);
+ else
+ list = (ns_bsd_addr_t **)list_append((void **)list,
+ (void *)addr);
+ }
+
+ return (list);
+}
+
+ns_bsd_addr_t *
+ns_bsd_addr_get_default()
+{
+ char *def = NULL;
+ ns_bsd_addr_t *addr;
+
+ if (((def = (char *)getenv("PRINTER")) == NULL) &&
+ ((def = (char *)getenv("LPDEST")) == NULL)) {
+ def = NS_NAME_DEFAULT;
+ addr = ns_bsd_addr_get_name(def);
+ if (addr != NULL) {
+ addr->pname = def;
+ return (addr);
+ }
+ }
+
+ return (NULL);
+}
diff --git a/usr/src/lib/print/libprint/common/ns_cmn_kvp.c b/usr/src/lib/print/libprint/common/ns_cmn_kvp.c
new file mode 100644
index 0000000000..3fdacd7e5d
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/ns_cmn_kvp.c
@@ -0,0 +1,262 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <ns.h>
+#include <list.h>
+
+/*
+ * Commonly Used routines...
+ */
+
+/*
+ * FUNCTION:
+ * kvp_create(const char *key, const void *value)
+ * INPUT(S):
+ * const char *key
+ * - key for key/value pair
+ * const void *value
+ * - value for key/value pair
+ * OUTPUT(S):
+ * ns_kvp_t * (return value)
+ * - pointer to structure containing the key/value pair
+ * DESCRIPTION:
+ */
+ns_kvp_t *
+ns_kvp_create(const char *key, const char *value)
+{
+ ns_kvp_t *kvp;
+
+ if ((kvp = calloc(1, sizeof (*kvp))) != NULL) {
+ kvp->key = strdup(key);
+ kvp->value = (char *)value;
+ }
+ return (kvp);
+}
+
+void
+ns_kvp_destroy(ns_kvp_t *kvp)
+{
+ if (kvp != NULL) {
+ if (kvp->key != NULL)
+ free(kvp->key);
+ if (kvp->value != NULL)
+ free(kvp->value);
+ free(kvp);
+ }
+}
+
+
+
+
+/*
+ * FUNCTION:
+ * ns_kvp_match_key(const ns_kvp_t *kvp, const char *key)
+ * INPUT(S):
+ * const ns_kvp_t *kvp
+ * - key/value pair to check
+ * const char *key
+ * - key for matching
+ * OUTPUT(S):
+ * int (return value)
+ * - 0 if matched
+ * DESCRIPTION:
+ */
+static int
+ns_kvp_match_key(const ns_kvp_t *kvp, char *key)
+{
+ if ((kvp != NULL) && (kvp->key != NULL) && (key != NULL))
+ return (strcmp(kvp->key, key));
+ return (-1);
+}
+
+
+/*
+ * FUNCTION:
+ * ns_r_get_value(const char *key, const ns_printer_t *printer)
+ * INPUT(S):
+ * const char *key
+ * - key for matching
+ * const ns_printer_t *printer
+ * - printer to glean this from
+ * OUTPUT(S):
+ * char * (return value)
+ * - NULL, if not matched
+ * DESCRIPTION:
+ */
+static void *
+ns_r_get_value(const char *key, const ns_printer_t *printer, int level)
+{
+ ns_kvp_t *kvp, **attrs;
+
+ if ((key == NULL) || (printer == NULL) ||
+ (printer->attributes == NULL))
+ return (NULL);
+
+ if (level++ == 16)
+ return (NULL);
+
+ /* find it right here */
+ if ((kvp = list_locate((void **)printer->attributes,
+ (COMP_T)ns_kvp_match_key, (void *)key)) != NULL) {
+ void *value = string_to_value(key, kvp->value);
+
+ /* fill in an empty printer for a bsdaddr */
+ if (strcmp(key, NS_KEY_BSDADDR) == 0) {
+ ns_bsd_addr_t *addr = value;
+
+ if (addr->printer == NULL)
+ addr->printer = strdup(printer->name);
+ }
+ return (value);
+ }
+
+ /* find it in a child */
+ for (attrs = printer->attributes; attrs != NULL && *attrs != NULL;
+ attrs++) {
+ void *value = NULL;
+
+ if ((strcmp((*attrs)->key, NS_KEY_ALL) == 0) ||
+ (strcmp((*attrs)->key, NS_KEY_GROUP) == 0)) {
+ char **printers;
+
+ for (printers = string_to_value((*attrs)->key,
+ (*attrs)->value);
+ printers != NULL && *printers != NULL; printers++) {
+ ns_printer_t *printer =
+ ns_printer_get_name(*printers, NULL);
+
+ if ((value = ns_r_get_value(key, printer,
+ level)) != NULL)
+ return (value);
+ ns_printer_destroy(printer);
+ }
+ } else if (strcmp((*attrs)->key, NS_KEY_LIST) == 0) {
+ ns_printer_t **printers;
+
+ for (printers = string_to_value((*attrs)->key,
+ (*attrs)->value);
+ printers != NULL && *printers != NULL; printers++) {
+ if ((value = ns_r_get_value(key, *printers,
+ level)) != NULL)
+ return (value);
+ }
+ } else if (strcmp((*attrs)->key, NS_KEY_USE) == 0) {
+ char *string = NULL;
+ ns_printer_t *printer =
+ ns_printer_get_name((*attrs)->value, NULL);
+ if ((value = ns_r_get_value(key, printer,
+ level)) != NULL)
+ string = value_to_string(string, value);
+ if (string != NULL)
+ value = string_to_value(key, string);
+ ns_printer_destroy(printer);
+ }
+
+ if (value != NULL)
+ return (value);
+ }
+
+ return (NULL);
+}
+
+
+/*
+ * ns_get_value() gets the value of the passed in attribute from the passed
+ * in printer structure. The value is returned in a converted format.
+ */
+void *
+ns_get_value(const char *key, const ns_printer_t *printer)
+{
+ return (ns_r_get_value(key, printer, 0));
+}
+
+
+/*
+ * ns_get_value_string() gets the value of the key passed in from the
+ * printer structure passed in. The results is an ascii string.
+ */
+char *
+ns_get_value_string(const char *key, const ns_printer_t *printer)
+{
+ return ((char *)value_to_string(key, ns_get_value(key, printer)));
+}
+
+
+/*
+ * ns_set_value() sets the passed in kvp in the passed in printer structure,
+ * This is done by converting the value to a string first.
+ */
+int
+ns_set_value(const char *key, const void *value, ns_printer_t *printer)
+{
+ return (ns_set_value_from_string(key,
+ value_to_string(key, (void *)value), printer));
+}
+
+
+/*
+ * ns_set_value_from_string() sets the passed in kvp in the passed in printer
+ * structure.
+ */
+int
+ns_set_value_from_string(const char *key, const char *string,
+ ns_printer_t *printer)
+{
+ if (printer == NULL)
+ return (-1);
+
+ if (key == NULL)
+ list_iterate((void **)printer->attributes,
+ (VFUNC_T)ns_kvp_destroy);
+ else {
+ ns_kvp_t *kvp;
+
+ if (((kvp = list_locate((void **)printer->attributes,
+ (COMP_T)ns_kvp_match_key,
+ (void *)key)) == NULL) &&
+ ((kvp = calloc(1, sizeof (*kvp))) != NULL)) {
+ kvp->key = strdup(key);
+ printer->attributes = (ns_kvp_t **)
+ list_append((void **)printer->attributes, kvp);
+ }
+ if (string != NULL)
+ kvp->value = strdup(string);
+ else
+ kvp->value = NULL;
+ }
+
+ return (0);
+}
diff --git a/usr/src/lib/print/libprint/common/ns_cmn_printer.c b/usr/src/lib/print/libprint/common/ns_cmn_printer.c
new file mode 100644
index 0000000000..25e344b3c4
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/ns_cmn_printer.c
@@ -0,0 +1,157 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*LINTLIBRARY*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <ns.h>
+#include <list.h>
+
+extern void ns_kvp_destroy(ns_kvp_t *);
+
+/*
+ * Commonly Used routines...
+ */
+
+/*
+ * FUNCTION:
+ * printer_create(char *name, char **aliases, char *source,
+ * ns_kvp_t **attributes)
+ * INPUT(S):
+ * char *name
+ * - primary name of printer
+ * char **aliases
+ * - aliases for printer
+ * char *source
+ * - name service derived from
+ * ks_kvp_t **attributes
+ * - key/value pairs
+ * OUTPUT(S):
+ * ns_printer_t * (return value)
+ * - pointer to printer object structure
+ * DESCRIPTION:
+ */
+ns_printer_t *
+ns_printer_create(char *name, char **aliases, char *source,
+ ns_kvp_t **attributes)
+{
+ ns_printer_t *printer;
+
+ if ((printer = (ns_printer_t *)calloc(1, sizeof (*printer))) != NULL) {
+ printer->name = (char *)name;
+ printer->aliases = (char **)aliases;
+ printer->source = (char *)source;
+ printer->attributes = (ns_kvp_t **)attributes;
+ }
+ return (printer);
+}
+
+
+static int
+ns_strcmp(char *s1, char *s2)
+{
+ return (strcmp(s1, s2) != 0);
+}
+
+
+/*
+ * FUNCTION:
+ * ns_printer_match_name(const ns_printer_t *printer, const char *name)
+ * INPUT(S):
+ * const ns_printer_t *printer
+ * - key/value pair to check
+ * const char *key
+ * - key for matching
+ * OUTPUT(S):
+ * int (return value)
+ * - 0 if matched
+ * DESCRIPTION:
+ */
+int
+ns_printer_match_name(ns_printer_t *printer, const char *name)
+{
+ if ((printer == NULL) || (printer->name == NULL) || (name == NULL))
+ return (-1);
+
+ if ((strcmp(printer->name, name) == 0) ||
+ (list_locate((void **)printer->aliases,
+ (COMP_T)ns_strcmp, (void *)name) != NULL))
+ return (0);
+
+ return (-1);
+}
+
+
+static void
+_ns_append_printer_name(const char *name, va_list ap)
+{
+ char *buf = va_arg(ap, char *);
+ int bufsize = va_arg(ap, int);
+
+ if (name == NULL)
+ return;
+
+ (void) strlcat(buf, name, bufsize);
+ (void) strlcat(buf, "|", bufsize);
+}
+
+/*
+ * FUNCTION:
+ * char *ns_printer_name_list(const ns_printer_t *printer)
+ * INPUT:
+ * const ns_printer_t *printer - printer object to generate list from
+ * OUTPUT:
+ * char * (return) - a newly allocated string containing the names of
+ * the printer
+ */
+char *
+ns_printer_name_list(const ns_printer_t *printer)
+{
+ char buf[BUFSIZ];
+
+ if ((printer == NULL) || (printer->name == NULL))
+ return (NULL);
+
+ if (snprintf(buf, sizeof (buf), "%s|", printer->name) >= sizeof (buf)) {
+ syslog(LOG_ERR, "ns_printer_name:buffer overflow");
+ return (NULL);
+ }
+
+ list_iterate((void **)printer->aliases,
+ (VFUNC_T)_ns_append_printer_name, buf, sizeof (buf));
+
+ buf[strlen(buf) - 1] = (char)NULL;
+
+ return (strdup(buf));
+}
diff --git a/usr/src/lib/print/libprint/common/nss_convert.c b/usr/src/lib/print/libprint/common/nss_convert.c
new file mode 100644
index 0000000000..eaee6df5b2
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/nss_convert.c
@@ -0,0 +1,207 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * This file contains routines necessary to convert a string buffer into
+ * a printer object.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include <ns.h>
+#include <list.h>
+
+#define ESCAPE_CHARS "\\\n=:" /* \, \n, =, : */
+
+/*
+ * Just like strncat(3C), but escapes the supplied characters.
+ * This allows the escape character '\' and seperators to be part of the
+ * keys or values.
+ */
+char *
+strncat_escaped(char *d, char *s, int len, char *escape)
+{
+ char *t = d;
+
+ while ((*t != NULL) && (len > 0))
+ len--, t++;
+
+ if (escape == NULL)
+ escape = "\\";
+
+ while ((*s != NULL) && (len > 0)) {
+ if (strchr(escape, *s) != NULL)
+ len--, *t++ = '\\';
+ len--, *t++ = *s++;
+ }
+ *t = NULL;
+
+ return (d);
+}
+
+
+
+char *
+_cvt_printer_to_entry(ns_printer_t *printer, char *buf, int buflen)
+{
+ int i, len;
+ int bufferok = 1;
+
+ (void) memset(buf, NULL, buflen);
+
+ if ((printer == NULL) || (printer->attributes == NULL))
+ return (NULL);
+
+ if (snprintf(buf, buflen, "%s", printer->name) >= buflen) {
+ (void) memset(buf, NULL, buflen);
+ syslog(LOG_ERR, "_cvt_printer_to_entry: buffer overflow");
+ return (NULL);
+ }
+
+ if ((printer->aliases != NULL) && (printer->aliases[0] != NULL)) {
+ char **alias = printer->aliases;
+
+ while (*alias != NULL) {
+ (void) strlcat(buf, "|", buflen);
+ (void) strncat_escaped(buf, *alias++, buflen,
+ ESCAPE_CHARS);
+ }
+ }
+
+ if (strlcat(buf, ":", buflen) >= buflen) {
+ (void) memset(buf, NULL, buflen);
+ syslog(LOG_ERR, "_cvt_printer_to_entry: buffer overflow");
+ return (NULL);
+ }
+
+ len = strlen(buf);
+
+ for (i = 0; printer->attributes[i] != NULL && bufferok; i++) {
+ ns_kvp_t *kvp = printer->attributes[i];
+
+ if (kvp->value == NULL)
+ continue;
+ (void) strlcat(buf, "\\\n\t:", buflen);
+ (void) strncat_escaped(buf, kvp->key, buflen, ESCAPE_CHARS);
+ (void) strlcat(buf, "=", buflen);
+ (void) strncat_escaped(buf, kvp->value, buflen, ESCAPE_CHARS);
+ if (strlcat(buf, ":", buflen) >= buflen) {
+ bufferok = 0;
+ }
+ }
+
+ if (!bufferok) {
+ (void) memset(buf, NULL, buflen);
+ syslog(LOG_ERR, "_cvt_printer_to_entry: buffer overflow");
+ return (NULL);
+ }
+
+ if (strlen(buf) == len) { /* there were no attributes */
+ (void) memset(buf, NULL, buflen);
+ buf = NULL;
+ }
+
+ return (buf);
+}
+
+
+ns_printer_t *
+_cvt_nss_entry_to_printer(char *entry, char *ns)
+{
+ char *name = NULL,
+ *key = NULL,
+ **aliases = NULL,
+ *cp,
+ buf[BUFSIZ];
+ int in_namelist = 1, buf_pos = 0;
+ ns_printer_t *printer = NULL;
+
+ if (entry == NULL)
+ return (NULL);
+
+ (void) memset(buf, NULL, sizeof (buf));
+ for (cp = entry; *cp != NULL; cp++) {
+ switch (*cp) {
+ case ':': /* end of kvp */
+ if (in_namelist != 0) {
+ if (name == NULL)
+ name = strdup(buf);
+ else
+ aliases = (char **)list_append(
+ (void **)aliases,
+ (void *)strdup(buf));
+ printer = (ns_printer_t *)ns_printer_create(
+ name, aliases, ns, NULL);
+ in_namelist = 0;
+ } else if (key != NULL)
+ (void) ns_set_value_from_string(key, buf,
+ printer);
+ (void) memset(buf, NULL, sizeof (buf));
+ buf_pos = 0;
+ key = NULL;
+ break;
+ case '=': /* kvp seperator */
+ if (key == NULL) {
+ key = strdup(buf);
+ (void) memset(buf, NULL, sizeof (buf));
+ buf_pos = 0;
+ } else
+ buf[buf_pos++] = *cp;
+ break;
+ case '|': /* namelist seperator */
+ if (in_namelist != 0) {
+ if (name == NULL)
+ name = strdup(buf);
+ else
+ aliases = (char **)list_append(
+ (void **)aliases,
+ (void *)strdup(buf));
+ (void) memset(buf, NULL, sizeof (buf));
+ buf_pos = 0;
+ } else /* add it to the buffer */
+ buf[buf_pos++] = *cp;
+ break;
+ case '\\': /* escape char */
+ buf[buf_pos++] = *(++cp);
+ break;
+ default:
+ buf[buf_pos++] = *cp;
+ }
+
+ }
+
+ if (key != NULL)
+ (void) ns_set_value_from_string(key, buf, printer);
+
+ return (printer);
+}
diff --git a/usr/src/lib/print/libprint/common/nss_ldap.c b/usr/src/lib/print/libprint/common/nss_ldap.c
new file mode 100644
index 0000000000..c2140d5048
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/nss_ldap.c
@@ -0,0 +1,2477 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <pwd.h>
+#include <libintl.h>
+#include <netdb.h> /* for rcmd() */
+
+#include <ns.h>
+#include <list.h>
+
+#define LDAP_REFERRALS
+#include <lber.h>
+#include <ldap.h>
+#include <sys/systeminfo.h>
+
+
+/*
+ * This modules contains the code required to manipulate printer objects in
+ * a LDAP directory for the Naming Service (NS) switch.
+ * It can "add", "modify" and "delete" the objects on the given ldap server
+ * and in the given NS domain DN, eg. "dc=mkg,dc=sun,dc=com".
+ * Note: printers known to the naming service are contained in the RDN
+ * "ou=printers" under the NS domain DN
+ */
+
+#define PCONTAINER "ou=printers"
+
+/* attribute keywords */
+#define ATTR_DN "dn"
+#define ATTR_OCLASS "objectClass"
+#define ATTR_URI "printer-uri"
+#define ATTR_PNAME "printer-name"
+#define ATTR_XRISUP "printer-xri-supported"
+#define ATTR_BSDADDR "sun-printer-bsdaddr"
+#define ATTR_KVP "sun-printer-kvp"
+
+/* objectClass values */
+#define OCV_TOP "top"
+#define OCV_PSERVICE "printerService"
+#define OCV_SUNPRT "sunPrinter"
+#define OCV_PABSTRACT "printerAbstract"
+
+/* xri-supported attribute value */
+#define AV_UNKNOWN "unknown"
+
+
+/*
+ * LDAP objectclass atributes that the user can explicity change
+ */
+
+static const char *nsl_attr_printerService[] = {
+ "printer-uri",
+ "printer-xri-supported",
+ /* Not allowed "printer-name", */
+ "printer-natural-language-configured",
+ "printer-location",
+ "printer-info",
+ "printer-more-info",
+ "printer-make-and-model",
+ "printer-charset-configured",
+ "printer-charset-supported",
+ "printer-generated-natural-language-supported",
+ "printer-document-format-supported",
+ "printer-color-supported",
+ "printer-compression-supported",
+ "printer-pages-per-minute",
+ "printer-pages-per-minute-color",
+ "printer-finishings-supported",
+ "printer-number-up-supported",
+ "printer-sides-supported",
+ "printer-media-supported",
+ "printer-media-local-supported",
+ "printer-resolution-supported",
+ "printer-print-quality-supported",
+ "printer-job-priority-supported",
+ "printer-copies-supported",
+ "printer-job-k-octets-supported",
+ "printer-current-operator",
+ "printer-service-person",
+ "printer-delivery-orientation-supported",
+ "printer-stacking-order-supported",
+ "printer-output-features-supported",
+ (char *)NULL
+};
+
+
+static const char *nsl_attr_printerIPP[] = {
+ "printer-ipp-versions-supported",
+ "printer-multiple-document-jobs-supported",
+ (char *)NULL
+};
+
+static const char *nsl_attr_sunPrinter[] = {
+ /* Not allowed "sun-printer-bsdaddr", */
+ /* Not allowed "sun-printer-kvp", */
+ (char *)NULL
+};
+
+
+/*
+ * List of LDAP attributes that user is not allowed to explicitly change
+ */
+static const char *nsl_attr_notAllowed[] = {
+ ATTR_DN,
+ ATTR_OCLASS, /* objectclass */
+ ATTR_PNAME, /* printer-name */
+ ATTR_BSDADDR,
+ ATTR_KVP,
+ (char *)NULL
+};
+
+
+static NSL_RESULT _connectToLDAP(ns_cred_t *cred, LDAP **ld);
+static uchar_t *_constructPrinterDN(uchar_t *printerName,
+ uchar_t *domainDN, char **attrList);
+static NSL_RESULT _checkPrinterExists(LDAP *ld, uchar_t *printerName,
+ uchar_t *domainDN, uchar_t **printerDN);
+static NSL_RESULT _checkPrinterDNExists(LDAP *ld, uchar_t *objectDN);
+static NSL_RESULT _checkSunPrinter(LDAP *ld, uchar_t *printerDN);
+static NSL_RESULT _addNewPrinterObject(LDAP *ld, uchar_t *printerName,
+ uchar_t *domainDN, char **attrList);
+static NSL_RESULT _modifyPrinterObject(LDAP *ld, uchar_t *printerDN,
+ uchar_t *printerName, uchar_t *domainDN, char **attrList);
+static NSL_RESULT _checkAttributes(char **list);
+static NSL_RESULT _addLDAPmodValue(LDAPMod ***attrs, char *type, char *value);
+static NSL_RESULT _modLDAPmodValue(LDAPMod ***attrs, char *type, char *value);
+static NSL_RESULT _constructAddLDAPMod(uchar_t *printerName,
+ char **attrList, LDAPMod ***attrs);
+static NSL_RESULT _constructModLDAPMod(uchar_t *printerName, int sunPrinter,
+ char **attrList, char ***oldKVPList, LDAPMod ***attrs);
+static NSL_RESULT _compareURIinDNs(uchar_t *dn1, uchar_t *dn2);
+static uchar_t *_getThisNSDomainDN(void);
+static int _popen(char *cmd, char *results, int size);
+static int _attrInList(char *attr, const char **list);
+static int _attrInLDAPList(char *attr);
+static NSL_RESULT _getCurrentKVPValues(LDAP *ld,
+ uchar_t *objectDN, char ***list);
+static void _freeList(char ***list);
+static NSL_RESULT _modAttrKVP(char *value, char ***kvpList);
+static NSL_RESULT _attrAddKVP(LDAPMod ***attrs, char **kvpList, int kvpExists);
+static int _manageReferralCredentials(LDAP *ld, char **dn, char **credp,
+ int *methodp, int freeit);
+
+/*
+ * *****************************************************************************
+ *
+ * Function: ldap_put_printer()
+ *
+ * Description: Action the request to change a printer object in the LDAP
+ * directory DIT. The object is either added, modified or deleted
+ * depending on the request's attribute list. A null list indicates
+ * the request is a delete.
+ * The object's DN is constructed from the supplied domain DN and
+ * a check is done to see if the object exists already, if it
+ * doesn't exist then this is a request to add a new object
+ * If a URI is given in the attribute list and it is different to
+ * the existing printing object's DN then the request will be
+ * rejected.
+ *
+ *
+ * Parameters:
+ * Input: const ns_printer_t *printer
+ * - this structure contains the following :
+ * char *printerName - name of the printer
+ * ns_cred_t *cred - structure containing the ldap host and
+ * port, user, password and NS domain DN for the
+ * directory server to be updated.
+ * char **attrList - pointer to a list of attribute key values
+ * for the printer object. If the object does
+ * not already exist then this list contains the
+ * values for the new object, otherwise this list
+ * is a list of attributes to modify. For modify
+ * a null attribute value is a attribute delete
+ * request. A NULL ptr = delete the object.
+ * Output: None
+ *
+ * Returns: int - 0 = request actioned okay
+ * !0 = error - see NSL_RESULT codes
+ *
+ * *****************************************************************************
+ */
+
+int
+ldap_put_printer(const ns_printer_t *printer)
+
+{
+ NSL_RESULT result = NSL_OK;
+ NSL_RESULT printerExists = NSL_ERR_UNKNOWN_PRINTER;
+ LDAP *ld = NULL;
+ uchar_t *printerDN = NULL;
+ uchar_t *domainDN = NULL;
+ char *printerName = NULL;
+ ns_cred_t *cred = NULL;
+ char **attrList = NULL;
+
+ /* -------- */
+
+ /*
+ * Note: the "attributes" list should be null for ldap as the attribute
+ * values are passed in the nsdata field
+ */
+
+ if ((printer != NULL) &&
+ (printer->attributes == NULL) && (printer->name != NULL))
+ {
+ /* extract required pointer values from structure */
+
+ printerName = printer->name;
+ cred = printer->cred;
+ if (printer->nsdata != NULL)
+ {
+ attrList = ((NS_LDAPDATA *)(printer->nsdata))->attrList;
+ }
+
+ /* connect and bind to the ldap directory server */
+
+ result = _connectToLDAP(cred, &ld);
+ if ((result == NSL_OK) && (ld != NULL))
+ {
+ /*
+ * check if the NS domain DN was given, if not use the
+ * current NS domain
+ */
+
+ if (cred->domainDN != NULL)
+ {
+ domainDN = (uchar_t *)
+ strdup((char *)cred->domainDN);
+ }
+ else
+ {
+ /* get DN of current domain */
+ domainDN = _getThisNSDomainDN();
+ }
+
+ printerExists =
+ _checkPrinterExists(ld, (uchar_t *)printerName,
+ domainDN, &printerDN);
+ if (printerExists != LDAP_SUCCESS)
+ {
+ /*
+ * could not find the printer by printer-name,
+ * but there could be a non sunPrinter object
+ * so if the printer-uri was given check if
+ * an object for that exists
+ */
+ printerDN =
+ _constructPrinterDN(NULL,
+ domainDN, attrList);
+ if (printerDN != NULL)
+ {
+ printerExists = _checkPrinterDNExists(
+ ld, printerDN);
+ }
+ }
+#ifdef DEBUG
+if (printerExists == NSL_OK)
+{
+printf("DN found = '%s' for '%s'\n", printerDN, printerName);
+}
+#endif
+
+ if (attrList == NULL)
+ {
+ /*
+ * a null list indicates that this is a DELETE
+ * object request, so if object exists delete
+ * it, otherwise report an error.
+ */
+ if (printerExists == LDAP_SUCCESS)
+ {
+ result = ldap_delete_s(ld,
+ (char *)printerDN);
+ if (result != LDAP_SUCCESS)
+ {
+ result = NSL_ERR_DEL_FAILED;
+#ifdef DEBUG
+ldap_perror(ld, "ldap_delete_s failed");
+#endif
+ }
+ }
+ else
+ {
+ result = NSL_ERR_UNKNOWN_PRINTER;
+ }
+ }
+ else
+ {
+ /*
+ * if object exists then this is a
+ * modify request otherwise is is an add request
+ */
+
+ if (printerExists == LDAP_SUCCESS)
+ {
+ /*
+ * Modify the printer object to
+ * give it the new attribute values
+ * specified by the user
+ */
+ result =
+ _modifyPrinterObject(ld, printerDN,
+ (uchar_t *)printerName,
+ domainDN, attrList);
+ }
+ else
+ {
+ /*
+ * add new printer object into the
+ * ldap directory with the user
+ * specified attribute values
+ */
+ result =
+ _addNewPrinterObject(ld,
+ (uchar_t *)printerName,
+ domainDN, attrList);
+ }
+ }
+
+ if (printerDN != NULL)
+ {
+ free(printerDN);
+ }
+ if (domainDN != NULL)
+ {
+ free(domainDN);
+ }
+
+ /* disconnect from LDAP server */
+
+ (void) ldap_unbind(ld);
+ }
+ }
+
+ else
+ {
+ /* no printerName given */
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return ((int)result);
+} /* ldap_put_printer */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _connectToLDAP()
+ *
+ * Description: Setup the connection and bind to the LDAP directory server.
+ * The function returns the ldap connection descriptor
+ *
+ * Note: Currently the native ldap functions do not support secure
+ * passwords, when this is supported this function will require
+ * updating to allow the type passed in cred->passwdType to
+ * be used with the ldap_simple_bind()
+ *
+ * Parameters:
+ * Input: ns_cred_t *cred - structure containing the credentials (host,
+ * port, user and password) required to bind
+ * to the directory server to be updated.
+ * char *printerName - printer name used only for error messages
+ * Output: LDAP** - ldap connection descriptor pointer. NULL = failed
+ *
+ * Returns: NSL_RESULT - NSL_OK = connected okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_connectToLDAP(ns_cred_t *cred, LDAP **ld)
+
+{
+ NSL_RESULT result = NSL_OK;
+ int lresult = 0;
+ int ldapPort = LDAP_PORT; /* default LDAP port number */
+ int protoVersion = LDAP_VERSION3;
+ int derefOption = LDAP_DEREF_NEVER;
+ int referrals = 1;
+ char hostname[MAXHOSTNAMELEN];
+ int tmpMethod = LDAP_AUTH_SIMPLE; /* temp - until its passed in */
+
+ /* -------- */
+
+ if ((ld == NULL) || (cred == NULL) ||
+ ((cred->passwd == NULL) || (cred->binddn == NULL)))
+ {
+ result = NSL_ERR_CREDENTIALS;
+ }
+
+ else
+ {
+ *ld = NULL;
+
+ /* if host was not given then bind to local host */
+
+ if (cred->host != NULL)
+ {
+ (void) strlcpy(hostname, cred->host, sizeof (hostname));
+ }
+ else
+ {
+ (void) sysinfo(SI_HOSTNAME,
+ hostname, sizeof (hostname));
+ }
+
+ /* initialise the connection to the ldap server */
+
+ if (cred->port != 0)
+ {
+ ldapPort = cred->port;
+ }
+ *ld = ldap_init(hostname, ldapPort);
+ if (*ld == NULL)
+ {
+ /* connection setup failed */
+ result = NSL_ERR_CONNECT;
+#ifdef DEBUG
+(void) perror("ldap_init");
+#endif
+ }
+ else
+ {
+ /* set ldap options */
+
+ (void) ldap_set_option(*ld, LDAP_OPT_DEREF,
+ &derefOption);
+ (void) ldap_set_option(*ld, LDAP_OPT_PROTOCOL_VERSION,
+ &protoVersion);
+ (void) ldap_set_option(*ld, LDAP_OPT_REFERRALS,
+ &referrals);
+
+ /* bind to the user DN in the directory */
+
+ /* cred->passwdType is currently not supported */
+
+ lresult = ldap_simple_bind_s(*ld,
+ cred->binddn, cred->passwd);
+
+ /*
+ * before doing anything else, set up the function to
+ * call to get authentication details if the
+ * ldap update function calls (eg. ldap_add_s()) get a
+ * "referral" (to another ldap server) from the
+ * original ldap server, eg. if we are trying to do
+ * a update on a LDAP replica server.
+ */
+ (void) _manageReferralCredentials(*ld,
+ &(cred->binddn), &(cred->passwd),
+ &tmpMethod, -1);
+ ldap_set_rebind_proc(*ld,
+ (LDAP_REBINDPROC_CALLBACK *)
+ _manageReferralCredentials, NULL);
+
+ if (lresult != LDAP_SUCCESS)
+ {
+ result = NSL_ERR_BIND;
+ *ld = NULL;
+#ifdef DEBUG
+(void) ldap_perror(*ld, "ldap_simple_bind_s");
+#endif
+ }
+ }
+ }
+
+ return (result);
+} /* _connectToLDAP */
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _constructPrinterDN()
+ *
+ * Description: Construct the DN for the printer object from its name and NS
+ * domain DN. If the printer-uri is given in the attrList then
+ * that is used instead of the printerName.
+ *
+ * Parameters:
+ * Input: uchar_t *printerName
+ * uchar_t *domainDN
+ * char **attrList - this list is searched for printer-uri
+ * Output: None
+ *
+ * Returns: uchar_t* - pointer to the DN, this memory is malloced so
+ * must be freed using free() when finished with.
+ *
+ * *****************************************************************************
+ */
+
+static uchar_t *
+_constructPrinterDN(uchar_t *printerName, uchar_t *domainDN, char **attrList)
+
+{
+ uchar_t *dn = NULL;
+ uchar_t *uri = NULL;
+ char **p = NULL;
+ int len = 0;
+
+ /* ------- */
+
+ /* first search for printer-uri in the attribute list */
+
+ for (p = attrList; (p != NULL) && (*p != NULL) && (uri == NULL); p++)
+ {
+ /* get length of this key word */
+
+ for (len = 0; ((*p)[len] != '=') && ((*p)[len] != '\0'); len++);
+
+ if ((strncasecmp(*p, ATTR_URI, len) == 0) &&
+ (strlen(*p) > len+1))
+ {
+ uri = (uchar_t *)&((*p)[len+1]);
+ }
+ }
+
+
+ if (domainDN != NULL) {
+ size_t size;
+
+ /* malloc memory for the DN and then construct it */
+
+ if ((uri == NULL) && (printerName != NULL))
+ {
+ /* use the printerName for the RDN */
+
+ size = strlen(ATTR_URI) +
+ strlen((char *)printerName) +
+ strlen((char *)domainDN) +
+ strlen(PCONTAINER) +
+ 10; /* plus a few extra */
+
+ if ((dn = malloc(size)) != NULL)
+ (void) snprintf((char *)dn, size, "%s=%s,%s,%s",
+ ATTR_URI, printerName, PCONTAINER, domainDN);
+ }
+ else
+ if (uri != NULL)
+ {
+ /* use the URI for the RDN */
+
+ size = strlen(ATTR_URI) +
+ strlen((char *)uri) +
+ strlen((char *)domainDN) +
+ strlen(PCONTAINER) +
+ 10; /* plus a few extra */
+
+ if ((dn = malloc(size)) != NULL)
+ (void) snprintf((char *)dn, size, "%s=%s,%s,%s",
+ ATTR_URI, uri, PCONTAINER, domainDN);
+ }
+
+ /*
+ * else
+ * {
+ * printName not given so return null
+ * }
+ */
+
+ }
+
+ return (dn); /* caller must free this memory */
+} /* _constructPrinterDN */
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _checkPrinterExists()
+ *
+ * Description: Check that the printer object for the printerName exists in the
+ * directory DIT and then extract the object's DN
+ * The function uses an exiting ldap connection and does a
+ * search for the printerName in the supplied domain DN.
+ *
+ * Parameters:
+ * Input: LDAP *ld - existing ldap connection descriptor
+ * uchar_t *printerName - printer name
+ * uchar_t *domainDN - DN of domain to search in
+ * Output: uchar_t **printerDN - DN of the printer - the caller should
+ * free this memory using free()
+ *
+ * Result: NSL_RESULT - NSL_OK = object exists
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_checkPrinterExists(LDAP *ld, uchar_t *printerName, uchar_t *domainDN,
+ uchar_t **printerDN)
+
+{
+ NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER;
+ int sresult = LDAP_NO_SUCH_OBJECT;
+ LDAPMessage *ldapMsg = NULL;
+ char *requiredAttrs[2] = { ATTR_PNAME, NULL };
+ LDAPMessage *ldapEntry = NULL;
+ uchar_t *filter = NULL;
+ uchar_t *baseDN = NULL;
+
+ /* ---------- */
+
+ if ((printerName != NULL) && (domainDN != NULL) && (printerDN != NULL))
+ {
+ size_t size;
+
+ if (printerDN != NULL)
+ {
+ *printerDN = NULL;
+ }
+
+ /* search for this Printer in the directory */
+
+ size = (3 + strlen((char *)printerName) + strlen(ATTR_PNAME) +
+ 2);
+
+ if ((filter = malloc(size)) != NULL)
+ (void) snprintf((char *)filter, size, "(%s=%s)",
+ ATTR_PNAME, (char *)printerName);
+
+ size = (strlen((char *)domainDN) + strlen(PCONTAINER) + 5);
+
+ if ((baseDN = malloc(size)) != NULL)
+ (void) snprintf((char *)baseDN, size, "%s,%s",
+ PCONTAINER, (char *)domainDN);
+
+ sresult = ldap_search_s(ld, (char *)baseDN, LDAP_SCOPE_SUBTREE,
+ (char *)filter, requiredAttrs, 0, &ldapMsg);
+ if (sresult == LDAP_SUCCESS)
+ {
+ /* check that the object exists and extract its DN */
+
+ ldapEntry = ldap_first_entry(ld, ldapMsg);
+ if (ldapEntry != NULL)
+ {
+ /* object found - there should only be one */
+ result = NSL_OK;
+
+ if (printerDN != NULL)
+ {
+ *printerDN = (uchar_t *)
+ ldap_get_dn(ld, ldapEntry);
+ }
+ }
+
+ (void) ldap_msgfree(ldapMsg);
+ }
+ }
+
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return (result);
+} /* _checkPrinterExists */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _checkPrinterDNExists()
+ *
+ * Description: Check that the printer object for the DN exists in the
+ * directory DIT.
+ * The function uses an exiting ldap connection and does a
+ * search for the DN supplied.
+ *
+ * Parameters: LDAP *ld - existing ldap connection descriptor
+ * char *objectDN - DN to search for
+ *
+ * Result: NSL_RESULT - NSL_OK = object exists
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_checkPrinterDNExists(LDAP *ld, uchar_t *objectDN)
+
+{
+ NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER;
+ int sresult = LDAP_NO_SUCH_OBJECT;
+ LDAPMessage *ldapMsg;
+ char *requiredAttrs[2] = { ATTR_PNAME, NULL };
+ LDAPMessage *ldapEntry;
+
+ /* ---------- */
+
+ if ((ld != NULL) && (objectDN != NULL))
+ {
+ /* search for this Printer in the directory */
+
+ sresult = ldap_search_s(ld, (char *)objectDN, LDAP_SCOPE_BASE,
+ "(objectclass=*)", requiredAttrs, 0, &ldapMsg);
+ if (sresult == LDAP_SUCCESS)
+ {
+ /* check that the object exists */
+ ldapEntry = ldap_first_entry(ld, ldapMsg);
+ if (ldapEntry != NULL)
+ {
+ /* object found */
+ result = NSL_OK;
+ }
+
+ (void) ldap_msgfree(ldapMsg);
+ }
+ }
+
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return (result);
+} /* _checkPrinterDNExists */
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _checkSunPrinter()
+ *
+ * Description: Check that the printer object for the printerDN is a sunPrinter
+ * ie. it has the required objectclass attribute value.
+ *
+ * Parameters:
+ * Input: LDAP *ld - existing ldap connection descriptor
+ * Output: uchar_t *printerDN - DN of the printer
+ *
+ * Result: NSL_RESULT - NSL_OK = object exists and is a sunPrinter
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_checkSunPrinter(LDAP *ld, uchar_t *printerDN)
+
+{
+ NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER;
+ int sresult = LDAP_NO_SUCH_OBJECT;
+ char *requiredAttrs[2] = { ATTR_PNAME, NULL };
+ LDAPMessage *ldapMsg = NULL;
+ LDAPMessage *ldapEntry = NULL;
+ char *filter = NULL;
+
+ /* ---------- */
+
+ if ((ld != NULL) && (printerDN != NULL))
+ {
+ size_t size;
+
+ /* search for this Printer in the directory */
+
+ size = (3 + strlen(OCV_SUNPRT) + strlen(ATTR_OCLASS) + 2);
+ if ((filter = malloc(size)) != NULL)
+ (void) snprintf(filter, size, "(%s=%s)",
+ ATTR_OCLASS, OCV_SUNPRT);
+
+ sresult = ldap_search_s(ld, (char *)printerDN,
+ LDAP_SCOPE_SUBTREE, filter,
+ requiredAttrs, 0, &ldapMsg);
+ if (sresult == LDAP_SUCCESS)
+ {
+ /* check that the printer object exists */
+
+ ldapEntry = ldap_first_entry(ld, ldapMsg);
+ if (ldapEntry != NULL)
+ {
+ /* object is a sunPrinter */
+ result = NSL_OK;
+ }
+
+ (void) ldap_msgfree(ldapMsg);
+ }
+ }
+
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return (result);
+} /* _checkSunPrinter */
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _addNewPrinterObject()
+ *
+ * Description: For the given printerName add a printer object into the
+ * LDAP directory NS domain. The object is created with the
+ * supplied attribute values. Note: if the printer's uri is
+ * given that is used as the RDN otherwise the printer's
+ * name is used as the RDN
+ *
+ * Parameters:
+ * Input: LDAP *ld - existing ldap connection descriptor
+ * uchar_t *printerName - Name of printer to be added
+ * uchar_t *domainDN - DN of the domain to add the printer
+ * char **attrList - user specified attribute values list
+ * Output: None
+ *
+ * Returns: NSL_RESULT - NSL_OK = request actioned okay
+ * !NSL_OK = error
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_addNewPrinterObject(LDAP *ld, uchar_t *printerName,
+ uchar_t *domainDN, char **attrList)
+
+{
+ NSL_RESULT result = NSL_ERR_ADD_FAILED;
+ int lresult = 0;
+ uchar_t *printerDN = NULL;
+ LDAPMod **attrs = NULL;
+
+ /* ---------- */
+
+ if ((ld != NULL) && (printerName != NULL) && (domainDN != NULL) &&
+ (attrList != NULL) && (attrList[0] != NULL))
+ {
+ result = _checkAttributes(attrList);
+
+ if (result == NSL_OK)
+ {
+ /*
+ * construct a DN for the printer from the
+ * printerName and printer-uri if given.
+ */
+ printerDN = _constructPrinterDN(printerName,
+ domainDN, attrList);
+ if (printerDN != NULL)
+ {
+ /*
+ * setup attribute values in an LDAPMod
+ * structure and then add the object
+ */
+ result = _constructAddLDAPMod(printerName,
+ attrList, &attrs);
+ if (result == NSL_OK)
+ {
+ lresult = ldap_add_s(ld,
+ (char *)printerDN, attrs);
+ if (lresult == LDAP_SUCCESS)
+ {
+ result = NSL_OK;
+ }
+ else
+ {
+ result = NSL_ERR_ADD_FAILED;
+#ifdef DEBUG
+(void) ldap_perror(ld, "ldap_add_s");
+#endif
+ }
+
+ (void) ldap_mods_free(attrs, 1);
+ }
+ free(printerDN);
+ }
+
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+ }
+ }
+
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return (result);
+} /* _addNewPrinterObject */
+
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _modifyPrinterObject()
+ *
+ * Description: Modify the given LDAP printer object to set the new attributes
+ * in the attribute list. If the printer's URI (specified in the
+ * attrList) changes the URI of the object the request is rejected.
+ *
+ * Parameters:
+ * Input: LDAP *ld - existing ldap connection descriptor
+ * uchar_t *printerDN - DN of printer object to modify
+ * uchar_t *printerName - Name of printer to be modified
+ * uchar_t *domainDN - DN of the domain the printer is in
+ * char **attrList - user specified attribute values list
+ * Output: None
+ *
+ * Returns: NSL_RESULT - NSL_OK = object modified okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_modifyPrinterObject(LDAP *ld, uchar_t *printerDN,
+ uchar_t *printerName, uchar_t *domainDN, char **attrList)
+
+{
+ NSL_RESULT result = NSL_ERR_INTERNAL;
+ int lresult = 0;
+ int sunPrinter = 0;
+ uchar_t *uriDN = NULL;
+ LDAPMod **attrs = NULL;
+ char **kvpList = NULL;
+
+ /* ---------- */
+
+ if ((ld != NULL) && (printerDN != NULL) && (printerName != NULL) &&
+ (domainDN != NULL) && (attrList != NULL) && (attrList[0] != NULL))
+ {
+ result = _checkAttributes(attrList);
+
+ if (result == NSL_OK)
+ {
+ /*
+ * The user may have requested that the printer object
+ * be given a new URI RDN, so construct a DN for the
+ * printer from the printerName or the printer-uri (if
+ * given).
+ */
+ uriDN = _constructPrinterDN(NULL, domainDN, attrList);
+
+ /*
+ * compare the 2 DNs to see if the URI has changed,
+ * if uriDN is null then the DN hasn't changed
+ */
+ if ((uriDN == NULL) || ((uriDN != NULL) &&
+ (_compareURIinDNs(printerDN, uriDN) == NSL_OK)))
+ {
+ /*
+ * setup the modify object LDAPMod
+ * structure and then do the modify
+ */
+
+ if (_checkSunPrinter(ld, printerDN) == NSL_OK)
+ {
+ sunPrinter = 1;
+ }
+
+ (void) _getCurrentKVPValues(ld,
+ printerDN, &kvpList);
+
+ result = _constructModLDAPMod(printerName,
+ sunPrinter, attrList,
+ &kvpList, &attrs);
+ _freeList(&kvpList);
+
+ if ((result == NSL_OK) && (attrs != NULL))
+ {
+ lresult = ldap_modify_s(
+ ld, (char *)printerDN, attrs);
+ if (lresult == LDAP_SUCCESS)
+ {
+ result = NSL_OK;
+ }
+ else
+ {
+ result = NSL_ERR_MOD_FAILED;
+#ifdef DEBUG
+(void) ldap_perror(ld, "ldap_modify_s");
+#endif
+ }
+
+ (void) ldap_mods_free(attrs, 1);
+ }
+ }
+ else
+ {
+ /*
+ * printer-uri name change has been requested
+ * this is NOT allowed as it requires that
+ * a new printer object is created
+ */
+ result = NSL_ERR_RENAME; /* NOT ALLOWED */
+ }
+
+ if (uriDN != NULL)
+ {
+ free(uriDN);
+ }
+ }
+ }
+
+ return (result);
+} /* _modifyPrinterObject */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _checkAttributes()
+ *
+ * Description: Check that the given attribute lists does not contain any
+ * key words that are not allowed.
+ *
+ * Parameters:
+ * Input: char **list - attribute list to check
+ * Output: None
+ *
+ * Returns: NSL_RESULT - NSL_OK = checked okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_checkAttributes(char **list)
+
+{
+ NSL_RESULT result = NSL_OK;
+ int len = 0;
+ char *attr = NULL;
+ char **p = NULL;
+
+ /* ------ */
+
+ for (p = list; (p != NULL) && (*p != NULL) && (result == NSL_OK); p++)
+ {
+ /* get length of this key word */
+
+ for (len = 0; ((*p)[len] != '=') && ((*p)[len] != '\0'); len++);
+
+ /* check if the key word is allowed */
+
+ if (strncasecmp(*p, ATTR_KVP, len) == 0)
+ {
+ /* not supported through this interface */
+ result = NSL_ERR_KVP;
+ }
+ else
+ if (strncasecmp(*p, ATTR_BSDADDR, len) == 0)
+ {
+ /* not supported through this interface */
+ result = NSL_ERR_BSDADDR;
+ }
+ else
+ if (strncasecmp(*p, ATTR_PNAME, len) == 0)
+ {
+ /* not supported through this interface */
+ result = NSL_ERR_PNAME;
+ }
+ else
+ {
+ /* check for any others */
+
+ attr = strdup(*p);
+ attr[len] = '\0'; /* terminate the key */
+
+ if (_attrInList(attr, nsl_attr_notAllowed))
+ {
+ result = NSL_ERR_NOTALLOWED;
+ }
+ }
+
+ }
+
+ return (result);
+} /* _checkAttributes */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _addLDAPmodValue()
+ *
+ * Description: Add the given attribute and its value to the LDAPMod array.
+ * If this is the first entry in the array then create it.
+ *
+ * Parameters:
+ * Input: LDAPMod ***attrs - array to update
+ * char *type - attribute to add into array
+ * char *value - attribute value
+ * Output: None
+ *
+ * Returns: NSL_RESULT - NSL_OK = added okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_addLDAPmodValue(LDAPMod ***attrs, char *type, char *value)
+
+{
+ int i = 0;
+ int j = 0;
+ NSL_RESULT result = NSL_OK;
+
+ /* ---------- */
+
+ if ((attrs != NULL) && (type != NULL) && (value != NULL))
+ {
+#ifdef DEBUG
+printf("_addLDAPmodValue() type='%s', value='%s'\n", type, value);
+#endif
+ /* search the existing LDAPMod array for the attribute */
+
+ for (i = 0; *attrs != NULL && (*attrs)[i] != NULL; i++)
+ {
+ if (strcasecmp((*attrs)[i]->mod_type, type) == 0)
+ {
+ break;
+ }
+ }
+
+ if (*attrs == NULL)
+ {
+ /* array empty so create it */
+
+ *attrs = (LDAPMod **)calloc(1, 2 * sizeof (LDAPMod *));
+ if (*attrs != NULL)
+ {
+ i = 0;
+ }
+ else
+ {
+ result = NSL_ERR_MEMORY;
+ }
+
+ }
+ else
+ if ((*attrs)[i] == NULL)
+ {
+ *attrs = (LDAPMod **)
+ realloc(*attrs, (i+2) * sizeof (LDAPMod *));
+ if (*attrs == NULL)
+ {
+ result = NSL_ERR_MEMORY;
+ }
+ }
+ }
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ if (result == NSL_OK)
+ {
+ if ((*attrs)[i] == NULL)
+ {
+ /* We've got a new slot. Create the new mod. */
+
+ (*attrs)[i] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ if ((*attrs)[i] != NULL)
+ {
+ (*attrs)[i]->mod_op = LDAP_MOD_ADD;
+ (*attrs)[i]->mod_type = strdup(type);
+ (*attrs)[i]->mod_values = (char **)
+ malloc(2 * sizeof (char *));
+ if ((*attrs)[i]->mod_values != NULL)
+ {
+ (*attrs)[i]->mod_values[0] =
+ strdup(value);
+ (*attrs)[i]->mod_values[1] = NULL;
+ (*attrs)[i+1] = NULL;
+ }
+ else
+ {
+ result = NSL_ERR_MEMORY;
+ }
+ }
+ else
+ {
+ result = NSL_ERR_MEMORY;
+ }
+ }
+
+ else
+ {
+ /* Found an existing entry so add value to it */
+
+ for (j = 0; (*attrs)[i]->mod_values[j] != NULL; j++);
+
+ (*attrs)[i]->mod_values =
+ (char **)realloc((*attrs)[i]->mod_values,
+ (j + 2) * sizeof (char *));
+ if ((*attrs)[i]->mod_values != NULL)
+ {
+ (*attrs)[i]->mod_values[j] = strdup(value);
+ (*attrs)[i]->mod_values[j+1] = NULL;
+ }
+ else
+ {
+ result = NSL_ERR_MEMORY;
+ }
+ }
+ }
+
+ return (result);
+} /* _addLDAPmodValue */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _modLDAPmodValue()
+ *
+ * Description: Add the given attribute modify operation and its value into
+ * the LDAPMod array. This will either be a "replace" or a
+ * "delete"; value = null implies a "delete".
+ * If this is the first entry in the array then create it.
+ *
+ * Parameters:
+ * Input: LDAPMod ***attrs - array to update
+ * char *type - attribute to modify
+ * char *value - attribute value, null implies "delete"
+ * Output: None
+ *
+ * Returns: NSL_RESULT - NSL_OK = added okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_modLDAPmodValue(LDAPMod ***attrs, char *type, char *value)
+
+{
+ int i = 0;
+ int j = 0;
+ NSL_RESULT result = NSL_OK;
+
+ /* ---------- */
+
+ if ((attrs != NULL) && (type != NULL))
+ {
+#ifdef DEBUG
+if (value != NULL)
+printf("_modLDAPmodValue() REPLACE type='%s', value='%s'\n", type, value);
+else
+printf("_modLDAPmodValue() DELETE type='%s'\n", type);
+#endif
+ /* search the existing LDAPMod array for the attribute */
+
+ for (i = 0; *attrs != NULL && (*attrs)[i] != NULL; i++)
+ {
+ if (strcasecmp((*attrs)[i]->mod_type, type) == 0)
+ {
+ break;
+ }
+ }
+
+ if (*attrs == NULL)
+ {
+ /* array empty so create it */
+
+ *attrs = (LDAPMod **)calloc(1, 2 * sizeof (LDAPMod *));
+ if (*attrs != NULL)
+ {
+ i = 0;
+ }
+ else
+ {
+ result = NSL_ERR_MEMORY;
+ }
+
+ }
+ else
+ if ((*attrs)[i] == NULL)
+ {
+ /* attribute not found in array so add slot for it */
+
+ *attrs = (LDAPMod **)
+ realloc(*attrs, (i+2) * sizeof (LDAPMod *));
+ if (*attrs == NULL)
+ {
+ result = NSL_ERR_MEMORY;
+ }
+ }
+ }
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ if (result == NSL_OK)
+ {
+ if ((*attrs)[i] == NULL)
+ {
+ /* We've got a new slot. Create the new mod entry */
+
+ (*attrs)[i] = (LDAPMod *) malloc(sizeof (LDAPMod));
+ if (((*attrs)[i] != NULL) && (value != NULL))
+ {
+ /* Do an attribute replace */
+
+ (*attrs)[i]->mod_op = LDAP_MOD_REPLACE;
+ (*attrs)[i]->mod_type = strdup(type);
+ (*attrs)[i]->mod_values = (char **)
+ malloc(2 * sizeof (char *));
+ if ((*attrs)[i]->mod_values != NULL)
+ {
+ (*attrs)[i]->mod_values[0] =
+ strdup(value);
+ (*attrs)[i]->mod_values[1] = NULL;
+ (*attrs)[i+1] = NULL;
+ }
+ else
+ {
+ result = NSL_ERR_MEMORY;
+ }
+ }
+ else
+ if ((*attrs)[i] != NULL)
+ {
+ /* value is null so do an attribute delete */
+
+ (*attrs)[i]->mod_op = LDAP_MOD_DELETE;
+ (*attrs)[i]->mod_type = strdup(type);
+ (*attrs)[i]->mod_values = NULL;
+ (*attrs)[i+1] = NULL;
+ }
+ else
+ {
+ result = NSL_ERR_MEMORY; /* malloc failed */
+ }
+ }
+
+ else
+ {
+ /* Found an existing entry so add value to it */
+
+ if (value != NULL)
+ {
+ /* add value to attribute's replace list */
+
+ if ((*attrs)[i]->mod_op == LDAP_MOD_REPLACE)
+ {
+ for (j = 0;
+ (*attrs)[i]->mod_values[j] != NULL; j++);
+
+ (*attrs)[i]->mod_values =
+ (char **)realloc((*attrs)[i]->mod_values,
+ (j + 2) * sizeof (char *));
+ if ((*attrs)[i]->mod_values != NULL)
+ {
+ (*attrs)[i]->mod_values[j] =
+ strdup(value);
+ (*attrs)[i]->mod_values[j+1] = NULL;
+ }
+ else
+ {
+ result = NSL_ERR_MEMORY;
+ }
+ }
+ else
+ {
+ /* Delete and replace not allowed */
+ result = NSL_ERR_MULTIOP;
+ }
+ }
+
+ else
+ {
+ /*
+ * attribute delete - so free any existing
+ * entries in the value array
+ */
+
+ (*attrs)[i]->mod_op = LDAP_MOD_DELETE;
+
+ if ((*attrs)[i]->mod_values != NULL)
+ {
+ for (j = 0;
+ (*attrs)[i]->mod_values[j] != NULL;
+ j++)
+ {
+ free((*attrs)[i]->mod_values[j]);
+ }
+
+ free((*attrs)[i]->mod_values);
+ (*attrs)[i]->mod_values = NULL;
+ }
+ }
+ }
+ }
+
+ return (result);
+} /* _modLDAPmodValue */
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _constructAddLDAPMod()
+ *
+ * Description: For the given attribute list construct an
+ * LDAPMod array for the printer object to be added. Default
+ * attribute values are included.
+ *
+ * Parameters:
+ * Input:
+ * uchar_t *printerName - Name of printer to be added
+ * char **attrList - user specified attribute values list
+ * Output: LDAPMod ***attrs - pointer to the constructed array
+ *
+ * Returns: NSL_RESULT - NSL_OK = constructed okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_constructAddLDAPMod(uchar_t *printerName, char **attrList, LDAPMod ***attrs)
+
+{
+ NSL_RESULT result = NSL_ERROR;
+ int len = 0;
+ char **p = NULL;
+ char *value = NULL;
+ char *attr = NULL;
+
+ /* ---------- */
+
+ if ((printerName != NULL) &&
+ ((attrList != NULL) && (attrList[0] != NULL)) && (attrs != NULL))
+ {
+ *attrs = NULL;
+
+ /*
+ * setup printer object attribute values in an LDAPMod structure
+ */
+ result = _addLDAPmodValue(attrs, ATTR_OCLASS, OCV_TOP);
+ if (result == NSL_OK)
+ {
+ /* Structural Objectclass */
+ result =
+ _addLDAPmodValue(attrs, ATTR_OCLASS, OCV_PSERVICE);
+ }
+ if (result == NSL_OK)
+ {
+ result = _addLDAPmodValue(attrs,
+ ATTR_OCLASS, OCV_PABSTRACT);
+ }
+ if (result == NSL_OK)
+ {
+ result = _addLDAPmodValue(attrs,
+ ATTR_OCLASS, OCV_SUNPRT);
+ }
+ if (result == NSL_OK)
+ {
+ result = _addLDAPmodValue(attrs,
+ ATTR_PNAME, (char *)printerName);
+ }
+
+ /*
+ * Now work through the user supplied attribute
+ * values list and add them into the LDAPMod array
+ */
+
+ for (p = attrList;
+ (p != NULL) && (*p != NULL) && (result == NSL_OK); p++)
+ {
+ /* get length of this key word */
+
+ for (len = 0;
+ ((*p)[len] != '=') && ((*p)[len] != '\0'); len++);
+
+ if ((strlen(*p) > len+1))
+ {
+ attr = strdup(*p);
+ attr[len] = '\0';
+ value = strdup(&attr[len+1]);
+
+ /* handle specific Key Value Pairs (KVP) */
+
+ if (strcasecmp(attr, NS_KEY_BSDADDR) == 0)
+ {
+ /* use LDAP attribute name */
+ free(attr);
+ attr = strdup(ATTR_BSDADDR);
+ }
+ else
+ if (_attrInLDAPList(attr) == 0)
+ {
+ /*
+ * Non-LDAP attribute so use LDAP
+ * KVP attribute and the given KVP
+ * as the value, ie.
+ * sun-printer-kvp=description=printer
+ */
+ free(attr);
+ attr = strdup(ATTR_KVP);
+ value = strdup(*p);
+ }
+
+ /* add it into the LDAPMod array */
+
+ result = _addLDAPmodValue(attrs, attr, value);
+
+ free(attr);
+ free(value);
+ }
+ } /* for */
+
+ if ((result != NSL_OK) && (*attrs != NULL))
+ {
+ (void) ldap_mods_free(*attrs, 1);
+ attrs = NULL;
+ }
+ }
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return (result);
+} /* _constructAddLDAPMod */
+
+
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _constructModLDAPMod()
+ *
+ * Description: For the given modify attribute list, construct an
+ * LDAPMod array for the printer object to be modified
+ *
+ * Parameters:
+ * Input: uchar_t *printerName - name of printer to be modified
+ * int sunPrinter - Boolean; object is a sunPrinter
+ * char **attrList - user specified attribute values list
+ * char ***oldKVPList - current list of KVP values on object
+ * Output: LDAPMod ***attrs - pointer to the constructed array
+ *
+ * Returns: NSL_RESULT - NSL_OK = constructed okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_constructModLDAPMod(uchar_t *printerName, int sunPrinter, char **attrList,
+ char ***oldKVPList, LDAPMod ***attrs)
+
+{
+ NSL_RESULT result = NSL_OK;
+ int len = 0;
+ int kvpUpdated = 0;
+ int kvpExists = 0;
+ char **p = NULL;
+ char *value = NULL;
+ char *attr = NULL;
+
+ /* ---------- */
+
+ if ((printerName != NULL) &&
+ ((attrList != NULL) && (attrList[0] != NULL)) && (attrs != NULL))
+ {
+ *attrs = NULL;
+
+ if ((oldKVPList != NULL) && (*oldKVPList != NULL))
+ {
+ kvpExists = 1;
+ }
+
+ if (!sunPrinter)
+ {
+ /*
+ * The object was previously not a sunPrinter, so
+ * add the required objectclass attribute value, and
+ * ensure it has the printername attribute.
+ */
+ result = _addLDAPmodValue(attrs,
+ ATTR_OCLASS, OCV_SUNPRT);
+ if (result == NSL_OK)
+ {
+ result = _modLDAPmodValue(attrs,
+ ATTR_PNAME, (char *)printerName);
+ }
+ }
+
+ /*
+ * work through the user supplied attribute
+ * values list and add them into the LDAPMod array depending
+ * on if they are a replace or delete attribute operation,
+ * a "null value" means delete.
+ */
+
+ for (p = attrList;
+ (p != NULL) && (*p != NULL) && (result == NSL_OK); p++)
+ {
+ /* get length of this key word */
+
+ for (len = 0;
+ ((*p)[len] != '=') && ((*p)[len] != '\0'); len++);
+
+ if ((strlen(*p) > len+1))
+ {
+ attr = strdup(*p);
+ attr[len] = '\0';
+ value = strdup(&attr[len+1]);
+
+ /* handle specific Key Value Pairs (KVP) */
+
+ if ((_attrInLDAPList(attr) == 0) &&
+ (strcasecmp(attr, NS_KEY_BSDADDR) != 0))
+ {
+ /*
+ * Non-LDAP attribute so use LDAP
+ * KVP attribute and the given KVP as
+ * the value, ie.
+ * sun-printer-kvp=description=printer
+ */
+ result = _modAttrKVP(*p, oldKVPList);
+ kvpUpdated = 1;
+ }
+
+ else
+ {
+ if (strcasecmp(attr, NS_KEY_BSDADDR) ==
+ 0)
+ {
+ /*
+ * use LDAP bsdaddr attribute
+ * name
+ */
+ free(attr);
+ attr = strdup(ATTR_BSDADDR);
+ }
+
+ /*
+ * else
+ * use the supplied attribute name
+ */
+
+ /* add it into the LDAPMod array */
+
+ result = _modLDAPmodValue(attrs,
+ attr, value);
+ }
+
+ free(attr);
+ free(value);
+ }
+
+ else
+ if (strlen(*p) >= 1)
+ {
+ /* handle attribute DELETE request */
+
+ attr = strdup(*p);
+ if (attr[len] == '=')
+ {
+ /* terminate "attribute=" */
+ attr[len] = '\0';
+ }
+
+ /* handle specific Key Value Pairs (KVP) */
+
+ if (strcasecmp(attr, NS_KEY_BSDADDR) == 0)
+ {
+ /* use LDAP bsdaddr attribute name */
+ result = _modLDAPmodValue(attrs,
+ ATTR_BSDADDR, NULL);
+ }
+ else
+ if (_attrInLDAPList(attr) == 0)
+ {
+ /*
+ * Non-LDAP kvp, so sort items
+ * in the kvp list
+ */
+ result = _modAttrKVP(*p, oldKVPList);
+ kvpUpdated = 1;
+ }
+ else
+ {
+ result = _modLDAPmodValue(attrs,
+ attr, NULL);
+ }
+
+ free(attr);
+ }
+ } /* for */
+
+ if ((result == NSL_OK) && (kvpUpdated))
+ {
+ result = _attrAddKVP(attrs, *oldKVPList, kvpExists);
+ }
+
+ if ((result != NSL_OK) && (*attrs != NULL))
+ {
+ (void) ldap_mods_free(*attrs, 1);
+ *attrs = NULL;
+ }
+ }
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return (result);
+} /* _constructModLDAPMod */
+
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _compareURIinDNs()
+ *
+ * Description: For the 2 given printer object DNs compare the naming part
+ * part of the DN (printer-uri) to see if they are the same.
+ *
+ * Note: This function only returns "compare failed" if their URI don't
+ * compare. Problems with the dn etc., return a good compare
+ * because I don't want us to create a new object for these
+ *
+ * Parameters:
+ * Input: uchar_t *dn1
+ * uchar_t *dn2
+ * Output: None
+ *
+ * Returns: NSL_RESULT - NSL_OK = URIs are the same
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_compareURIinDNs(uchar_t *dn1, uchar_t *dn2)
+
+{
+ NSL_RESULT result = NSL_OK;
+ uchar_t *DN1 = NULL;
+ uchar_t *DN2 = NULL;
+ char *p1 = NULL;
+ char *p2 = NULL;
+
+ /* --------- */
+
+ if ((dn1 != NULL) && (dn2 != NULL))
+ {
+ DN1 = (uchar_t *)strdup((char *)dn1);
+ DN2 = (uchar_t *)strdup((char *)dn2);
+
+ /* terminate each string after the printer-uri */
+
+ p1 = strstr((char *)DN1, PCONTAINER);
+ /* move back to the comma */
+ while ((p1 != NULL) && (*p1 != ',') && (p1 >= (char *)DN1))
+ {
+ p1--;
+ }
+
+ p2 = strstr((char *)DN2, PCONTAINER);
+ /* move back to the comma */
+ while ((p2 != NULL) && (*p2 != ',') && (p2 >= (char *)DN2))
+ {
+ p2--;
+ }
+
+ if ((*p1 == ',') && (*p2 == ','))
+ {
+ *p1 = '\0'; /* re-terminate it */
+ *p2 = '\0'; /* re-terminate it */
+
+ /* do the compare */
+
+ /*
+ * Note: SHOULD really normalise the 2 DNs before
+ * doing the compare
+ */
+#ifdef DEBUG
+printf("_compareURIinDNs() @1 (%s) (%s)\n", DN1, DN2);
+#endif
+ if (strcasecmp((char *)DN1, (char *)DN2) != 0)
+ {
+ result = NSL_ERROR;
+ }
+
+ }
+
+ free(DN1);
+ free(DN2);
+ }
+
+ return (result);
+} /* _compareURIinDNs */
+
+
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _getThisNSDomainDN()
+ *
+ * Description: Get the current Name Service Domain DN
+ * This is extracted from the result of executing ldaplist.
+ *
+ * Note: Do it this way until the NS LDAP library interface is
+ * made public.
+ *
+ * Parameters:
+ * Input: None
+ * Output: None
+ *
+ * Returns: uchar_t* - pointer to NS Domain DN (The caller should free this
+ * returned memory).
+ *
+ * *****************************************************************************
+ */
+
+#define LDAPLIST_D "/usr/bin/ldaplist -d 2>&1"
+#define DNID "dn: "
+
+static uchar_t *
+_getThisNSDomainDN(void)
+
+{
+ uchar_t *domainDN = NULL;
+ char *cp = NULL;
+ char buf[BUFSIZ] = "";
+
+ /* --------- */
+
+ if (_popen(LDAPLIST_D, buf, sizeof (buf)) == 0)
+ {
+ if ((cp = strstr(buf, DNID)) != NULL)
+ {
+ cp += strlen(DNID); /* increment past "dn: " label */
+ domainDN = (uchar_t *)strdup(cp);
+
+ if ((cp = strchr((char *)domainDN, '\n')) != NULL)
+ {
+ *cp = '\0'; /* terminate it */
+ }
+ }
+ }
+
+ return (domainDN);
+} /* _getThisNSDomainDN */
+
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _popen()
+ *
+ * Description: General popen function. The caller should always use a full
+ * path cmd.
+ *
+ * Parameters:
+ * Input: char *cmd - command line to execute
+ * char *buffer - ptr to buffer to put result in
+ * int size - size of result buffer
+ * Output: None
+ *
+ * Returns: int - 0 = opened okay
+ *
+ * *****************************************************************************
+ */
+
+static int
+_popen(char *cmd, char *buffer, int size)
+
+{
+ int result = -1;
+ int rsize = 0;
+ FILE *fptr;
+ char safe_cmd[BUFSIZ];
+ char linebuf[BUFSIZ];
+
+ /* -------- */
+
+ if ((cmd != NULL) && (buffer != NULL) && (size != 0))
+ {
+ (void) strcpy(buffer, "");
+ (void) strcpy(linebuf, "");
+ (void) snprintf(safe_cmd, BUFSIZ, "IFS=' \t'; %s", cmd);
+
+ if ((fptr = popen(safe_cmd, "r")) != NULL)
+ {
+ while ((fgets(linebuf, BUFSIZ, fptr) != NULL) &&
+ (rsize < size))
+ {
+ rsize = strlcat(buffer, linebuf, size);
+ if (rsize >= size)
+ {
+ /* result is too long */
+ (void) memset(buffer, '\0', size);
+ }
+ }
+
+ if (strlen(buffer) > 0)
+ {
+ result = 0;
+ }
+
+ (void) pclose(fptr);
+ }
+ }
+
+ return (result);
+} /* popen */
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _attrInList()
+ *
+ * Description: For the given list check if the attribute is it
+ *
+ * Parameters:
+ * Input: char *attr - attribute to check
+ * char **list - list of attributes to check against
+ * Output: None
+ *
+ * Returns: int - TRUE = attr found in list
+ *
+ * *****************************************************************************
+ */
+
+static int
+_attrInList(char *attr, const char **list)
+
+{
+ int result = 0;
+ int j;
+
+ /* ------- */
+
+ if ((attr != NULL) && (list != NULL))
+ {
+ for (j = 0; (list[j] != NULL) && (result != 1); j++)
+ {
+ if (strcasecmp(list[j], attr) == 0)
+ {
+ result = 1; /* found */
+ }
+ }
+ }
+
+ return (result);
+} /* _attrInList */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _attrInLDAPList()
+ *
+ * Description: Checks to see if the given attribute is an LDAP printing
+ * attribute, ie. is either in an IPP objectclass or the
+ * sun printer objectclass. Note: some attributes are handled
+ * specifically outside this function, so are excluded from
+ * the lists that are checked.
+ *
+ * Parameters:
+ * Input: char *attr - attribute to check
+ * Output: None
+ *
+ * Returns: int - TRUE = attr found in list
+ *
+ * *****************************************************************************
+ */
+
+static int
+_attrInLDAPList(char *attr)
+
+{
+ int result = 0;
+
+ /* ------- */
+
+ if (_attrInList(attr, nsl_attr_printerService))
+ {
+ result = 1; /* in list */
+ }
+ else
+ if (_attrInList(attr, nsl_attr_printerIPP))
+ {
+ result = 1; /* in list */
+ }
+ else
+ if (_attrInList(attr, nsl_attr_sunPrinter))
+ {
+ result = 1; /* in list */
+ }
+
+ return (result);
+} /* _attrInLDAPList */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _getCurrentKVPValues()
+ *
+ * Description: For the given printer object read the current set of values
+ * the object has for the sun-printer-kvp (Key Value pair)
+ *
+ * Parameters:
+ * Input: LDAP *ld - existing ldap connection descriptor
+ * char *objectDN - DN to search for
+ * Output: char ***list - returned set of kvp values
+ *
+ * Result: NSL_RESULT - NSL_OK = object exists
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_getCurrentKVPValues(LDAP *ld, uchar_t *objectDN, char ***list)
+
+{
+ NSL_RESULT result = NSL_ERR_UNKNOWN_PRINTER;
+ int sresult = LDAP_NO_SUCH_OBJECT;
+ int i = 0;
+ LDAPMessage *ldapMsg;
+ char *requiredAttrs[2] = { ATTR_KVP, NULL };
+ LDAPMessage *ldapEntry = NULL;
+ char *entryAttrib = NULL;
+ char **attribValues = NULL;
+ BerElement *berElement = NULL;
+
+ /* ---------- */
+
+ if ((list != NULL) && (ld != NULL) && (objectDN != NULL))
+ {
+ /* search for this Printer in the directory */
+
+ sresult = ldap_search_s(ld, (char *)objectDN, LDAP_SCOPE_BASE,
+ "(objectclass=*)", requiredAttrs, 0, &ldapMsg);
+ if (sresult == LDAP_SUCCESS)
+ {
+ /*
+ * check that the object exists and extract its
+ * KVP attribute values
+ */
+ ldapEntry = ldap_first_entry(ld, ldapMsg);
+ if (ldapEntry != NULL)
+ {
+ entryAttrib = ldap_first_attribute(ld,
+ ldapEntry, &berElement);
+ if ((entryAttrib != NULL) &&
+ (strcasecmp(entryAttrib, ATTR_KVP) == 0))
+
+ {
+#ifdef DEBUG
+printf("Attribute: %s, its values are:\n", entryAttrib);
+#endif
+ /*
+ * add each KVP value to the list
+ * that we will return
+ */
+ attribValues = ldap_get_values(
+ ld, ldapEntry, entryAttrib);
+ for (i = 0;
+ attribValues[i] != NULL; i++)
+ {
+ *list = (char **)
+ list_append((void **)*list,
+ strdup(attribValues[i]));
+#ifdef DEBUG
+printf("\t%s\n", attribValues[i]);
+#endif
+ }
+ (void) ldap_value_free(attribValues);
+ }
+
+ if ((entryAttrib != NULL) &&
+ (berElement != NULL))
+ {
+ ber_free(berElement, 0);
+ }
+
+
+ /* object found */
+ result = NSL_OK;
+ }
+
+ (void) ldap_msgfree(ldapMsg);
+ }
+ }
+
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return (result);
+} /* _getCurrentKVPValues */
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _freeList()
+ *
+ * Description: Free the list created by list_append() where the items in
+ * the list have been strdup'ed.
+ *
+ * Parameters:
+ * Input: char ***list - returned set of kvp values
+ *
+ * Result: void
+ *
+ * *****************************************************************************
+ */
+
+static void
+_freeList(char ***list)
+
+{
+ int i = 0;
+
+ /* ------ */
+
+ if (list != NULL)
+ {
+ if (*list != NULL)
+ {
+ for (i = 0; (*list)[i] != NULL; i++)
+ {
+ free((*list)[i]);
+ }
+ free(*list);
+ }
+
+ *list = NULL;
+ }
+} /* _freeList */
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _modAttrKVP()
+ *
+ * Description: Sort out the KVP attribute value list, such that this new
+ * value takes precidence over any existing value in the list.
+ * The current list is updated to remove this key, and the new
+ * key "value" is added to the list, eg. for
+ * value: bbb=ddddd
+ * and kvpList:
+ * aaa=yyyy
+ * bbb=zzzz
+ * ccc=xxxx
+ * the resulting kvpList is:
+ * aaa=yyyy
+ * ccc=xxxx
+ * bbb=ddddd
+ *
+ * Note: When all new values have been handled the function _attrAddKVP()
+ * must be called to add the "new list" values into the
+ * LDAPMod array.
+ *
+ * Parameters:
+ * Input: char *value - Key Value Pair to process,
+ * eg. aaaaa=hhhhh, where aaaaa is the key
+ * char ***kvpList - list of current KVP values
+ * Output: char ***kvpList - updated list of KVP values
+ *
+ * Returns: NSL_RESULT - NSL_OK = done okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_modAttrKVP(char *value, char ***kvpList)
+
+{
+ NSL_RESULT result = NSL_ERR_INTERNAL;
+ int i = 0;
+ int inList = 0;
+ int keyDelete = 0;
+ char *key = NULL;
+ char **p = NULL;
+ char **newList = NULL;
+
+ /* ------- */
+
+ if ((value != NULL) && (kvpList != NULL))
+ {
+ result = NSL_OK;
+
+ /* extract "key" from value */
+
+ key = strdup(value);
+
+ for (i = 0; ((key)[i] != '=') && ((key)[i] != '\0'); i++);
+ key[i] = '\0'; /* terminate the key */
+
+ /* Is this a request to delete a "key" value */
+
+ if ((value[i] == '\0') || (value[i+1] == '\0'))
+ {
+ /* this is a request to delete the key */
+ keyDelete = 1;
+ }
+
+ if ((*kvpList != NULL) && (**kvpList != NULL))
+ {
+ /*
+ * for each item in the list remove it if the keys match
+ */
+ for (p = *kvpList; *p != NULL; p++)
+ {
+ for (i = 0;
+ ((*p)[i] != '=') && ((*p)[i] != '\0'); i++);
+
+ if ((strlen(key) == i) &&
+ (strncasecmp(*p, key, i) == 0))
+ {
+ inList = 1;
+ }
+ else
+ {
+ /* no match so add value to new list */
+ newList = (char **)list_append(
+ (void **)newList,
+ strdup(*p));
+ }
+ }
+ }
+
+ /*
+ * if it was not a DELETE request add the new key value into
+ * the newList, otherwise we have already removed the key
+ */
+
+ if (!keyDelete)
+ {
+ newList = (char **)list_append((void **)newList,
+ strdup(value));
+ }
+
+ if ((newList != NULL) || (inList))
+ {
+ /* replace old list with the newList */
+ _freeList(kvpList);
+ *kvpList = newList;
+ }
+
+ free(key);
+ }
+
+ return (result);
+} /* modAttrKVP */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _attrAddKVP()
+ *
+ * Description: Process KVP items in the kvpList adding them to the
+ * LDAPMod modify array. If the list is empty but there were
+ * previously LDAP KVP values delete them.
+ *
+ * Note: This function should only be called when all the new KVP
+ * items have been processed by _modAttrKVP()
+ *
+ * Parameters:
+ * Input: LDAPMod ***attrs - array to update
+ * char **kvpList - list KVP values
+ * int kvpExists - object currently has LDAP KVP values
+ * Output: None
+ *
+ * Returns: NSL_RESULT - NSL_OK = done okay
+ *
+ * *****************************************************************************
+ */
+
+static NSL_RESULT
+_attrAddKVP(LDAPMod ***attrs, char **kvpList, int kvpExists)
+
+{
+ NSL_RESULT result = NSL_OK;
+
+ /* ------- */
+
+ if (attrs != NULL)
+ {
+ if (kvpList != NULL)
+ {
+ while ((kvpList != NULL) && (*kvpList != NULL))
+ {
+ /* add item to LDAPMod array */
+
+ result =
+ _modLDAPmodValue(attrs, ATTR_KVP, *kvpList);
+
+ kvpList++;
+ }
+ }
+ else
+ if (kvpExists)
+ {
+ /*
+ * We now have no LDAP KVP values but there were
+ * some previously, so delete them
+ */
+ result = _modLDAPmodValue(attrs, ATTR_KVP, NULL);
+ }
+ }
+
+ else
+ {
+ result = NSL_ERR_INTERNAL;
+ }
+
+ return (result);
+} /* _attrAddKVP */
+
+
+
+
+/*
+ * *****************************************************************************
+ *
+ * Function: _manageReferralCredentials()
+ *
+ * Description: This function is called if a referral request is returned by
+ * the origonal LDAP server during the ldap update request call,
+ * eg. ldap_add_s(), ldap_modify_s() or ldap_delete_s().
+ * Parameters:
+ * Input: LDAP *ld - LDAP descriptor
+ * int freeit - 0 = first call to get details
+ * - 1 = second call to free details
+ * - -1 = initial store of authentication details
+ * Input/Output: char **dn - returns DN to bind to on master
+ * char **credp - returns password for DN
+ * int *methodp - returns authentication type, eg. simple
+ *
+ * Returns: int - 0 = okay
+ *
+ * *****************************************************************************
+ */
+static int _manageReferralCredentials(LDAP *ld, char **dn, char **credp,
+ int *methodp, int freeit)
+
+{
+ int result = 0;
+ static char *sDN = NULL;
+ static char *sPasswd = NULL;
+ static int sMethod = LDAP_AUTH_SIMPLE;
+
+ /* -------- */
+
+ if (freeit == 1)
+ {
+ /* second call - free memory */
+
+ if ((dn != NULL) && (*dn != NULL))
+ {
+ free(*dn);
+ }
+
+ if ((credp != NULL) && (*credp != NULL))
+ {
+ free(*credp);
+ }
+ }
+
+ else
+ if ((ld != NULL) &&
+ (dn != NULL) && (credp != NULL) && (methodp != NULL))
+ {
+ if ((freeit == 0) && (sDN != NULL) && (sPasswd != NULL))
+ {
+ /* first call - get the saved bind credentials */
+
+ *dn = strdup(sDN);
+ *credp = strdup(sPasswd);
+ *methodp = sMethod;
+ }
+ else
+ if (freeit == -1)
+ {
+ /* initial call - save the saved bind credentials */
+
+ sDN = *dn;
+ sPasswd = *credp;
+ sMethod = *methodp;
+ }
+ else
+ {
+ result = 1; /* error */
+ }
+ }
+ else
+ {
+ result = 1; /* error */
+ }
+
+ return (result);
+} /* _manageReferralCredentials */
diff --git a/usr/src/lib/print/libprint/common/nss_printer.c b/usr/src/lib/print/libprint/common/nss_printer.c
new file mode 100644
index 0000000000..149ddadd5c
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/nss_printer.c
@@ -0,0 +1,151 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <nss_dbdefs.h>
+#include <syslog.h>
+#include <ns.h>
+
+#ifndef NSS_DBNAM__PRINTERS /* not in nss_dbdefs.h because it's private */
+#define NSS_DBNAM__PRINTERS "_printers"
+#endif
+
+static DEFINE_NSS_DB_ROOT(db_root);
+static DEFINE_NSS_GETENT(context);
+
+static int printers_stayopen;
+static char *private_ns = NULL;
+
+static void
+_nss_initf_printers(p)
+ nss_db_params_t *p;
+{
+ if (private_ns != NULL) {
+ /*
+ * because we need to support a legacy interface that allows
+ * us to select a specific name service, we need to dummy up
+ * the parameters to use a private nsswitch database and set
+ * the * default_config entry to the name service we are
+ * looking into.
+ */
+ p->name = NSS_DBNAM__PRINTERS; /* "_printers" */
+ p->default_config = normalize_ns_name(private_ns);
+ } else {
+ /* regular behaviour */
+ p->name = NSS_DBNAM_PRINTERS; /* "printers" */
+ p->default_config = NSS_DEFCONF_PRINTERS;
+ }
+ syslog(LOG_DEBUG, "database: %s, default: %s",
+ (p->name ? p->name : "NULL"),
+ (p->default_config ? p->default_config : "NULL"));
+}
+
+/*
+ * Return values: 0 = success, 1 = parse error, 2 = erange ...
+ * The structure pointer passed in is a structure in the caller's space
+ * wherein the field pointers would be set to areas in the buffer if
+ * need be. instring and buffer should be separate areas.
+ */
+/* ARGSUSED */
+static int
+str2printer(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
+{
+ if (lenstr + 1 > buflen)
+ return (NSS_STR_PARSE_ERANGE);
+
+ /* skip entries that begin with '#' */
+ if (instr[0] == '#')
+ return (NSS_STR_PARSE_PARSE);
+
+ /*
+ * We copy the input string into the output buffer
+ */
+ (void) memcpy(buffer, instr, lenstr);
+ buffer[lenstr] = '\0';
+
+ return (NSS_STR_PARSE_SUCCESS);
+}
+
+
+int
+setprinterentry(int stayopen, char *ns)
+{
+ printers_stayopen |= stayopen;
+ private_ns = ns;
+ nss_setent(&db_root, _nss_initf_printers, &context);
+ private_ns = NULL;
+ return (0);
+}
+
+
+int
+endprinterentry()
+{
+ printers_stayopen = 0;
+ nss_endent(&db_root, _nss_initf_printers, &context);
+ nss_delete(&db_root);
+ private_ns = NULL;
+ return (0);
+}
+
+
+/* ARGSUSED2 */
+int
+getprinterentry(char *linebuf, int linelen, char *ns)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ private_ns = ns;
+ NSS_XbyY_INIT(&arg, linebuf, linebuf, linelen, str2printer);
+ res = nss_getent(&db_root, _nss_initf_printers, &context, &arg);
+ (void) NSS_XbyY_FINI(&arg);
+ private_ns = NULL;
+
+ return (arg.status = res);
+}
+
+
+int
+getprinterbyname(char *name, char *linebuf, int linelen, char *ns)
+{
+ nss_XbyY_args_t arg;
+ nss_status_t res;
+
+ private_ns = ns;
+ NSS_XbyY_INIT(&arg, linebuf, linebuf, linelen, str2printer);
+ arg.key.name = name;
+ res = nss_search(&db_root, _nss_initf_printers,
+ NSS_DBOP_PRINTERS_BYNAME, &arg);
+ (void) NSS_XbyY_FINI(&arg);
+ private_ns = NULL;
+
+ return (arg.status = res);
+}
diff --git a/usr/src/lib/print/libprint/common/nss_write.c b/usr/src/lib/print/libprint/common/nss_write.c
new file mode 100644
index 0000000000..c617f0d0a5
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/nss_write.c
@@ -0,0 +1,325 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <pwd.h>
+#include <libintl.h>
+#include <netdb.h> /* for rcmd() */
+
+#include <ns.h>
+#include <list.h>
+
+/* escaped chars include delimiters and shell meta characters */
+#define ESCAPE_CHARS "\\\n=: `&;|>^$()<*?["
+
+/*
+ * This modules contains all of the code nedessary to write back to each
+ * printing configuration data repository. The support is intended to
+ * introduce the least number of dependencies in the library, so it doesn't
+ * always perform it's operations in the cleanest fashion.
+ */
+
+
+/*
+ * Generic Files support begins here.
+ */
+static char *
+freadline(FILE *fp, char *buf, int buflen)
+{
+ char *s = buf;
+
+ while (fgets(s, buflen, fp)) {
+ if ((s == buf) && ((*s == '#') || (*s == '\n'))) {
+ continue;
+ } else {
+ if ((*s == '#') || (*s == '\n')) {
+ *s = NULL;
+ break;
+ }
+
+ buflen -= strlen(s);
+ s += strlen(s);
+
+ if (*(s - 2) != '\\')
+ break;
+#ifdef STRIP_CONTINUATION
+ buflen -= 2;
+ s -= 2;
+#endif
+ }
+ }
+
+ if (s == buf)
+ return (NULL);
+ else
+ return (buf);
+}
+
+
+static int
+_file_put_printer(const char *file, const ns_printer_t *printer)
+{
+ FILE *ifp,
+ *ofp;
+ char *tmpfile;
+ int fd;
+ int exit_status = 0;
+ int size;
+
+ size = strlen(file) + 1 + 20;
+ if ((tmpfile = malloc(size)) == NULL)
+ return (-1);
+
+ if (snprintf(tmpfile, size, "%sXXXXXX", file) >= size) {
+ syslog(LOG_ERR, "_file_put_printer:buffer overflow:tmpfile");
+ return (-1);
+ }
+
+ /* LINTED */
+ while (1) { /* syncronize writes */
+ fd = open(file, O_RDWR|O_CREAT|O_EXCL, 0644);
+ if ((fd < 0) && (errno == EEXIST))
+ fd = open(file, O_RDWR);
+ if (fd < 0) {
+ if (errno == EAGAIN)
+ continue;
+ free(tmpfile);
+ return (-1);
+ }
+ if (lockf(fd, F_TLOCK, 0) == 0)
+ break;
+ (void) close(fd);
+ }
+
+ if ((ifp = fdopen(fd, "r")) == NULL) {
+ (void) close(fd);
+ free(tmpfile);
+ return (-1);
+ }
+
+ if ((fd = mkstemp(tmpfile)) < 0) {
+ (void) fclose(ifp);
+ free(tmpfile);
+ return (-1);
+ }
+
+ (void) fchmod(fd, 0644);
+ if ((ofp = fdopen(fd, "wb+")) != NULL) {
+ char buf[4096];
+
+ (void) fprintf(ofp,
+ "#\n#\tIf you hand edit this file, comments and structure may change.\n"
+ "#\tThe preferred method of modifying this file is through the use of\n"
+ "#\tlpset(1M)\n#\n");
+
+ /*
+ * Handle the special case of lpset -x all
+ * This deletes all entries in the file
+ * In this case, just don't write any entries to the tmpfile
+ */
+
+ if (!((strcmp(printer->name, "all") == 0) &&
+ (printer->attributes == NULL))) {
+ char *t, *entry, *pentry;
+
+ (void) _cvt_printer_to_entry((ns_printer_t *)printer,
+ buf, sizeof (buf));
+ t = pentry = strdup(buf);
+
+ while (freadline(ifp, buf, sizeof (buf)) != NULL) {
+ ns_printer_t *tmp = (ns_printer_t *)
+ _cvt_nss_entry_to_printer(buf, "");
+
+ if (ns_printer_match_name(tmp, printer->name)
+ == 0) {
+ entry = pentry;
+ pentry = NULL;
+ } else
+ entry = buf;
+
+ (void) fprintf(ofp, "%s\n", entry);
+ }
+
+ if (pentry != NULL)
+ (void) fprintf(ofp, "%s\n", pentry);
+ free(t);
+ }
+
+ (void) fclose(ofp);
+ (void) rename(tmpfile, file);
+ } else {
+ (void) close(fd);
+ (void) unlink(tmpfile);
+ exit_status = -1;
+ }
+
+ (void) fclose(ifp); /* releases the lock, after rename on purpose */
+ (void) free(tmpfile);
+ return (exit_status);
+}
+
+
+/*
+ * Support for writing a printer into the FILES /etc/printers.conf
+ * file.
+ */
+int
+files_put_printer(const ns_printer_t *printer)
+{
+ static char *file = "/etc/printers.conf";
+
+ return (_file_put_printer(file, printer));
+}
+
+/*
+ * Support for writing a printer into the NIS printers.conf.byname
+ * map.
+ */
+
+#include <rpc/rpc.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yp_prot.h>
+
+/*
+ * Run the remote command. We aren't interested in any io, Only the
+ * return code.
+ */
+static int
+remote_command(char *command, char *host)
+{
+ struct passwd *pw;
+
+ if ((pw = getpwuid(getuid())) != NULL) {
+ int fd;
+
+ if ((fd = rcmd_af(&host, htons(514), pw->pw_name, "root",
+ command, NULL, AF_INET6)) < 0)
+ return (-1);
+ (void) close(fd);
+ return (0);
+ } else
+ return (-1);
+}
+
+
+/*
+ * This isn't all that pretty, but you can update NIS if the machine this
+ * runs on is in the /.rhosts or /etc/hosts.equiv on the NIS master.
+ * copy it local, update it, copy it remote
+ */
+#define TMP_PRINTERS_FILE "/tmp/printers.NIS"
+#define NIS_MAKEFILE "/var/yp/Makefile"
+#define MAKE_EXCERPT "/usr/lib/print/Makefile.yp"
+/*ARGSUSED*/
+int
+nis_put_printer(const ns_printer_t *printer)
+{
+ static char *domain = NULL;
+ char *map = "printers.conf.byname";
+ char *tmp = NULL;
+ char *host = NULL;
+ char lfile[BUFSIZ];
+ char rfile[BUFSIZ];
+ char cmd[BUFSIZ];
+
+ if (domain == NULL)
+ (void) yp_get_default_domain(&domain);
+
+ if ((yp_master(domain, (char *)map, &host) != 0) &&
+ (yp_master(domain, "passwd.byname", &host) != 0))
+ return (-1);
+
+ if (snprintf(lfile, sizeof (lfile), "/tmp/%s", map) >=
+ sizeof (lfile)) {
+ syslog(LOG_ERR, "nis_put_printer:lfile buffer overflow");
+ return (-1);
+ }
+ if (snprintf(rfile, sizeof (rfile), "root@%s:/etc/%s", host, map) >=
+ sizeof (rfile)) {
+ syslog(LOG_ERR, "nis_put_printer:rfile buffer overflow");
+ return (-1);
+ }
+
+ if (((tmp = strrchr(rfile, '.')) != NULL) &&
+ (strcmp(tmp, ".byname") == 0))
+ *tmp = NULL; /* strip the .byname */
+
+ /* copy it local */
+ if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1",
+ rfile, lfile) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nis_put_printer:buffer overflow building cmd");
+ return (-1);
+ }
+ (void) system(cmd); /* could fail because it doesn't exist */
+
+
+ /* update it */
+ if (_file_put_printer(lfile, printer) != 0)
+ return (-1);
+
+ /* copy it back */
+ if (snprintf(cmd, sizeof (cmd), "rcp %s %s >/dev/null 2>&1",
+ lfile, rfile) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nis_put_printer:buffer overflow building cmd");
+ return (-1);
+ }
+ if (system(cmd) != 0)
+ return (-1);
+
+ /* copy the Makefile excerpt */
+ if (snprintf(cmd, sizeof (cmd),
+ "rcp %s root@%s:%s.print >/dev/null 2>&1",
+ MAKE_EXCERPT, host, NIS_MAKEFILE) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nis_put_printer:buffer overflow building cmd");
+ return (-1);
+ }
+
+ if (system(cmd) != 0)
+ return (-1);
+
+ /* run the make */
+ if (snprintf(cmd, sizeof (cmd),
+ "/bin/sh -c 'PATH=/usr/ccs/bin:/bin:/usr/bin:$PATH "
+ "make -f %s -f %s.print printers.conf >/dev/null 2>&1'",
+ NIS_MAKEFILE, NIS_MAKEFILE) >= sizeof (cmd)) {
+ syslog(LOG_ERR,
+ "nis_put_printer:buffer overflow on make");
+ return (-1);
+ }
+
+ return (remote_command(cmd, host));
+}
diff --git a/usr/src/lib/print/libprint/common/sunPrinter.at.conf.txt b/usr/src/lib/print/libprint/common/sunPrinter.at.conf.txt
new file mode 100644
index 0000000000..0cac14ae95
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/sunPrinter.at.conf.txt
@@ -0,0 +1,64 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+# IPP Draft 4 schema and Sun Printer Schema
+
+attribute printer-uri 1.3.18.0.2.4.1140 cis single
+attribute printer-xri-supported 1.3.18.0.2.4.1107 cis
+attribute printer-name 1.3.18.0.2.4.1135 cis single
+attribute printer-natural-language-configured 1.3.18.0.2.4.1119 cis single
+attribute printer-location 1.3.18.0.2.4.1136 cis single
+attribute printer-info 1.3.18.0.2.4.1139 cis single
+attribute printer-more-info 1.3.18.0.2.4.1134 cis single
+attribute printer-make-and-model 1.3.18.0.2.4.1138 cis single
+attribute printer-ipp-versions-supported 1.3.18.0.2.4.1133 cis
+attribute printer-multiple-document-jobs-supported 1.3.18.0.2.4.1132 bin single
+attribute printer-charset-configured 1.3.18.0.2.4.1109 cis single
+attribute printer-charset-supported 1.3.18.0.2.4.1131 cis
+attribute printer-generated-natural-language-supported 1.3.18.0.2.4.1137 cis
+attribute printer-document-format-supported 1.3.18.0.2.4.1130 cis
+attribute printer-color-supported 1.3.18.0.2.4.1129 bin single
+attribute printer-compression-supported 1.3.18.0.2.4.1128 cis
+attribute printer-pages-per-minute 1.3.18.0.2.4.1127 bin single
+attribute printer-pages-per-minute-color 1.3.18.0.2.4.1126 bin single
+attribute printer-finishings-supported 1.3.18.0.2.4.1125 cis
+attribute printer-number-up-supported 1.3.18.0.2.4.1124 bin
+attribute printer-sides-supported 1.3.18.0.2.4.1123 cis
+attribute printer-media-supported 1.3.18.0.2.4.1122 cis
+attribute printer-media-local-supported 1.3.18.0.2.4.1117 cis
+attribute printer-resolution-supported 1.3.18.0.2.4.1121 cis
+attribute printer-print-quality-supported 1.3.18.0.2.4.1120 cis
+attribute printer-job-priority-supported 1.3.18.0.2.4.1110 bin single
+attribute printer-copies-supported 1.3.18.0.2.4.1118 bin single
+attribute printer-job-k-octets-supported 1.3.18.0.2.4.1111 bin single
+attribute printer-current-operator 1.3.18.0.2.4.1112 cis single
+attribute printer-service-person 1.3.18.0.2.4.1113 cis single
+attribute printer-delivery-orientation-supported 1.3.18.0.2.4.1114 cis
+attribute printer-stacking-order-supported 1.3.18.0.2.4.1115 cis
+attribute printer-output-features-supported 1.3.18.0.2.4.1116 cis
+attribute printer-aliases 1.3.18.0.2.4.1108 cis
+attribute sun-printer-bsdaddr 1.3.6.1.4.1.42.2.27.5.1.63 cis single
+attribute sun-printer-kvp 1.3.6.1.4.1.42.2.27.5.1.64 cis
diff --git a/usr/src/lib/print/libprint/common/sunPrinter.oc.conf.txt b/usr/src/lib/print/libprint/common/sunPrinter.oc.conf.txt
new file mode 100644
index 0000000000..77f365819d
--- /dev/null
+++ b/usr/src/lib/print/libprint/common/sunPrinter.oc.conf.txt
@@ -0,0 +1,116 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2001 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+
+# IPP Schema Draft 4 and Sun Printer Schema
+
+objectclass slpService
+ oid 1.3.18.0.2.6.2549
+ superior
+ top
+
+objectclass slpServicePrinter
+ oid 1.3.18.0.2.6.254
+ superior
+ slpService
+
+objectclass printerAbstract
+ oid 1.3.18.0.2.6.258
+ superior
+ top
+ allows
+ printer-charset-configured,
+ printer-charset-supported,
+ printer-color-supported,
+ printer-compression-supported,
+ printer-copies-supported,
+ printer-current-operator,
+ printer-delivery-orientation-supported,
+ printer-document-format-supported,
+ printer-finishings-supported,
+ printer-generated-natural-language-supported,
+ printer-info,
+ printer-job-k-octets-supported,
+ printer-job-priority-supported,
+ printer-location,
+ printer-make-and-model,
+ printer-media-local-supported,
+ printer-media-supported,
+ printer-more-info,
+ printer-multiple-document-jobs-supported,
+ printer-name,
+ printer-natural-language-configured,
+ printer-number-up-supported,
+ printer-output-features-supported,
+ printer-pages-per-minute,
+ printer-pages-per-minute-color,
+ printer-print-quality-supported,
+ printer-resolution-supported,
+ printer-service-person,
+ printer-sides-supported,
+ printer-stacking-order-supported
+
+objectclass printerService
+ oid 1.3.18.0.2.6.255
+ superior
+ printerAbstract
+ allows
+ printer-uri,
+ printer-xri-supported
+
+objectclass printerServiceAuxClass
+ oid 1.3.18.0.2.6.257
+ superior
+ printerAbstract
+ allows
+ printer-uri,
+ printer-xri-supported
+
+objectclass printerIPP
+ oid 1.3.18.0.2.6.256
+ superior
+ top
+ allows
+ printer-ipp-versions-supported,
+ printer-multiple-document-jobs-supported
+
+objectclass printerLPR
+ oid 1.3.18.0.2.6.253
+ superior
+ top
+ requires
+ printer-name
+ allows
+ printer-aliases
+
+objectclass sunPrinter
+ oid 1.3.6.1.4.1.42.2.27.5.2.14
+ superior
+ top
+ requires
+ printer-name
+ allows
+ sun-printer-bsdaddr,
+ sun-printer-kvp
diff --git a/usr/src/lib/print/libprint/i386/Makefile b/usr/src/lib/print/libprint/i386/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libprint/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/libprint/sparc/Makefile b/usr/src/lib/print/libprint/sparc/Makefile
new file mode 100644
index 0000000000..3b985583a4
--- /dev/null
+++ b/usr/src/lib/print/libprint/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) # $(ROOTLINT)
diff --git a/usr/src/lib/print/mod_ipp/Makefile b/usr/src/lib/print/mod_ipp/Makefile
new file mode 100644
index 0000000000..137e88bbf8
--- /dev/null
+++ b/usr/src/lib/print/mod_ipp/Makefile
@@ -0,0 +1,95 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY = mod_ipp.a
+VERS =
+OBJECTS = mod_ipp.o
+
+include ../../Makefile.lib
+include ../../Makefile.rootfs
+
+APACHEMODDIR = $(ROOT)/usr/apache/libexec
+APACHECONFDIR = $(ROOT)/etc/apache
+LISTENERDIR = $(ROOT)/var/lp/ipp-listener
+
+ROOTDIRS = $(ROOT)/usr/apache $(APACHEMODDIR) $(APACHECONFDIR) \
+ $(ROOT)/var/lp $(LISTENERDIR)
+
+$(ROOT)/var/lp:= DIRMODE = 775
+$(ROOT)/var/lp:= FILEMODE = 775
+
+LIBS = $(DYNLIB)
+
+SRCS = $(OBJECTS:%.o = %.c)
+
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I../libipp-listener/common
+CPPFLAGS += -I../libipp-core/common
+CPPFLAGS += -I$(ADJUNCT_PROTO)/usr/apache/include
+CPPFLAGS += -DEAPI
+ZDEFS = $(ZNODEFS)
+
+MAPFILES = mapfile
+
+LDLIBS += -lipp-listener -lipp-core -lpapi -lc
+
+# SMF manifest
+MANIFEST= ipp-listener.xml
+ROOTMANIFESTDIR= $(ROOT)/lib/svc/manifest/application/print
+ROOTMANIFEST= $(MANIFEST:%=$(ROOTMANIFESTDIR)/%)
+$(ROOTMANIFEST) := FILEMODE= 444
+
+# Apache module
+$(APACHEMODDIR)/$(LIBLINKS): $(ROOTDIRS)
+
+# Apache config
+APACHECONFFILE= $(APACHECONFDIR)/httpd-standalone-ipp.conf
+$(APACHECONFFILE) := FILEMODE= 644
+LISTENERFILE= $(LISTENERDIR)/index.html
+$(LISTENERFILE) := FILEMODE= 444
+
+$(ROOT)/var/lp:= FILEMODE = 0775
+
+$(APACHEMODDIR)/$(LIBLINKS):= FILEMODE = 0555
+
+$(ROOTMANIFESTDIR)/% $(APACHEMODDIR)/% $(APACHECONFDIR)/% $(LISTENERDIR)/%: %
+ $(INS.file)
+
+$(ROOTDIRS):
+ $(INS.dir)
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: all $(APACHEMODDIR)/$(LIBLINKS) $(APACHECONFFILE) \
+ $(LISTENERFILE) $(ROOTMANIFEST)
+
+install_h:
+
+lint:
+
+include ../../Makefile.targ
diff --git a/usr/src/lib/print/mod_ipp/httpd-standalone-ipp.conf b/usr/src/lib/print/mod_ipp/httpd-standalone-ipp.conf
new file mode 100644
index 0000000000..07a4b8dc11
--- /dev/null
+++ b/usr/src/lib/print/mod_ipp/httpd-standalone-ipp.conf
@@ -0,0 +1,341 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# "$Id: httpd-standalone-ipp.conf,v 1.4 2006/03/24 00:26:54 njacobs Exp $"
+#
+
+# ident "%Z%%M% %I% %E% SMI"
+
+##
+## httpd-standalone-ipp.conf -- Apache HTTP server configuration file for
+## an Internet Print Protocol (IPP) listener
+##
+
+#
+# Based upon the NCSA server configuration files originally by Rob McCool.
+#
+# This is the main Apache server configuration file. It contains the
+# configuration directives that give the server its instructions.
+# See <URL:http://www.apache.org/docs/> for detailed information about
+# the directives. mod_ipp specific directives are described in the
+# mod_ipp(4) man page.
+#
+
+### Section 1: Global Environment
+#
+# The directives in this section affect the overall operation of Apache,
+# such as the number of concurrent requests it can handle or where it
+# can find its configuration files.
+#
+
+#
+# ServerType is either inetd, or standalone. Inetd mode is only supported on
+# Unix platforms.
+#
+ServerType standalone
+
+#
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# NOTE! If you intend to place this on an NFS (or otherwise network)
+# mounted filesystem then please read the LockFile documentation
+# (available at <URL:http://www.apache.org/docs/mod/core.html#lockfile>);
+# you will save yourself a lot of trouble.
+#
+ServerRoot "/usr/apache"
+
+#
+# The LockFile directive sets the path to the lockfile used when Apache
+# is compiled with either USE_FCNTL_SERIALIZED_ACCEPT or
+# USE_FLOCK_SERIALIZED_ACCEPT. This directive should normally be left at
+# its default value. The main reason for changing it is if the logs
+# directory is NFS mounted, since the lockfile MUST BE STORED ON A LOCAL
+# DISK. The PID of the main server process is automatically appended to
+# the filename.
+#
+#LockFile /var/run/httpd.lock
+LockFile /var/run/httpd-standalone-ipp.lock
+
+#
+# PidFile: The file in which the server should record its process
+# identification number when it starts.
+#
+PidFile /var/run/httpd-standalone-ipp.pid
+
+#
+# ScoreBoardFile: File used to store internal server process information.
+# Not all architectures require this. But if yours does (you'll know because
+# this file will be created when you run Apache) then you *must* ensure that
+# no two invocations of Apache share the same scoreboard file.
+#
+ScoreBoardFile /var/run/httpd-standalone-ipp.scoreboard
+
+#
+# In the standard configuration, the server will process httpd.conf (this
+# file, specified by the -f command line option), srm.conf, and access.conf
+# in that order. The latter two files are now distributed empty, as it is
+# recommended that all directives be kept in a single file for simplicity.
+# The commented-out values below are the built-in defaults. You can have the
+# server ignore these files altogether by using "/dev/null" (for Unix) or
+# "nul" (for Win32) for the arguments to the directives.
+#
+#ResourceConfig conf/srm.conf
+#AccessConfig conf/access.conf
+
+#
+# Timeout: The number of seconds before receives and sends time out.
+#
+Timeout 300
+
+#
+# KeepAlive: Whether or not to allow persistent connections (more than
+# one request per connection). Set to "Off" to deactivate.
+#
+KeepAlive On
+
+#
+# MaxKeepAliveRequests: The maximum number of requests to allow
+# during a persistent connection. Set to 0 to allow an unlimited amount.
+# We recommend you leave this number high, for maximum performance.
+#
+MaxKeepAliveRequests 100
+
+#
+# KeepAliveTimeout: Number of seconds to wait for the next request from the
+# same client on the same connection.
+#
+KeepAliveTimeout 15
+
+#
+# Server-pool size regulation. Rather than making you guess how many
+# server processes you need, Apache dynamically adapts to the load it
+# sees --- that is, it tries to maintain enough server processes to
+# handle the current load, plus a few spare servers to handle transient
+# load spikes (e.g., multiple simultaneous requests from a single
+# Netscape browser).
+#
+# It does this by periodically checking how many servers are waiting
+# for a request. If there are fewer than MinSpareServers, it creates
+# a new spare. If there are more than MaxSpareServers, some of the
+# spares die off. The default values are probably OK for most sites.
+#
+MinSpareServers 1
+MaxSpareServers 2
+
+#
+# Number of servers to start initially --- should be a reasonable ballpark
+# figure.
+#
+StartServers 1
+
+#
+# Limit on total number of servers running, i.e., limit on the number
+# of clients who can simultaneously connect --- if this limit is ever
+# reached, clients will be LOCKED OUT, so it should NOT BE SET TOO LOW.
+# It is intended mainly as a brake to keep a runaway server from taking
+# the system with it as it spirals down...
+#
+MaxClients 150
+
+#
+# MaxRequestsPerChild: the number of requests each child process is
+# allowed to process before the child dies. The child will exit so
+# as to avoid problems after prolonged use when Apache (and maybe the
+# libraries it uses) leak memory or other resources. On most systems, this
+# isn't really needed, but a few (such as Solaris) do have notable leaks
+# in the libraries. For these platforms, set to something like 10000
+# or so; a setting of 0 means unlimited.
+#
+# NOTE: This value does not include keepalive requests after the initial
+# request per connection. For example, if a child process handles
+# an initial request and 10 subsequent "keptalive" requests, it
+# would only count as 1 request towards this limit.
+#
+MaxRequestsPerChild 10
+
+#
+# Dynamic Shared Object (DSO) Support
+#
+# To be able to use the functionality of a module which was built as a DSO you
+# have to place corresponding `LoadModule' lines at this location so the
+# directives contained in it are actually available _before_ they are used.
+# Please read the file http://httpd.apache.org/docs/dso.html for more
+# details about the DSO mechanism and run `httpd -l' for the list of already
+# built-in (statically linked and thus always available) modules in your httpd
+# binary.
+#
+# Note: The order in which modules are loaded is important. Don't change
+# the order below without expert advice.
+#
+LoadModule access_module libexec/mod_access.so
+LoadModule alias_module libexec/mod_alias.so
+LoadModule auth_module libexec/mod_auth.so
+LoadModule mime_module libexec/mod_mime.so
+LoadModule mime_magic_module libexec/mod_mime_magic.so
+LoadModule ipp_module libexec/mod_ipp.so
+
+# Reconstruction of the complete module list from all available modules
+# (static and shared ones) to achieve correct module execution order.
+# [WHENEVER YOU CHANGE THE LOADMODULE SECTION ABOVE UPDATE THIS, TOO]
+ClearModuleList
+AddModule mod_access.c
+AddModule mod_alias.c
+AddModule mod_auth.c
+AddModule mod_mime.c
+AddModule mod_mime_magic.c
+AddModule mod_ipp.c
+AddModule mod_so.c
+
+### Section 2: 'Main' server configuration
+#
+# The directives in this section set up the values used by the 'main'
+# server, which responds to any requests that aren't handled by a
+# <VirtualHost> definition. These values also provide defaults for
+# any <VirtualHost> containers you may define later in the file.
+#
+# All of these directives may appear inside <VirtualHost> containers,
+# in which case these default settings will be overridden for the
+# virtual host being defined.
+#
+
+#
+# If your ServerType directive (set earlier in the 'Global Environment'
+# section) is set to "inetd", the next few directives don't have any
+# effect since their settings are defined by the inetd configuration.
+# Skip ahead to the ServerAdmin directive.
+#
+
+#
+# Port: The port to which the standalone server listens. For
+# ports < 1023, you will need httpd to be run as root initially.
+#
+Port 631
+
+#
+# If you wish httpd to run as a different user or group, you must run
+# httpd as root initially and it will switch.
+#
+# User/Group: The name (or #number) of the user/group to run httpd as.
+# . On SCO (ODT 3) use "User nouser" and "Group nogroup".
+# . On HPUX you may not be able to use shared memory as nobody, and the
+# suggested workaround is to create a user www and use that user.
+# NOTE that some kernels refuse to setgid(Group) or semctl(IPC_SET)
+# when the value of (unsigned)Group is above 60000;
+# don't use Group nobody on these systems!
+#
+User lp
+Group lp
+
+#
+# ServerAdmin: Your address, where problems with the server should be
+# e-mailed. This address appears on some server-generated pages, such
+# as error documents.
+#
+ServerAdmin lp@localhost
+
+#
+# ServerName allows you to set a host name which is sent back to clients for
+# your server if it's different than the one the program would get (i.e., use
+# "www" instead of the host's real name).
+#
+# Note: You cannot just invent host names and hope they work. The name you
+# define here must be a valid DNS name for your host. If you don't understand
+# this, ask your network administrator.
+# If your host doesn't have a registered DNS name, enter its IP address here.
+# You will have to access it by its address (e.g., http://123.45.67.89/)
+# anyway, and this will make redirections work in a sensible way.
+#
+# 127.0.0.1 is the TCP/IP local loop-back address, often named localhost. Your
+# machine always knows itself by this address. If you use Apache strictly for
+# local testing and development, you may use 127.0.0.1 as the server name.
+#
+#Servername printserver.some_company.com
+
+DefaultType application/ipp
+
+ErrorLog /var/lp/logs/ipp-errors
+LogLevel warn
+
+DocumentRoot /var/lp/ipp-listener
+
+# Allow passing PPD files from this service as well
+Alias /etc/lp/ppd/ /etc/lp/ppd/
+<Directory /etc/lp/ppd>
+ SetHandler send-as-is
+ <LimitExcept GET>
+ Deny from all
+ </LimitExcept>
+</Directory>
+
+# mod_ipp specific configuration
+<IfModule mod_ipp.c>
+
+ <Location />
+ # ipp-conformance automatic # default
+ # ipp-default-user nobody
+ ipp-default-service lpsched
+ #
+ # By default, only turn on operations that are not
+ # likely to cause real problems when the user can't
+ # be trusted.
+ #
+ ipp-operation all off
+ ipp-operation print-job on
+ ipp-operation validate-job on
+ ipp-operation create-job on
+ ipp-operation get-jobs on
+ ipp-operation get-printer-attributes on
+ ipp-operation send-document on
+ ipp-operation cancel-job on
+ ipp-operation get-job-attributes on
+ ipp-operation cups-get-default on
+ ipp-operation cups-get-printers on
+ ipp-operation cups-get-classes on
+ ipp-operation cups-move-job on
+
+ # redirect non-IPP requests
+ ErrorDocument 404 /index.html
+ </Location>
+
+ <Location /admin>
+ # ipp-conformance automatic # default
+ # ipp-default-user nobody
+ ipp-default-service lpsched
+
+ ipp-operation all on
+
+ AuthType Basic
+ AuthName "IPP Server"
+ AuthUserFile /etc/ipp-users
+ Require valid-user
+
+ # redirect non-IPP requests
+ ErrorDocument 404 /index.html
+ </Location>
+</IfModule>
+
diff --git a/usr/src/lib/print/mod_ipp/index.html b/usr/src/lib/print/mod_ipp/index.html
new file mode 100644
index 0000000000..15f680c666
--- /dev/null
+++ b/usr/src/lib/print/mod_ipp/index.html
@@ -0,0 +1,44 @@
+<!--
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+
+ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ ident "%Z%%M% %I% %E% SMI"
+-->
+<html>
+<body>
+The Internet Print Protocol (IPP) requires that all protocol requests be
+encapsulated in HTTP and that all HTTP protocol requests be POST requests with
+a Content-Type of "application/ipp". Since your request did not meet this
+criteria, it has been ignored by the IPP listener. You will be redirected to
+the
+<a href=http://docs.sun.com/db?q=%22Internet+Print+Protocol%22&p=prod%2Fsolaris>
+<b>Solaris&reg</b> AnswerBook
+</a>
+so that you can learn more about the Internet Print Protocol Listener.
+<p>
+If you would like more information about the Internet Print Protocol itself,
+please visit <a href=http://www.pwg.org/ipp>http://www.pwg.org/ipp/</a>.
+</body>
+</html>
+<meta HTTP-EQUIV=REFRESH CONTENT=10;URL=http://docs.sun.com/db?q=%22Internet+Print+Protocol%22&p=prod%2Fsolaris>
diff --git a/usr/src/lib/print/mod_ipp/ipp-listener.xml b/usr/src/lib/print/mod_ipp/ipp-listener.xml
new file mode 100644
index 0000000000..686646a78c
--- /dev/null
+++ b/usr/src/lib/print/mod_ipp/ipp-listener.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0"?>
+<!--
+CDDL HEADER START
+
+The contents of this file are subject to the terms of the
+Common Development and Distribution License (the "License").
+You may not use this file except in compliance with the License.
+
+You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+or http://www.opensolaris.org/os/licensing.
+See the License for the specific language governing permissions
+and limitations under the License.
+
+When distributing Covered Code, include this CDDL HEADER in each
+file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+If applicable, add the following below this CDDL HEADER, with the
+fields enclosed by brackets "[]" replaced with your own identifying
+information: Portions Copyright [yyyy] [name of copyright owner]
+
+CDDL HEADER END
+-->
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+-->
+
+<service_bundle type='manifest' name='SUNWipplr:ipp-listener'>
+
+<service
+ name='application/print/ipp-listener'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <dependency name='print-service'
+ grouping='require_any'
+ restart_on='refresh'
+ type='service'>
+ <service_fmri value='svc:/application/print/server' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/usr/apache/bin/httpd -f /etc/apache/httpd-standalone-ipp.conf'
+ timeout_seconds='10' />
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec='/bin/pkill -f httpd-standalone-ipp.conf'
+ timeout_seconds='5' />
+
+ <property_group name='general' type='framework'>
+ <!-- to start/stop IPP listening service-->
+ <propval name='action_authorization' type='astring'
+ value='solaris.print.admin' />
+ <propval name='value_authorization' type='astring'
+ value='solaris.print.admin' />
+ </property_group>
+
+ <property_group name='firewall_context' type='com.sun,fw_definition'>
+ <propval name='ipf_method' type='astring'
+ value='/lib/svc/method/print-svc ipfilter svc:/application/print/server:default' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Internet Print Protocol Listening Service
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='mod_ipp' section='4'
+ manpath='/usr/share/man' />
+ </documentation>
+ </template>
+</service>
+
+</service_bundle>
diff --git a/usr/src/lib/print/mod_ipp/mapfile b/usr/src/lib/print/mod_ipp/mapfile
new file mode 100644
index 0000000000..ffdec222b5
--- /dev/null
+++ b/usr/src/lib/print/mod_ipp/mapfile
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+#
+# $Id: mapfile 149 2006-04-25 16:55:01Z njacobs $
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+$mapfile_version 2
+
+SYMBOL_VERSION SUNWprivate_1.0 {
+ global:
+ ipp_module;
+
+ local:
+ *;
+};
diff --git a/usr/src/lib/print/mod_ipp/mod_ipp.c b/usr/src/lib/print/mod_ipp/mod_ipp.c
new file mode 100644
index 0000000000..2d9ece2287
--- /dev/null
+++ b/usr/src/lib/print/mod_ipp/mod_ipp.c
@@ -0,0 +1,552 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+/* $Id: mod_ipp.c 149 2006-04-25 16:55:01Z njacobs $ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Internet Printing Protocol (IPP) module for Apache.
+ */
+
+#include "ap_config.h"
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+#include <values.h>
+#include <libintl.h>
+#include <alloca.h>
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_protocol.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "papi.h"
+#ifndef APACHE_RELEASE /* appears to only exist in Apache 1.X */
+#define APACHE2
+#include "apr_compat.h"
+#endif
+
+#include <papi.h>
+#include <ipp-listener.h>
+
+#ifndef APACHE2
+module MODULE_VAR_EXPORT ipp_module;
+#else
+module AP_MODULE_DECLARE_DATA ipp_module;
+#endif
+
+#ifndef AP_INIT_TAKE1 /* Apache 2.X has this, but 1.3.X does not */
+#define AP_INIT_NO_ARGS(directive, action, arg, where, mesg) \
+ { directive, action, arg, where, NO_ARGS, mesg }
+#define AP_INIT_TAKE1(directive, action, arg, where, mesg) \
+ { directive, action, arg, where, TAKE1, mesg }
+#define AP_INIT_TAKE2(directive, action, arg, where, mesg) \
+ { directive, action, arg, where, TAKE2, mesg }
+#endif
+
+typedef struct {
+ int conformance;
+ char *default_user;
+ char *default_svc;
+ papi_attribute_t **operations;
+} IPPListenerConfig;
+
+#ifdef DEBUG
+void
+dump_buffer(FILE *fp, char *tag, char *buffer, int bytes)
+{
+ int i, j, ch;
+
+ fprintf(fp, "%s %d(0x%x) bytes\n", (tag ? tag : ""), bytes, bytes);
+ for (i = 0; i < bytes; i += 16) {
+ fprintf(fp, "%s ", (tag ? tag : ""));
+
+ for (j = 0; j < 16 && (i + j) < bytes; j ++)
+ fprintf(fp, " %02X", buffer[i + j] & 255);
+
+ while (j < 16) {
+ fprintf(fp, " ");
+ j++;
+ }
+
+ fprintf(fp, " ");
+ for (j = 0; j < 16 && (i + j) < bytes; j ++) {
+ ch = buffer[i + j] & 255;
+ if (ch < ' ' || ch == 127)
+ ch = '.';
+ putc(ch, fp);
+ }
+ putc('\n', fp);
+ }
+ fflush(fp);
+}
+#endif
+
+static ssize_t
+read_data(void *fd, void *buf, size_t siz)
+{
+ ssize_t len_read;
+ request_rec *ap_r = (request_rec *)fd;
+
+ len_read = ap_get_client_block(ap_r, buf, siz);
+#ifndef APACHE2
+ ap_reset_timeout(ap_r);
+#endif
+
+#ifdef DEBUG
+ fprintf(stderr, "read_data(0x%8.8x, 0x%8.8x, %d): %d",
+ fd, buf, siz, len_read);
+ if (len_read < 0)
+ fprintf(stderr, ": %s", strerror(errno));
+ putc('\n', stderr);
+ dump_buffer(stderr, "read_data:", buf, len_read);
+#endif
+
+ return (len_read);
+}
+
+static ssize_t
+write_data(void *fd, void *buf, size_t siz)
+{
+ ssize_t len_written;
+ request_rec *ap_r = (request_rec *)fd;
+
+#ifndef APACHE2
+ ap_reset_timeout(ap_r);
+#endif
+#ifdef DEBUG
+ dump_buffer(stderr, "write_data:", buf, siz);
+#endif
+ len_written = ap_rwrite(buf, siz, ap_r);
+
+ return (len_written);
+}
+
+static void
+discard_data(request_rec *r)
+{
+#ifdef APACHE2
+ (void) ap_discard_request_body(r);
+#else
+ /*
+ * This is taken from ap_discard_request_body(). The reason we can't
+ * just use it in Apache 1.3 is that it does various timeout things we
+ * don't want it to do. Apache 2.0 doesn't do that, so we can safely
+ * use the normal function.
+ */
+ if (r->read_chunked || r->remaining > 0) {
+ char dumpbuf[HUGE_STRING_LEN];
+ int i;
+
+ do {
+ i = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN);
+#ifdef DEBUG
+ dump_buffer(stderr, "discarded", dumpbuf, i);
+#endif
+ } while (i > 0);
+ }
+#endif
+}
+
+void _log_rerror(const char *file, int line, int level, request_rec *r,
+ const char *fmt, ...)
+{
+ va_list args;
+ size_t size;
+ char *message = alloca(BUFSIZ);
+
+ va_start(args, fmt);
+ /*
+ * fill in the message. If the buffer is too small, allocate
+ * one that is large enough and fill it in.
+ */
+ if ((size = vsnprintf(message, BUFSIZ, fmt, args)) >= BUFSIZ)
+ if ((message = alloca(size)) != NULL)
+ vsnprintf(message, size, fmt, args);
+ va_end(args);
+
+#ifdef APACHE2
+ ap_log_rerror(file, line, level, NULL, r, message);
+#else
+ ap_log_rerror(file, line, level, r, message);
+#endif
+}
+
+static int
+ipp_handler(request_rec *r)
+{
+ papi_attribute_t **request = NULL, **response = NULL;
+ IPPListenerConfig *config;
+ papi_status_t status;
+ int ret;
+
+ /* Really, IPP is all POST requests */
+ if (r->method_number != M_POST)
+ return (DECLINED);
+
+#ifndef APACHE2
+ /*
+ * An IPP request must have a MIME type of "application/ipp"
+ * (RFC-2910, Section 4, page 19). If it doesn't match this
+ * MIME type, we should decline the request and let someone else
+ * try and handle it.
+ */
+ if (r->headers_in != NULL) {
+ char *mime_type = (char *)ap_table_get(r->headers_in,
+ "Content-Type");
+
+ if ((mime_type == NULL) ||
+ (strcasecmp(mime_type, "application/ipp") != 0))
+ return (DECLINED);
+ }
+#endif
+ /* CHUNKED_DECHUNK might not work right for IPP? */
+ if ((ret = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) != OK)
+ return (ret);
+
+ if (!ap_should_client_block(r))
+ return (HTTP_INTERNAL_SERVER_ERROR);
+
+#ifndef APACHE2
+ ap_soft_timeout("ipp_module: read/reply request ", r);
+#endif
+ /* read the IPP request off the network */
+ status = ipp_read_message(read_data, r, &request, IPP_TYPE_REQUEST);
+
+ if (status != PAPI_OK)
+ _log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "read failed: %s\n", papiStatusString(status));
+#ifdef DEBUG
+ papiAttributeListPrint(stderr, request, "request (%d) ", getpid());
+#endif
+
+ (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
+ "originating-host", (char *)
+#ifdef APACHE2
+ ap_get_remote_host
+ (r->connection, r->per_dir_config, REMOTE_NAME, NULL));
+#else
+ ap_get_remote_host
+ (r->connection, r->per_dir_config, REMOTE_NAME));
+#endif
+
+ (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
+ "uri-port", ap_get_server_port(r));
+ if (r->headers_in != NULL) {
+ char *host = (char *)ap_table_get(r->headers_in, "Host");
+
+ if ((host == NULL) || (host[0] == '\0'))
+ host = (char *)ap_get_server_name(r);
+
+ (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
+ "uri-host", host);
+ }
+ (void) papiAttributeListAddString(&request, PAPI_ATTR_EXCL,
+ "uri-path", r->uri);
+
+ config = ap_get_module_config(r->per_dir_config, &ipp_module);
+ if (config != NULL) {
+ (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
+ "conformance", config->conformance);
+ (void) papiAttributeListAddCollection(&request, PAPI_ATTR_EXCL,
+ "operations", config->operations);
+ if (config->default_user != NULL)
+ (void) papiAttributeListAddString(&request,
+ PAPI_ATTR_EXCL, "default-user",
+ config->default_user);
+ if (config->default_svc != NULL)
+ (void) papiAttributeListAddString(&request,
+ PAPI_ATTR_EXCL, "default-service",
+ config->default_svc);
+ }
+
+ /*
+ * For Trusted Solaris, pass the fd number of the socket connection
+ * to the backend so the it can be forwarded to the backend print
+ * service to retrieve the sensativity label off of a multi-level
+ * port.
+ */
+ (void) papiAttributeListAddInteger(&request, PAPI_ATTR_EXCL,
+ "peer-socket", ap_bfileno(r->connection->client, B_RD));
+
+ /* process the request */
+ status = ipp_process_request(request, &response, read_data, r);
+ if (status != PAPI_OK) {
+ errno = 0;
+ _log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "request failed: %s\n", papiStatusString(status));
+ discard_data(r);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "processing result: %s\n", papiStatusString(status));
+ papiAttributeListPrint(stderr, response, "response (%d) ", getpid());
+#endif
+
+ /*
+ * If the client is using chunking and we have not yet received the
+ * final "0" sized chunk, we need to discard any data that may
+ * remain in the post request.
+ */
+ if ((r->read_chunked != 0) &&
+ (ap_table_get(r->headers_in, "Content-Length") == NULL))
+ discard_data(r);
+
+ /* write an IPP response back to the network */
+ r->content_type = "application/ipp";
+
+#ifndef APACHE2
+ ap_send_http_header(r);
+#endif
+
+ status = ipp_write_message(write_data, r, response);
+ if (status != PAPI_OK)
+ _log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "write failed: %s\n", papiStatusString(status));
+#ifdef DEBUG
+ fprintf(stderr, "write result: %s\n", papiStatusString(status));
+ fflush(stderr);
+#endif
+
+ papiAttributeListFree(request);
+ papiAttributeListFree(response);
+
+#ifndef APACHE2
+ ap_kill_timeout(r);
+ if (ap_rflush(r) < 0)
+ _log_rerror(APLOG_MARK, APLOG_ERR, r,
+ "flush failed, response may not have been sent");
+#endif
+
+ return (OK);
+}
+
+
+/*ARGSUSED1*/
+static void *
+create_ipp_dir_config(
+#ifndef APACHE2
+ pool *p,
+#else
+ apr_pool_t *p,
+#endif
+ char *dirspec)
+{
+ IPPListenerConfig *config =
+#ifndef APACHE2
+ ap_pcalloc(p, sizeof (*config));
+#else
+ apr_pcalloc(p, sizeof (*config));
+#endif
+
+ if (config != NULL) {
+ (void) memset(config, 0, sizeof (*config));
+ config->conformance = IPP_PARSE_CONFORMANCE_RASH;
+ config->default_user = NULL;
+ config->default_svc = NULL;
+ (void) ipp_configure_operation(&config->operations, "required",
+ "enable");
+ }
+
+ return (config);
+}
+
+/*ARGSUSED0*/
+static const char *
+ipp_conformance(cmd_parms *cmd, void *cfg, const char *arg)
+{
+ IPPListenerConfig *config = (IPPListenerConfig *)cfg;
+
+ if (strncasecmp(arg, "automatic", 4) == 0) {
+ config->conformance = IPP_PARSE_CONFORMANCE_RASH;
+ } else if (strcasecmp(arg, "1.0") == 0) {
+ config->conformance = IPP_PARSE_CONFORMANCE_LOOSE;
+ } else if (strcasecmp(arg, "1.1") == 0) {
+ config->conformance = IPP_PARSE_CONFORMANCE_STRICT;
+ } else {
+ return ("unknown conformance, try (automatic/1.0/1.1)");
+ }
+
+ return (NULL);
+}
+
+/*ARGSUSED0*/
+static const char *
+ipp_operation(cmd_parms *cmd, void *cfg, char *op, char *toggle)
+{
+ IPPListenerConfig *config = (IPPListenerConfig *)cfg;
+ papi_status_t status;
+
+ status = ipp_configure_operation(&config->operations, op, toggle);
+ switch (status) {
+ case PAPI_OK:
+ return (NULL);
+ case PAPI_BAD_ARGUMENT:
+ return (gettext("internal error (invalid argument)"));
+ default:
+ return (papiStatusString(status));
+ }
+
+ /* NOTREACHED */
+ /* return (gettext("contact your software vendor")); */
+}
+
+static const char *
+ipp_default_user(cmd_parms *cmd, void *cfg, const char *arg)
+{
+ IPPListenerConfig *config = (IPPListenerConfig *)cfg;
+
+ config->default_user = (char *)arg;
+
+ return (NULL);
+}
+
+static const char *
+ipp_default_svc(cmd_parms *cmd, void *cfg, const char *arg)
+{
+ IPPListenerConfig *config = (IPPListenerConfig *)cfg;
+
+ config->default_svc = (char *)arg;
+
+ return (NULL);
+}
+
+#ifdef DEBUG
+/*ARGSUSED0*/
+static const char *
+ipp_module_hang(cmd_parms *cmd, void *cfg)
+{
+ static int i = 1;
+
+ /* wait so we can attach a debugger, assign i = 0, and step through */
+ while (i);
+
+ return (NULL);
+}
+#endif /* DEBUG */
+
+static const command_rec ipp_cmds[] =
+{
+ AP_INIT_TAKE1("ipp-conformance", ipp_conformance, NULL, ACCESS_CONF,
+ "IPP protocol conformance (loose/strict)"),
+ AP_INIT_TAKE2("ipp-operation", ipp_operation, NULL, ACCESS_CONF,
+ "IPP protocol operations to enable/disable)"),
+ AP_INIT_TAKE1("ipp-default-user", ipp_default_user, NULL, ACCESS_CONF,
+ "default user for various operations"),
+ AP_INIT_TAKE1("ipp-default-service", ipp_default_svc, NULL, ACCESS_CONF,
+ "default service for various operations"),
+#ifdef DEBUG
+ AP_INIT_NO_ARGS("ipp-module-hang", ipp_module_hang, NULL, ACCESS_CONF,
+ "hang the module until we can attach a debugger (no args)"),
+#endif
+ { NULL }
+};
+
+#ifdef APACHE2
+/*ARGSUSED0*/
+static const char *
+ipp_method(const request_rec *r)
+{
+ return ("ipp");
+}
+
+/*ARGSUSED0*/
+static unsigned short
+ipp_port(const request_rec *r)
+{
+ return (631);
+}
+
+/* Dispatch list for API hooks */
+/*ARGSUSED0*/
+static void
+ipp_register_hooks(apr_pool_t *p)
+{
+ static const char * const modules[] = { "mod_dir.c", NULL };
+
+ /* Need to make sure we don't get directory listings by accident */
+ ap_hook_handler(ipp_handler, NULL, modules, APR_HOOK_MIDDLE);
+ ap_hook_default_port(ipp_port, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_http_method(ipp_method, NULL, NULL, APR_HOOK_MIDDLE);
+}
+
+module AP_MODULE_DECLARE_DATA ipp_module = {
+ STANDARD20_MODULE_STUFF,
+ create_ipp_dir_config, /* create per-dir config */
+ NULL, /* merge per-dir config */
+ NULL, /* create per-server config */
+ NULL, /* merge per-server config */
+ ipp_cmds, /* table of config commands */
+ ipp_register_hooks /* register hooks */
+};
+
+#else /* Apache 1.X */
+
+/* Dispatch list of content handlers */
+static const handler_rec ipp_handlers[] = {
+ /*
+ * This handler association causes all IPP request with the
+ * correct MIME type to call the protocol handler.
+ */
+ { "application/ipp", ipp_handler },
+ /*
+ * This hander association is causes everything to go through the IPP
+ * protocol request handler. This is necessary because client POST
+ * request may be for something outside of the normal printer-uri
+ * space.
+ */
+ { "*/*", ipp_handler },
+
+ { NULL, NULL }
+};
+
+
+module MODULE_VAR_EXPORT ipp_module = {
+ STANDARD_MODULE_STUFF,
+ NULL, /* module initializer */
+ create_ipp_dir_config, /* create per-dir config structures */
+ NULL, /* merge per-dir config structures */
+ NULL, /* create per-server config structures */
+ NULL, /* merge per-server config structures */
+ ipp_cmds, /* table of config file commands */
+ ipp_handlers, /* [#8] MIME-typed-dispatched handlers */
+ NULL, /* [#1] URI to filename translation */
+ NULL, /* [#4] validate user id from request */
+ NULL, /* [#5] check if the user is ok _here_ */
+ NULL, /* [#3] check access by host address */
+ NULL, /* [#6] determine MIME type */
+ NULL, /* [#7] pre-run fixups */
+ NULL, /* [#9] log a transaction */
+ NULL, /* [#2] header parser */
+ NULL, /* child_init */
+ NULL, /* child_exit */
+ NULL /* [#0] post read-request */
+};
+#endif
diff --git a/usr/src/pkg/manifests/SUNWippcore.mf b/usr/src/pkg/manifests/SUNWippcore.mf
new file mode 100644
index 0000000000..c3e9ac8bde
--- /dev/null
+++ b/usr/src/pkg/manifests/SUNWippcore.mf
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/SUNWippcore@0.5.11,5.11-0.133
+set name=pkg.renamed value=true
+set name=variant.arch value=$(ARCH)
+depend fmri=pkg:/print/lp/ipp/libipp@0.5.11,5.11-0.133 type=require
diff --git a/usr/src/pkg/manifests/SUNWippl.mf b/usr/src/pkg/manifests/SUNWippl.mf
new file mode 100644
index 0000000000..e654f167b9
--- /dev/null
+++ b/usr/src/pkg/manifests/SUNWippl.mf
@@ -0,0 +1,29 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/SUNWippl@0.5.11,5.11-0.133
+set name=pkg.renamed value=true
+set name=variant.arch value=$(ARCH)
+depend fmri=pkg:/print/lp/ipp/ipp-listener@0.5.11,5.11-0.133 type=require
diff --git a/usr/src/pkg/manifests/SUNWlp-cmds.mf b/usr/src/pkg/manifests/SUNWlp-cmds.mf
new file mode 100644
index 0000000000..4f2da711e4
--- /dev/null
+++ b/usr/src/pkg/manifests/SUNWlp-cmds.mf
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/SUNWlp-cmds@0.5.11,5.11-0.130
+set name=pkg.obsolete value=true
+set name=variant.arch value=$(ARCH)
diff --git a/usr/src/pkg/manifests/SUNWlpr-cmds.mf b/usr/src/pkg/manifests/SUNWlpr-cmds.mf
new file mode 100644
index 0000000000..7c24e7dfbe
--- /dev/null
+++ b/usr/src/pkg/manifests/SUNWlpr-cmds.mf
@@ -0,0 +1,28 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/SUNWlpr-cmds@0.5.11,5.11-0.130
+set name=pkg.obsolete value=true
+set name=variant.arch value=$(ARCH)
diff --git a/usr/src/pkg/manifests/SUNWps.mf b/usr/src/pkg/manifests/SUNWps.mf
index e9113f083a..1b6a424bf6 100644
--- a/usr/src/pkg/manifests/SUNWps.mf
+++ b/usr/src/pkg/manifests/SUNWps.mf
@@ -26,3 +26,4 @@
set name=pkg.fmri value=pkg:/SUNWps@0.5.11,5.11-0.133
set name=pkg.renamed value=true
set name=variant.arch value=$(ARCH)
+depend fmri=pkg:/print/lp@0.5.11,5.11-0.133 type=require
diff --git a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf
index c7cc82c13d..cd9fd8743e 100644
--- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf
+++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf
@@ -334,6 +334,10 @@ file path=usr/lib/locale/C/LC_MESSAGES/priv_names group=sys
file path=usr/lib/locale/C/LC_MESSAGES/uxlibc.src group=sys
file path=usr/lib/locale/C/LC_TIME/SUNW_OST_OSCMD.po group=sys
file path=usr/lib/locale/C/LC_TIME/SUNW_OST_OSLIB.po group=sys
+file path=usr/share/lib/locale/com/sun/admin/pm/client/pmHelpResources.java \
+ group=lp
+file path=usr/share/lib/locale/com/sun/admin/pm/client/pmResources.java \
+ group=lp
file \
path=usr/share/lib/locale/com/sun/dhcpmgr/bridge/ResourceBundle.properties
file \
diff --git a/usr/src/pkg/manifests/library-print-open-printing-ipp.mf b/usr/src/pkg/manifests/library-print-open-printing-ipp.mf
new file mode 100644
index 0000000000..f1765ebffc
--- /dev/null
+++ b/usr/src/pkg/manifests/library-print-open-printing-ipp.mf
@@ -0,0 +1,185 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/library/print/open-printing/ipp@$(PKGVERS)
+set name=pkg.description \
+ value="Client side support for communicating with IPP based print servers"
+set name=pkg.summary value="FSG Open Printing API IPP Print Service Module"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=usr group=sys
+dir path=usr/lib
+dir path=usr/lib/print group=lp
+dir path=usr/share/man
+dir path=usr/share/man/man4
+file path=usr/lib/print/libhttp-core.so.1
+file path=usr/lib/print/psm-ipp.so.1
+file path=usr/share/man/man4/mod_ipp.4
+legacy pkg=SUNWpsm-ipp \
+ desc="Client side support for communicating with IPP based print servers" \
+ name="FSG Open Printing API IPP Print Service Module" \
+ version=11.11.0,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+license usr/src/lib/print/libhttp-core/common/LICENSE.txt \
+ license=usr/src/lib/print/libhttp-core/common/LICENSE.txt
+link path=usr/lib/print/libhttp-core.so target=./libhttp-core.so.1
+link path=usr/lib/print/psm-http.so target=./psm-ipp.so
+link path=usr/lib/print/psm-ipp.so target=./psm-ipp.so.1
+link path=usr/share/man/man3papi/papiAttributeListAddBoolean.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListAddCollection.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListAddDatetime.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListAddInteger.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListAddMetadata.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListAddRange.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListAddResolution.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListAddString.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListDelete.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListFind.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListFree.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListFromString.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetBoolean.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetCollection.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetDatetime.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetInteger.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetMetadata.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetNext.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetRange.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetResolution.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetString.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListGetValue.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiAttributeListToString.3papi \
+ target=papiAttributeListAddValue.3papi
+link path=usr/share/man/man3papi/papiJobCancel.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobFree.3papi target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobGetAttributeList.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobGetId.3papi target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobGetJobTicket.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobGetPrinterName.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobHold.3papi target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobListFree.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobModify.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobMove.3papi target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobPromote.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobQuery.3papi target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobRelease.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobRestart.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobStreamClose.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobStreamOpen.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobStreamWrite.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobSubmitByReference.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiJobValidate.3papi \
+ target=papiJobSubmit.3papi
+link path=usr/share/man/man3papi/papiLibrarySupportedCalls.3papi \
+ target=papiLibrarySupportedCall.3papi
+link path=usr/share/man/man3papi/papiPrinterAdd.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterDisable.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterEnable.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterFree.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterGetAttributeList.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterListFree.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterListJobs.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterModify.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterPause.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterPurgeJobs.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterQuery.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterRemove.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiPrinterResume.3papi \
+ target=papiPrintersList.3papi
+link path=usr/share/man/man3papi/papiServiceDestroy.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceGetAppData.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceGetAttributeList.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceGetEncryption.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceGetPassword.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceGetServiceName.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceGetStatusMessage.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceGetUserName.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceSetAppData.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceSetAuthCB.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceSetEncryption.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceSetPassword.3papi \
+ target=papiServiceCreate.3papi
+link path=usr/share/man/man3papi/papiServiceSetUserName.3papi \
+ target=papiServiceCreate.3papi
diff --git a/usr/src/pkg/manifests/library-print-open-printing-lpd.mf b/usr/src/pkg/manifests/library-print-open-printing-lpd.mf
new file mode 100644
index 0000000000..ea8ade1ebb
--- /dev/null
+++ b/usr/src/pkg/manifests/library-print-open-printing-lpd.mf
@@ -0,0 +1,46 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/library/print/open-printing/lpd@$(PKGVERS)
+set name=pkg.description \
+ value="Client side support for communicating with RFC-1179 based print servers"
+set name=pkg.summary \
+ value="FSG Open Printing API RFC-1179 Print Service Module"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=usr group=sys
+dir path=usr/lib
+dir path=usr/lib/print group=lp
+file path=usr/lib/print/lpd-port mode=4511
+file path=usr/lib/print/psm-lpd.so.1
+legacy pkg=SUNWpsm-lpd \
+ desc="Client side support for communicating with RFC-1179 based print servers" \
+ name="FSG Open Printing API RFC-1179 Print Service Module" \
+ version=11.11.0,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+link path=usr/lib/print/psm-lpd.so target=./psm-lpd.so.1
+link path=usr/lib/print/psm-rfc-1179.so target=./psm-lpd.so
diff --git a/usr/src/pkg/manifests/library-print-open-printing.mf b/usr/src/pkg/manifests/library-print-open-printing.mf
new file mode 100644
index 0000000000..cd5519a2a9
--- /dev/null
+++ b/usr/src/pkg/manifests/library-print-open-printing.mf
@@ -0,0 +1,55 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/library/print/open-printing@$(PKGVERS)
+set name=pkg.description \
+ value="Free Standards Group Open Printing API, Draft v0.9"
+set name=pkg.summary value="Free Standards Group Open Printing API"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=usr group=sys
+dir path=usr/include
+dir path=usr/lib
+dir path=usr/share/man
+dir path=usr/share/man/man3lib
+dir path=usr/share/man/man3papi
+file path=usr/include/papi.h
+file path=usr/lib/libpapi-common.so.0
+file path=usr/lib/libpapi.so.0
+file path=usr/share/man/man3lib/libpapi.3lib
+file path=usr/share/man/man3papi/papiAttributeListAddValue.3papi
+file path=usr/share/man/man3papi/papiJobSubmit.3papi
+file path=usr/share/man/man3papi/papiLibrarySupportedCall.3papi
+file path=usr/share/man/man3papi/papiPrintersList.3papi
+file path=usr/share/man/man3papi/papiServiceCreate.3papi
+file path=usr/share/man/man3papi/papiStatusString.3papi
+legacy pkg=SUNWpapi desc="Free Standards Group Open Printing API, Draft v0.9" \
+ name="Free Standards Group Open Printing API" \
+ version=11.11.0,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+link path=usr/lib/libpapi-common.so target=./libpapi-common.so.0
+link path=usr/lib/libpapi.so target=./libpapi.so.0
diff --git a/usr/src/pkg/manifests/print-lp-compatibility-sunos4.mf b/usr/src/pkg/manifests/print-lp-compatibility-sunos4.mf
new file mode 100644
index 0000000000..0608a1589b
--- /dev/null
+++ b/usr/src/pkg/manifests/print-lp-compatibility-sunos4.mf
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/print/lp/compatibility/sunos4@$(PKGVERS)
+set name=pkg.description \
+ value="print utilities for user interface and source build compatibility with SunOS 4.x"
+set name=pkg.summary value="Solaris Print - Source Compatibility"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=usr group=sys
+dir path=usr/ucb
+legacy pkg=SUNWscplp \
+ desc="print utilities for user interface and source build compatibility with SunOS 4.x" \
+ name="Solaris Print - Source Compatibility, (Usr)" \
+ version=13.1,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+license usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE \
+ license=usr/src/cmd/lp/cmd/lptest/THIRDPARTYLICENSE
+link path=usr/ucb/lpc target=../bin/lpc
+link path=usr/ucb/lpq target=../bin/lpq
+link path=usr/ucb/lpr target=../bin/lpr
+link path=usr/ucb/lprm target=../bin/lprm
+link path=usr/ucb/lptest target=../bin/lptest
diff --git a/usr/src/pkg/manifests/print-lp-filter-postscript-lp-filter.mf b/usr/src/pkg/manifests/print-lp-filter-postscript-lp-filter.mf
new file mode 100644
index 0000000000..4892b5524e
--- /dev/null
+++ b/usr/src/pkg/manifests/print-lp-filter-postscript-lp-filter.mf
@@ -0,0 +1,63 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/print/lp/filter/postscript-lp-filter@$(PKGVERS)
+set name=pkg.description \
+ value="client configuration files and utilities for the print service"
+set name=pkg.summary value="PostScript filters -"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=usr group=sys
+dir path=usr/lib
+dir path=usr/lib/lp group=lp
+dir path=usr/lib/lp/postscript group=lp
+dir path=usr/share/man/man1
+file path=usr/lib/lp/postscript/aps.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/banner.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/baseline.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/color.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/download group=lp mode=0555
+file path=usr/lib/lp/postscript/dpost group=lp mode=0555
+file path=usr/lib/lp/postscript/dpost.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/draw.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/fatcourier.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/forms.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/postcomm group=lp mode=0555
+file path=usr/lib/lp/postscript/postio group=lp mode=0555
+file path=usr/lib/lp/postscript/postprint group=lp mode=0555
+file path=usr/lib/lp/postscript/postprint.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/postreverse group=lp mode=0555
+file path=usr/lib/lp/postscript/ps.requests group=lp mode=0555
+file path=usr/share/man/man1/download.1
+file path=usr/share/man/man1/dpost.1
+file path=usr/share/man/man1/postio.1
+file path=usr/share/man/man1/postprint.1
+file path=usr/share/man/man1/postreverse.1
+legacy pkg=SUNWpsf \
+ desc="client configuration files and utilities for the print service" \
+ name="PostScript filters - (Usr)" version=13.1,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
diff --git a/usr/src/pkg/manifests/print-lp-ipp-ipp-listener.mf b/usr/src/pkg/manifests/print-lp-ipp-ipp-listener.mf
new file mode 100644
index 0000000000..fe8c53ad36
--- /dev/null
+++ b/usr/src/pkg/manifests/print-lp-ipp-ipp-listener.mf
@@ -0,0 +1,61 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/print/lp/ipp/ipp-listener@$(PKGVERS)
+set name=pkg.description \
+ value="Internet Printing Protocol(IPP) Apache module for listening service"
+set name=pkg.summary value="Internet Printing Protocol(IPP) listener module"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=etc group=sys
+dir path=etc/apache
+dir path=lib
+dir path=lib/svc
+dir path=lib/svc/manifest group=sys
+dir path=lib/svc/manifest/application group=sys
+dir path=lib/svc/manifest/application/print group=sys
+dir path=usr group=sys
+dir path=usr/apache
+dir path=usr/apache/libexec
+dir path=var group=sys
+dir path=var/lp group=lp mode=0775 owner=lp
+dir path=var/lp/ipp-listener
+file path=etc/apache/httpd-standalone-ipp.conf \
+ original_name=SUNWippl:etc/apache/httpd-standalone-ipp.conf preserve=true
+file path=lib/svc/manifest/application/print/ipp-listener.xml group=sys \
+ mode=0444
+file path=usr/apache/libexec/mod_ipp.so mode=0555
+file path=var/lp/ipp-listener/index.html mode=0444
+legacy pkg=SUNWipplr \
+ desc="Internet Printing Protocol(IPP) Apache configuration for service module" \
+ name="Internet Printing Protocol(IPP) listener, (root)" \
+ version=13.1,REV=2009.11.11
+legacy pkg=SUNWipplu \
+ desc="Internet Printing Protocol(IPP) Apache module for listening service" \
+ name="Internet Printing Protocol(IPP) listener module (/usr)" \
+ version=13.1,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
diff --git a/usr/src/pkg/manifests/print-lp-ipp-libipp.mf b/usr/src/pkg/manifests/print-lp-ipp-libipp.mf
new file mode 100644
index 0000000000..1de66b84cd
--- /dev/null
+++ b/usr/src/pkg/manifests/print-lp-ipp-libipp.mf
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/print/lp/ipp/libipp@$(PKGVERS)
+set name=pkg.description \
+ value="Internet Print Protocol (IPP) encoding/decoding/operation support"
+set name=pkg.summary value="Internet Printing Protocol(IPP) core libraries"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=usr group=sys
+dir path=usr/lib
+file path=usr/lib/libipp-core.so.0
+file path=usr/lib/libipp-listener.so.0
+legacy pkg=SUNWippcore \
+ desc="Internet Print Protocol (IPP) encoding/decoding/operation support" \
+ name="Internet Printing Protocol(IPP) core libraries, (usr)" \
+ version=13.1,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+link path=usr/lib/libipp-core.so target=./libipp-core.so.0
+link path=usr/lib/libipp-listener.so target=./libipp-listener.so.0
diff --git a/usr/src/pkg/manifests/print-lp-print-client-commands.mf b/usr/src/pkg/manifests/print-lp-print-client-commands.mf
new file mode 100644
index 0000000000..00c95a7972
--- /dev/null
+++ b/usr/src/pkg/manifests/print-lp-print-client-commands.mf
@@ -0,0 +1,84 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/print/lp/print-client-commands@$(PKGVERS)
+set name=pkg.description \
+ value="client configuration files and utilities for the print service"
+set name=pkg.summary value="Solaris Print - Client"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=usr group=sys
+dir path=usr/bin
+dir path=usr/lib
+dir path=usr/lib/lp group=lp
+dir path=usr/lib/lp/bin group=lp
+dir path=usr/sbin
+dir path=usr/share
+dir path=usr/share/applications group=other
+dir path=usr/share/gnome group=other
+dir path=usr/share/gnome/autostart
+dir path=usr/share/man/man1
+dir path=usr/share/man/man1m
+file path=usr/bin/desktop-print-management-applet mode=0555
+file path=usr/lib/lp/bin/desktop-print-management mode=0555
+file path=usr/lib/lp/bin/desktop-print-management-applet mode=0555
+file path=usr/lib/lp/bin/desktop-print-management-prefs mode=0555
+file path=usr/sbin/print-service mode=0555
+file path=usr/share/applications/desktop-print-management-prefs.desktop
+file path=usr/share/applications/desktop-print-management.desktop
+file path=usr/share/gnome/autostart/desktop-print-management-applet.desktop
+file path=usr/share/man/man1/cancel.1
+file path=usr/share/man/man1/enable.1
+file path=usr/share/man/man1/lp.1
+file path=usr/share/man/man1/lpstat.1
+file path=usr/share/man/man1m/accept.1m
+file path=usr/share/man/man1m/lpadmin.1m
+file path=usr/share/man/man1m/lpmove.1m
+file path=usr/share/man/man1m/print-service.1m
+legacy pkg=SUNWpcu \
+ desc="client configuration files and utilities for the print service" \
+ name="Solaris Print - Client, (usr)" version=13.1,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+link path=usr/bin/cancel target=../sbin/print-service
+link path=usr/bin/desktop-print-management target=../sbin/print-service
+link path=usr/bin/desktop-print-management-prefs target=../sbin/print-service
+link path=usr/bin/disable target=../sbin/print-service
+link path=usr/bin/enable target=../sbin/print-service
+link path=usr/bin/lp target=../sbin/print-service
+link path=usr/bin/lpc target=../sbin/print-service
+link path=usr/bin/lpq target=../sbin/print-service
+link path=usr/bin/lpr target=../sbin/print-service
+link path=usr/bin/lprm target=../sbin/print-service
+link path=usr/bin/lpstat target=../sbin/print-service
+link path=usr/sbin/accept target=./print-service
+link path=usr/sbin/lpadmin target=./print-service
+link path=usr/sbin/lpmove target=./print-service
+link path=usr/sbin/reject target=./print-service
+link path=usr/share/man/man1/disable.1 target=enable.1
+link path=usr/share/man/man1m/reject.1m target=accept.1m
+depend fmri=runtime/perl-510 type=require
diff --git a/usr/src/pkg/manifests/print-lp-print-manager-legacy.mf b/usr/src/pkg/manifests/print-lp-print-manager-legacy.mf
new file mode 100644
index 0000000000..864255aedc
--- /dev/null
+++ b/usr/src/pkg/manifests/print-lp-print-manager-legacy.mf
@@ -0,0 +1,79 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/print/lp/print-manager/legacy@$(PKGVERS)
+set name=pkg.description \
+ value="Graphical tool for managing printers under Solaris."
+set name=pkg.summary value="Solaris Print Manager"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=lib
+dir path=lib/svc
+dir path=lib/svc/manifest group=sys
+dir path=lib/svc/manifest/application group=sys
+dir path=lib/svc/manifest/application/print group=sys
+dir path=lib/svc/method
+dir path=usr group=sys
+dir path=usr/lib
+dir path=usr/lib/lp group=lp
+dir path=usr/lib/lp/bin group=lp
+dir path=usr/sadm
+dir path=usr/sadm/admin
+dir path=usr/sadm/admin/bin
+dir path=usr/sadm/admin/printmgr
+dir path=usr/sadm/admin/printmgr/classes
+dir path=usr/sadm/admin/printmgr/lib
+dir path=usr/sbin
+dir path=usr/share/man/man1m
+dir path=var group=sys
+dir path=var/lp group=lp mode=0775 owner=lp
+dir path=var/lp/ppd group=lp
+dir path=var/lp/ppd/caches group=lp
+file path=lib/svc/manifest/application/print/ppd-cache-update.xml group=sys \
+ mode=0444
+file path=lib/svc/method/ppd-cache-update mode=0555
+file path=usr/lib/lp/bin/getmakes group=lp mode=0555
+file path=usr/lib/lp/bin/getmodels group=lp mode=0555
+file path=usr/lib/lp/bin/getppdfile group=lp mode=0555
+file path=usr/lib/lp/bin/getppds group=lp mode=0555
+file path=usr/lib/lp/bin/ppdfilename2mmp group=lp mode=0555
+file path=usr/lib/lp/bin/printer-info group=lp mode=0555
+file path=usr/sadm/admin/bin/printmgr group=lp mode=0555
+file path=usr/sadm/admin/printmgr/classes/pmclient.jar group=lp
+file path=usr/sadm/admin/printmgr/classes/pmserver.jar group=lp
+file path=usr/sadm/admin/printmgr/lib/libpmgr.so.1 group=lp
+file path=usr/sbin/ppdmgr group=lp mode=0555
+file path=usr/share/man/man1m/ppdmgr.1m
+file path=usr/share/man/man1m/printmgr.1m
+file path=var/lp/ppd/manufaliases group=lp mode=0444
+legacy pkg=SUNWppm desc="Graphical tool for managing printers under Solaris." \
+ name="Solaris Print Manager"
+legacy pkg=SUNWppmr desc="Graphical tool for managing printers under Solaris." \
+ name="Solaris Print Manager (Root)"
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+link path=usr/sadm/admin/printmgr/lib/libpmgr.so target=./libpmgr.so.1
+link path=usr/sbin/printmgr target=../../usr/sadm/admin/bin/printmgr
diff --git a/usr/src/pkg/manifests/print-lp.mf b/usr/src/pkg/manifests/print-lp.mf
new file mode 100644
index 0000000000..a8088194a7
--- /dev/null
+++ b/usr/src/pkg/manifests/print-lp.mf
@@ -0,0 +1,171 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+#
+
+set name=pkg.fmri value=pkg:/print/lp@$(PKGVERS)
+set name=pkg.description \
+ value="client configuration files and utilities for the print service"
+set name=pkg.summary value="Solaris Print - LP Server"
+set name=info.classification \
+ value=org.opensolaris.category.2008:System/Printing
+set name=variant.arch value=$(ARCH)
+dir path=etc group=sys
+dir path=etc/lp group=lp mode=0775 owner=lp
+dir path=etc/lp/classes group=lp mode=0775 owner=lp
+dir path=etc/lp/fd group=lp
+dir path=etc/lp/forms group=lp mode=0775 owner=lp
+dir path=etc/lp/interfaces group=lp mode=0775 owner=lp
+dir path=etc/lp/ppd group=lp mode=0775 owner=lp
+dir path=etc/lp/printers group=lp mode=0775 owner=lp
+dir path=etc/lp/pwheels group=lp mode=0775 owner=lp
+dir path=lib
+dir path=lib/svc
+dir path=lib/svc/manifest group=sys
+dir path=lib/svc/manifest/application group=sys
+dir path=lib/svc/manifest/application/print group=sys
+dir path=lib/svc/method
+dir path=usr group=sys
+dir path=usr/bin
+dir path=usr/lib
+dir path=usr/lib/lp group=lp
+dir path=usr/lib/lp/bin group=lp
+dir path=usr/lib/lp/local group=lp
+dir path=usr/lib/lp/model group=lp
+dir path=usr/lib/print group=lp
+dir path=usr/sbin
+dir path=usr/share
+dir path=usr/share/man
+dir path=usr/share/man/man1m
+dir path=usr/share/man/man4
+dir path=var group=sys
+dir path=var/lp group=lp mode=0775 owner=lp
+dir path=var/lp/logs group=lp mode=0775 owner=lp
+dir path=var/spool
+dir path=var/spool/cron group=sys
+dir path=var/spool/cron/crontabs group=sys
+dir path=var/spool/lp group=lp mode=0775 owner=lp
+dir path=var/spool/lp/admins group=lp mode=0775 owner=lp
+dir path=var/spool/lp/requests group=lp mode=0775 owner=lp
+dir path=var/spool/lp/system group=lp mode=0775 owner=lp
+dir path=var/spool/print group=lp
+file path=etc/lp/fd/catv.fd group=lp
+file path=etc/lp/fd/download.fd group=lp
+file path=etc/lp/fd/dpost.fd group=lp
+file path=etc/lp/fd/postio.fd group=lp
+file path=etc/lp/fd/postior.fd group=lp
+file path=etc/lp/fd/postpages.fd group=lp
+file path=etc/lp/fd/postprint.fd group=lp
+file path=etc/lp/fd/postreverse.fd group=lp
+file path=etc/lp/fd/pr.fd group=lp
+file path=etc/printers.conf group=sys original_name=SUNWpc:etc/printers.conf \
+ preserve=true
+file path=lib/svc/manifest/application/print/rfc1179.xml group=sys mode=0444
+file path=lib/svc/manifest/application/print/server.xml group=sys mode=0444
+file path=lib/svc/method/print-svc mode=0555
+file path=usr/bin/lpget group=lp mode=0511
+file path=usr/bin/lpset group=lp mode=4511
+file path=usr/bin/lptest group=lp mode=0555
+file path=usr/lib/libprint.so.2
+file path=usr/lib/lp/bin/accept mode=0555
+file path=usr/lib/lp/bin/alert.proto group=lp mode=0444
+file path=usr/lib/lp/bin/cancel mode=0555
+file path=usr/lib/lp/bin/disable mode=0555
+file path=usr/lib/lp/bin/drain.output group=lp mode=0555
+file path=usr/lib/lp/bin/enable mode=0555
+file path=usr/lib/lp/bin/lp mode=0555
+file path=usr/lib/lp/bin/lp.cat group=lp mode=0555
+file path=usr/lib/lp/bin/lp.set group=lp mode=0555
+file path=usr/lib/lp/bin/lp.tell group=lp mode=0555
+file path=usr/lib/lp/bin/lpadmin mode=0555
+file path=usr/lib/lp/bin/lpc mode=0555
+file path=usr/lib/lp/bin/lpmove mode=0555
+file path=usr/lib/lp/bin/lpq mode=0555
+file path=usr/lib/lp/bin/lpr mode=0555
+file path=usr/lib/lp/bin/lprm mode=0555
+file path=usr/lib/lp/bin/lpstat mode=0555
+file path=usr/lib/lp/bin/netpr mode=4511
+file path=usr/lib/lp/bin/reject mode=0555
+file path=usr/lib/lp/bin/slow.filter group=lp mode=0555
+file path=usr/lib/lp/local/lpadmin group=lp mode=0555
+file path=usr/lib/lp/local/lpsched group=lp mode=0555
+file path=usr/lib/lp/local/lpshut group=lp mode=0555
+file path=usr/lib/lp/model/netstandard group=lp mode=0555
+file path=usr/lib/lp/model/standard group=lp mode=0555
+file path=usr/lib/lp/model/uri group=lp mode=0555
+file path=usr/lib/lpsched group=lp mode=0555
+file path=usr/lib/print/Makefile.yp group=lp mode=0444
+file path=usr/lib/print/conv_fix group=lp mode=0555
+file path=usr/lib/print/conv_lp group=lp mode=0555
+file path=usr/lib/print/conv_lpd group=lp mode=0555
+file path=usr/lib/print/in.lpd mode=0555
+file path=usr/lib/print/psm-lpsched.so.1 group=lp
+file path=usr/sbin/lpfilter group=lp mode=0555
+file path=usr/sbin/lpforms group=lp mode=0555
+file path=usr/sbin/lpshut group=lp mode=0555
+file path=usr/sbin/lpsystem group=lp mode=0555
+file path=usr/sbin/lpusers group=lp mode=0555
+file path=usr/share/man/man1m/conv_lp.1m
+file path=usr/share/man/man1m/conv_lpd.1m
+file path=usr/share/man/man1m/in.lpd.1m
+file path=usr/share/man/man1m/lpfilter.1m
+file path=usr/share/man/man1m/lpforms.1m
+file path=usr/share/man/man1m/lpget.1m
+file path=usr/share/man/man1m/lpsched.1m
+file path=usr/share/man/man1m/lpset.1m
+file path=usr/share/man/man1m/lpshut.1m
+file path=usr/share/man/man1m/lpsystem.1m
+file path=usr/share/man/man1m/lpusers.1m
+file path=usr/share/man/man4/printers.4
+file path=usr/share/man/man4/printers.conf.4
+file path=var/spool/cron/crontabs/lp group=root mode=0400 \
+ original_name=SUNWps:var/spool/cron/crontabs/lp preserve=true
+legacy pkg=SUNWpsr \
+ desc="configuration and start-up files for the print service" \
+ name="Solaris Print - LP Server, (root)" version=13.1,REV=2009.11.11
+legacy pkg=SUNWpsu \
+ desc="client configuration files and utilities for the print service" \
+ name="Solaris Print - LP Server, (usr)" version=13.1,REV=2009.11.11
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+link path=etc/lp/logs target=../../var/lp/logs
+link path=usr/lib/accept target=../sbin/accept
+link path=usr/lib/libprint.so target=./libprint.so.2
+link path=usr/lib/lpadmin target=../sbin/lpadmin
+link path=usr/lib/lpfilter target=../sbin/lpfilter
+link path=usr/lib/lpforms target=../sbin/lpforms
+link path=usr/lib/lpmove target=../sbin/lpmove
+link path=usr/lib/lpshut target=../sbin/lpshut
+link path=usr/lib/lpsystem target=../sbin/lpsystem
+link path=usr/lib/lpusers target=../sbin/lpusers
+link path=usr/lib/print/psm-lpsched.so target=./psm-lpsched.so.1
+link path=usr/lib/reject target=../sbin/reject
+link path=var/spool/lp/admins/lp target=../../../../etc/lp
+link path=var/spool/lp/bin target=../../../usr/lib/lp/bin
+link path=var/spool/lp/logs target=../../lp/logs
+link path=var/spool/lp/model target=../../../usr/lib/lp/model
+#
+# Depend on terminfo data.
+#
+depend fmri=system/data/terminfo type=require
diff --git a/usr/src/pkg/manifests/system-trusted.mf b/usr/src/pkg/manifests/system-trusted.mf
index cea17dd482..a3dbebe5ae 100644
--- a/usr/src/pkg/manifests/system-trusted.mf
+++ b/usr/src/pkg/manifests/system-trusted.mf
@@ -51,6 +51,10 @@ dir path=usr/lib/help/auths/locale/C
dir path=usr/lib/help/profiles
dir path=usr/lib/help/profiles/locale
dir path=usr/lib/help/profiles/locale/C
+dir path=usr/lib/lp group=lp
+dir path=usr/lib/lp/bin group=lp
+dir path=usr/lib/lp/model group=lp
+dir path=usr/lib/lp/postscript group=lp
dir path=usr/lib/zones
dir path=usr/sbin
dir path=usr/share/man
@@ -98,6 +102,16 @@ file path=usr/lib/help/profiles/locale/C/RtInfoSec.html
file path=usr/lib/help/profiles/locale/C/RtObjectLabelMngmnt.html
file path=usr/lib/help/profiles/locale/C/RtOutsideAccred.html
file path=usr/lib/labeld mode=0555
+file path=usr/lib/lp/bin/lp.tsol_separator group=lp mode=0555
+file path=usr/lib/lp/model/tsol_netstandard group=lp mode=0555
+file path=usr/lib/lp/model/tsol_netstandard_foomatic group=lp mode=0555
+file path=usr/lib/lp/model/tsol_standard group=lp mode=0555
+file path=usr/lib/lp/model/tsol_standard_foomatic group=lp mode=0555
+file path=usr/lib/lp/postscript/tsol_banner.ps group=lp mode=0555
+file path=usr/lib/lp/postscript/tsol_separator.ps group=lp mode=0555 \
+ original_name=SUNWts:usr/lib/lp/postscript/tsol_separator.ps \
+ preserve=renamenew
+file path=usr/lib/lp/postscript/tsol_trailer.ps group=lp mode=0555
file path=usr/lib/lslabels group=sys mode=0555
file path=usr/lib/zones/zoneshare group=sys mode=0555
file path=usr/lib/zones/zoneunshare group=sys mode=0555
diff --git a/usr/src/pkg/manifests/text-doctools.mf b/usr/src/pkg/manifests/text-doctools.mf
index efe5ae29e5..96100bcc65 100644
--- a/usr/src/pkg/manifests/text-doctools.mf
+++ b/usr/src/pkg/manifests/text-doctools.mf
@@ -68,6 +68,168 @@ file path=usr/bin/tbl mode=0555
file path=usr/bin/troff mode=0555
file path=usr/bin/ul mode=0555
file path=usr/bin/vgrind mode=0555
+file path=usr/lib/font/devpost/AB group=lp mode=0444
+file path=usr/lib/font/devpost/AB.name group=lp mode=0444
+file path=usr/lib/font/devpost/AB.out group=lp mode=0444
+file path=usr/lib/font/devpost/AI group=lp mode=0444
+file path=usr/lib/font/devpost/AI.name group=lp mode=0444
+file path=usr/lib/font/devpost/AI.out group=lp mode=0444
+file path=usr/lib/font/devpost/AR group=lp mode=0444
+file path=usr/lib/font/devpost/AR.name group=lp mode=0444
+file path=usr/lib/font/devpost/AR.out group=lp mode=0444
+file path=usr/lib/font/devpost/AX group=lp mode=0444
+file path=usr/lib/font/devpost/AX.name group=lp mode=0444
+file path=usr/lib/font/devpost/AX.out group=lp mode=0444
+file path=usr/lib/font/devpost/B group=lp mode=0444
+file path=usr/lib/font/devpost/B.name group=lp mode=0444
+file path=usr/lib/font/devpost/B.out group=lp mode=0444
+file path=usr/lib/font/devpost/BI group=lp mode=0444
+file path=usr/lib/font/devpost/BI.name group=lp mode=0444
+file path=usr/lib/font/devpost/BI.out group=lp mode=0444
+file path=usr/lib/font/devpost/CB group=lp mode=0444
+file path=usr/lib/font/devpost/CB.name group=lp mode=0444
+file path=usr/lib/font/devpost/CB.out group=lp mode=0444
+file path=usr/lib/font/devpost/CI group=lp mode=0444
+file path=usr/lib/font/devpost/CI.name group=lp mode=0444
+file path=usr/lib/font/devpost/CI.out group=lp mode=0444
+file path=usr/lib/font/devpost/CO group=lp mode=0444
+file path=usr/lib/font/devpost/CO.name group=lp mode=0444
+file path=usr/lib/font/devpost/CO.out group=lp mode=0444
+file path=usr/lib/font/devpost/CW group=lp mode=0444
+file path=usr/lib/font/devpost/CW.name group=lp mode=0444
+file path=usr/lib/font/devpost/CW.out group=lp mode=0444
+file path=usr/lib/font/devpost/CX group=lp mode=0444
+file path=usr/lib/font/devpost/CX.name group=lp mode=0444
+file path=usr/lib/font/devpost/CX.out group=lp mode=0444
+file path=usr/lib/font/devpost/DESC group=lp mode=0444
+file path=usr/lib/font/devpost/DESC.out group=lp mode=0444
+file path=usr/lib/font/devpost/G.out group=lp mode=0444
+file path=usr/lib/font/devpost/GI.out group=lp mode=0444
+file path=usr/lib/font/devpost/GR group=lp mode=0444
+file path=usr/lib/font/devpost/GR.name group=lp mode=0444
+file path=usr/lib/font/devpost/GR.out group=lp mode=0444
+file path=usr/lib/font/devpost/H group=lp mode=0444
+file path=usr/lib/font/devpost/H.name group=lp mode=0444
+file path=usr/lib/font/devpost/H.out group=lp mode=0444
+file path=usr/lib/font/devpost/HB group=lp mode=0444
+file path=usr/lib/font/devpost/HB.name group=lp mode=0444
+file path=usr/lib/font/devpost/HB.out group=lp mode=0444
+file path=usr/lib/font/devpost/HI group=lp mode=0444
+file path=usr/lib/font/devpost/HI.name group=lp mode=0444
+file path=usr/lib/font/devpost/HI.out group=lp mode=0444
+file path=usr/lib/font/devpost/HK.out group=lp mode=0444
+file path=usr/lib/font/devpost/HL.out group=lp mode=0444
+file path=usr/lib/font/devpost/HM.out group=lp mode=0444
+file path=usr/lib/font/devpost/HX group=lp mode=0444
+file path=usr/lib/font/devpost/HX.name group=lp mode=0444
+file path=usr/lib/font/devpost/HX.out group=lp mode=0444
+file path=usr/lib/font/devpost/Hb group=lp mode=0444
+file path=usr/lib/font/devpost/Hb.name group=lp mode=0444
+file path=usr/lib/font/devpost/Hb.out group=lp mode=0444
+file path=usr/lib/font/devpost/Hi group=lp mode=0444
+file path=usr/lib/font/devpost/Hi.name group=lp mode=0444
+file path=usr/lib/font/devpost/Hi.out group=lp mode=0444
+file path=usr/lib/font/devpost/Hr group=lp mode=0444
+file path=usr/lib/font/devpost/Hr.name group=lp mode=0444
+file path=usr/lib/font/devpost/Hr.out group=lp mode=0444
+file path=usr/lib/font/devpost/Hx group=lp mode=0444
+file path=usr/lib/font/devpost/Hx.name group=lp mode=0444
+file path=usr/lib/font/devpost/Hx.out group=lp mode=0444
+file path=usr/lib/font/devpost/I group=lp mode=0444
+file path=usr/lib/font/devpost/I.name group=lp mode=0444
+file path=usr/lib/font/devpost/I.out group=lp mode=0444
+file path=usr/lib/font/devpost/KB group=lp mode=0444
+file path=usr/lib/font/devpost/KB.name group=lp mode=0444
+file path=usr/lib/font/devpost/KB.out group=lp mode=0444
+file path=usr/lib/font/devpost/KI group=lp mode=0444
+file path=usr/lib/font/devpost/KI.name group=lp mode=0444
+file path=usr/lib/font/devpost/KI.out group=lp mode=0444
+file path=usr/lib/font/devpost/KR group=lp mode=0444
+file path=usr/lib/font/devpost/KR.name group=lp mode=0444
+file path=usr/lib/font/devpost/KR.out group=lp mode=0444
+file path=usr/lib/font/devpost/KX group=lp mode=0444
+file path=usr/lib/font/devpost/KX.name group=lp mode=0444
+file path=usr/lib/font/devpost/KX.out group=lp mode=0444
+file path=usr/lib/font/devpost/NB group=lp mode=0444
+file path=usr/lib/font/devpost/NB.name group=lp mode=0444
+file path=usr/lib/font/devpost/NB.out group=lp mode=0444
+file path=usr/lib/font/devpost/NI group=lp mode=0444
+file path=usr/lib/font/devpost/NI.name group=lp mode=0444
+file path=usr/lib/font/devpost/NI.out group=lp mode=0444
+file path=usr/lib/font/devpost/NR group=lp mode=0444
+file path=usr/lib/font/devpost/NR.name group=lp mode=0444
+file path=usr/lib/font/devpost/NR.out group=lp mode=0444
+file path=usr/lib/font/devpost/NX group=lp mode=0444
+file path=usr/lib/font/devpost/NX.name group=lp mode=0444
+file path=usr/lib/font/devpost/NX.out group=lp mode=0444
+file path=usr/lib/font/devpost/PA group=lp mode=0444
+file path=usr/lib/font/devpost/PA.name group=lp mode=0444
+file path=usr/lib/font/devpost/PA.out group=lp mode=0444
+file path=usr/lib/font/devpost/PB group=lp mode=0444
+file path=usr/lib/font/devpost/PB.name group=lp mode=0444
+file path=usr/lib/font/devpost/PB.out group=lp mode=0444
+file path=usr/lib/font/devpost/PI group=lp mode=0444
+file path=usr/lib/font/devpost/PI.name group=lp mode=0444
+file path=usr/lib/font/devpost/PI.out group=lp mode=0444
+file path=usr/lib/font/devpost/PX group=lp mode=0444
+file path=usr/lib/font/devpost/PX.name group=lp mode=0444
+file path=usr/lib/font/devpost/PX.out group=lp mode=0444
+file path=usr/lib/font/devpost/R group=lp mode=0444
+file path=usr/lib/font/devpost/R.name group=lp mode=0444
+file path=usr/lib/font/devpost/R.out group=lp mode=0444
+file path=usr/lib/font/devpost/S group=lp mode=0444
+file path=usr/lib/font/devpost/S.name group=lp mode=0444
+file path=usr/lib/font/devpost/S.out group=lp mode=0444
+file path=usr/lib/font/devpost/S1 group=lp mode=0444
+file path=usr/lib/font/devpost/S1.name group=lp mode=0444
+file path=usr/lib/font/devpost/S1.out group=lp mode=0444
+file path=usr/lib/font/devpost/VB group=lp mode=0444
+file path=usr/lib/font/devpost/VB.name group=lp mode=0444
+file path=usr/lib/font/devpost/VB.out group=lp mode=0444
+file path=usr/lib/font/devpost/VI group=lp mode=0444
+file path=usr/lib/font/devpost/VI.name group=lp mode=0444
+file path=usr/lib/font/devpost/VI.out group=lp mode=0444
+file path=usr/lib/font/devpost/VR group=lp mode=0444
+file path=usr/lib/font/devpost/VR.name group=lp mode=0444
+file path=usr/lib/font/devpost/VR.out group=lp mode=0444
+file path=usr/lib/font/devpost/VX group=lp mode=0444
+file path=usr/lib/font/devpost/VX.name group=lp mode=0444
+file path=usr/lib/font/devpost/VX.out group=lp mode=0444
+file path=usr/lib/font/devpost/ZD group=lp mode=0444
+file path=usr/lib/font/devpost/ZD.name group=lp mode=0444
+file path=usr/lib/font/devpost/ZD.out group=lp mode=0444
+file path=usr/lib/font/devpost/ZI group=lp mode=0444
+file path=usr/lib/font/devpost/ZI.name group=lp mode=0444
+file path=usr/lib/font/devpost/ZI.out group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/12 group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/14 group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/34 group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/BRACKETS_NOTE group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/Fi group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/Fl group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/L1 group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/L1.map group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/LH group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/LH.map group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/Lb group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/Lb.map group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/OLD_LH group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/OLD_LH.map group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/README group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/Sl group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/bx group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/ci group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/ff group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/lc group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/lf group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/lh group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/ob group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/rc group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/rf group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/rh group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/sq group=lp mode=0444
+file path=usr/lib/font/devpost/charlib/~ group=lp mode=0444
+file path=usr/lib/font/makedev group=lp mode=0555
file path=usr/lib/getNAME mode=0555
file path=usr/lib/makewhatis mode=0555
file path=usr/lib/refer/hunt mode=0555