IdSysLogMessage.pas 28 KB

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