IdSysLogMessage.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  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.8 7/23/04 1:32:08 PM RLebeau
  18. Bug fix for TIdSyslogFacility where sfUUCP and sfClockDeamonOne were in the
  19. wrong order
  20. Rev 1.7 7/8/04 11:43:08 PM RLebeau
  21. Updated ReadFromBytes(c) to use new BytesToString() parameters
  22. Rev 1.6 2004.02.03 5:44:28 PM czhower
  23. Name changes
  24. Rev 1.5 1/31/2004 1:23:24 PM JPMugaas
  25. Eliminated Todo item.
  26. Rev 1.4 2004.01.22 3:23:36 PM czhower
  27. IsCharInSet
  28. Rev 1.3 1/21/2004 4:03:58 PM JPMugaas
  29. InitComponent
  30. Rev 1.2 10/24/2003 01:58:30 PM JPMugaas
  31. Attempt to port Syslog over to new code.
  32. Rev 1.1 2003.10.12 6:36:44 PM czhower
  33. Now compiles.
  34. Rev 1.0 11/13/2002 08:02:12 AM JPMugaas
  35. }
  36. unit IdSysLogMessage;
  37. {
  38. Copyright the Indy pit crew
  39. Original Author: Stephane Grobety ([email protected])
  40. Release history:
  41. 25/2/02; - Stephane Grobety
  42. - Moved Facility and Severity translation functions out of the class
  43. - Restored the "SendToHost" method
  44. - Changed the ASCII check tzo include only the PRI and HEADER part.
  45. - Now allow nul chars in message result (Special handeling should be required, though)
  46. 09/20/01; - J. Peter Mugaas
  47. Added more properties dealing with Msg parts of the SysLog Message
  48. 09/19/01; - J. Peter Mugaas
  49. restructured syslog classes
  50. 08/09/01: Dev started
  51. }
  52. interface
  53. {$i IdCompilerDefines.inc}
  54. uses
  55. Classes,
  56. IdGlobal, IdGlobalProtocols, IdBaseComponent;
  57. type
  58. // TIdSyslogSeverity = ID_SYSLOG_SEVERITY_EMERGENCY..ID_SYSLOG_SEVERITY_DEBUG;
  59. // TIdSyslogFacility = ID_SYSLOG_FACILITY_KERNEL..ID_SYSLOG_FACILITY_LOCAL7;
  60. TIdSyslogPRI = 0..191;
  61. TIdSyslogFacility = (sfKernel, { ID_SYSLOG_FACILITY_KERNEL}
  62. sfUserLevel, { ID_SYSLOG_FACILITY_USER }
  63. sfMailSystem, { ID_SYSLOG_FACILITY_MAIL }
  64. sfSystemDaemon, { ID_SYSLOG_FACILITY_SYS_DAEMON }
  65. sfSecurityOne, { ID_SYSLOG_FACILITY_SECURITY1 }
  66. sfSysLogInternal, { ID_SYSLOG_FACILITY_INTERNAL }
  67. sfLPR, {ID_SYSLOG_FACILITY_LPR}
  68. sfNNTP, { ID_SYSLOG_FACILITY_NNTP }
  69. sfUUCP, { ID_SYSLOG_FACILITY_UUCP }
  70. sfClockDaemonOne, { CILITY_CLOCK1 }
  71. sfSecurityTwo, { ID_SYSLOG_FACILITY_SECURITY2 }
  72. sfFTPDaemon, { ID_SYSLOG_FACILITY_FTP }
  73. sfNTP, { ID_SYSLOG_FACILITY_NTP }
  74. sfLogAudit, { ID_SYSLOG_FACILITY_AUDIT }
  75. sfLogAlert, { ID_SYSLOG_FACILITY_ALERT }
  76. sfClockDaemonTwo, { ID_SYSLOG_FACILITY_CLOCK2 }
  77. sfLocalUseZero, { ID_SYSLOG_FACILITY_LOCAL0 }
  78. sfLocalUseOne, { ID_SYSLOG_FACILITY_LOCAL1 }
  79. sfLocalUseTwo, { ID_SYSLOG_FACILITY_LOCAL2 }
  80. sfLocalUseThree, { ID_SYSLOG_FACILITY_LOCAL3 }
  81. sfLocalUseFour, { ID_SYSLOG_FACILITY_LOCAL4 }
  82. sfLocalUseFive, { ID_SYSLOG_FACILITY_LOCAL5 }
  83. sfLocalUseSix, { ID_SYSLOG_FACILITY_LOCAL6 }
  84. sfLocalUseSeven); { ID_SYSLOG_FACILITY_LOCAL7 }
  85. TIdSyslogSeverity = (slEmergency, {0 - emergency - system unusable}
  86. slAlert, {1 - action must be taken immediately }
  87. slCritical, { 2 - critical conditions }
  88. slError, {3 - error conditions }
  89. slWarning, {4 - warning conditions }
  90. slNotice, {5 - normal but signification condition }
  91. slInformational, {6 - informational }
  92. slDebug); {7 - debug-level messages }
  93. TIdSysLogMsgPart = class(TPersistent)
  94. protected
  95. FPIDAvailable: Boolean;
  96. FProcess: String;
  97. FPID: Integer;
  98. FContent: String;
  99. procedure SetPID(AValue: Integer);
  100. procedure SetProcess(const AValue: String);
  101. function GetText: String;
  102. procedure SetText(const AValue: String);
  103. public
  104. procedure Assign(Source: TPersistent); override;
  105. published
  106. property Text: String read GetText write SetText;
  107. property PIDAvailable : Boolean read FPIDAvailable write FPIDAvailable stored false;
  108. property Process : String read FProcess write SetProcess stored false;
  109. property PID : Integer read FPID write SetPID stored false;
  110. property Content : String read FContent write FContent stored false;
  111. end;
  112. TIdSysLogMessage = class(TIdBaseComponent)
  113. protected
  114. FMsg : TIdSysLogMsgPart;
  115. FFacility: TidSyslogFacility;
  116. FSeverity: TIdSyslogSeverity;
  117. FHostname: string;
  118. FMessage: String;
  119. FTimeStamp: TDateTime;
  120. FRawMessage: String;
  121. FPeer: String;
  122. FPri: TIdSyslogPRI;
  123. FUDPCliComp: TIdBaseComponent;
  124. procedure SetFacility(const AValue: TidSyslogFacility);
  125. procedure SetSeverity(const AValue: TIdSyslogSeverity);
  126. procedure SetHostname(const AValue: string);
  127. procedure SetRawMessage(const Value: string);
  128. procedure SetTimeStamp(const AValue: TDateTime);
  129. procedure SetMsg(const AValue : TIdSysLogMsgPart);
  130. procedure SetPri(const Value: TIdSyslogPRI);
  131. function GetHeader: String;
  132. procedure CheckASCIIRange(var Data: String); virtual;
  133. procedure ReadPRI(var StartPos: Integer); virtual;
  134. procedure ReadHeader(var StartPos: Integer); virtual;
  135. procedure ReadMSG(var StartPos: Integer); virtual;
  136. procedure Parse; virtual;
  137. procedure UpdatePRI; virtual;
  138. function DecodeTimeStamp(TimeStampString: String): TDateTime; virtual;
  139. procedure InitComponent; override;
  140. public
  141. procedure Assign(Source: TPersistent); override;
  142. destructor Destroy; override;
  143. function EncodeMessage: String; virtual;
  144. procedure ReadFromBytes(const ASrc: TIdBytes; const APeer : String); virtual;
  145. //
  146. property RawMessage: string read FRawMessage write SetRawMessage;
  147. procedure SendToHost(const Dest: String);
  148. property Peer: string read FPeer write FPeer;
  149. property TimeStamp: TDateTime read FTimeStamp write SetTimeStamp;
  150. published
  151. property Pri: TIdSyslogPRI read FPri write SetPri default 13;
  152. property Facility: TidSyslogFacility read FFacility write SetFacility stored false;
  153. property Severity: TIdSyslogSeverity read FSeverity write SetSeverity stored false;
  154. property Hostname: string read FHostname write SetHostname stored false;
  155. property Msg : TIdSysLogMsgPart read FMsg write SetMsg;
  156. end; // class
  157. function FacilityToString(AFac: TIdSyslogFacility): string;
  158. function SeverityToString(ASec: TIdsyslogSeverity): string;
  159. function NoToSeverity(ASev : Word) : TIdSyslogSeverity;
  160. function logSeverityToNo(ASev : TIdSyslogSeverity) : Word;
  161. function NoToFacility(AFac : Word) : TIdSyslogFacility;
  162. function logFacilityToNo(AFac : TIdSyslogFacility) : Word;
  163. implementation
  164. uses
  165. IdAssignedNumbers, IdException, IdExceptionCore, IdResourceStringsProtocols, IdStack, IdUDPClient, SysUtils;
  166. const
  167. // facility
  168. ID_SYSLOG_FACILITY_KERNEL = 0; // kernel messages
  169. ID_SYSLOG_FACILITY_USER = 1; // user-level messages
  170. ID_SYSLOG_FACILITY_MAIL = 2; // mail system
  171. ID_SYSLOG_FACILITY_SYS_DAEMON = 3; // system daemons
  172. ID_SYSLOG_FACILITY_SECURITY1 = 4; // security/authorization messages (1)
  173. ID_SYSLOG_FACILITY_INTERNAL = 5; // messages generated internally by syslogd
  174. ID_SYSLOG_FACILITY_LPR = 6; // line printer subsystem
  175. ID_SYSLOG_FACILITY_NNTP = 7; // network news subsystem
  176. ID_SYSLOG_FACILITY_UUCP = 8; // UUCP subsystem
  177. ID_SYSLOG_FACILITY_CLOCK1 = 9; // clock daemon (1)
  178. ID_SYSLOG_FACILITY_SECURITY2 = 10; // security/authorization messages (2)
  179. ID_SYSLOG_FACILITY_FTP = 11; // FTP daemon
  180. ID_SYSLOG_FACILITY_NTP = 12; // NTP subsystem
  181. ID_SYSLOG_FACILITY_AUDIT = 13; // log audit
  182. ID_SYSLOG_FACILITY_ALERT = 14; // log alert
  183. ID_SYSLOG_FACILITY_CLOCK2 = 15; // clock daemon (2)
  184. ID_SYSLOG_FACILITY_LOCAL0 = 16; // local use 0 (local0)
  185. ID_SYSLOG_FACILITY_LOCAL1 = 17; // local use 1 (local1)
  186. ID_SYSLOG_FACILITY_LOCAL2 = 18; // local use 2 (local2)
  187. ID_SYSLOG_FACILITY_LOCAL3 = 19; // local use 3 (local3)
  188. ID_SYSLOG_FACILITY_LOCAL4 = 20; // local use 4 (local4)
  189. ID_SYSLOG_FACILITY_LOCAL5 = 21; // local use 5 (local5)
  190. ID_SYSLOG_FACILITY_LOCAL6 = 22; // local use 6 (local6)
  191. ID_SYSLOG_FACILITY_LOCAL7 = 23; // local use 7 (local7)
  192. // Severity
  193. ID_SYSLOG_SEVERITY_EMERGENCY = 0; // Emergency: system is unusable
  194. ID_SYSLOG_SEVERITY_ALERT = 1; // Alert: action must be taken immediately
  195. ID_SYSLOG_SEVERITY_CRITICAL = 2; // Critical: critical conditions
  196. ID_SYSLOG_SEVERITY_ERROR = 3; // Error: error conditions
  197. ID_SYSLOG_SEVERITY_WARNING = 4; // Warning: warning conditions
  198. ID_SYSLOG_SEVERITY_NOTICE = 5; // Notice: normal but significant condition
  199. ID_SYSLOG_SEVERITY_INFORMATIONAL = 6; // Informational: informational messages
  200. ID_SYSLOG_SEVERITY_DEBUG = 7; // Debug: debug-level messages
  201. function logFacilityToNo(AFac : TIdSyslogFacility) : Word;
  202. begin
  203. case AFac of
  204. sfKernel : Result := ID_SYSLOG_FACILITY_KERNEL;
  205. sfUserLevel : Result := ID_SYSLOG_FACILITY_USER;
  206. sfMailSystem : Result := ID_SYSLOG_FACILITY_MAIL;
  207. sfSystemDaemon : Result := ID_SYSLOG_FACILITY_SYS_DAEMON;
  208. sfSecurityOne : Result := ID_SYSLOG_FACILITY_SECURITY1;
  209. sfSysLogInternal : Result := ID_SYSLOG_FACILITY_INTERNAL;
  210. sfLPR : Result := ID_SYSLOG_FACILITY_LPR;
  211. sfNNTP : Result := ID_SYSLOG_FACILITY_NNTP;
  212. sfClockDaemonOne : Result := ID_SYSLOG_FACILITY_CLOCK1;
  213. sfUUCP : Result := ID_SYSLOG_FACILITY_UUCP;
  214. sfSecurityTwo : Result := ID_SYSLOG_FACILITY_SECURITY2;
  215. sfFTPDaemon : Result := ID_SYSLOG_FACILITY_FTP;
  216. sfNTP : Result := ID_SYSLOG_FACILITY_NTP;
  217. sfLogAudit : Result := ID_SYSLOG_FACILITY_AUDIT;
  218. sfLogAlert : Result := ID_SYSLOG_FACILITY_ALERT;
  219. sfClockDaemonTwo : Result := ID_SYSLOG_FACILITY_CLOCK2;
  220. sfLocalUseZero : Result := ID_SYSLOG_FACILITY_LOCAL0;
  221. sfLocalUseOne : Result := ID_SYSLOG_FACILITY_LOCAL1;
  222. sfLocalUseTwo : Result := ID_SYSLOG_FACILITY_LOCAL2;
  223. sfLocalUseThree : Result := ID_SYSLOG_FACILITY_LOCAL3;
  224. sfLocalUseFour : Result := ID_SYSLOG_FACILITY_LOCAL4;
  225. sfLocalUseFive : Result := ID_SYSLOG_FACILITY_LOCAL5;
  226. sfLocalUseSix : Result := ID_SYSLOG_FACILITY_LOCAL6;
  227. sfLocalUseSeven : Result := ID_SYSLOG_FACILITY_LOCAL7;
  228. else
  229. Result := ID_SYSLOG_FACILITY_LOCAL7;
  230. end;
  231. end;
  232. function NoToFacility(AFac : Word) : TIdSyslogFacility;
  233. begin
  234. case AFac of
  235. ID_SYSLOG_FACILITY_KERNEL : Result := sfKernel;
  236. ID_SYSLOG_FACILITY_USER : Result := sfUserLevel;
  237. ID_SYSLOG_FACILITY_MAIL : Result := sfMailSystem;
  238. ID_SYSLOG_FACILITY_SYS_DAEMON : Result := sfSystemDaemon;
  239. ID_SYSLOG_FACILITY_SECURITY1 : Result := sfSecurityOne;
  240. ID_SYSLOG_FACILITY_INTERNAL : Result := sfSysLogInternal;
  241. ID_SYSLOG_FACILITY_LPR : Result := sfLPR;
  242. ID_SYSLOG_FACILITY_NNTP : Result := sfNNTP;
  243. ID_SYSLOG_FACILITY_CLOCK1 : Result := sfClockDaemonOne;
  244. ID_SYSLOG_FACILITY_UUCP : Result := sfUUCP;
  245. ID_SYSLOG_FACILITY_SECURITY2 : Result := sfSecurityTwo;
  246. ID_SYSLOG_FACILITY_FTP : Result := sfFTPDaemon;
  247. ID_SYSLOG_FACILITY_NTP : Result := sfNTP;
  248. ID_SYSLOG_FACILITY_AUDIT : Result := sfLogAudit;
  249. ID_SYSLOG_FACILITY_ALERT : Result := sfLogAlert;
  250. ID_SYSLOG_FACILITY_CLOCK2 : Result := sfClockDaemonTwo;
  251. ID_SYSLOG_FACILITY_LOCAL0 : Result := sfLocalUseZero;
  252. ID_SYSLOG_FACILITY_LOCAL1 : Result := sfLocalUseOne;
  253. ID_SYSLOG_FACILITY_LOCAL2 : Result := sfLocalUseTwo;
  254. ID_SYSLOG_FACILITY_LOCAL3 : Result := sfLocalUseThree;
  255. ID_SYSLOG_FACILITY_LOCAL4 : Result := sfLocalUseFour;
  256. ID_SYSLOG_FACILITY_LOCAL5 : Result := sfLocalUseFive;
  257. ID_SYSLOG_FACILITY_LOCAL6 : Result := sfLocalUseSix;
  258. ID_SYSLOG_FACILITY_LOCAL7 : Result := sfLocalUseSeven;
  259. else
  260. Result := sfLocalUseSeven;
  261. end;
  262. end;
  263. function logSeverityToNo(ASev : TIdSyslogSeverity) : Word;
  264. begin
  265. case ASev of
  266. slEmergency : Result := ID_SYSLOG_SEVERITY_EMERGENCY;
  267. slAlert : Result := ID_SYSLOG_SEVERITY_ALERT;
  268. slCritical : Result := ID_SYSLOG_SEVERITY_CRITICAL;
  269. slError : Result := ID_SYSLOG_SEVERITY_ERROR;
  270. slWarning : Result := ID_SYSLOG_SEVERITY_WARNING;
  271. slNotice : Result := ID_SYSLOG_SEVERITY_NOTICE;
  272. slInformational : Result := ID_SYSLOG_SEVERITY_INFORMATIONAL;
  273. slDebug : Result := ID_SYSLOG_SEVERITY_DEBUG;
  274. else
  275. Result := ID_SYSLOG_SEVERITY_DEBUG;
  276. end;
  277. end;
  278. function NoToSeverity(ASev : Word) : TIdSyslogSeverity;
  279. begin
  280. case ASev of
  281. ID_SYSLOG_SEVERITY_EMERGENCY : Result := slEmergency;
  282. ID_SYSLOG_SEVERITY_ALERT : Result := slAlert;
  283. ID_SYSLOG_SEVERITY_CRITICAL : Result := slCritical;
  284. ID_SYSLOG_SEVERITY_ERROR : Result := slError;
  285. ID_SYSLOG_SEVERITY_WARNING : Result := slWarning;
  286. ID_SYSLOG_SEVERITY_NOTICE : Result := slNotice;
  287. ID_SYSLOG_SEVERITY_INFORMATIONAL : Result := slInformational;
  288. ID_SYSLOG_SEVERITY_DEBUG : Result := slDebug;
  289. else
  290. Result := slDebug;
  291. end;
  292. end;
  293. function SeverityToString(ASec: TIdsyslogSeverity): string;
  294. begin
  295. case ASec of
  296. slEmergency: Result := STR_SYSLOG_SEVERITY_EMERGENCY;
  297. slAlert: Result := STR_SYSLOG_SEVERITY_ALERT;
  298. slCritical: Result := STR_SYSLOG_SEVERITY_CRITICAL;
  299. slError: Result := STR_SYSLOG_SEVERITY_ERROR;
  300. slWarning: Result := STR_SYSLOG_SEVERITY_WARNING;
  301. slNotice: Result := STR_SYSLOG_SEVERITY_NOTICE;
  302. slInformational: Result := STR_SYSLOG_SEVERITY_INFORMATIONAL;
  303. slDebug: Result := STR_SYSLOG_SEVERITY_DEBUG;
  304. else
  305. Result := STR_SYSLOG_SEVERITY_UNKNOWN;
  306. end;
  307. end;
  308. function FacilityToString(AFac: TIdSyslogFacility): string;
  309. begin
  310. case AFac of
  311. sfKernel: Result := STR_SYSLOG_FACILITY_KERNEL;
  312. sfUserLevel: Result := STR_SYSLOG_FACILITY_USER;
  313. sfMailSystem: Result := STR_SYSLOG_FACILITY_MAIL;
  314. sfSystemDaemon: Result := STR_SYSLOG_FACILITY_SYS_DAEMON;
  315. sfSecurityOne: Result := STR_SYSLOG_FACILITY_SECURITY1;
  316. sfSysLogInternal: Result := STR_SYSLOG_FACILITY_INTERNAL;
  317. sfLPR: Result := STR_SYSLOG_FACILITY_LPR;
  318. sfNNTP: Result := STR_SYSLOG_FACILITY_NNTP;
  319. sfClockDaemonOne: Result := STR_SYSLOG_FACILITY_CLOCK1;
  320. sfUUCP: Result := STR_SYSLOG_FACILITY_UUCP;
  321. sfSecurityTwo: Result := STR_SYSLOG_FACILITY_SECURITY2;
  322. sfFTPDaemon: Result := STR_SYSLOG_FACILITY_FTP;
  323. sfNTP: Result := STR_SYSLOG_FACILITY_NTP;
  324. sfLogAudit: Result := STR_SYSLOG_FACILITY_AUDIT;
  325. sfLogAlert: Result := STR_SYSLOG_FACILITY_ALERT;
  326. sfClockDaemonTwo: Result := STR_SYSLOG_FACILITY_CLOCK2;
  327. sfLocalUseZero: Result := STR_SYSLOG_FACILITY_LOCAL0;
  328. sfLocalUseOne: Result := STR_SYSLOG_FACILITY_LOCAL1;
  329. sfLocalUseTwo: Result := STR_SYSLOG_FACILITY_LOCAL2;
  330. sfLocalUseThree: Result := STR_SYSLOG_FACILITY_LOCAL3;
  331. sfLocalUseFour: Result := STR_SYSLOG_FACILITY_LOCAL4;
  332. sfLocalUseFive: Result := STR_SYSLOG_FACILITY_LOCAL5;
  333. sfLocalUseSix: Result := STR_SYSLOG_FACILITY_LOCAL6;
  334. sfLocalUseSeven: Result := STR_SYSLOG_FACILITY_LOCAL7;
  335. else
  336. Result := STR_SYSLOG_FACILITY_UNKNOWN;
  337. end;
  338. end;
  339. function ExtractAlphaNumericStr(var VString : String) : String;
  340. var
  341. i, len : Integer;
  342. begin
  343. len := 0;
  344. for i := 1 to IndyMin(Length(VString), 32) do begin
  345. //numbers or alphabet only
  346. if IsAlphaNumeric(VString[i]) then begin
  347. Inc(len);
  348. end else begin
  349. Break;
  350. end;
  351. end;
  352. Result := Copy(VString, 1, len);
  353. VString := Copy(VString, len+1, MaxInt);
  354. end;
  355. { TIdSysLogMessage }
  356. procedure TIdSysLogMessage.Assign(Source: TPersistent);
  357. var
  358. ms : TIdSysLogMessage;
  359. begin
  360. if Source is TIdSysLogMessage then begin
  361. ms := Source as TIdSysLogMessage;
  362. {Priority and facility properties are set with this so those assignments
  363. are not needed}
  364. Pri := Ms.Pri;
  365. HostName := ms.Hostname;
  366. FMsg.Assign(ms.Msg);
  367. TimeStamp := ms.TimeStamp;
  368. end else begin
  369. inherited Assign(Source);
  370. end;
  371. end;
  372. function TIdSysLogMessage.DecodeTimeStamp(TimeStampString: String): TDateTime;
  373. var
  374. AYear, AMonth, ADay, AHour, AMin, ASec: Word;
  375. LDate : TDateTime;
  376. begin
  377. // SG 25/2/02: Check the ASCII range
  378. CheckASCIIRange(TimeStampString);
  379. // Get the current date to get the current year
  380. LDate := Now;
  381. DecodeDate(LDate, AYear, AMonth, ADay);
  382. if Length(TimeStampString) <> 16 then begin
  383. raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogTimeStamp, [TimeStampString]);
  384. end;
  385. // Month
  386. AMonth := StrToMonth(Copy(TimeStampString, 1, 3));
  387. if not (AMonth in [1..12]) then begin
  388. raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogTimeStamp, [TimeStampString]);
  389. end;
  390. // day
  391. ADay := IndyStrToInt(Copy(TimeStampString, 5, 2), 0);
  392. if not (ADay in [1..31]) then begin
  393. raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogTimeStamp, [TimeStampString]);
  394. end;
  395. // Time
  396. AHour := IndyStrToInt(Copy(TimeStampString, 8, 2), 0);
  397. if not (AHour in [0..23]) then begin
  398. raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogTimeStamp, [TimeStampString]);
  399. end;
  400. AMin := IndyStrToInt(Copy(TimeStampString, 11, 2), 0);
  401. if not (AMin in [0..59]) then begin
  402. raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogTimeStamp, [TimeStampString]);
  403. end;
  404. ASec := IndyStrToInt(Copy(TimeStampString, 14, 2), 0);
  405. if not (ASec in [0..59]) then begin
  406. raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogTimeStamp, [TimeStampString]);
  407. end;
  408. if TimeStampString[16] <> ' ' then begin {Do not Localize}
  409. Raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogTimeStamp, [TimeStampString]);
  410. end;
  411. Result := EncodeDate(AYear, AMonth, ADay) + EncodeTime(AHour, AMin, ASec, 0);
  412. end;
  413. procedure TIdSysLogMessage.ReadFromBytes(const ASrc: TIdBytes; const APeer : String);
  414. const
  415. MSGLEN = 1024;
  416. begin
  417. FPeer := APeer;
  418. RawMessage := BytesToString(ASrc, 0, MSGLEN);
  419. end;
  420. procedure TIdSysLogMessage.Parse;
  421. var
  422. APos: Integer;
  423. begin
  424. APos := 1;
  425. ReadPRI(APos);
  426. ReadHeader(APos);
  427. ReadMSG(APos);
  428. end;
  429. procedure TIdSysLogMessage.ReadHeader(var StartPos: Integer);
  430. var
  431. AHostNameEnd: Integer;
  432. begin
  433. // DateTimeToInternetStr and StrInternetToDateTime
  434. // Time stamp string is 15 char long
  435. try
  436. FTimeStamp := DecodeTimeStamp(Copy(FRawMessage, StartPos, 16));
  437. Inc(StartPos, 16);
  438. // HostName
  439. AHostNameEnd := StartPos;
  440. while (AHostNameEnd < Length(FRawMessage)) and (FRawMessage[AHostNameEnd] <> ' ') do begin {Do not Localize}
  441. Inc(AHostNameEnd);
  442. end; // while
  443. FHostname := Copy(FRawMessage, StartPos, AHostNameEnd - StartPos);
  444. if Pos(':', FHostname) <> 0 then begin // check if the hostname doesn't contain a semicolon (so it's not a process)
  445. FHostname := Peer;
  446. end else begin
  447. StartPos := AHostNameEnd + 1;
  448. end;
  449. // SG 25/2/02: Check the ASCII range of host name
  450. CheckASCIIRange(FHostname);
  451. except
  452. on e: Exception do
  453. begin
  454. FTimeStamp := Now;
  455. FHostname := FPeer;
  456. end;
  457. end;
  458. end;
  459. procedure TIdSysLogMessage.ReadMSG(var StartPos: Integer);
  460. begin
  461. FMessage := Copy(FRawMessage, StartPos, Length(FRawMessage));
  462. Msg.Text := FMessage;
  463. end;
  464. procedure TIdSysLogMessage.ReadPRI(var StartPos: Integer);
  465. var
  466. StartPosSave: Integer;
  467. Buffer: string;
  468. begin
  469. StartPosSave := StartPos;
  470. try
  471. // Read the PRI string
  472. // PRI must start with "less than" sign
  473. Buffer := ''; {Do not Localize}
  474. if not CharEquals(FRawMessage, StartPos, '<') then begin {Do not Localize}
  475. raise EInvalidSyslogMessage.Create(RSInvalidSyslogPRI);
  476. end;
  477. repeat
  478. Inc(StartPos);
  479. if CharEquals(FRawMessage, StartPos, '>') then begin {Do not Localize}
  480. Break;
  481. end;
  482. if not IsNumeric(FRawMessage, 1, StartPos) then begin {Do not Localize}
  483. raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogPRINumber, [Buffer]);
  484. end;
  485. Buffer := Buffer + FRawMessage[StartPos];
  486. until StartPos = StartPosSave + 5;
  487. // PRI must end with "greater than" sign
  488. if not CharEquals(FRawMessage, StartPos, '>') then begin {Do not Localize}
  489. raise EInvalidSyslogMessage.Create(RSInvalidSyslogPRI);
  490. end;
  491. // Convert PRI to numerical value
  492. Inc(StartPos);
  493. CheckASCIIRange(Buffer);
  494. PRI := IndyStrToInt(Buffer, -1);
  495. except
  496. // as per RFC, on invalid/missing PRI, use value 13
  497. on e: Exception do
  498. begin
  499. Pri := 13;
  500. // Reset the position to saved value
  501. StartPos := StartPosSave;
  502. end;
  503. end;
  504. end;
  505. procedure TIdSysLogMessage.UpdatePRI;
  506. begin
  507. PRI := logFacilityToNo(Facility) * 8 + logSeverityToNo(Severity);
  508. end;
  509. procedure TIdSysLogMessage.SetFacility(const AValue: TidSyslogFacility);
  510. begin
  511. if FFacility <> AValue then begin
  512. FFacility := AValue;
  513. UpdatePRI;
  514. end;
  515. end;
  516. procedure TIdSysLogMessage.SetHostname(const AValue: string);
  517. begin
  518. if FHostname <> AValue then begin
  519. if Pos(' ', AValue) <> 0 then begin {Do not Localize}
  520. raise EInvalidSyslogMessage.CreateFmt(RSInvalidHostName, [AValue]);
  521. end;
  522. FHostname := AValue;
  523. end;
  524. end;
  525. procedure TIdSysLogMessage.SetSeverity(const AValue: TIdSyslogSeverity);
  526. begin
  527. if FSeverity <> AValue then begin
  528. FSeverity := AValue;
  529. UpdatePRI;
  530. end;
  531. end;
  532. procedure TIdSysLogMessage.SetTimeStamp(const AValue: TDateTime);
  533. begin
  534. FTimeStamp := AValue;
  535. end;
  536. function TIdSysLogMessage.GetHeader: String;
  537. var
  538. AYear, AMonth, ADay, AHour, AMin, ASec, AMSec: Word;
  539. function YearOf(ADate : TDateTime) : Word;
  540. var
  541. mm, dd : Word;
  542. begin
  543. DecodeDate(ADate, Result, mm, dd);
  544. end;
  545. Function DayToStr(day: Word): String;
  546. begin
  547. if Day < 10 then begin
  548. Result := ' ' + IntToStr(day); {Do not Localize}
  549. end else begin
  550. Result := IntToStr(day);
  551. end;
  552. end;
  553. begin
  554. // if the year of the message is not the current year, the timestamp is
  555. // invalid -> Create a new timestamp with the current date/time
  556. if YearOf(Now) <> YearOf(TimeStamp) then
  557. begin
  558. TimeStamp := Now;
  559. end;
  560. DecodeDate(TimeStamp, AYear, AMonth, ADay);
  561. DecodeTime(TimeStamp, AHour, AMin, ASec, AMSec);
  562. Result := IndyFormat('%s %s %.2d:%.2d:%.2d %s', [monthnames[AMonth], DayToStr(ADay), AHour, AMin, ASec, Hostname]); {Do not Localize}
  563. end;
  564. function TIdSysLogMessage.EncodeMessage: String;
  565. begin
  566. // Create a syslog message string
  567. // PRI
  568. Result := IndyFormat('<%d>%s %s', [PRI, GetHeader, FMsg.Text]); {Do not Localize}
  569. // If the message is too long, tuncate it
  570. if Length(result) > 1024 then
  571. begin
  572. result := Copy(result, 1, 1024);
  573. end;
  574. end;
  575. procedure TIdSysLogMessage.SetPri(const Value: TIdSyslogPRI);
  576. begin
  577. if FPri <> Value then begin
  578. if not (Value in [0..191]) then begin
  579. raise EInvalidSyslogMessage.CreateFmt(RSInvalidSyslogPRINumber, [IntToStr(value)]);
  580. end;
  581. FPri := Value;
  582. FFacility := NoToFacility(Value div 8);
  583. FSeverity := NoToSeverity(Value mod 8);
  584. end;
  585. end;
  586. procedure TIdSysLogMessage.InitComponent;
  587. begin
  588. inherited;
  589. PRI := 13; //default
  590. {This stuff is necessary to prevent an AV in the IDE if GStack does not exist}
  591. // RLebeau: should we really be doing this here? At the least, maybe detect
  592. // DFM streaming and don't do this if it will just be overriden afterwards...
  593. TIdStack.IncUsage;
  594. try
  595. Hostname := GStack.HostName;
  596. finally
  597. TIdStack.DecUsage;
  598. end;
  599. FMsg := TIdSysLogMsgPart.Create;
  600. end;
  601. procedure TIdSysLogMessage.CheckASCIIRange(var Data: String);
  602. var
  603. i: Integer;
  604. ValidChars : String;
  605. {$IFDEF STRING_IS_IMMUTABLE}
  606. LSB: TIdStringBuilder;
  607. {$ENDIF}
  608. begin
  609. ValidChars := CharRange(#0, #127);
  610. {$IFDEF STRING_IS_IMMUTABLE}
  611. LSB := TIdStringBuilder.Create(Data);
  612. for i := 0 to LSB.Length-1 do // Iterate
  613. begin
  614. if not CharIsInSet(LSB, i, ValidChars) then begin
  615. LSB[i] := '?'; {Do not Localize}
  616. end;
  617. end; // for
  618. Data := LSB.ToString;
  619. {$ELSE}
  620. for i := 1 to Length(Data) do // Iterate
  621. begin
  622. if not CharIsInSet(Data, i, ValidChars) then begin
  623. Data[i] := '?'; {Do not Localize}
  624. end;
  625. end; // for
  626. {$ENDIF}
  627. end;
  628. destructor TIdSysLogMessage.Destroy;
  629. begin
  630. FreeAndNil(FMsg);
  631. inherited Destroy;
  632. end;
  633. procedure TIdSysLogMessage.SetMsg(const AValue: TIdSysLogMsgPart);
  634. begin
  635. FMsg.Assign(AValue);
  636. end;
  637. procedure TIdSysLogMessage.SetRawMessage(const Value: string);
  638. begin
  639. FRawMessage := Value;
  640. // check that message contains only valid ASCII chars.
  641. // Replace Invalid entries by "?"
  642. // SG 25/2/02: Moved to header decoding
  643. Parse;
  644. end;
  645. procedure TIdSysLogMessage.SendToHost(const Dest: String);
  646. var
  647. LEncoding: IIdTextEncoding;
  648. begin
  649. if not Assigned(FUDPCliComp) then begin
  650. FUDPCliComp := TIdUDPClient.Create(Self);
  651. end;
  652. LEncoding := IndyTextEncoding_8Bit;
  653. (FUDPCliComp as TIdUDPClient).Send(Dest, IdPORT_syslog, EncodeMessage, LEncoding{$IFDEF STRING_IS_ANSI}, LEncoding{$ENDIF});
  654. end;
  655. { TIdSysLogMsgPart }
  656. procedure TIdSysLogMsgPart.Assign(Source: TPersistent);
  657. begin
  658. if Source is TIdSysLogMsgPart then begin
  659. {This sets about everything here}
  660. Text := (Source as TIdSysLogMsgPart).Text;
  661. end else begin
  662. inherited Assign(Source);
  663. end;
  664. end;
  665. procedure TIdSysLogMsgPart.SetPID(AValue: Integer);
  666. begin
  667. FPID := AValue;
  668. FPIDAvailable := FPID <> -1;
  669. end;
  670. procedure TIdSysLogMsgPart.SetProcess(const AValue: String);
  671. var
  672. LTmp: String;
  673. begin
  674. //we have to ensure that the TAG field will never be greater than 32 characters
  675. //and the program name must contain alphanumeric characters
  676. LTmp := AValue;
  677. FProcess := ExtractAlphaNumericStr(LTmp);
  678. end;
  679. function TIdSysLogMsgPart.GetText: String;
  680. begin
  681. Result := Process;
  682. if FPIDAvailable then begin
  683. Result := Result + IndyFormat('[%d]', [FPID]); {Do not Localize}
  684. end;
  685. Result := Result + ': ' + Content; {Do not Localize}
  686. if Result = ': ' then begin {Do not Localize}
  687. Result := '';
  688. end;
  689. end;
  690. procedure TIdSysLogMsgPart.SetText(const AValue: String);
  691. var
  692. SBuf: String;
  693. begin
  694. FProcess := ''; {Do not Localize}
  695. FPID := -1;
  696. FPIDAvailable := False;
  697. FContent := ''; {Do not Localize}
  698. SBuf := AValue;
  699. FProcess := ExtractAlphaNumericStr(SBuf);
  700. if TextStartsWith(SBuf, '[') then begin {Do not Localize}
  701. SBuf := Copy(SBuf, 2, MaxInt);
  702. FPID := IndyStrToInt(Fetch(SBuf, ']'), -1); {Do not Localize}
  703. FPIDAvailable := FPID <> -1;
  704. end;
  705. if TextStartsWith(SBuf, ': ') then begin {Do not Localize}
  706. SBuf := Copy(SBuf, 3, MaxInt);
  707. end
  708. else if TextStartsWith(SBuf, ':') or TextStartsWith(SBuf, ' ') then begin {Do not Localize}
  709. SBuf := Copy(SBuf, 2, MaxInt);
  710. end;
  711. FContent := SBuf;
  712. end;
  713. end.