diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..4367613 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Adam Blackburn +AJ ONeal diff --git a/README.md b/README.md index b539d63..4d32191 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,108 @@ +sms-address +==================== -### Basic Usage +(this project may be merged into the `sms-address` module) -sms-address returns an email address that can be used to send an SMS -message. +Performs a lookup of the mobile phone carrier company name to get the sms and mms gateway email addresses for that carrier. -It takes two arguments, phone number, and carrier. +You can use the SMS gateway address to send text messages from email. + +Usage +=== + +```bash +npm install sms-address +``` ```javascript -var sms = require('sms-address'); +'use strict'; + +var smsAddress = require('sms-address') + , email + ; + +email = smsAddress.sms('verizon', 5550002222); + +console.log(email); +// 5550002222@vtext.com +``` + +API +=== + + * `sms` - lookup sms domain or email + * `mms` - lookup mms domain or email + * `carrier` - reverse lookup carrier from sms, mms, or company name + * `lookup` - return an object with sms, mms, wireless, and carrier short name -var email = sms('123-456-7890', 'Verizon'); +### sms -email === '1234567890@vtext.com'; +Accepts any carrier name / company name string and an optional phone number +and returns the gateway domain or email to sms address or `null` + +```javascript +lookups.sms(carrierString); // gateway +lookups.sms(carrierString[, phone]); // phone@gateway +``` + +```javascript +lookups.sms('Cellco DBA Verizon Wireless'); // "vtext.com" +lookups.sms('T-Mobile', '+15550002222'); // "5550002222@tmomail.net" +lookups.sms('att', '+15550002222'); // "5550002222@txt.att.net" ``` -sms-address also exports the carriers it supports. US only for now. +### mms + +Accepts any carrier name / company name string and an optional phone number +and returns the gateway domain or email to mms address or `null` + +```javascript +lookups.mms(carrierString); // gateway +lookups.mms(carrierString[, phone]); // phone@gateway +``` ```javascript -var sms = require('sms-address'); +lookups.mms('AT&T Mobility'); // "mms.att.net" +lookups.mms('Sprint', '+15550002222'); // "5550002222@pm.sprint.com" +lookups.mms('tmobile', '+15550002222'); // "5550002222@tmomail.net" +``` + +### carrier + +Accepts an sms or mms gateway domain or email address, or a carrier string +and returns the simple carrier string or `null` + +```javascript +lookups.carrier(smsMmsOrCarrierString); // programmer-friendly carrier name +``` + +```javascript +lookups.sms('AT&T Mobility'); // "att" +lookups.sms('messaging.sprintpcs.com'); // "sprint" +lookups.carrier('5550002222@vzwpix.com'); // "verizon" +``` + +### lookup + +```javascript +lookups.lookup(carrierStr[, phone, object]); +``` + +```javascript +lookups.lookup("Verizon"); + +{ carrier: 'verizon' +, smsGateway: 'vtext.com' +, mmsGateway: 'vzwpix.com' +} + -console.log(sms.carriers) +lookups.lookup("Verizon Wireless", '5550002222', { foo: "bar" }); -// outputs: -{ - "Alaska Communications": "msg.acsalaska.com", - "Alltel": "sms.alltelwireless.com", - "Ameritech": "paging.acswireless.com", - "AT&T": "txt.att.net", - "BellSouth": "bellsouth.cl", - "Bluegrass Cellular": "sms.bluecell.com", - // and so on and so forth ... +{ foo: 'bar' +, wireless: true +, carrier: 'verizon' +, smsAddress: '5550002222@vtext.com +, mmsAddress: '5550002222@vzwpix.com +} ``` diff --git a/carriers.json b/carriers-original.json similarity index 100% rename from carriers.json rename to carriers-original.json diff --git a/carriers/historic.js b/carriers/historic.js new file mode 100644 index 0000000..ff80402 --- /dev/null +++ b/carriers/historic.js @@ -0,0 +1,168 @@ +'use strict'; +// HISTORIC +// this is a compiled list of known carriers that have not yet +// yet been seen in the wild. It is believed that they are +// bought out and deprecated (such as Alltel and Cingular), but since many +// numbers are still listed under their original carrier in many +// public records and some of their gateways still function, they +// are useful nonetheless. + +// ALPHABETIC +// When editing this file, please maintain alphabetic order +module.exports = [ + { "name": 'alltel' + , "carrier": "Alltel" + , "sms": 'text.wireless.alltel.com' + , "wireless": true + } + // listed a second time for reverse lookup by the alternate sms address +, { "name": 'alltel' + , "carrier": "Alltel" + , "sms": 'message.alltel.com' + , "wireless": true + } +, { "name": 'alltel' + , "carrier": "Alltel" + , "sms": "sms.alltelwireless.com" + } +, { "name": "ameritech" + , "carrier": "Ameritech" + , "sms": "paging.acswireless.com" + } +, { "name": "bellsouth" + , "carrier": "BellSouth" + , "sms": "bellsouth.cl" + } +, { "name": "bluegrass" + , "carrier": "Bluegrass Cellular" + , "sms": "sms.bluecell.com" + } +, { "name": "cspire" + , "carrier": "C Spire Wireless" + , "sms": "cspire1.com" + } +, { "name": "cellcom" + , "carrier": "Cellcom" + , "sms": "cellcom.quiktxt.com" + } +, { "name": "cellularone" + , "carrier": "Cellular One" + , "sms": "mobile.celloneusa.com" + } +, { "name": "cellularsouth" + , "carrier": "Cellular South" + , "sms": "csouth1.com" + } +, { "name": 'cingular' + , "sms": 'cingularme.com' + , "wireless": true + } +, { "name": "charitonvalley" + , "carrier": "Chariton Valley Wireless" + , "sms": "sms.cvalley.net" + } +, { "name": "cleartalk" + , "carrier": "Cleartalk" + , "sms": "sms.cleartalk.us" + } +, { "name": "edge" + , "carrier": "Edge Wireless" + , "sms": "sms.edgewireless.com" + } +, { "name": "element" + , "carrier": "Element Mobile" + , "sms": "SMS.elementmobile.net" + } +, { "name": "esendex" + , "carrier": "Esendex" + , "sms": "echoemail.net" + } +, { "name": "googlevoice" + , "carrier": "Google Voice" + // valid only for receiving, not for sending + , "sms": "txt.voice.google.com" + , "test": function (string) { + // allow googlevoice or gvoice or google voice + var re = /\b(g(oogle)?\s*voice)\b/i + ; + + return re.test(string); + } + } +, { "name": 'gophone' + , "sms": 'cingularme.com' + , "wireless": true + } +, { "name": 'gophone' + , "carrier": "Cingular (GoPhone prepaid)" + , "sms": "cingulartext.com" + } +, { "name": "kajeet" + , "carrier": "Kajeet" + , "sms": "mobile.kajeet.net" + } +, { "name": "longlines" + , "carrier": "LongLines" + , "sms": "text.longlines.com" + } +, { "name": "metropcs" + , "carrier": "MetroPCS" + , "sms": "mymetropcs.com" + } +, { "name": 'nextel' + , "carrier": "Nextel" + , "sms": "messaging.nextel.com" + , "wireless": true + } +, { "name": "o2" + , "carrier": "O2" + , "sms": "mobile.celloneusa.com" + } +, { "name": "orange" + , "carrier": "Orange" + , "sms": "mobile.celloneusa.com" + } +, { "name": "pioneer" + , "carrier": "Pioneer Cellular" + , "sms": "zsend.com" + } +, { "name": 'powertel' + , "sms": 'ptel.net' + } +, { "name": "qwest" + // duplicated for second name as Qwest Wireless + , "carrier": "Qwest Wireless" + , "sms": "qwestmp.com" + } +, { "name": "redpocket" + , "carrier": "Red Pocket Mobile" + , "sms": "txt.att.net" + } +, { "name": "simple" + , "carrier": "Simple Mobile" + , "sms": "smtext.com" + } +, { "name": "southcentral" + , "carrier": "South Central Communications" + , "sms": "rinasms.com" + } +, { "name": "straighttalk" + , "carrier": "Straight Talk" + , "sms": "vtext.com" + } +, { "name": 'suncom' + , "sms": 'tms.suncom.com' + } +, { "name": "teleflip" + , "carrier": "Teleflip" + , "sms": "teleflip.com" + } +, { "name": "unicel" + , "carrier": "Unicel" + , "sms": "utext.com" + } +, { "name": "usamobility" + , "carrier": "USA Mobility" + , "sms": "usamobility.net" + } +]; diff --git a/carriers/in-the-wild.js b/carriers/in-the-wild.js new file mode 100644 index 0000000..f364325 --- /dev/null +++ b/carriers/in-the-wild.js @@ -0,0 +1,144 @@ +'use strict'; +// IN THE WILD +// these carriers have been discovered through actual lookups on real numbers + +// ALPHABETIC ORDER +// When editing this file, please maintain alphabetic order + +// WIRELESS vs LANDLINE +// Note that most of the time there are two separate companies +// for cell and landline coverage. The cell companies are usually +// postfixed with Wireless, Mobile, Mobility, PCS, or Cellular + +// EXAMPLE +/* + { "name": "boost" // programmer-friendly name + , "carrier": "Boost" // print-friendly name + , "wireless": true // cellular only (true), landline only (false), or null / function to test + , "sms": "myboostmobile.com" // sms gateway + , "mms": "myboostmobile.com" // mms gateway + , "updated": 1393227602319 // last time this was found in the wild + } +*/ + +module.exports = [ + { "name": "alaska" + , "carrier": "Alaska" + , "wireless": true + , "sms": "sms.alaska-wireless.com" + , "mms": "msg.acsalaska.net" + , "updated": 1393227602319 + } +, { "name": 'att' + , "carrier": "AT&T Mobility" + // the default wireles function will test for carrier the strings + // Wireless / Mobility / PCS, etc to determine whether AT&T or Cingular + , "wireless": null + , "sms": "txt.att.net" + , "mms": "mms.att.net" + , "test": function test(string) { + var re = /\b(AT\s*&?\s*T|cingular)\b/i + ; + + return re.test(string); + } + , "updated": 1393227602319 + } +, { "name": "boost" + , "carrier": "Boost" + , "wireless": true + , "sms": "myboostmobile.com" + , "mms": "myboostmobile.com" + , "updated": 1393227602319 + } +, { "name": "cricket" + , "carrier": "Cricket" + , "wireless": true + , "sms": "sms.mycricket.com" + , "mms": "mms.mycricket.com" + , "updated": 1393227602319 + } +, { "name": "qwest" + , "carrier": "Qwest Corporation" + // might be voip? or mislabled? + , "wireless": false + , "sms": "qwestmp.com" + , "updated": 1393227602319 + } +, { "name": "sprint" + , "carrier": "Sprint" + , "wireless": true + , "sms": "messaging.sprintpcs.com" + , "mms": "pm.sprint.com" + , "updated": 1393227602319 + } +, { "name": "syringa" + , "carrier": "Syringa Wireless" + , "wireless": true + , "sms": "rinasms.com" + , "updated": 1393227602319 + } +, { "name": "tmobile" + , "carrier": "T-Mobile" + , "wireless": true + , "sms": "tmomail.net" + , "mms": "tmomail.net" + , "test": function (string) { + // being careful not to match boos*tmobile* + var re = /\bt-?mobile\b/i + ; + + return re.test(string); + } + , "updated": 1393227602319 + } +, { "name": "metropcs" + , "carrier": "T-Mobile_MetroPCS" + , "wireless": true + // was "mymetropcs.com" but is now T-Mobile + , "sms": "tmomail.net" + , "mms": "tmomail.net" + , "updated": 1393227602319 + } +, { "name": "uscellular" + , "carrier": "US Cellular" + , "wireless": true + , "sms": "email.uscc.net" + , "mms": "mms.uscc.net" + , "test": function (string) { + var re = /\b((u\.?s\.?\s*cellular)|(united\s*states\s*cellular))\b/i + ; + + return re.test(string); + } + , "updated": 1393227602319 + } +, { "name": "verizon" + , "carrier": "Verizon Wireless" + , "wireless": null + , "sms": "vtext.com" + , "mms": "vzwpix.com" + , "updated": 1393227602319 + } +, { "name": "viaero" + , "carrier": "Viaero Wireless" + , "wireless": true + , "sms": "viaerosms.com" + , "mms": "mmsviaero.com" + , "updated": 1393227602319 + } +, { "name": "virgin" + , "carrier": "Virgin Mobile" + , "wireless": true + , "sms": "vmobl.com" + , "mms": "vmpix.com" + , "updated": 1393227602319 + } +, { "name": "wind" + , "carrier": "Wind Telecom" + , "wireless": true + , "sms": "txt.windmobile.ca" + , "mms": "mms.windmobile.ca" + , "updated": 1393227602319 + } +]; diff --git a/carriers/index.js b/carriers/index.js new file mode 100644 index 0000000..e012acb --- /dev/null +++ b/carriers/index.js @@ -0,0 +1,227 @@ +'use strict'; + +var carriers + , carriersSms = {} + ; + +carriers = require('./in-the-wild').concat(require('./historic')); +carriers.forEach(function (c) { + carriersSms[c.name] = c.sms; +}); + +function formatNum(num) { + num = String(num).replace(/\D/g, '').replace(/^\+?1/, ''); + if (!/^\d{10}/.test(num)) { + return null; + } + return num; +} + +function lookupByComment(comment) { + var name + ; + + if (!comment) { + return; + } + + carriers.some(function (carrier) { + if (new RegExp(carrier.name, 'i').test(comment.replace(/\W/, ''))) { + name = carrier.name; + return true; + } + }); + + return name; +} + +function lookupBySms(gateway) { + var name + ; + + if (!gateway) { + return; + } + + carriers.some(function (carrier) { + if (carrier.sms) { + if (new RegExp(carrier.sms, 'i').test(gateway)) { + name = carrier.name; + return true; + } + } + }); + + return name; +} + +function lookupByMms(gateway) { + var name + ; + + if (!gateway) { + return; + } + + carriers.some(function (carrier) { + if (carrier.mms) { + if (new RegExp(carrier.mms, 'i').test(gateway)) { + name = carrier.name; + return true; + } + } + }); + + return name; +} + +function createTestCarrier(carrierName) { + function testCarrier(string) { + var re = new RegExp(carrierName, 'i') + ; + + return re.test((string||'').replace(/[\W\-]+/g, '')); + } + + return testCarrier; +} + +function lookup(type, number, map) { + map = map || {}; + var ctype = (type||'').replace(/-/, '').replace(/\s+/g, ' ') + ; + + carriers.some(function (carrier) { + var testWireless + ; + + function isWireless(string) { + if (/wireless|pcs|cellular/i.test(string)) { + return true; + } + } + + if ((carrier.test||createTestCarrier(carrier.name))(ctype)) { + if (true === typeof carrier.wireless) { + map.wireless = true; + } else { + if ('function' === typeof carrier.wireless) { + testWireless = carrier.wireless; + } else { + testWireless = isWireless; + } + if (testWireless(ctype)) { + map.wireless = true; + } + } + + map.carrier = carrier.name; + if (carrier.sms) { + if (number) { + map.smsAddress = formatNum(number) + '@' + carrier.sms; + } else { + map.smsGateway = carrier.sms; + } + } + if (carrier.mms) { + if (number) { + map.mmsAddress = formatNum(number) + '@' + carrier.mms; + } else { + map.mmsGateway = carrier.mms; + } + } + + return true; + } + }); + + return map; +} + +function lookupSms(str) { + var sms + ; + + carriers.some(function (carrier) { + var test = carrier.test || createTestCarrier(carrier.name) + ; + + if (test(str)) { + sms = carrier.sms || null; + return sms; + } + }); + + return sms; +} + +function lookupMms(str) { + var mms + ; + + carriers.some(function (carrier) { + var test = carrier.test || createTestCarrier(carrier.name) + ; + + if (test(str)) { + mms = carrier.mms || null; + return mms; + } + }); + + return mms; +} + +function phoneToEmail(number, carrier) { + return module.exports.sms(carrier, number); +} + +function lookupCarrierName(str) { + str = (str || '').replace(/.*@/, ''); + + return (lookupBySms(str) || lookupByMms(str) || lookupByComment(str) || null); +} + +function lookupSmsAddress(carrierString, num) { + num = formatNum(num); + var sms = lookupSms(carrierString) + ; + + if (sms) { + if (num) { + return num + '@' + sms; + } + return sms; + } + return null; +} + +function lookupMmsAddress(carrierString, num) { + num = formatNum(num); + var mms = lookupMms(carrierString) + ; + + if (mms) { + if (num) { + return num + '@' + mms; + } + return mms; + } + return null; +} + +module.exports = phoneToEmail; +module.exports.carriers = carriersSms; +module.exports.gateways = carriers; + +module.exports.sms = lookupSmsAddress; +module.exports.mms = lookupMmsAddress; +module.exports.carrier = lookupCarrierName; +module.exports.lookup = lookup; +module.exports.carrierBySms = lookupBySms; +module.exports.carrierByMms = lookupBySms; +module.exports.carrierByComment = lookupByComment; + +// Deprecated +module.exports.lookupBySmsGateway = lookupBySms; +module.exports.lookupByComment = lookupByComment; diff --git a/package.json b/package.json index cf0e22c..b8b40a3 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,22 @@ { "name": "sms-address", - "description": "Get the email address to send SMS messages to based on number and carrier.", - "author": "Adam Blackburn ", - "version": "0.0.2", - "main": "sms.js", - "keywords": ["sms", "email", "phone"], + "description": "Lookup the email address to send text messages to (sms and mms gateway addreses) by carrier or company name", + "version": "1.0.0", + "main": "carriers/index", + "keywords": [ + "sms", + "mms", + "text", + "gateway", + "email", + "reverse", + "lookup", + "carrier", + "cell", + "tel", + "phone", + "call" + ], "repository": "git://github.com/regality/sms-address.git", "homepage": "https://github.com/regality/sms-address" } diff --git a/sms.js b/sms.js deleted file mode 100644 index ce5ea2a..0000000 --- a/sms.js +++ /dev/null @@ -1,15 +0,0 @@ -var carriers = require('./carriers.json'); - -function phoneToEmail(number, carrier) { - number = number.replace(/[^\d]/g, ''); - var domain = carriers[carrier]; - if (domain) { - return number + "@" + domain; - } else { - return null; - } -} - -phoneToEmail.carriers = carriers; - -module.exports = phoneToEmail; diff --git a/test-original.js b/test-original.js new file mode 100644 index 0000000..050d9cc --- /dev/null +++ b/test-original.js @@ -0,0 +1,20 @@ +'use strict'; + +var carriersL = require('./carriers-original') + , maps = [] + , carriers = require('./carriers') + ; + +Object.keys(carriersL).forEach(function (k) { + var sms = carriersL[k] + ; + + if (carriers.sms(k) !== sms) { + console.log('[MISMATCH]', k, sms, carriers.sms(k)); + } + + maps.push({ + carrier: k + , sms: sms + }); +}); diff --git a/test.js b/test.js new file mode 100644 index 0000000..0daff6f --- /dev/null +++ b/test.js @@ -0,0 +1,79 @@ +'use strict'; + +var carriers = require('./') + ; + +// SMS LOOKUP (old API) + +if ('5550002222@vtext.com' !== carriers(5550002222, 'Verizon Wireless')) { + throw new Error('carrier num@vtext fail'); +} + +// +// GATEWAY LOOKUP +// + +if ('vtext.com' !== carriers.sms('Verizon Wireless')) { + throw new Error('vtext fail'); +} + +if ('5550002222@vtext.com' !== carriers.sms('Verizon Wireless', 5550002222)) { + throw new Error('num@vtext fail'); +} + +if ('vzwpix.com' !== carriers.mms('Verizon Wireless')) { + throw new Error('vzwpix fail'); +} + +if ('5550002222@vzwpix.com' !== carriers.mms('Verizon Wireless', 5550002222)) { + throw new Error('num@vzwpix fail'); +} + +if (null !== carriers.mms('Foobar', 5550002222)) { + throw new Error('null fail'); +} + +// +// CARRIER LOOKUP +// + +if ('verizon' !== carriers.carrier('CELLCO Network DBA Verizon Wireless - UT')) { + console.log('carrier lookup:', carriers.carrier('CELLCO Network DBA Verizon Wireless - UT')); + throw new Error('comment fail'); +} + +if ('verizon' !== carriers.carrier('Verizon Wireless')) { + throw new Error('company fail'); +} + +if ('verizon' !== carriers.carrier('verizon')) { + throw new Error('name fail'); +} + +if ('verizon' !== carriers.carrier('vtext.com')) { + throw new Error('vtext fail'); +} + +if ('verizon' !== carriers.carrier('5550002222@vtext.com')) { + throw new Error('num@vtext fail'); +} + +if ('verizon' !== carriers.carrier('vzwpix.com')) { + throw new Error('vzwpix fail'); +} + +if ('verizon' !== carriers.carrier('5550002222@vzwpix.com')) { + throw new Error('num@vzwpix fail'); +} + +if (null !== carriers.carrier('Foobar')) { + throw new Error('2 null fail'); +} + +// +// LOOKUP ALL +// + +console.log(carriers.lookup('Verizon Wireless', 5550002222, { heya: 'blah' })); +console.log(carriers.lookup('Verizon')); +//console.log(carriers.carriers);