IdLPR.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.12 7/24/04 12:56:14 PM RLebeau
  18. Compiler fix for Print(TIdBytes)
  19. Rev 1.11 7/23/04 7:15:16 PM RLebeau
  20. Added extra exception handling to various Print...() methods
  21. Rev 1.10 2004.05.20 11:36:50 AM czhower
  22. IdStreamVCL
  23. Rev 1.9 2004.03.03 11:54:32 AM czhower
  24. IdStream change
  25. Rev 1.8 2004.02.03 5:43:56 PM czhower
  26. Name changes
  27. Rev 1.7 1/21/2004 3:11:22 PM JPMugaas
  28. InitComponent
  29. Rev 1.6 10/24/2003 02:54:52 PM JPMugaas
  30. These should now work with the new code.
  31. Rev 1.5 2003.10.24 10:43:10 AM czhower
  32. TIdSTream to dos
  33. Rev 1.4 2003.10.12 4:04:00 PM czhower
  34. compile todos
  35. Rev 1.3 2/24/2003 09:07:26 PM JPMugaas
  36. Rev 1.2 2/6/2003 03:18:08 AM JPMugaas
  37. Updated components that compile with Indy 10.
  38. Rev 1.1 12/6/2002 05:30:18 PM JPMugaas
  39. Now decend from TIdTCPClientCustom instead of TIdTCPClient.
  40. Rev 1.0 11/13/2002 07:56:22 AM JPMugaas
  41. 27.07. rewrite component for integration
  42. in Indy core library
  43. }
  44. unit IdLPR;
  45. {
  46. Indy Line Print Remote TIdLPR
  47. Version 9.1.0
  48. Original author Mario Mueller
  49. home: www.hemasoft.de
  50. mail: [email protected]
  51. }
  52. interface
  53. {$i IdCompilerDefines.inc}
  54. uses
  55. Classes,
  56. IdAssignedNumbers, IdGlobal, IdException, IdTCPClient,
  57. IdComponent;
  58. type
  59. TIdLPRFileFormat =
  60. (ffCIF, // CalTech Intermediate Form
  61. ffDVI, // DVI (TeX output).
  62. ffFormattedText, //add formatting as needed to text file
  63. ffPlot, // Berkeley Unix plot library
  64. ffControlCharText, //text file with control charactors
  65. ffDitroff, // ditroff output
  66. ffPostScript, //Postscript output file
  67. ffPR,//'pr' format {Do not Localize}
  68. ffFORTRAM, // FORTRAN carriage control
  69. ffTroff, //Troff output
  70. ffSunRaster); // Sun raster format file
  71. const
  72. DEF_FILEFORMAT = ffControlCharText;
  73. DEF_INDENTCOUNT = 0;
  74. DEF_BANNERPAGE = False;
  75. DEF_OUTPUTWIDTH = 0;
  76. DEF_MAILWHENPRINTED = False;
  77. type
  78. TIdLPRControlFile = class(TPersistent)
  79. protected
  80. FBannerClass: String; // 'C' {Do not Localize}
  81. FHostName: String; // 'H' {Do not Localize}
  82. FIndentCount: Integer; // 'I' {Do not Localize}
  83. FJobName: String; // 'J' {Do not Localize}
  84. FBannerPage: Boolean; // 'L' {Do not Localize}
  85. FUserName: String; // 'P' {Do not Localize}
  86. FOutputWidth: Integer; // 'W' {Do not Localize}
  87. FFileFormat : TIdLPRFileFormat;
  88. FTroffRomanFont : String; //substitue the Roman font with the font in file
  89. FTroffItalicFont : String;//substitue the Italic font with the font in file
  90. FTroffBoldFont : String; //substitue the bold font with the font in file
  91. FTroffSpecialFont : String; //substitue the special font with the font
  92. //in this file
  93. FMailWhenPrinted : Boolean; //mail me when you have printed the job
  94. public
  95. constructor Create;
  96. procedure Assign(Source: TPersistent); override;
  97. property HostName: String read FHostName write FHostName;
  98. published
  99. property BannerClass: String read FBannerClass write FBannerClass;
  100. property IndentCount: Integer read FIndentCount write FIndentCount default DEF_INDENTCOUNT;
  101. property JobName: String read FJobName write FJobName;
  102. property BannerPage: Boolean read FBannerPage write FBannerPage default DEF_BANNERPAGE;
  103. property UserName: String read FUserName write FUserName;
  104. property OutputWidth: Integer read FOutputWidth write FOutputWidth default DEF_OUTPUTWIDTH;
  105. property FileFormat: TIdLPRFileFormat read FFileFormat write FFileFormat default DEF_FILEFORMAT;
  106. {font data }
  107. property TroffRomanFont : String read FTroffRomanFont write FTroffRomanFont;
  108. property TroffItalicFont : String read FTroffItalicFont write FTroffItalicFont;
  109. property TroffBoldFont : String read FTroffBoldFont write FTroffBoldFont;
  110. property TroffSpecialFont : String read FTroffSpecialFont write FTroffSpecialFont;
  111. {misc}
  112. property MailWhenPrinted : Boolean read FMailWhenPrinted write FMailWhenPrinted default DEF_MAILWHENPRINTED;
  113. end;
  114. type
  115. TIdLPRStatus = (psPrinting, psJobCompleted, psError, psGettingQueueState,
  116. psGotQueueState, psDeletingJobs, psJobsDeleted, psPrintingWaitingJobs,
  117. psPrintedWaitingJobs);
  118. type
  119. TIdLPRStatusEvent = procedure(ASender: TObject;
  120. const AStatus: TIdLPRStatus;
  121. const AStatusText: String) of object;
  122. type
  123. TIdLPR = class(TIdTCPClientCustom)
  124. protected
  125. FOnLPRStatus: TIdLPRStatusEvent;
  126. FQueue: String;
  127. FJobId: Integer;
  128. FControlFile: TIdLPRControlFile;
  129. procedure DoOnLPRStatus(const AStatus: TIdLPRStatus;
  130. const AStatusText: String);
  131. procedure SeTIdLPRControlFile(const Value: TIdLPRControlFile);
  132. procedure CheckReply;
  133. function GetJobId: String;
  134. procedure SetJobId(const Value: String);
  135. procedure InternalPrint(Data: TStream);
  136. function GetControlData: String;
  137. public
  138. constructor Create(AOwner: TComponent); override;
  139. destructor Destroy; override;
  140. procedure Connect; override;
  141. procedure Print(const AText: String); overload;
  142. procedure Print(const ABuffer: TIdBytes); overload;
  143. procedure PrintFile(const AFileName: String);
  144. function GetQueueState(const AShortFormat: Boolean = False; const AList : String = '') : String; {Do not Localize}
  145. procedure PrintWaitingJobs;
  146. procedure RemoveJobList(const AList: String; const AAsRoot: Boolean = False);
  147. property JobId: String read GetJobId write SetJobId;
  148. published
  149. property Queue: String read FQueue write FQueue;
  150. property ControlFile: TIdLPRControlFile read FControlFile write SeTIdLPRControlFile;
  151. property Host;
  152. property Port default IdPORT_LPD;
  153. property OnLPRStatus: TIdLPRStatusEvent read FOnLPRStatus write FOnLPRStatus;
  154. end;
  155. type
  156. EIdLPRErrorException = class(EIdException);
  157. implementation
  158. uses
  159. IdGlobalProtocols, IdResourceStringsProtocols, IdStack, IdStackConsts,
  160. SysUtils;
  161. { TIdLPR }
  162. constructor TIdLPR.Create(AOwner: TComponent);
  163. begin
  164. inherited Create(AOwner);
  165. Port := IdPORT_LPD;
  166. Queue := 'pr1'; {Do not Localize}
  167. FJobId := 1;
  168. FControlFile := TIdLPRControlFile.Create;
  169. // Restriction in RFC 1179
  170. // The source port must be in the range 721 to 731, inclusive.
  171. BoundPortMin := 721;
  172. BoundPortMax := 731;
  173. end;
  174. destructor TIdLPR.Destroy;
  175. begin
  176. FControlFile.Free;
  177. inherited Destroy;
  178. end;
  179. procedure TIdLPR.Connect;
  180. var
  181. LPort: TIdPort;
  182. begin
  183. // RLebeau 3/7/2010: there is a problem on Windows where sometimes it will
  184. // not raise a WSAEADDRINUSE error in TIdSocketHandle.TryBind(), but will
  185. // delay it until TIdSocketHandle.Connect() instead. So we will loop here
  186. // to force a Connect() on each port, rather than let TIdSocketHandle do
  187. // the looping in BindPortReserved(). If this logic proves useful in other
  188. // protocols, we can move it into TIdSocketHandle later on...
  189. // AWinkelsdorf 3/9/2010: Implemented, adjusted to use BoundPortMax and
  190. // BoundPortMin
  191. // looping backwards because that is what TIdSocketHandle.BindPortReserved() does
  192. for LPort := BoundPortMax downto BoundPortMin do
  193. begin
  194. BoundPort := LPort;
  195. try
  196. inherited Connect;
  197. Exit;
  198. except
  199. on E: EIdCouldNotBindSocket do begin end;
  200. on E: EIdSocketError do begin
  201. if E.LastError <> Id_WSAEADDRINUSE then begin
  202. raise;
  203. end;
  204. // Socket already in use, cleanup and try again with the next
  205. Disconnect;
  206. end;
  207. end;
  208. end;
  209. // no local ports could be bound successfully
  210. raise EIdCanNotBindPortInRange.CreateFmt(RSLPRCannotBindRange, [BoundPortMin, BoundPortMax]);
  211. end;
  212. procedure TIdLPR.Print(const AText: String);
  213. var
  214. LStream: TStream;
  215. begin
  216. LStream := TMemoryStream.Create;
  217. try
  218. WriteStringToStream(LStream, AText, IndyTextEncoding_8Bit);
  219. LStream.Position := 0;
  220. InternalPrint(LStream);
  221. finally
  222. LStream.Free;
  223. end;
  224. end;
  225. procedure TIdLPR.Print(const ABuffer: TIdBytes);
  226. var
  227. LStream: TStream;
  228. begin
  229. LStream := TIdReadOnlyMemoryBufferStream.Create(PByte(ABuffer), Length(ABuffer));
  230. try
  231. InternalPrint(LStream);
  232. finally
  233. LStream.Free;
  234. end;
  235. end;
  236. procedure TIdLPR.PrintFile(const AFileName: String);
  237. var
  238. LStream: TIdReadFileExclusiveStream;
  239. p: Integer;
  240. begin
  241. p := RPos(GPathDelim, AFileName);
  242. ControlFile.JobName := Copy(AFileName, p+1, Length(AFileName)-p);
  243. LStream := TIdReadFileExclusiveStream.Create(AFileName);
  244. try
  245. InternalPrint(LStream);
  246. finally
  247. LStream.Free;
  248. end;
  249. end;
  250. function TIdLPR.GetJobId: String;
  251. begin
  252. Result := IndyFormat('%.3d', [FJobId]); {Do not Localize}
  253. end;
  254. procedure TIdLPR.SetJobId(const Value: String);
  255. var
  256. I: Integer;
  257. begin
  258. I := IndyStrToInt(Value);
  259. if I < 999 then begin
  260. FJobId := I;
  261. end;
  262. end;
  263. procedure TIdLPR.InternalPrint(Data: TStream);
  264. begin
  265. try
  266. if not Connected then begin
  267. Exit;
  268. end;
  269. Inc(FJobID);
  270. if FJobID > 999 then begin
  271. FJobID := 1;
  272. end;
  273. DoOnLPRStatus(psPrinting, JobID);
  274. try
  275. ControlFile.HostName := GStack.HostName
  276. except
  277. ControlFile.HostName := 'localhost'; {Do not Localize}
  278. end;
  279. // Receive a printer job
  280. IOHandler.Write(#02 + Queue + LF);
  281. CheckReply;
  282. // Receive control file
  283. IOHandler.Write(#02 + IntToStr(Length(GetControlData)) + ' cfA' + JobId + ControlFile.HostName + LF); {Do not Localize}
  284. CheckReply;
  285. // Send control file
  286. IOHandler.Write(GetControlData);
  287. IOHandler.Write(#0);
  288. CheckReply;
  289. // Send data file
  290. IOHandler.Write(#03 + IntToStr(Data.Size) + ' dfA' + JobId + ControlFile.HostName + LF); {Do not Localize}
  291. CheckReply;
  292. // Send data
  293. IOHandler.Write(Data);
  294. IOHandler.Write(#0);
  295. CheckReply;
  296. DoOnLPRStatus(psJobCompleted, JobID);
  297. except
  298. on E: Exception do begin
  299. DoOnLPRStatus(psError, E.Message);
  300. end;
  301. end;
  302. end;
  303. function TIdLPR.GetQueueState(const AShortFormat: Boolean = False; const AList : String = '') : String; {Do not Localize}
  304. begin
  305. DoOnLPRStatus(psGettingQueueState, AList);
  306. if AShortFormat then begin
  307. IOHandler.Write(#03 + Queue + ' ' + AList + LF) {Do not Localize}
  308. end else begin
  309. IOHandler.Write(#04 + Queue + ' ' + AList + LF); {Do not Localize}
  310. end;
  311. // This was the original code - problematic as this is more than one line
  312. // read until I close the connection
  313. // result:=ReadLn(LF);
  314. Result := IOHandler.AllData;
  315. DoOnLPRStatus(psGotQueueState, result);
  316. end;
  317. function TIdLPR.GetControlData: String;
  318. var
  319. Data: String;
  320. begin
  321. Data := ''; {Do not Localize}
  322. try
  323. // H - Host name
  324. Data := Data + 'H' + FControlFile.HostName + LF; {Do not Localize}
  325. // P - User identification
  326. Data := Data + 'P' + FControlFile.UserName + LF; {Do not Localize}
  327. // J - Job name for banner page
  328. if FControlFile.JobName <> '' then begin
  329. Data := Data + 'J' + FControlFile.JobName + LF; {Do not Localize}
  330. end else begin
  331. Data := Data + 'JcfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  332. end;
  333. //mail when printed
  334. if FControlFile.FMailWhenPrinted then begin
  335. Data := Data + 'M' + FControlFile.UserName + LF; {Do not Localize}
  336. end;
  337. case FControlFile.FFileFormat of
  338. ffCIF : // CalTech Intermediate Form
  339. begin
  340. Data := Data + 'cdfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  341. end;
  342. ffDVI : // DVI (TeX output).
  343. begin
  344. Data := Data + 'ddfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  345. end;
  346. ffFormattedText : //add formatting as needed to text file
  347. begin
  348. Data := Data + 'fdfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  349. end;
  350. ffPlot : // Berkeley Unix plot library
  351. begin
  352. Data := Data + 'gdfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  353. end;
  354. ffControlCharText : //text file with control charactors
  355. begin
  356. Data := Data + 'ldfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  357. end;
  358. ffDitroff : // ditroff output
  359. begin
  360. Data := Data + 'ndfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  361. end;
  362. ffPostScript : //Postscript output file
  363. begin
  364. Data := Data + 'odfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  365. end;
  366. ffPR : //'pr' format {Do not Localize}
  367. begin
  368. Data := Data + 'pdfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  369. end;
  370. ffFORTRAM : // FORTRAN carriage control
  371. begin
  372. Data := Data + 'rdfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  373. end;
  374. ffTroff : //Troff output
  375. begin
  376. Data := Data + 'ldfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  377. end;
  378. ffSunRaster : // Sun raster format file
  379. begin
  380. end;
  381. end;
  382. // U - Unlink data file
  383. Data := Data + 'UdfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  384. // N - Name of source file
  385. Data := Data + 'NcfA' + JobId + FControlFile.HostName + LF; {Do not Localize}
  386. if FControlFile.FFileFormat = ffFormattedText then begin
  387. if FControlFile.IndentCount > 0 then begin
  388. Data := Data + 'I' + IntToStr(FControlFile.IndentCount) + LF; {Do not Localize}
  389. end;
  390. if FControlFile.OutputWidth > 0 then begin
  391. Data := Data + 'W' + IntToStr(FControlFile.OutputWidth) + LF; {Do not Localize}
  392. end;
  393. end;
  394. if FControlFile.BannerClass <> '' then begin
  395. Data := Data + 'C' + FControlFile.BannerClass + LF; {Do not Localize}
  396. end;
  397. if FControlFile.BannerPage then begin
  398. Data := Data + 'L' + FControlFile.UserName + LF; {Do not Localize}
  399. end;
  400. if FControlFile.TroffRomanFont <> '' then begin
  401. Data := Data + '1' + FControlFile.TroffRomanFont + LF; {Do not Localize}
  402. end;
  403. if FControlFile.TroffItalicFont <> '' then begin
  404. Data := Data + '2' + FControlFile.TroffItalicFont + LF; {Do not Localize}
  405. end;
  406. if FControlFile.TroffBoldFont <> '' then begin
  407. Data := Data + '3' + FControlFile.TroffBoldFont + LF; {Do not Localize}
  408. end;
  409. if FControlFile.TroffSpecialFont <> '' then begin
  410. Data := Data + '4' + FControlFile.TroffSpecialFont + LF; {Do not Localize}
  411. end;
  412. Result := Data;
  413. except
  414. Result := 'error'; {Do not Localize}
  415. end;
  416. end;
  417. procedure TIdLPR.SeTIdLPRControlFile(const Value: TIdLPRControlFile);
  418. begin
  419. FControlFile.Assign(Value);
  420. end;
  421. procedure TIdLPR.PrintWaitingJobs;
  422. begin
  423. try
  424. DoOnLPRStatus(psPrintingWaitingJobs, ''); {Do not Localize}
  425. IOHandler.Write(#03 + Queue + LF);
  426. CheckReply;
  427. DoOnLPRStatus(psPrintedWaitingJobs, ''); {Do not Localize}
  428. except
  429. on E: Exception do begin
  430. DoOnLPRStatus(psError, E.Message);
  431. end;
  432. end;
  433. end;
  434. procedure TIdLPR.RemoveJobList(const AList: String; const AAsRoot: Boolean = False);
  435. begin
  436. try
  437. DoOnLPRStatus(psDeletingJobs, JobID);
  438. if AAsRoot then begin
  439. {Only root can delete other people's print jobs} {Do not Localize}
  440. IOHandler.Write(#05 + Queue + ' root ' + AList + LF); {Do not Localize}
  441. end else begin
  442. IOHandler.Write(#05 + Queue + ' ' + ControlFile.UserName + ' ' + AList + LF); {Do not Localize}
  443. end;
  444. CheckReply;
  445. DoOnLPRStatus(psJobsDeleted, JobID);
  446. except
  447. on E: Exception do begin
  448. DoOnLPRStatus(psError, E.Message);
  449. end;
  450. end;
  451. end;
  452. procedure TIdLPR.CheckReply;
  453. var
  454. Ret : Byte;
  455. begin
  456. Ret := IOHandler.ReadByte;
  457. if Ret <> $00 then begin
  458. raise EIdLPRErrorException.CreateFmt(RSLPRError, [Integer(Ret), JobID]);
  459. end;
  460. end;
  461. procedure TIdLPR.DoOnLPRStatus(const AStatus: TIdLPRStatus; const AStatusText: String);
  462. begin
  463. if Assigned(FOnLPRStatus) then begin
  464. FOnLPRStatus(Self, AStatus, AStatusText);
  465. end;
  466. end;
  467. { TIdLPRControlFile }
  468. procedure TIdLPRControlFile.Assign(Source: TPersistent);
  469. var
  470. cnt : TIdLPRControlFile;
  471. begin
  472. if Source is TIdLPRControlFile then
  473. begin
  474. cnt := Source as TIdLPRControlFile;
  475. FBannerClass := cnt.BannerClass;
  476. FIndentCount := cnt.IndentCount;
  477. FJobName := cnt.JobName;
  478. FBannerPage := cnt.BannerPage;
  479. FUserName := cnt.UserName;
  480. FOutputWidth := cnt.OutputWidth;
  481. FFileFormat := cnt.FileFormat;
  482. FTroffRomanFont := cnt.TroffRomanFont;
  483. FTroffItalicFont := cnt.TroffItalicFont;
  484. FTroffBoldFont := cnt.TroffBoldFont;
  485. FTroffSpecialFont := cnt.TroffSpecialFont;
  486. FMailWhenPrinted := cnt.MailWhenPrinted;
  487. end else begin
  488. inherited Assign(Source);
  489. end;
  490. end;
  491. constructor TIdLPRControlFile.Create;
  492. begin
  493. inherited Create;
  494. try
  495. HostName := GStack.HostName;
  496. except
  497. HostName := RSLPRUnknown;
  498. end;
  499. FFileFormat := DEF_FILEFORMAT;
  500. FIndentCount := DEF_INDENTCOUNT;
  501. FBannerPage := DEF_BANNERPAGE;
  502. FOutputWidth := DEF_OUTPUTWIDTH;
  503. end;
  504. end.