PageRenderTime 46ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/core/SIP/SIPConstants.cs

https://github.com/sipsorcery/sipsorcery
C# | 665 lines | 475 code | 58 blank | 132 comment | 25 complexity | e897bc693e290222bcb8c96c48c661f7 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause
  1. //-----------------------------------------------------------------------------
  2. // Filename: SIPConstants.cs
  3. //
  4. // Description: SIP constants.
  5. //
  6. // Author(s):
  7. // Aaron Clauson (aaron@sipsorcery.com)
  8. //
  9. // History:
  10. // 17 Sep 2005 Aaron Clauson Created, Hobart, Australia.
  11. //
  12. // License:
  13. // BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file.
  14. //-----------------------------------------------------------------------------
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Reflection;
  18. using System.Text;
  19. using SIPSorcery.Sys;
  20. // ReSharper disable InconsistentNaming
  21. namespace SIPSorcery.SIP
  22. {
  23. public static class SIPConstants
  24. {
  25. public const string CRLF = "\r\n";
  26. public const string SIP_VERSION_STRING = "SIP";
  27. public const int SIP_MAJOR_VERSION = 2;
  28. public const int SIP_MINOR_VERSION = 0;
  29. public const string SIP_FULLVERSION_STRING = "SIP/2.0";
  30. public const int NONCE_TIMEOUT_MINUTES = 5; // Length of time an issued nonce is valid for.
  31. /// <summary>
  32. /// The maximum size supported for an incoming SIP message.
  33. /// </summary>
  34. /// <remarks>
  35. /// From https://tools.ietf.org/html/rfc3261#section-18.1.1:
  36. /// However, implementations MUST be able to handle messages up to the maximum
  37. /// datagram packet size.For UDP, this size is 65,535 bytes, including
  38. /// IP and UDP headers.
  39. /// </remarks>
  40. public const int SIP_MAXIMUM_RECEIVE_LENGTH = 65535;
  41. public const string SIP_REQUEST_REGEX = @"^\w+ .* SIP/.*"; // bnf: Request-Line = Method SP Request-URI SP SIP-Version CRLF
  42. public const string SIP_RESPONSE_REGEX = @"^SIP/.* \d{3}"; // bnf: Status-Line = SIP-Version SP Status-Code SP Reason-Phrase CRLF
  43. public const string SIP_BRANCH_MAGICCOOKIE = "z9hG4bK";
  44. public const string SIP_DEFAULT_USERNAME = "Anonymous";
  45. public const string SIP_DEFAULT_FROMURI = "sip:thisis@anonymous.invalid";
  46. public const string SIP_REGISTER_REMOVEALL = "*"; // The value in a REGISTER request id a UA wishes to remove all REGISTER bindings.
  47. public const string SIP_LOOSEROUTER_PARAMETER = "lr";
  48. public const string SIP_REMOTEHANGUP_CAUSE = "remote end hungup";
  49. public const char HEADER_DELIMITER_CHAR = ':';
  50. public const int DEFAULT_MAX_FORWARDS = 70;
  51. public const int DEFAULT_REGISTEREXPIRY_SECONDS = 600;
  52. public const ushort DEFAULT_SIP_PORT = 5060;
  53. public const ushort DEFAULT_SIP_TLS_PORT = 5061;
  54. public const ushort DEFAULT_SIP_WEBSOCKET_PORT = 80;
  55. public const ushort DEFAULT_SIPS_WEBSOCKET_PORT = 443;
  56. public const string ALLOWED_SIP_METHODS = "ACK, BYE, CANCEL, INFO, INVITE, NOTIFY, OPTIONS, PRACK, REFER, REGISTER, SUBSCRIBE";
  57. private static string _userAgentVersion;
  58. public static string SIP_USERAGENT_STRING
  59. {
  60. get
  61. {
  62. if (_userAgentVersion == null)
  63. {
  64. _userAgentVersion = $"sipsorcery_v{Assembly.GetExecutingAssembly().GetName().Version}";
  65. }
  66. return _userAgentVersion;
  67. }
  68. }
  69. public static Encoding DEFAULT_ENCODING = Encoding.UTF8;
  70. /// <summary>
  71. /// Gets the default SIP port for the protocol.
  72. /// </summary>
  73. /// <param name="protocol">The transport layer protocol to get the port for.</param>
  74. /// <returns>The default port to use.</returns>
  75. public static int GetDefaultPort(SIPProtocolsEnum protocol)
  76. {
  77. switch (protocol)
  78. {
  79. case SIPProtocolsEnum.udp:
  80. return SIPConstants.DEFAULT_SIP_PORT;
  81. case SIPProtocolsEnum.tcp:
  82. return SIPConstants.DEFAULT_SIP_PORT;
  83. case SIPProtocolsEnum.tls:
  84. return SIPConstants.DEFAULT_SIP_TLS_PORT;
  85. case SIPProtocolsEnum.ws:
  86. return SIPConstants.DEFAULT_SIP_WEBSOCKET_PORT;
  87. case SIPProtocolsEnum.wss:
  88. return SIPConstants.DEFAULT_SIPS_WEBSOCKET_PORT;
  89. default:
  90. throw new ApplicationException($"Protocol {protocol} was not recognised in GetDefaultPort.");
  91. }
  92. }
  93. }
  94. public enum SIPMessageTypesEnum
  95. {
  96. Unknown = 0,
  97. Request = 1,
  98. Response = 2,
  99. }
  100. public static class SIPTimings
  101. {
  102. /// <summary>
  103. /// Value of the SIP defined timer T1 in milliseconds and is the time for the first retransmit.
  104. /// Should not need to be adjusted in normal circumstances.
  105. /// </summary>
  106. public static int T1 = 500;
  107. /// <summary>
  108. /// Value of the SIP defined timer T2 in milliseconds and is the maximum time between retransmits.
  109. /// Should not need to be adjusted in normal circumstances.
  110. /// </summary>
  111. public static int T2 = 4000;
  112. /// <summary>
  113. /// Value of the SIP defined timer T6 in milliseconds and is the period after which a transaction
  114. /// has timed out. Should not need to be adjusted in normal circumstances.
  115. /// </summary>
  116. public static int T6 = 64 * T1;
  117. /// <summary>
  118. /// The number of milliseconds a transaction can stay in the proceeding state
  119. /// (i.e. an INVITE will ring for) before the call is given up and timed out.
  120. /// </summary>
  121. public static int MAX_RING_TIME = 180000;
  122. }
  123. public enum SIPSchemesEnum
  124. {
  125. sip = 1,
  126. sips = 2,
  127. tel = 3,
  128. }
  129. public static class SIPSchemesType
  130. {
  131. public static SIPSchemesEnum GetSchemeType(string schemeType)
  132. {
  133. return (SIPSchemesEnum)Enum.Parse(typeof(SIPSchemesEnum), schemeType, true);
  134. }
  135. public static bool IsAllowedScheme(string schemeType)
  136. {
  137. try
  138. {
  139. Enum.Parse(typeof(SIPSchemesEnum), schemeType, true);
  140. return true;
  141. }
  142. catch
  143. {
  144. return false;
  145. }
  146. }
  147. }
  148. /// <summary>
  149. /// A list of the transport layer protocols that are supported (the network layers
  150. /// supported are IPv4 and IPv6).
  151. /// </summary>
  152. public enum SIPProtocolsEnum
  153. {
  154. /// <summary>
  155. /// User Datagram Protocol.
  156. /// </summary>
  157. udp = 1,
  158. /// <summary>.
  159. /// Transmission Control Protocol
  160. /// </summary>
  161. tcp = 2,
  162. /// <summary>
  163. /// Transport Layer Security.
  164. /// </summary>
  165. tls = 3,
  166. /// <summary>
  167. /// Web Socket.
  168. /// </summary>
  169. ws = 4,
  170. /// <summary>
  171. /// Web Socket over TLS.
  172. /// </summary>
  173. wss = 5,
  174. }
  175. public static class SIPProtocolsType
  176. {
  177. public static SIPProtocolsEnum GetProtocolType(string protocolType)
  178. {
  179. return (SIPProtocolsEnum)Enum.Parse(typeof(SIPProtocolsEnum), protocolType, true);
  180. }
  181. public static SIPProtocolsEnum GetProtocolTypeFromId(int protocolTypeId)
  182. {
  183. return (SIPProtocolsEnum)Enum.Parse(typeof(SIPProtocolsEnum), protocolTypeId.ToString(), true);
  184. }
  185. public static bool IsAllowedProtocol(string protocol)
  186. {
  187. try
  188. {
  189. Enum.Parse(typeof(SIPProtocolsEnum), protocol, true);
  190. return true;
  191. }
  192. catch
  193. {
  194. return false;
  195. }
  196. }
  197. /// <summary>
  198. /// Returns true for connectionless transport protocols, such as UDP, and false for
  199. /// connection oriented protocols.
  200. /// </summary>
  201. /// <param name="protocol">The protocol to check.</param>
  202. /// <returns>True if the protocol is connectionless.</returns>
  203. public static bool IsConnectionless(SIPProtocolsEnum protocol)
  204. {
  205. if (protocol == SIPProtocolsEnum.udp)
  206. {
  207. return true;
  208. }
  209. else
  210. {
  211. return false;
  212. }
  213. }
  214. }
  215. public static class SIPHeaders
  216. {
  217. // SIP Header Keys.
  218. public const string SIP_HEADER_ACCEPT = "Accept";
  219. public const string SIP_HEADER_ACCEPTENCODING = "Accept-Encoding";
  220. public const string SIP_HEADER_ACCEPTLANGUAGE = "Accept-Language";
  221. public const string SIP_HEADER_ALERTINFO = "Alert-Info";
  222. public const string SIP_HEADER_ALLOW = "Allow";
  223. public const string SIP_HEADER_ALLOW_EVENTS = "Allow-Events"; // RC3265 (SIP Events).
  224. public const string SIP_HEADER_AUTHENTICATIONINFO = "Authentication-Info";
  225. public const string SIP_HEADER_AUTHORIZATION = "Authorization";
  226. public const string SIP_HEADER_CALLID = "Call-ID";
  227. public const string SIP_HEADER_CALLINFO = "Call-Info";
  228. public const string SIP_HEADER_CONTACT = "Contact";
  229. public const string SIP_HEADER_CONTENT_DISPOSITION = "Content-Disposition";
  230. public const string SIP_HEADER_CONTENT_ENCODING = "Content-Encoding";
  231. public const string SIP_HEADER_CONTENT_LANGUAGE = "Content-Language";
  232. public const string SIP_HEADER_CONTENTLENGTH = "Content-Length";
  233. public const string SIP_HEADER_CONTENTTYPE = "Content-Type";
  234. public const string SIP_HEADER_CSEQ = "CSeq";
  235. public const string SIP_HEADER_DATE = "Date";
  236. public const string SIP_HEADER_ERROR_INFO = "Error-Info";
  237. public const string SIP_HEADER_EVENT = "Event"; // RC3265 (SIP Events).
  238. public const string SIP_HEADER_ETAG = "SIP-ETag"; // RFC3903
  239. public const string SIP_HEADER_EXPIRES = "Expires";
  240. public const string SIP_HEADER_FROM = "From";
  241. public const string SIP_HEADER_IN_REPLY_TO = "In-Reply-To";
  242. public const string SIP_HEADER_MAXFORWARDS = "Max-Forwards";
  243. public const string SIP_HEADER_MINEXPIRES = "Min-Expires";
  244. public const string SIP_HEADER_MIME_VERSION = "MIME-Version";
  245. public const string SIP_HEADER_ORGANIZATION = "Organization";
  246. public const string SIP_HEADER_PRIORITY = "Priority";
  247. public const string SIP_HEADER_PROXYAUTHENTICATION = "Proxy-Authenticate";
  248. public const string SIP_HEADER_PROXYAUTHORIZATION = "Proxy-Authorization";
  249. public const string SIP_HEADER_PROXY_REQUIRE = "Proxy-Require";
  250. public const string SIP_HEADER_RELIABLE_ACK = "RAck"; // RFC 3262 "The RAck header is sent in a PRACK request to support reliability of provisional responses."
  251. public const string SIP_HEADER_REASON = "Reason";
  252. public const string SIP_HEADER_RECORDROUTE = "Record-Route";
  253. public const string SIP_HEADER_REFERREDBY = "Referred-By"; // RFC 3515 "The Session Initiation Protocol (SIP) Refer Method".
  254. public const string SIP_HEADER_REFERSUB = "Refer-Sub"; // RFC 4488 Used to stop the implicit SIP event subscription on a REFER request.
  255. public const string SIP_HEADER_REFERTO = "Refer-To"; // RFC 3515 "The Session Initiation Protocol (SIP) Refer Method".
  256. public const string SIP_HEADER_REPLY_TO = "Reply-To";
  257. public const string SIP_HEADER_REPLACES = "Replaces";
  258. public const string SIP_HEADER_REQUIRE = "Require";
  259. public const string SIP_HEADER_RETRY_AFTER = "Retry-After";
  260. public const string SIP_HEADER_RELIABLE_SEQ = "RSeq"; // RFC 3262 "The RSeq header is used in provisional responses in order to transmit them reliably."
  261. public const string SIP_HEADER_ROUTE = "Route";
  262. public const string SIP_HEADER_SERVER = "Server";
  263. public const string SIP_HEADER_SUBJECT = "Subject";
  264. public const string SIP_HEADER_SUBSCRIPTION_STATE = "Subscription-State"; // RC3265 (SIP Events).
  265. public const string SIP_HEADER_SUPPORTED = "Supported";
  266. public const string SIP_HEADER_TIMESTAMP = "Timestamp";
  267. public const string SIP_HEADER_TO = "To";
  268. public const string SIP_HEADER_UNSUPPORTED = "Unsupported";
  269. public const string SIP_HEADER_USERAGENT = "User-Agent";
  270. public const string SIP_HEADER_VIA = "Via";
  271. public const string SIP_HEADER_WARNING = "Warning";
  272. public const string SIP_HEADER_WWWAUTHENTICATE = "WWW-Authenticate";
  273. // SIP Compact Header Keys.
  274. public const string SIP_COMPACTHEADER_ALLOWEVENTS = "u"; // RC3265 (SIP Events).
  275. public const string SIP_COMPACTHEADER_CALLID = "i";
  276. public const string SIP_COMPACTHEADER_CONTACT = "m";
  277. public const string SIP_COMPACTHEADER_CONTENTLENGTH = "l";
  278. public const string SIP_COMPACTHEADER_CONTENTTYPE = "c";
  279. public const string SIP_COMPACTHEADER_EVENT = "o"; // RC3265 (SIP Events).
  280. public const string SIP_COMPACTHEADER_FROM = "f";
  281. public const string SIP_COMPACTHEADER_REFERTO = "r"; // RFC 3515 "The Session Initiation Protocol (SIP) Refer Method".
  282. public const string SIP_COMPACTHEADER_SUBJECT = "s";
  283. public const string SIP_COMPACTHEADER_SUPPORTED = "k";
  284. public const string SIP_COMPACTHEADER_TO = "t";
  285. public const string SIP_COMPACTHEADER_VIA = "v";
  286. // Custom SIP headers to allow proxy to communicate network info to internal servers.
  287. public const string SIP_HEADER_PROXY_RECEIVEDON = "Proxy-ReceivedOn";
  288. public const string SIP_HEADER_PROXY_RECEIVEDFROM = "Proxy-ReceivedFrom";
  289. public const string SIP_HEADER_PROXY_SENDFROM = "Proxy-SendFrom";
  290. }
  291. public static class SIPHeaderAncillary
  292. {
  293. // Header parameters used in the core SIP protocol.
  294. public const string SIP_HEADERANC_TAG = "tag";
  295. public const string SIP_HEADERANC_BRANCH = "branch";
  296. public const string SIP_HEADERANC_RECEIVED = "received";
  297. public const string SIP_HEADERANC_TRANSPORT = "transport";
  298. public const string SIP_HEADERANC_MADDR = "maddr";
  299. // Via header parameter, documented in RFC 3581 "An Extension to the Session Initiation Protocol (SIP)
  300. // for Symmetric Response Routing".
  301. public const string SIP_HEADERANC_RPORT = "rport";
  302. // SIP header parameter from RFC 3515 "The Session Initiation Protocol (SIP) Refer Method".
  303. public const string SIP_REFER_REPLACES = "Replaces";
  304. }
  305. /// <summary>
  306. /// Authorization Headers
  307. /// </summary>
  308. public static class AuthHeaders
  309. {
  310. public const string AUTH_DIGEST_KEY = "Digest";
  311. public const string AUTH_REALM_KEY = "realm";
  312. public const string AUTH_NONCE_KEY = "nonce";
  313. public const string AUTH_USERNAME_KEY = "username";
  314. public const string AUTH_RESPONSE_KEY = "response";
  315. public const string AUTH_URI_KEY = "uri";
  316. public const string AUTH_ALGORITHM_KEY = "algorithm";
  317. public const string AUTH_CNONCE_KEY = "cnonce";
  318. public const string AUTH_NONCECOUNT_KEY = "nc";
  319. public const string AUTH_QOP_KEY = "qop";
  320. public const string AUTH_OPAQUE_KEY = "opaque";
  321. }
  322. /// <summary>
  323. /// A list of the different SIP request methods that are supported.
  324. /// </summary>
  325. public enum SIPMethodsEnum
  326. {
  327. NONE = 0,
  328. UNKNOWN = 1,
  329. // Core.
  330. REGISTER = 2,
  331. INVITE = 3,
  332. BYE = 4,
  333. ACK = 5,
  334. CANCEL = 6,
  335. OPTIONS = 7,
  336. INFO = 8, // RFC2976.
  337. NOTIFY = 9, // RFC3265.
  338. SUBSCRIBE = 10, // RFC3265.
  339. PUBLISH = 11, // RFC3903.
  340. PING = 13,
  341. REFER = 14, // RFC3515 "The Session Initiation Protocol (SIP) Refer Method"
  342. MESSAGE = 15, // RFC3428.
  343. PRACK = 16, // RFC3262.
  344. UPDATE = 17, // RFC3311.
  345. }
  346. public static class SIPMethods
  347. {
  348. public static SIPMethodsEnum GetMethod(string method)
  349. {
  350. SIPMethodsEnum sipMethod = SIPMethodsEnum.UNKNOWN;
  351. try
  352. {
  353. sipMethod = (SIPMethodsEnum)Enum.Parse(typeof(SIPMethodsEnum), method, true);
  354. }
  355. catch { }
  356. return sipMethod;
  357. }
  358. }
  359. public enum SIPResponseStatusCodesEnum
  360. {
  361. None = 0,
  362. // Informational
  363. Trying = 100,
  364. Ringing = 180,
  365. CallIsBeingForwarded = 181,
  366. Queued = 182,
  367. SessionProgress = 183,
  368. // Success
  369. Ok = 200,
  370. Accepted = 202, // RC3265 (SIP Events).
  371. NoNotification = 204,
  372. // Redirection
  373. MultipleChoices = 300,
  374. MovedPermanently = 301,
  375. MovedTemporarily = 302,
  376. AlternativeService = 304,
  377. UseProxy = 305,
  378. // Client-Error
  379. BadRequest = 400,
  380. Unauthorised = 401,
  381. PaymentRequired = 402,
  382. Forbidden = 403,
  383. NotFound = 404,
  384. MethodNotAllowed = 405,
  385. NotAcceptable = 406,
  386. ProxyAuthenticationRequired = 407,
  387. RequestTimeout = 408,
  388. Gone = 410,
  389. ConditionalRequestFailed = 412,
  390. RequestEntityTooLarge = 413,
  391. RequestURITooLong = 414,
  392. UnsupportedMediaType = 415,
  393. UnsupportedURIScheme = 416,
  394. UnknownResourcePriority = 417,
  395. BadExtension = 420,
  396. ExtensionRequired = 421,
  397. SessionIntervalTooSmall = 422,
  398. IntervalTooBrief = 423,
  399. UseIdentityHeader = 428,
  400. ProvideReferrerIdentity = 429,
  401. FlowFailed = 430,
  402. AnonymityDisallowed = 433,
  403. BadIdentityInfo = 436,
  404. UnsupportedCertificate = 437,
  405. InvalidIdentityHeader = 438,
  406. FirstHopLacksOutboundSupport = 439,
  407. MaxBreadthExceeded = 440,
  408. ConsentNeeded = 470,
  409. TemporarilyUnavailable = 480,
  410. CallLegTransactionDoesNotExist = 481,
  411. LoopDetected = 482,
  412. TooManyHops = 483,
  413. AddressIncomplete = 484,
  414. Ambiguous = 485,
  415. BusyHere = 486,
  416. RequestTerminated = 487,
  417. NotAcceptableHere = 488,
  418. BadEvent = 489, // RC3265 (SIP Events).
  419. RequestPending = 491,
  420. Undecipherable = 493,
  421. // Server Failure.
  422. InternalServerError = 500,
  423. NotImplemented = 501,
  424. BadGateway = 502,
  425. ServiceUnavailable = 503,
  426. ServerTimeout = 504,
  427. SIPVersionNotSupported = 505,
  428. MessageTooLarge = 513,
  429. PreconditionFailure = 580,
  430. // Global Failures.
  431. BusyEverywhere = 600,
  432. Decline = 603,
  433. DoesNotExistAnywhere = 604,
  434. NotAcceptableAnywhere = 606,
  435. }
  436. public static class SIPResponseStatusCodes
  437. {
  438. public static SIPResponseStatusCodesEnum GetStatusTypeForCode(int statusCode)
  439. {
  440. return (SIPResponseStatusCodesEnum)Enum.Parse(typeof(SIPResponseStatusCodesEnum), statusCode.ToString(), true);
  441. }
  442. }
  443. public enum SIPUserAgentRoles
  444. {
  445. Unknown = 0,
  446. Client = 1, // UAC.
  447. Server = 2, // UAS.
  448. }
  449. public static class SIPMIMETypes
  450. {
  451. public const string DIALOG_INFO_CONTENT_TYPE = "application/dialog-info+xml"; // RFC4235 INVITE dialog event package.
  452. public const string MWI_CONTENT_TYPE = "application/simple-message-summary"; // RFC3842 MWI event package.
  453. public const string REFER_CONTENT_TYPE = "message/sipfrag"; // RFC3515 REFER event package.
  454. public const string MWI_TEXT_TYPE = "text/text";
  455. public const string PRESENCE_NOTIFY_CONTENT_TYPE = "application/pidf+xml"; // RFC3856 presence event package.
  456. }
  457. /// <summary>
  458. /// For SIP URI user portion the reserved characters below need to be escaped.
  459. ///
  460. /// <code>
  461. /// <![CDATA[
  462. /// reserved = ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
  463. /// user-unreserved = "&" / "=" / "+" / "$" / "," / ";" / "?" / "/"
  464. /// Leaving to be escaped = ":" / "@"
  465. /// ]]>
  466. /// </code>
  467. ///
  468. /// For SIP URI parameters different characters are unreserved (just to make life difficult).
  469. /// <code>
  470. /// <![CDATA[
  471. /// reserved = ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
  472. /// param-unreserved = "[" / "]" / "/" / ":" / "&" / "+" / "$"
  473. /// Leaving to be escaped = ";" / "?" / "@" / "=" / ","
  474. /// ]]>
  475. /// </code>
  476. /// </summary>
  477. public static class SIPEscape
  478. {
  479. public static string SIPURIUserEscape(string unescapedString)
  480. {
  481. string result = unescapedString;
  482. if (!result.IsNullOrBlank())
  483. {
  484. result = result.Replace(":", "%3A");
  485. result = result.Replace("@", "%40");
  486. result = result.Replace(" ", "%20");
  487. }
  488. return result;
  489. }
  490. public static string SIPURIUserUnescape(string escapedString)
  491. {
  492. string result = escapedString;
  493. if (!result.IsNullOrBlank())
  494. {
  495. result = result.Replace("%3A", ":");
  496. result = result.Replace("%3a", ":");
  497. result = result.Replace("%20", " ");
  498. }
  499. return result;
  500. }
  501. public static string SIPURIParameterEscape(string unescapedString)
  502. {
  503. string result = unescapedString;
  504. if (!result.IsNullOrBlank())
  505. {
  506. result = result.Replace(";", "%3B");
  507. result = result.Replace("?", "%3F");
  508. result = result.Replace("@", "%40");
  509. result = result.Replace("=", "%3D");
  510. result = result.Replace(",", "%2C");
  511. result = result.Replace(" ", "%20");
  512. }
  513. return result;
  514. }
  515. public static string SIPURIParameterUnescape(string escapedString)
  516. {
  517. string result = escapedString;
  518. if (!result.IsNullOrBlank())
  519. {
  520. result = result.Replace("%3B", ";");
  521. result = result.Replace("%3b", ";");
  522. //result = result.Replace("%2F", "/");
  523. //result = result.Replace("%2f", "/");
  524. result = result.Replace("%3F", "?");
  525. result = result.Replace("%3f", "?");
  526. //result = result.Replace("%3A", ":");
  527. //result = result.Replace("%3a", ":");
  528. result = result.Replace("%40", "@");
  529. //result = result.Replace("%26", "&");
  530. result = result.Replace("%3D", "=");
  531. result = result.Replace("%3d", "=");
  532. //result = result.Replace("%2B", "+");
  533. //result = result.Replace("%2b", "+");
  534. //result = result.Replace("%24", "$");
  535. result = result.Replace("%2C", ",");
  536. result = result.Replace("%2c", ",");
  537. result = result.Replace("%20", " ");
  538. }
  539. return result;
  540. }
  541. }
  542. ///<summary>
  543. /// List of SIP extensions to RFC3262.
  544. /// </summary>
  545. public enum SIPExtensions
  546. {
  547. None = 0,
  548. Prack = 1, // Reliable provisional responses as per RFC3262.
  549. NoReferSub = 2, // No subscription for REFERs as per RFC4488.
  550. Replaces = 3,
  551. SipRec = 4,
  552. }
  553. /// <summary>
  554. /// Constants that can be placed in the SIP Supported or Required headers to indicate support or mandate for
  555. /// a particular SIP extension.
  556. /// </summary>
  557. public static class SIPExtensionHeaders
  558. {
  559. public const string PRACK = "100rel";
  560. public const string NO_REFER_SUB = "norefersub";
  561. public const string REPLACES = "replaces";
  562. public const string SIPREC = "siprec";
  563. /// <summary>
  564. /// Parses a string containing a list of SIP extensions into a list of extensions that this library
  565. /// understands.
  566. /// </summary>
  567. /// <param name="extensionList">The string containing the list of extensions to parse.</param>
  568. /// <param name="unknownExtensions">A comma separated list of the unsupported extensions.</param>
  569. /// <returns>A list of extensions that were understood and a boolean indicating whether any unknown extensions were present.</returns>
  570. public static List<SIPExtensions> ParseSIPExtensions(string extensionList, out string unknownExtensions)
  571. {
  572. List<SIPExtensions> knownExtensions = new List<SIPExtensions>();
  573. unknownExtensions = null;
  574. if (String.IsNullOrEmpty(extensionList) == false)
  575. {
  576. string[] extensions = extensionList.Trim().Split(',');
  577. foreach (string extension in extensions)
  578. {
  579. if (String.IsNullOrEmpty(extension) == false)
  580. {
  581. if (extension.Trim().ToLower() == PRACK)
  582. {
  583. knownExtensions.Add(SIPExtensions.Prack);
  584. }
  585. else if (extension.Trim().ToLower() == NO_REFER_SUB)
  586. {
  587. knownExtensions.Add(SIPExtensions.NoReferSub);
  588. }
  589. else if (extension.Trim().ToLower() == REPLACES)
  590. {
  591. knownExtensions.Add(SIPExtensions.Replaces);
  592. }
  593. else if (extension.Trim().ToLower() == SIPREC)
  594. {
  595. knownExtensions.Add(SIPExtensions.SipRec);
  596. }
  597. else
  598. {
  599. unknownExtensions += (unknownExtensions != null) ? $",{extension.Trim()}" : extension.Trim();
  600. }
  601. }
  602. }
  603. }
  604. return knownExtensions;
  605. }
  606. }
  607. }