IdLPR.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. { $HDR$}
  2. {**********************************************************************}
  3. { Unit archived using Team Coherence }
  4. { Team Coherence is Copyright 2002 by Quality Software Components }
  5. { }
  6. { For further information / comments, visit our WEB site at }
  7. { http://www.TeamCoherence.com }
  8. {**********************************************************************}
  9. {}
  10. { $Log: 10241: IdLPR.pas
  11. {
  12. { Rev 1.1 7/23/04 6:12:02 PM RLebeau
  13. { Added try...finally block to PrintFile()
  14. }
  15. {
  16. { Rev 1.0 2002.11.12 10:44:46 PM czhower
  17. }
  18. unit IdLPR;
  19. (*******************************************************}
  20. { }
  21. { Indy Line Print Remote TIdLPR }
  22. { }
  23. { Version 9.1.0 }
  24. { }
  25. { Original author Mario Mueller }
  26. { }
  27. { home: www.hemasoft.de }
  28. { mail: [email protected] }
  29. { }
  30. { 27.07. rewrite component for integration }
  31. { in Indy core library }
  32. { }
  33. {*******************************************************)
  34. interface
  35. uses
  36. Classes,
  37. IdAssignedNumbers, IdException, IdGlobal, IdTCPClient, IdComponent, SysUtils;
  38. type
  39. TIdLPRFileFormat =
  40. (ffCIF, // CalTech Intermediate Form
  41. ffDVI, // DVI (TeX output).
  42. ffFormattedText, //add formatting as needed to text file
  43. ffPlot, // Berkeley Unix plot library
  44. ffControlCharText, //text file with control charactors
  45. ffDitroff, // ditroff output
  46. ffPostScript, //Postscript output file
  47. ffPR,//'pr' format {Do not Localize}
  48. ffFORTRAM, // FORTRAN carriage control
  49. ffTroff, //Troff output
  50. ffSunRaster); // Sun raster format file
  51. const
  52. DEF_FILEFORMAT = ffControlCharText;
  53. DEF_INDENTCOUNT = 0;
  54. DEF_BANNERPAGE = False;
  55. DEF_OUTPUTWIDTH = 0;
  56. DEF_MAILWHENPRINTED = False;
  57. type
  58. TIdLPRControlFile = class(TPersistent)
  59. protected
  60. FBannerClass: String; // 'C' {Do not Localize}
  61. FHostName: String; // 'H' {Do not Localize}
  62. FIndentCount: Integer; // 'I' {Do not Localize}
  63. FJobName: String; // 'J' {Do not Localize}
  64. FBannerPage: Boolean; // 'L' {Do not Localize}
  65. FUserName: String; // 'P' {Do not Localize}
  66. FOutputWidth: Integer; // 'W' {Do not Localize}
  67. FFileFormat : TIdLPRFileFormat;
  68. FTroffRomanFont : String; //substitue the Roman font with the font in file
  69. FTroffItalicFont : String;//substitue the Italic font with the font in file
  70. FTroffBoldFont : String; //substitue the bold font with the font in file
  71. FTroffSpecialFont : String; //substitue the special font with the font
  72. //in this file
  73. FMailWhenPrinted : Boolean; //mail me when you have printed the job
  74. public
  75. constructor Create;
  76. procedure Assign(Source: TPersistent); override;
  77. property HostName: String read FHostName write FHostName;
  78. published
  79. property BannerClass: String read FBannerClass write FBannerClass;
  80. property IndentCount: Integer read FIndentCount write FIndentCount
  81. default DEF_INDENTCOUNT;
  82. property JobName: String read FJobName write FJobName;
  83. property BannerPage: Boolean read FBannerPage write FBannerPage
  84. default DEF_BANNERPAGE;
  85. property UserName: String read FUserName write FUserName;
  86. property OutputWidth: Integer read FOutputWidth write FOutputWidth
  87. default DEF_OUTPUTWIDTH;
  88. property FileFormat: TIdLPRFileFormat read FFileFormat write FFileFormat
  89. default DEF_FILEFORMAT;
  90. {font data }
  91. property TroffRomanFont : String read FTroffRomanFont write FTroffRomanFont;
  92. property TroffItalicFont : String read FTroffItalicFont
  93. write FTroffItalicFont;
  94. property TroffBoldFont : String read FTroffBoldFont write FTroffBoldFont;
  95. property TroffSpecialFont : String read FTroffSpecialFont
  96. write FTroffSpecialFont;
  97. {misc}
  98. property MailWhenPrinted : Boolean read FMailWhenPrinted
  99. write FMailWhenPrinted default DEF_MAILWHENPRINTED;
  100. end;
  101. type
  102. TIdLPRStatus = (psPrinting, psJobCompleted, psError, psGettingQueueState,
  103. psGotQueueState, psDeletingJobs, psJobsDeleted, psPrintingWaitingJobs,
  104. psPrintedWaitingJobs);
  105. type
  106. TIdLPRStatusEvent = procedure(ASender: TObject;
  107. const AStatus: TIdLPRStatus;
  108. const AStatusText: String) of object;
  109. type
  110. TIdLPR = class(TIdTCPClient)
  111. protected
  112. FOnLPRStatus: TIdLPRStatusEvent;
  113. FQueue: String;
  114. FJobId: Integer;
  115. FControlFile: TIdLPRControlFile;
  116. procedure DoOnLPRStatus(const AStatus: TIdLPRStatus;
  117. const AStatusText: String);
  118. procedure SeTIdLPRControlFile(const Value: TIdLPRControlFile);
  119. procedure CheckReply;
  120. function GetJobId: String;
  121. procedure SetJobId(JobId: String);
  122. procedure InternalPrint(Data: TStream);
  123. function GetControlData: String;
  124. public
  125. constructor Create(AOwner: TComponent); override;
  126. destructor Destroy; override;
  127. procedure Print(AText: String); overload;
  128. procedure Print(ABuffer: array of Byte); overload;
  129. procedure PrintFile(AFileName: String);
  130. function GetQueueState(const AShortFormat: Boolean = false;
  131. const AList : String = '') : String; {Do not Localize}
  132. procedure PrintWaitingJobs;
  133. procedure RemoveJobList(AList : String; const AAsRoot: Boolean =False);
  134. property JobId: String read GetJobId write SetJobId;
  135. published
  136. property Queue: String read FQueue write FQueue;
  137. property ControlFile: TIdLPRControlFile read FControlFile write SeTIdLPRControlFile;
  138. property OnLPRStatus: TIdLPRStatusEvent read FOnLPRStatus write FOnLPRStatus;
  139. end;
  140. type EIdLPRErrorException = class(EIdException);
  141. implementation
  142. uses IdResourceStrings, IdStack;
  143. {*********************** TIdLPR **********************}
  144. constructor TIdLPR.Create(AOwner: TComponent);
  145. begin
  146. Inherited Create(AOwner);
  147. Port := IdPORT_LPD;
  148. Queue := 'pr1'; {Do not Localize}
  149. FJobId := 1;
  150. FControlFile := TIdLPRControlFile.Create;
  151. // Restriction in RFC 1179
  152. // The source port must be in the range 721 to 731, inclusive.
  153. // known -problem with this some trouble while multible printjobs are running
  154. // This is the FD_WAIT port problem where a port is in a FD_WAIT state
  155. // but you can bind to it. You get a port reuse error.
  156. BoundPortMin:=721;
  157. BoundPortMax:=731;
  158. end;
  159. procedure TIdLPR.Print(AText: String);
  160. var ds: TMemoryStream;
  161. begin
  162. ds:=TMemoryStream.Create;
  163. if Length(AText) > 0 then
  164. begin
  165. ds.Write(AText[1], Length(AText));
  166. end;
  167. InternalPrint(ds);
  168. FreeAndNil(ds);
  169. end;
  170. procedure TIdLPR.Print(ABuffer: array of Byte);
  171. var ds: TMemoryStream;
  172. begin
  173. ds:=TMemoryStream.Create;
  174. ds.Write(ABuffer[0], Length(ABuffer));
  175. InternalPrint(ds);
  176. FreeAndNil(ds);
  177. end;
  178. procedure TIdLPR.PrintFile(AFileName: String);
  179. var fs: TFileStream;
  180. p: Integer;
  181. begin
  182. p := RPos(GPathDelim, AFileName);
  183. ControlFile.JobName:=Copy(AFileName, p+1, Length(AFileName)-p);
  184. fs := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
  185. try
  186. InternalPrint(fs);
  187. finally
  188. FreeAndNil(fs);
  189. end;
  190. end;
  191. function TIdLPR.GetJobId: String;
  192. begin
  193. Result:=Format('%.3d', [FJobId]); {Do not Localize}
  194. end;
  195. procedure TIdLPR.SetJobId(JobId: String);
  196. begin
  197. if StrToInt(JobId) < 999 then
  198. FJobId:=StrToInt(JobId);
  199. end;
  200. procedure TIdLPR.InternalPrint(Data: TStream);
  201. begin
  202. try
  203. if Connected then
  204. begin
  205. Inc(FJobID);
  206. if FJobID > 999 then
  207. begin
  208. FJobID:=1;
  209. end;
  210. DoOnLPRStatus(psPrinting, JobID);
  211. try
  212. ControlFile.HostName:=Self.IOHandler.LocalName;
  213. except
  214. ControlFile.HostName:='localhost'; {Do not Localize}
  215. end;
  216. // Receive a printer job
  217. Write(#02 + Queue + LF);
  218. CheckReply;
  219. // Receive control file
  220. Write(#02 + IntToStr(Length(GetControlData)) +
  221. ' cfA' + JobId + ControlFile.HostName + LF); {Do not Localize}
  222. CheckReply;
  223. // Send control file
  224. Write(GetControlData);
  225. Write(#0);
  226. CheckReply;
  227. // Send data file
  228. Write(#03 + IntToStr(Data.Size) + ' dfA' + JobId + {Do not Localize}
  229. ControlFile.HostName + LF);
  230. CheckReply;
  231. // Send data
  232. WriteStream(Data);
  233. Write(#0);
  234. CheckReply;
  235. DoOnLPRStatus(psJobCompleted, JobID);
  236. end; // if connected
  237. except
  238. on E: Exception do
  239. DoOnLPRStatus(psError, E.Message);
  240. end;
  241. end;
  242. function TIdLPR.GetQueueState(const AShortFormat: Boolean = false;
  243. const AList : String = '') : String; {Do not Localize}
  244. begin
  245. DoOnLPRStatus(psGettingQueueState, AList);
  246. if AShortFormat then
  247. Write(#03 + Queue + ' ' + AList + LF) {Do not Localize}
  248. else
  249. Write(#04 + Queue + ' ' + AList + LF); {Do not Localize}
  250. // This was the original code - problematic as this is more than one line
  251. // read until I close the connection
  252. // result:=ReadLn(LF);
  253. Result := AllData;
  254. DoOnLPRStatus(psGotQueueState, result);
  255. end;
  256. function TIdLPR.GetControlData: String;
  257. var Data: String;
  258. begin
  259. try
  260. Data:=''; {Do not Localize}
  261. with ControlFile do
  262. begin
  263. // H - Host name
  264. Data:=Data + 'H' + HostName + LF; {Do not Localize}
  265. // P - User identification
  266. Data:=Data + 'P' + UserName + LF; {Do not Localize}
  267. // J - Job name for banner page
  268. if Length(JobName) > 0 then
  269. begin
  270. Data:=Data + 'J' + JobName + LF; {Do not Localize}
  271. end
  272. else
  273. begin
  274. Data:=Data + 'JcfA' + JobId + HostName + LF; {Do not Localize}
  275. end;
  276. //mail when printed
  277. if FMailWhenPrinted then
  278. begin
  279. Data:=Data + 'M' + UserName + LF; {Do not Localize}
  280. end;
  281. case FFileFormat of
  282. ffCIF : // CalTech Intermediate Form
  283. begin
  284. Data:=Data + 'cdfA' + JobId + HostName + LF; {Do not Localize}
  285. end;
  286. ffDVI : // DVI (TeX output).
  287. begin
  288. Data:=Data + 'ddfA' + JobId + HostName + LF; {Do not Localize}
  289. end;
  290. ffFormattedText : //add formatting as needed to text file
  291. begin
  292. Data:=Data + 'fdfA' + JobId + HostName + LF; {Do not Localize}
  293. end;
  294. ffPlot : // Berkeley Unix plot library
  295. begin
  296. Data:=Data + 'gdfA' + JobId + HostName + LF; {Do not Localize}
  297. end;
  298. ffControlCharText : //text file with control charactors
  299. begin
  300. Data:=Data + 'ldfA' + JobId + HostName + LF; {Do not Localize}
  301. end;
  302. ffDitroff : // ditroff output
  303. begin
  304. Data:=Data + 'ndfA' + JobId + HostName + LF; {Do not Localize}
  305. end;
  306. ffPostScript : //Postscript output file
  307. begin
  308. Data:=Data + 'odfA' + JobId + HostName + LF; {Do not Localize}
  309. end;
  310. ffPR : //'pr' format {Do not Localize}
  311. begin
  312. Data:=Data + 'pdfA' + JobId + HostName + LF; {Do not Localize}
  313. end;
  314. ffFORTRAM : // FORTRAN carriage control
  315. begin
  316. Data:=Data + 'rdfA' + JobId + HostName + LF; {Do not Localize}
  317. end;
  318. ffTroff : //Troff output
  319. begin
  320. Data:=Data + 'ldfA' + JobId + HostName + LF; {Do not Localize}
  321. end;
  322. ffSunRaster : // Sun raster format file
  323. begin
  324. end;
  325. end;
  326. // U - Unlink data file
  327. Data:=Data + 'UdfA' + JobId + HostName + LF; {Do not Localize}
  328. // N - Name of source file
  329. Data:=Data + 'NcfA' + JobId + HostName + LF; {Do not Localize}
  330. if (FFileFormat = ffFormattedText) then
  331. begin
  332. if (IndentCount > 0) then
  333. begin
  334. Data:=Data + 'I' + IntToStr(IndentCount) + LF; {Do not Localize}
  335. end;
  336. if (OutputWidth > 0) then
  337. begin
  338. Data:=Data + 'W' + IntToStr(OutputWidth) + LF; {Do not Localize}
  339. end;
  340. end;
  341. if Length(BannerClass) > 0 then
  342. begin
  343. Data:=Data + 'C' + BannerClass + LF; {Do not Localize}
  344. end;
  345. if BannerPage then
  346. begin
  347. Data:=Data + 'L' + UserName + LF; {Do not Localize}
  348. end;
  349. if Length(TroffRomanFont)>0 then
  350. begin
  351. Data:=Data + '1' + TroffRomanFont+LF; {Do not Localize}
  352. end;
  353. if Length(TroffItalicFont)>0 then
  354. begin
  355. Data:=Data + '2' + TroffItalicFont+LF; {Do not Localize}
  356. end;
  357. if Length(TroffBoldFont)>0 then
  358. begin
  359. Data:=Data + '3' + TroffBoldFont+LF; {Do not Localize}
  360. end;
  361. if Length(TroffSpecialFont)>0 then
  362. begin
  363. Data:=Data + '4' + TroffSpecialFont+LF; {Do not Localize}
  364. end;
  365. end;
  366. Result:=data;
  367. except
  368. Result:='error'; {Do not Localize}
  369. end;
  370. end;
  371. procedure TIdLPR.SeTIdLPRControlFile(const Value: TIdLPRControlFile);
  372. begin
  373. FControlFile.Assign(Value);
  374. end;
  375. destructor TIdLPR.Destroy;
  376. begin
  377. FreeAndNil(FControlFile);
  378. inherited;
  379. end;
  380. procedure TIdLPR.PrintWaitingJobs;
  381. begin
  382. try
  383. DoOnLPRStatus(psPrintingWaitingJobs, ''); {Do not Localize}
  384. Write(#03 + Queue + LF);
  385. CheckReply;
  386. DoOnLPRStatus(psPrintedWaitingJobs, ''); {Do not Localize}
  387. except
  388. on E: Exception do
  389. DoOnLPRStatus(psError, E.Message);
  390. end;
  391. end;
  392. procedure TIdLPR.RemoveJobList(AList: String; const AAsRoot: Boolean =False);
  393. begin
  394. try
  395. DoOnLPRStatus(psDeletingJobs, JobID);
  396. if AAsRoot then
  397. begin
  398. {Only root can delete other people's print jobs} {Do not Localize}
  399. Write(#05 + Queue + ' root ' + AList + LF); {Do not Localize}
  400. end
  401. else
  402. begin
  403. Write(#05 + Queue + ' ' + ControlFile.UserName + ' ' + AList + LF); {Do not Localize}
  404. end;
  405. CheckReply;
  406. DoOnLPRStatus(psJobsDeleted, JobID);
  407. except
  408. on E: Exception do
  409. DoOnLPRStatus(psError, E.Message);
  410. end;
  411. end;
  412. procedure TIdLPR.CheckReply;
  413. var ret : String;
  414. begin
  415. ret:=ReadString(1);
  416. if (Length(ret) > 0) and (ret[1] <> #00) then
  417. begin
  418. raise EIdLPRErrorException.Create(Format(RSLPRError,[ret[1],JobID]));
  419. end;
  420. end;
  421. procedure TIdLPR.DoOnLPRStatus(const AStatus: TIdLPRStatus;
  422. const AStatusText: String);
  423. begin
  424. if Assigned(FOnLPRStatus) then
  425. FOnLPRStatus(Self,AStatus,AStatusText);
  426. end;
  427. { TIdLPRControlFile }
  428. procedure TIdLPRControlFile.Assign(Source: TPersistent);
  429. var cnt : TIdLPRControlFile;
  430. begin
  431. if Source is TIdLPRControlFile then
  432. begin
  433. cnt := Source as TIdLPRControlFile;
  434. FBannerClass := cnt.BannerClass;
  435. FIndentCount := cnt.IndentCount;
  436. FJobName := cnt.JobName;
  437. FBannerPage := cnt.BannerPage;
  438. FUserName := cnt.UserName;
  439. FOutputWidth := cnt.OutputWidth;
  440. FFileFormat := cnt.FileFormat;
  441. FTroffRomanFont := cnt.TroffRomanFont;
  442. FTroffItalicFont := cnt.TroffItalicFont;
  443. FTroffBoldFont := cnt.TroffBoldFont;
  444. FTroffSpecialFont := cnt.TroffSpecialFont;
  445. FMailWhenPrinted := cnt.MailWhenPrinted;
  446. end
  447. else
  448. begin
  449. inherited Assign(Source);
  450. end;
  451. end;
  452. constructor TIdLPRControlFile.Create;
  453. begin
  454. inherited Create;
  455. try
  456. HostName := GStack.LocalAddress;
  457. except
  458. HostName:=RSLPRUnknown;
  459. end;
  460. FFileFormat := DEF_FILEFORMAT;
  461. FIndentCount := DEF_INDENTCOUNT;
  462. FBannerPage := DEF_BANNERPAGE;
  463. FOutputWidth := DEF_OUTPUTWIDTH;
  464. end;
  465. end.