/address.js

https://github.com/jdonnerstag/Haraka · JavaScript · 133 lines · 98 code · 26 blank · 9 comment · 17 complexity · bac7e1e5adb5ca2ed9b05dde385b2d39 MD5 · raw file

  1. // a class encapsulating an email address as per RFC-2821
  2. var logger = require('./logger');
  3. var qchar = /([^a-zA-Z0-9!#\$\%\&\x27\*\+\x2D\/=\?\^_`{\|}~.])/;
  4. function Address (user, host) {
  5. var match = /^<(.*)>$/.exec(user);
  6. if (match) {
  7. this.original = user;
  8. this.parse(match[1]);
  9. }
  10. else if (!host) {
  11. this.original = user;
  12. this.parse(user);
  13. }
  14. else {
  15. this.original = user + '@' + host;
  16. this.user = user;
  17. this.host = host;
  18. }
  19. }
  20. exports.atom_expr = /[a-zA-Z0-9!#%&*+=?^_`{|}~\$\x27\x2D\/]+/;
  21. exports.address_literal_expr =
  22. /(?:\[(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|IPv6:[0-9A-Fa-f:.]+)\])/;
  23. exports.subdomain_expr = /(?:[a-zA-Z0-9](?:[-a-zA-Z0-9]*[a-zA-Z0-9])?)/;
  24. exports.domain_expr;
  25. exports.qtext_expr = /[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]/;
  26. exports.text_expr = /\\([\x01-\x09\x0B\x0C\x0E-\x7F])/;
  27. var domain_re, source_route_re, user_host_re, atoms_re, qt_re;
  28. exports.compile_re = function () {
  29. domain_re = exports.domain_expr ? exports.domain_expr
  30. : new RegExp (
  31. exports.subdomain_expr.source +
  32. '(?:\.' + exports.subdomain_expr.source + ')*'
  33. );
  34. if (!exports.domain_expr && exports.address_literal_expr) {
  35. // if address_literal_expr is set, add it in
  36. domain_re = new RegExp('(?:' + exports.address_literal_expr.source +
  37. '|' + domain_re.source + ')');
  38. }
  39. source_route_re = new RegExp('^\@' + domain_re.source + '(?:,\@' + domain_re.source + ')*:');
  40. user_host_re = new RegExp('^(.*)\@(' + domain_re.source + ')$');
  41. atoms_re = new RegExp('^' + exports.atom_expr.source + '(\.' + exports.atom_expr.source + ')*');
  42. qt_re = new RegExp('^"((' + exports.qtext_expr.source + '|' + exports.text_expr.source + ')*)"$');
  43. }
  44. exports.compile_re();
  45. Address.prototype.parse = function (addr) {
  46. // strip source route
  47. addr = addr.replace(source_route_re, '');
  48. // empty addr is ok
  49. if (addr === '') {
  50. this.user = null;
  51. this.host = null;
  52. return;
  53. }
  54. // bare postmaster is permissible, perl RFC-2821 (4.5.1)
  55. if (addr.toLowerCase() === 'postmaster') {
  56. this.user = 'postmaster';
  57. this.host = null;
  58. return;
  59. }
  60. var matches;
  61. if (!(matches = user_host_re.exec(addr))) {
  62. throw new Error("Failed to parse address: " + addr);
  63. }
  64. var localpart = matches[1];
  65. var domainpart = matches[2];
  66. if (atoms_re.test(localpart)) {
  67. // simple case, we are done
  68. this.user = localpart;
  69. // I'm lower-case'ing here. Not sure if that's the "right" thing
  70. // to do, as the original case could be useful (but then you can get
  71. // that from address.original I guess).
  72. this.host = domainpart.toLowerCase();
  73. return;
  74. }
  75. else if (matches = qt_re.exec(localpart)) {
  76. localpart = matches[1];
  77. this.user = localpart.replace(exports.text_expr, '$1', 'g');
  78. this.host = domainpart.toLowerCase();
  79. return;
  80. }
  81. else {
  82. throw new Error("Failed to parse address: " + addr);
  83. }
  84. }
  85. Address.prototype.isNull = function () {
  86. return this.user ? 0 : 1;
  87. }
  88. Address.prototype.format = function () {
  89. if (this.isNull()) {
  90. return '<>';
  91. }
  92. var user = this.user.replace(qchar, '\\$1', 'g');
  93. if (user != this.user) {
  94. return '<"' + user + '"' + (this.host ? ('@' + this.host) : '') + '>';
  95. }
  96. return '<' + this.address() + '>';
  97. }
  98. Address.prototype.address = function (set) {
  99. if (set) {
  100. this.parse(set);
  101. }
  102. return (this.user ? this.user : '') + (this.host ? ('@' + this.host) : '');
  103. }
  104. Address.prototype.toString = function () {
  105. return this.format();
  106. }
  107. exports.Address = Address;