IdMessageCoderUUE.pas 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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.13 27.08.2004 22:04:00 Andreas Hausladen
  18. speed optimization ("const" for string parameters)
  19. Rev 1.12 2004.05.20 1:39:16 PM czhower
  20. Last of the IdStream updates
  21. Rev 1.11 2004.05.20 11:36:58 AM czhower
  22. IdStreamVCL
  23. Rev 1.10 2004.05.20 11:13:02 AM czhower
  24. More IdStream conversions
  25. Rev 1.9 2004.05.19 3:06:42 PM czhower
  26. IdStream / .NET fix
  27. Rev 1.8 2004.02.03 5:44:04 PM czhower
  28. Name changes
  29. Rev 1.7 2004.01.22 5:56:54 PM czhower
  30. TextIsSame
  31. Rev 1.6 1/21/2004 2:20:24 PM JPMugaas
  32. InitComponent
  33. Rev 1.5 1/21/2004 1:30:10 PM JPMugaas
  34. InitComponent
  35. Rev 1.4 10/17/2003 12:41:16 AM DSiders
  36. Added localization comments.
  37. Rev 1.3 26/09/2003 01:06:18 CCostelloe
  38. CodingType property added so caller can find out if it was UUE or XXE encoded
  39. Rev 1.2 6/14/2003 03:07:20 PM JPMugaas
  40. Fixed MessageDecoder so that DecodeBegin is called right after creation and
  41. DecodeEnd is called just before destruction. I also fixed where the code was
  42. always assuming that LDecode was always being created.
  43. Rev 1.1 6/13/2003 07:58:44 AM JPMugaas
  44. Should now compile with new decoder design.
  45. Rev 1.0 11/13/2002 07:57:14 AM JPMugaas
  46. 2003-Sep-20 Ciaran Costelloe
  47. CodingType property added so caller can find out if it was UUE or XXE encoded
  48. }
  49. unit IdMessageCoderUUE;
  50. interface
  51. {$i IdCompilerDefines.inc}
  52. uses
  53. Classes,
  54. IdCoder3to4,
  55. IdMessageCoder,
  56. IdMessage,
  57. IdGlobal;
  58. type
  59. TIdMessageDecoderUUE = class(TIdMessageDecoder)
  60. protected
  61. FCodingType: string;
  62. public
  63. function ReadBody(ADestStream: TStream; var AMsgEnd: Boolean): TIdMessageDecoder; override;
  64. property CodingType: string read FCodingType;
  65. end;
  66. TIdMessageDecoderInfoUUE = class(TIdMessageDecoderInfo)
  67. public
  68. function CheckForStart(ASender: TIdMessage; const ALine: string): TIdMessageDecoder; override;
  69. end;
  70. TIdMessageEncoderUUEBase = class(TIdMessageEncoder)
  71. protected
  72. FEncoderClass: TIdEncoder3to4Class; // TODO: change to "class of TIdEncoder00E" instead
  73. public
  74. procedure Encode(ASrc: TStream; ADest: TStream); override;
  75. end;
  76. TIdMessageEncoderUUE = class(TIdMessageEncoderUUEBase)
  77. public
  78. constructor Create(AOwner: TComponent); override;
  79. end;
  80. TIdMessageEncoderInfoUUE = class(TIdMessageEncoderInfo)
  81. public
  82. constructor Create; override;
  83. end;
  84. implementation
  85. uses
  86. IdCoderUUE, IdCoderXXE, IdException, IdGlobalProtocols, IdResourceStringsProtocols, SysUtils;
  87. { TIdMessageDecoderInfoUUE }
  88. function TIdMessageDecoderInfoUUE.CheckForStart(ASender: TIdMessage; const ALine: string): TIdMessageDecoder;
  89. var
  90. LUUE: TIdMessageDecoderUUE;
  91. begin
  92. Result := nil;
  93. if TextStartsWith(ALine, 'begin ') and CharEquals(ALine, 10, ' ') and IsNumeric(ALine, 3, 7) then begin {Do not Localize}
  94. LUUE := TIdMessageDecoderUUE.Create(ASender);
  95. LUUE.FFilename := Copy(ALine, 11, MaxInt);
  96. LUUE.FPartType := mcptAttachment;
  97. Result := LUUE;
  98. end;
  99. end;
  100. { TIdMessageDecoderUUE }
  101. function TIdMessageDecoderUUE.ReadBody(ADestStream: TStream; var AMsgEnd: Boolean): TIdMessageDecoder;
  102. var
  103. LDecoder: TIdDecoder4to3;
  104. LLine: string;
  105. LMsgEnd: Boolean;
  106. LEncoding: IIdTextEncoding;
  107. LFillCharStr: string;
  108. begin
  109. Result := nil;
  110. AMsgEnd := False;
  111. LEncoding := IndyTextEncoding_8Bit;
  112. LLine := ReadLnRFC(LMsgEnd, LEncoding);
  113. if LMsgEnd then begin
  114. Exit;
  115. end;
  116. LDecoder := nil;
  117. if LLine <> '' then
  118. begin
  119. case LLine[1] of
  120. #32..#85: begin {Do not Localize}
  121. // line length may be from 2 (first char + newline) to 65,
  122. // this is 0 useable to 63 usable bytes, + #32 gives this as a range.
  123. // (yes, the line length is encoded in the first bytes of each line!)
  124. // TODO: need to do a better job of differentiating between UUE and XXE.
  125. //
  126. // UUE and XXE both encode 45 bytes max per line. Each line starts with
  127. // an encoded character that indicates the number of encoded bytes in the
  128. // line, not counting padding.
  129. //
  130. // UUE encodes the byte count as one of the following characters:
  131. //
  132. // 0 1 2 3 4
  133. // 0123456789012345678901234567890123456789012345
  134. // `!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLM
  135. //
  136. // XXE encodes the byte count as one of the following characters:
  137. //
  138. // 0 1 2 3 4
  139. // 0123456789012345678901234567890123456789012345
  140. // +-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefgh
  141. // (some encoders use [space] instead of +)
  142. //
  143. // Without external information to indicate the actual encoding, if we
  144. // get input whose encoded byte length is encoded as one of the following
  145. // characters:
  146. //
  147. // -0123456789ABCDEFGHIJKLM
  148. //
  149. // We will not know if it is actually UUE or XXE. About all we could do
  150. // is calculate the expected input length in both encodings based on the
  151. // starting character and then check if the input actually matches one
  152. // of them...
  153. LDecoder := TIdDecoderUUE.Create(nil);
  154. LDecoder.DecodeBegin(ADestStream);
  155. FCodingType := 'UUE'; {do not localize}
  156. end;
  157. 'h': begin {do not localize}
  158. LDecoder := TIdDecoderXXE.Create(nil);
  159. LDecoder.DecodeBegin(ADestStream);
  160. FCodingType := 'XXE'; {do not localize}
  161. end;
  162. else begin
  163. raise EIdException.Create(RSUnrecognizedUUEEncodingScheme); // TODO: create a new Exception class for this
  164. end;
  165. end;
  166. end;
  167. try
  168. if Assigned(LDecoder) then
  169. begin
  170. LFillCharStr := String(LDecoder.FillChar);
  171. repeat
  172. if (Trim(LLine) = '') or (LLine = LFillCharStr) then begin
  173. // UUE: Comes on the line before end. Supposed to be `, but some put a
  174. // blank line instead
  175. end else begin
  176. LDecoder.Decode(LLine);
  177. end;
  178. LLine := ReadLnRFC(LMsgEnd, LEncoding);
  179. until TextIsSame(Trim(LLine), 'end') or LMsgEnd; {Do not Localize}
  180. LDecoder.DecodeEnd;
  181. end;
  182. finally
  183. LDecoder.Free;
  184. end;
  185. end;
  186. { TIdMessageEncoderInfoUUE }
  187. constructor TIdMessageEncoderInfoUUE.Create;
  188. begin
  189. inherited;
  190. FMessageEncoderClass := TIdMessageEncoderUUE;
  191. end;
  192. { TIdMessageEncoderUUEBase }
  193. procedure TIdMessageEncoderUUEBase.Encode(ASrc: TStream; ADest: TStream);
  194. var
  195. LEncoder: TIdEncoder3to4;
  196. begin
  197. ASrc.Position := 0;
  198. WriteStringToStream(ADest, 'begin ' + IntToStr(PermissionCode) + ' ' + Filename + EOL); {Do not Localize}
  199. LEncoder := FEncoderClass.Create(nil);
  200. try
  201. while ASrc.Position < ASrc.Size do begin
  202. LEncoder.Encode(ASrc, ADest, 45);
  203. WriteStringToStream(ADest, EOL);
  204. end;
  205. WriteStringToStream(ADest, String(LEncoder.FillChar) + EOL + 'end' + EOL); {Do not Localize}
  206. finally
  207. LEncoder.Free;
  208. end;
  209. end;
  210. { TIdMessageEncoderUUE }
  211. constructor TIdMessageEncoderUUE.Create(AOwner: TComponent);
  212. begin
  213. inherited Create(AOwner);
  214. FEncoderClass := TIdEncoderUUE;
  215. end;
  216. initialization
  217. TIdMessageDecoderList.RegisterDecoder('UUE', TIdMessageDecoderInfoUUE.Create); {Do not Localize}
  218. TIdMessageEncoderList.RegisterEncoder('UUE', TIdMessageEncoderInfoUUE.Create); {Do not Localize}
  219. end.