Download fixed idattachmentmemory.pas

  1. unit IdAttachmentMemory;
  2.  
  3. interface
  4.  
  5. uses
  6. Classes, SysUtils, IdAttachment, IdMessageParts, IdGlobal,
  7. ExtStreams;
  8.  
  9. type
  10. TIdAttachmentMemory = class(TIdAttachment)
  11. protected
  12. FDataStream: TFastMemoryStream;
  13. FDataStreamBeforeLoadPosition: Int64;
  14.  
  15. function GetDataStream: TStream;
  16. function GetDataString: string;
  17. procedure SetDataStream(const Value: TStream);
  18. procedure SetDataString(const Value: string);
  19. public
  20. {CC: Bug fix, remove default values to resolve ambiguities with Create(TCollection).}
  21. {constructor Create(Collection: TIdMessageParts; const CopyFrom: TStream = nil); reintroduce; overload;
  22. constructor Create(Collection: TIdMessageParts; const CopyFrom: String = ''); reintroduce; overload;
  23. }
  24. constructor Create(Collection: TIdMessageParts; const CopyFrom: TStream); reintroduce; overload;
  25. constructor Create(Collection: TIdMessageParts; const CopyFrom: string); reintroduce; overload;
  26. constructor Create(Collection: TCollection); overload; override;
  27. destructor Destroy; override;
  28.  
  29. property DataStream: TStream read GetDataStream write SetDataStream;
  30. property DataString: string read GetDataString write SetDataString;
  31. function OpenLoadStream: TStream; override;
  32. procedure CloseLoadStream; override;
  33. procedure FinishTempStream; override;
  34. function PrepareTempStream: TStream; override;
  35. procedure SaveToFile(const FileName: TFileName); override;
  36. procedure SaveToStream(const Stream: TStream); override;
  37. end;
  38.  
  39. TWideAttachmentMemory = class(TIdAttachmentMemory)
  40. protected
  41. fWideFileName: widestring;
  42. function GetWideFileName: widestring;
  43. public
  44. property WideFileName: widestring read GetWideFileName;
  45. property FastMemStream: TFastMemoryStream read FDataStream;
  46.  
  47. end;
  48.  
  49. function ExtractAttachmentFilename(const AContentType, AContentDisposition: string): string;
  50.  
  51. implementation
  52.  
  53. uses
  54. StrUtils, TntSysUtils, FileUtils, CharsetConvertors,
  55. IdCoderHeader, IdText, IdCharsets;
  56.  
  57. { TIdAttachmentMemory }
  58.  
  59. constructor TIdAttachmentMemory.Create(Collection: TIdMessageParts;
  60. const CopyFrom: TStream);
  61. begin
  62. inherited Create(Collection);
  63. FDataStream := TFastMemoryStream.Create();
  64. if Assigned(CopyFrom) then begin
  65. FDataStream.CopyFrom(CopyFrom, CopyFrom.Size);
  66. end;
  67. end;
  68.  
  69. constructor TIdAttachmentMemory.Create(Collection: TIdMessageParts;
  70. const CopyFrom: string);
  71. begin
  72. inherited Create(Collection);
  73. FDataStream := TFastMemoryStream.Create;
  74. SetDataString(CopyFrom);
  75. end;
  76.  
  77. constructor TIdAttachmentMemory.Create(Collection: TCollection);
  78. begin
  79. inherited;
  80. FDataStream := TFastMemoryStream.Create;
  81. end;
  82.  
  83. destructor TIdAttachmentMemory.Destroy;
  84. begin
  85. FreeAndNil(FDataStream);
  86. inherited;
  87. end;
  88.  
  89. function TIdAttachmentMemory.GetDataStream: TStream;
  90. begin
  91. Result := FDataStream;
  92. end;
  93.  
  94. procedure TIdAttachmentMemory.SetDataStream(const Value: TStream);
  95. begin
  96. FDataStream.CopyFrom(Value, Value.Size);
  97. end;
  98.  
  99. function TIdAttachmentMemory.GetDataString: string;
  100. begin
  101. Result := FDataStream.DataString;
  102. end;
  103.  
  104. procedure TIdAttachmentMemory.SetDataString(const Value: string);
  105. begin
  106. FDataStream.DataString := Value;
  107. end;
  108.  
  109. function TIdAttachmentMemory.OpenLoadStream: TStream;
  110. begin
  111. FDataStreamBeforeLoadPosition := DataStream.Position;
  112. fDataStream.Position := 0;
  113. Result := fDataStream;
  114. end;
  115.  
  116. procedure TIdAttachmentMemory.CloseLoadStream;
  117. begin
  118. fDataStream.Position := FDataStreamBeforeLoadPosition;
  119. end;
  120.  
  121. function TIdAttachmentMemory.PrepareTempStream: TStream;
  122. begin
  123. fDataStream.Size := 0;
  124. Result := fDataStream;
  125. end;
  126.  
  127. procedure TIdAttachmentMemory.FinishTempStream;
  128. begin
  129. fDataStream.Position := 0;
  130. end;
  131.  
  132. procedure TIdAttachmentMemory.SaveToFile(const FileName: TFileName);
  133. begin
  134. fDataStream.SaveToFile(FileName);
  135. end;
  136.  
  137. procedure TIdAttachmentMemory.SaveToStream(const Stream: TStream);
  138. begin
  139. fDataStream.SaveToStream(Stream);
  140. end;
  141.  
  142. function ExtractAttachmentFilename(const AContentType, AContentDisposition: string): string;
  143. var
  144. LValue: string;
  145. LPos: Integer;
  146. begin
  147. LPos := IndyPos('FILENAME=', UpperCase(AContentDisposition)); {do not localize}
  148. if LPos > 0 then begin
  149. LValue := Trim(Copy(AContentDisposition, LPos + 9, MaxInt));
  150. end else begin
  151. LValue := ''; //FileName not found
  152. end;
  153. if Length(LValue) = 0 then begin
  154. // Get filename from Content-Type
  155. LPos := IndyPos('NAME=', UpperCase(AContentType)); {do not localize}
  156. if LPos > 0 then begin
  157. LValue := Trim(Copy(AContentType, LPos + 5, MaxInt)); {do not localize}
  158. end;
  159. end;
  160. if Length(LValue) > 0 then begin
  161. if LValue[1] = '"' then begin {do not localize}
  162. // RLebeau - shouldn't this code use AnsiExtractQuotedStr() instead?
  163. Fetch(LValue, '"'); {do not localize}
  164. Result := Fetch(LValue, '"'); {do not localize}
  165. end else begin
  166. // RLebeau - just in case the name is not the last field in the line
  167. Result := Fetch(LValue, ';'); {do not localize}
  168. end;
  169. // Result := RemoveInvalidCharsFromFilename(DecodeHeader(Result));
  170. // Result := MakeCorrectFileName(WideExtractFileName(WideDecodeHeader(Result)));
  171. end else begin
  172. Result := '';
  173. end;
  174. end;
  175.  
  176. function TWideAttachmentMemory.GetWideFileName: widestring;
  177. var
  178. lAnsiFilename, AContentDisposition: string;
  179. lIdCharset: TIdCharset;
  180. i: integer;
  181. idText: TidText;
  182.  
  183. begin
  184. if fWideFileName = '' then begin
  185. AContentDisposition := Headers.Values['Content-Disposition'];
  186. Fetch(AContentDisposition, ';');
  187. lAnsiFileName := ExtractAttachmentFilename(Headers.Values['Content-Type'],
  188. AContentDisposition);
  189. if PosIdx('=?', lAnsiFileName, 1) > 0 then fWideFileName := WideDecodeHeader(lAnsiFileName)
  190. else begin
  191. lIdCharset := idcsINVALID;
  192. for i := 0 to Collection.Count - 1 do
  193. if TIdMessageParts(Collection)[i].PartType = mptText then begin
  194. idText := TIdText(TIdMessageParts(Collection)[i]);
  195. if AnsiStartsText('text/', IdText.ContentType) then begin
  196. lIdCharset := FindCharset(NormalizeCharset(idText.Charset));
  197. break;
  198. end;
  199. end;
  200. fWideFileName := ConvertFromIdCharsetToWide(lAnsiFileName, lIdCharset);
  201. end;
  202. fWideFileName := MakeCorrectFileName(WideExtractFileName(fWideFileName));
  203. end;
  204. Result := fWideFileName;
  205. end;
  206.  
  207. initialization
  208. RegisterClasses([TIdAttachmentMemory]);
  209. end.
  210.