/Growl/Growl.Connector/Header.cs

http://growl-for-windows.googlecode.com/ · C# · 528 lines · 217 code · 41 blank · 270 comment · 29 complexity · 4bed314ff9b49fcdfd728a862c3af301 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Text.RegularExpressions;
  5. using Growl.CoreLibrary;
  6. namespace Growl.Connector
  7. {
  8. /// <summary>
  9. /// Represents a single header in a GNTP message
  10. /// </summary>
  11. public class Header
  12. {
  13. /// <summary>
  14. /// The prefix used for application-specific (non-defined) data headers
  15. /// </summary>
  16. protected const string DATA_HEADER_PREFIX = "Data-";
  17. /// <summary>
  18. /// The prefix used for custom (non-defined) headers
  19. /// </summary>
  20. protected const string CUSTOM_HEADER_PREFIX = "X-";
  21. /// <summary>
  22. /// The prefix used to identify binary resources that will be passed along with the message
  23. /// </summary>
  24. private const string GROWL_RESOURCE_POINTER_PREFIX = "x-growl-resource://";
  25. /// <summary>
  26. /// The value of a boolean header that is set to true
  27. /// </summary>
  28. private const string BOOL_HEADER_TRUE_VALUE = "Yes";
  29. /// <summary>
  30. /// The value of a boolean header that is set to false
  31. /// </summary>
  32. private const string BOOL_HEADER_FALSE_VALUE = "No";
  33. /// <summary>
  34. /// The RegEx group name for the match that contains the header name (see regExHeader expression below)
  35. /// </summary>
  36. private const string HEADER_NAME_REGEX_GROUP_NAME = "HeaderName";
  37. /// <summary>
  38. /// The RegEx group name for the match that contains the header value (see regExHeader expression below)
  39. /// </summary>
  40. private const string HEADER_VALUE_REGEX_GROUP_NAME = "HeaderValue";
  41. /// <summary>
  42. /// The regular expression used to parse the header line
  43. /// </summary>
  44. //private static Regex regExHeader = new Regex(@"(?<HeaderName>[^\r\n:]+):\s+(?<HeaderValue>([\s\S]*\r\n)|(.+))");
  45. private static Regex regExHeader = new Regex(@"(?<HeaderName>[^\r\n:]+):\s+(?<HeaderValue>([\s\S]*\Z)|(.+))");
  46. /// <summary>
  47. /// A special <see cref="Header"/> that represents a header that was not found in the message
  48. /// </summary>
  49. public static readonly Header NotFoundHeader = new Header();
  50. /// <summary>
  51. /// The header name
  52. /// </summary>
  53. private string name;
  54. /// <summary>
  55. /// The header value
  56. /// </summary>
  57. private string val;
  58. /// <summary>
  59. /// Indicates if the header is valid or not
  60. /// </summary>
  61. private bool isValid;
  62. /// <summary>
  63. /// Indicates if the header is a blank line or not
  64. /// </summary>
  65. private bool isBlankLine;
  66. /// <summary>
  67. /// Indicates if the header is a pointer to a binary resource
  68. /// </summary>
  69. private bool isGrowlResourcePointer;
  70. /// <summary>
  71. /// The resource pointer value
  72. /// </summary>
  73. private string growlResourcePointerID;
  74. /// <summary>
  75. /// Indicates if this header is an 'Identifier' header
  76. /// </summary>
  77. private bool isIdentifier;
  78. /// <summary>
  79. /// Indicates if this header is a custom header
  80. /// </summary>
  81. private bool isCustomHeader;
  82. /// <summary>
  83. /// Indicates if this header is a application-specific data header
  84. /// </summary>
  85. private bool isDataHeader;
  86. /// <summary>
  87. /// The binary data associated with this header (if applicable)
  88. /// </summary>
  89. private BinaryData growlResource = null;
  90. /// <summary>
  91. /// Creates a new uninitialized instance of the <see cref="Header"/> class.
  92. /// </summary>
  93. public Header()
  94. {
  95. // skip initialize
  96. }
  97. /// <summary>
  98. /// Creates a new instance of the <see cref="Header"/> class
  99. /// </summary>
  100. /// <param name="name">The header name</param>
  101. /// <param name="val">The header value</param>
  102. public Header(string name, string val)
  103. {
  104. Initialize(name, val);
  105. }
  106. /// <summary>
  107. /// Creates a new instance of the <see cref="Header"/> class
  108. /// </summary>
  109. /// <param name="name">The header name</param>
  110. /// <param name="val">The header value</param>
  111. public Header(string name, bool val)
  112. {
  113. string yesOrNo = (val ? BOOL_HEADER_TRUE_VALUE : BOOL_HEADER_FALSE_VALUE);
  114. Initialize(name, yesOrNo);
  115. }
  116. /// <summary>
  117. /// Creates a new instance of the <see cref="Header"/> class
  118. /// </summary>
  119. /// <param name="name">The header name</param>
  120. /// <param name="val">The header value</param>
  121. public Header(string name, Resource val)
  122. {
  123. if (val != null)
  124. {
  125. Initialize(name, val.ToString());
  126. if (val.IsRawData) this.GrowlResource = val.Data;
  127. }
  128. }
  129. /// <summary>
  130. /// Initializes the header object
  131. /// </summary>
  132. /// <param name="name">The header name</param>
  133. /// <param name="val">The header value</param>
  134. private void Initialize(string name, string val)
  135. {
  136. this.name = name;
  137. this.val = val;
  138. this.isValid = true;
  139. if (name == null && val == null) this.isBlankLine = true;
  140. if (!this.isBlankLine)
  141. {
  142. if (val != null && val.StartsWith(GROWL_RESOURCE_POINTER_PREFIX, StringComparison.InvariantCultureIgnoreCase))
  143. {
  144. this.isGrowlResourcePointer = true;
  145. this.growlResourcePointerID = val.Replace(GROWL_RESOURCE_POINTER_PREFIX, "");
  146. }
  147. if (name != null && name == Header.RESOURCE_IDENTIFIER)
  148. {
  149. this.isIdentifier = true;
  150. }
  151. if (name != null && name.StartsWith(CUSTOM_HEADER_PREFIX))
  152. {
  153. this.isCustomHeader = true;
  154. }
  155. else if (name != null && name.StartsWith(DATA_HEADER_PREFIX))
  156. {
  157. this.isDataHeader = true;
  158. }
  159. }
  160. }
  161. /// <summary>
  162. /// Gets the header name
  163. /// </summary>
  164. /// <value>
  165. /// string - Ex: Application-Name: SurfWriter
  166. /// </value>
  167. public string Name
  168. {
  169. get
  170. {
  171. return this.name;
  172. }
  173. }
  174. /// <summary>
  175. /// Gets the actual header name
  176. /// </summary>
  177. /// <value>
  178. /// string
  179. /// </value>
  180. /// <remarks>
  181. /// If the header is a defined header, this property returns the same value as the Name property.
  182. /// If the header is a custom header, this property returns the header name with the custom header prefix removed.
  183. /// If the header is a data header, this property returns the header name with the custom header prefix removed.
  184. /// </remarks>
  185. public string ActualName
  186. {
  187. get
  188. {
  189. if (this.IsCustomHeader)
  190. return this.Name.Remove(0, CUSTOM_HEADER_PREFIX.Length);
  191. else if (this.isDataHeader)
  192. return this.name.Remove(0, DATA_HEADER_PREFIX.Length);
  193. return this.Name;
  194. }
  195. }
  196. /// <summary>
  197. /// Gets the value of the header
  198. /// </summary>
  199. /// <value>
  200. /// string
  201. /// </value>
  202. public string Value
  203. {
  204. get
  205. {
  206. return this.val;
  207. }
  208. }
  209. /// <summary>
  210. /// Indicates if the header is valid or not
  211. /// </summary>
  212. /// <value>
  213. /// bool - this value is only <c>true</c> for special cases, like <see cref="Header.NotFoundHeader"/>
  214. /// </value>
  215. public bool IsValid
  216. {
  217. get
  218. {
  219. return this.isValid;
  220. }
  221. }
  222. /// <summary>
  223. /// Indicates if the header is a blank line of not
  224. /// </summary>
  225. /// <value>
  226. /// <c>true</c> if the header is a blank line,
  227. /// <c>false</c> otherwise
  228. /// </value>
  229. public bool IsBlankLine
  230. {
  231. get
  232. {
  233. return this.isBlankLine;
  234. }
  235. }
  236. /// <summary>
  237. /// Indicates if the header is a custom header or not
  238. /// </summary>
  239. /// <value>
  240. /// <c>true</c> if the header is a custom header,
  241. /// <c>false</c> if the header is a defined header
  242. /// </value>
  243. public bool IsCustomHeader
  244. {
  245. get
  246. {
  247. return this.isCustomHeader;
  248. }
  249. }
  250. /// <summary>
  251. /// Indicates if the header is an application-specific data header or not
  252. /// </summary>
  253. /// <value>
  254. /// <c>true</c> if the header is a data header,
  255. /// <c>false</c> if the header is a defined header
  256. /// </value>
  257. public bool IsDataHeader
  258. {
  259. get
  260. {
  261. return this.isDataHeader;
  262. }
  263. }
  264. /// <summary>
  265. /// Indicates if the header is a <see cref="Header.RESOURCE_IDENTIFIER"/> header
  266. /// </summary>
  267. /// <value>
  268. /// <c>true</c> if the header is a <see cref="Header.RESOURCE_IDENTIFIER"/> header,
  269. /// <c>false</c> otherwise
  270. /// </value>
  271. public bool IsIdentifier
  272. {
  273. get
  274. {
  275. return this.isIdentifier;
  276. }
  277. }
  278. /// <summary>
  279. /// Indicates if the header is a binary resource pointer
  280. /// </summary>
  281. /// <value>
  282. /// <c>true</c> if the header is a binary resource pointer,
  283. /// <c>false</c> otherwise
  284. /// </value>
  285. public bool IsGrowlResourcePointer
  286. {
  287. get
  288. {
  289. return this.isGrowlResourcePointer;
  290. }
  291. }
  292. /// <summary>
  293. /// Gets the resource pointer value if this is a resource pointer header
  294. /// </summary>
  295. /// <value>
  296. /// string - Ex: x-growl-resource://1234567890
  297. /// </value>
  298. public string GrowlResourcePointerID
  299. {
  300. get
  301. {
  302. return this.growlResourcePointerID;
  303. }
  304. }
  305. /// <summary>
  306. /// Gets or sets the <see cref="BinaryData"/> associated with this header if this
  307. /// is a binary resource pointer header.
  308. /// </summary>
  309. /// <value>
  310. /// <see cref="BinaryData"/> or <c>null</c> if this is not a resource pointer header
  311. /// </value>
  312. public BinaryData GrowlResource
  313. {
  314. get
  315. {
  316. return this.growlResource;
  317. }
  318. set
  319. {
  320. this.growlResource = value;
  321. }
  322. }
  323. /// <summary>
  324. /// Creates a <see cref="Header"/> from a message line
  325. /// </summary>
  326. /// <param name="line">The individual message line</param>
  327. /// <returns><see cref="Header"/></returns>
  328. public static Header ParseHeader(string line)
  329. {
  330. Header header = null;
  331. if (line != null)
  332. {
  333. line = line.Trim();
  334. if(String.IsNullOrEmpty(line))
  335. {
  336. header = new Header();
  337. }
  338. else
  339. {
  340. // move this to static member variable
  341. Match m = regExHeader.Match(line);
  342. if (m.Success)
  343. {
  344. header = new Header(m.Groups[HEADER_NAME_REGEX_GROUP_NAME].Value.Trim(), m.Groups[HEADER_VALUE_REGEX_GROUP_NAME].Value.Trim());
  345. }
  346. }
  347. }
  348. return header;
  349. }
  350. /// <summary>
  351. /// Response-Action header
  352. /// </summary>
  353. public const string RESPONSE_ACTION = "Response-Action";
  354. /// <summary>
  355. /// Application-Name header
  356. /// </summary>
  357. public const string APPLICATION_NAME = "Application-Name";
  358. /// <summary>
  359. /// Application-Icon header
  360. /// </summary>
  361. public const string APPLICATION_ICON = "Application-Icon";
  362. /// <summary>
  363. /// Notifications-Count header
  364. /// </summary>
  365. public const string NOTIFICATIONS_COUNT = "Notifications-Count";
  366. /// <summary>
  367. /// Notification-Name header
  368. /// </summary>
  369. public const string NOTIFICATION_NAME = "Notification-Name";
  370. /// <summary>
  371. /// Notification-Display-Name header
  372. /// </summary>
  373. public const string NOTIFICATION_DISPLAY_NAME = "Notification-Display-Name";
  374. /// <summary>
  375. /// Notification-Enabled header
  376. /// </summary>
  377. public const string NOTIFICATION_ENABLED = "Notification-Enabled";
  378. /// <summary>
  379. /// Notification-Icon header
  380. /// </summary>
  381. public const string NOTIFICATION_ICON = "Notification-Icon";
  382. /// <summary>
  383. /// Notification-ID header
  384. /// </summary>
  385. public const string NOTIFICATION_ID = "Notification-ID";
  386. /// <summary>
  387. /// Notification-Title header
  388. /// </summary>
  389. public const string NOTIFICATION_TITLE = "Notification-Title";
  390. /// <summary>
  391. /// Notification-Text header
  392. /// </summary>
  393. public const string NOTIFICATION_TEXT = "Notification-Text";
  394. /// <summary>
  395. /// Notification-Sticky header
  396. /// </summary>
  397. public const string NOTIFICATION_STICKY = "Notification-Sticky";
  398. /// <summary>
  399. /// Notification-Priority header
  400. /// </summary>
  401. public const string NOTIFICATION_PRIORITY = "Notification-Priority";
  402. /// <summary>
  403. /// Notification-Coalescing-ID header
  404. /// </summary>
  405. public const string NOTIFICATION_COALESCING_ID = "Notification-Coalescing-ID";
  406. /// <summary>
  407. /// Notification-Callback-Result header
  408. /// </summary>
  409. public const string NOTIFICATION_CALLBACK_RESULT = "Notification-Callback-Result";
  410. /// <summary>
  411. /// Notification-Callback-Timestamp header
  412. /// </summary>
  413. public const string NOTIFICATION_CALLBACK_TIMESTAMP = "Notification-Callback-Timestamp";
  414. /// <summary>
  415. /// Notification-Callback-Context header
  416. /// </summary>
  417. public const string NOTIFICATION_CALLBACK_CONTEXT = "Notification-Callback-Context";
  418. /// <summary>
  419. /// Notification-Callback-Context-Type header
  420. /// </summary>
  421. public const string NOTIFICATION_CALLBACK_CONTEXT_TYPE = "Notification-Callback-Context-Type";
  422. /// <summary>
  423. /// Notification-Callback-Target header
  424. /// </summary>
  425. public const string NOTIFICATION_CALLBACK_TARGET = "Notification-Callback-Target";
  426. /// <summary>
  427. /// Notification-Callback-Context-Target header (this is not a valid header, but it is left in for compatibility with existing implementations)
  428. /// </summary>
  429. public const string NOTIFICATION_CALLBACK_CONTEXT_TARGET = "Notification-Callback-Context-Target";
  430. /// <summary>
  431. /// Identifier header
  432. /// </summary>
  433. public const string RESOURCE_IDENTIFIER = "Identifier";
  434. /// <summary>
  435. /// Length header
  436. /// </summary>
  437. public const string RESOURCE_LENGTH = "Length";
  438. /// <summary>
  439. /// Origin-Machine-Name header
  440. /// </summary>
  441. public const string ORIGIN_MACHINE_NAME = "Origin-Machine-Name";
  442. /// <summary>
  443. /// Origin-Software-Name header
  444. /// </summary>
  445. public const string ORIGIN_SOFTWARE_NAME = "Origin-Software-Name";
  446. /// <summary>
  447. /// Origin-Software-Version header
  448. /// </summary>
  449. public const string ORIGIN_SOFTWARE_VERSION = "Origin-Software-Version";
  450. /// <summary>
  451. /// Origin-Platform-Name header
  452. /// </summary>
  453. public const string ORIGIN_PLATFORM_NAME = "Origin-Platform-Name";
  454. /// <summary>
  455. /// Origin-Platform-Version header
  456. /// </summary>
  457. public const string ORIGIN_PLATFORM_VERSION = "Origin-Platform-Version";
  458. /// <summary>
  459. /// Error-Code header
  460. /// </summary>
  461. public const string ERROR_CODE = "Error-Code";
  462. /// <summary>
  463. /// Error-Description header
  464. /// </summary>
  465. public const string ERROR_DESCRIPTION = "Error-Description";
  466. /// <summary>
  467. /// Received header
  468. /// </summary>
  469. public const string RECEIVED = "Received";
  470. /// <summary>
  471. /// Subscriber-ID header
  472. /// </summary>
  473. public const string SUBSCRIBER_ID = "Subscriber-ID";
  474. /// <summary>
  475. /// Subscriber-Name header
  476. /// </summary>
  477. public const string SUBSCRIBER_NAME = "Subscriber-Name";
  478. /// <summary>
  479. /// Subscriber-Port header
  480. /// </summary>
  481. public const string SUBSCRIBER_PORT = "Subscriber-Port";
  482. /// <summary>
  483. /// Subscription-TTL header
  484. /// </summary>
  485. public const string SUBSCRIPTION_TTL = "Subscription-TTL";
  486. }
  487. }