PageRenderTime 43ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/sipsorcery-core/SIPSorcery.AppServer.DialPlan/DialPlanApps/GoogleVoiceSMS.cs

https://github.com/thecc4re/sipsorcery-mono
C# | 238 lines | 175 code | 22 blank | 41 comment | 11 complexity | ce7841d000a682742365b0749a899bd9 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //-----------------------------------------------------------------------------
  2. // Filename: GoogleVoiceSMS.cs
  3. //
  4. // Description: A dial plan command that places HTTP request to initiate an SMS
  5. // through the Google Voice service.
  6. //
  7. // History:
  8. // 26 Aug 2010 Aaron Clauson Created.
  9. //
  10. // License:
  11. // This software is licensed under the BSD License http://www.opensource.org/licenses/bsd-license.php
  12. //
  13. // Copyright (c) 2010 Aaron Clauson (aaron@sipsorcery.com), SIP Sorcery Ltd, Hobart, Tasmania, Australia
  14. // All rights reserved.
  15. //
  16. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that
  17. // the following conditions are met:
  18. //
  19. // Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  20. // Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
  21. // disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of SIP Sorcery Ltd.
  22. // nor the names of its contributors may be used to endorse or promote products derived from this software without specific
  23. // prior written permission.
  24. //
  25. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
  26. // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  27. // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  28. // OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  29. // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  30. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  31. // POSSIBILITY OF SUCH DAMAGE.
  32. //-----------------------------------------------------------------------------
  33. using System;
  34. using System.Collections.Generic;
  35. using System.IO;
  36. using System.Linq;
  37. using System.Net;
  38. using System.Security;
  39. using System.Text;
  40. using System.Text.RegularExpressions;
  41. using System.Threading;
  42. using System.Web;
  43. using SIPSorcery.SIP;
  44. using SIPSorcery.SIP.App;
  45. using SIPSorcery.Sys;
  46. using log4net;
  47. namespace SIPSorcery.AppServer.DialPlan
  48. {
  49. public class GoogleVoiceSMS
  50. {
  51. private const string PRE_LOGIN_URL = "https://www.google.com/accounts/ServiceLogin";
  52. private const string LOGIN_URL = "https://www.google.com/accounts/ServiceLoginAuth?service=grandcentral";
  53. private const string VOICE_HOME_URL = "https://www.google.com/voice";
  54. private const string SMS_SEND_URL = "https://www.google.com/voice/sms/send";
  55. private const int HTTP_REQUEST_TIMEOUT = 5;
  56. private static ILog logger = AppState.logger;
  57. private SIPMonitorLogDelegate Log_External;
  58. private string m_username;
  59. private string m_adminMemberId;
  60. private string m_destinationNumber;
  61. private CookieContainer m_cookies;
  62. private string m_rnrKey;
  63. public GoogleVoiceSMS(
  64. SIPMonitorLogDelegate logDelegate,
  65. string username,
  66. string adminMemberId)
  67. {
  68. Log_External = logDelegate;
  69. m_username = username;
  70. m_adminMemberId = adminMemberId;
  71. }
  72. public void SendSMS(string emailAddress, string password, string destinationNumber, string message)
  73. {
  74. try
  75. {
  76. m_destinationNumber = destinationNumber;
  77. m_cookies = new CookieContainer();
  78. m_rnrKey = Login(emailAddress, password);
  79. if (!m_rnrKey.IsNullOrBlank())
  80. {
  81. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call key " + m_rnrKey + " successfully retrieved for " + emailAddress + ", proceeding with SMS.", m_username));
  82. SendSMS(destinationNumber, message);
  83. }
  84. else
  85. {
  86. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call key was not retrieved for " + emailAddress + " SMS cannot proceed.", m_username));
  87. }
  88. }
  89. catch (Exception excp)
  90. {
  91. logger.Error("Exception GoogleVoiceSMS SendSMS. " + excp.Message);
  92. throw;
  93. }
  94. }
  95. private string Login(string emailAddress, string password)
  96. {
  97. try
  98. {
  99. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Logging into google.com for " + emailAddress + ".", m_username));
  100. // Fetch GALX
  101. HttpWebRequest galxRequest = (HttpWebRequest)WebRequest.Create(PRE_LOGIN_URL);
  102. galxRequest.ConnectionGroupName = "prelogin";
  103. galxRequest.CookieContainer = m_cookies;
  104. HttpWebResponse galxResponse = (HttpWebResponse)galxRequest.GetResponse();
  105. if (galxResponse.StatusCode != HttpStatusCode.OK)
  106. {
  107. galxResponse.Close();
  108. throw new ApplicationException("Load of the Google Voice pre-login page failed with response " + galxResponse.StatusCode + ".");
  109. }
  110. else
  111. {
  112. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Google Voice pre-login page loaded successfully.", m_username));
  113. }
  114. StreamReader galxReader = new StreamReader(galxResponse.GetResponseStream());
  115. string galxResponseFromServer = galxReader.ReadToEnd();
  116. galxResponse.Close();
  117. Match galxMatch = Regex.Match(galxResponseFromServer, @"name=""GALX""\s+?value=""(?<galxvalue>.*?)""");
  118. if (galxMatch.Success)
  119. {
  120. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "GALX key " + galxMatch.Result("${galxvalue}") + " successfully retrieved.", m_username));
  121. }
  122. else
  123. {
  124. throw new ApplicationException("Could not find GALX key on your Google Voice pre-login page, SMS cannot proceed.");
  125. }
  126. // Build login request.
  127. string loginData = "Email=" + Uri.EscapeDataString(emailAddress) + "&Passwd=" + Uri.EscapeDataString(password) + "&GALX=" + Uri.EscapeDataString(galxMatch.Result("${galxvalue}"));
  128. HttpWebRequest loginRequest = (HttpWebRequest)WebRequest.Create(LOGIN_URL);
  129. loginRequest.CookieContainer = m_cookies;
  130. loginRequest.ConnectionGroupName = "login";
  131. loginRequest.AllowAutoRedirect = true;
  132. loginRequest.Method = "POST";
  133. loginRequest.ContentType = "application/x-www-form-urlencoded;charset=utf-8";
  134. loginRequest.ContentLength = loginData.Length;
  135. loginRequest.GetRequestStream().Write(Encoding.UTF8.GetBytes(loginData), 0, loginData.Length);
  136. loginRequest.Timeout = HTTP_REQUEST_TIMEOUT * 1000;
  137. // Send login request and read response stream.
  138. HttpWebResponse response = (HttpWebResponse)loginRequest.GetResponse();
  139. if (response.StatusCode != HttpStatusCode.OK)
  140. {
  141. response.Close();
  142. throw new ApplicationException("Login to google.com failed for " + emailAddress + " with response " + response.StatusCode + ".");
  143. }
  144. response.Close();
  145. // We're now logged in. Need to load up the Google Voice page to get the rnr hidden input value which is needed for
  146. // the HTTP call requests.
  147. HttpWebRequest rnrRequest = (HttpWebRequest)WebRequest.Create(VOICE_HOME_URL);
  148. rnrRequest.ConnectionGroupName = "call";
  149. rnrRequest.CookieContainer = m_cookies;
  150. // Send the Google Voice account page request and read response stream.
  151. response = (HttpWebResponse)rnrRequest.GetResponse();
  152. if (response.StatusCode != HttpStatusCode.OK)
  153. {
  154. response.Close();
  155. throw new ApplicationException("Load of the Google Voice account page failed for " + emailAddress + " with response " + response.StatusCode + ".");
  156. }
  157. else
  158. {
  159. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Google Voice home page loaded successfully.", m_username));
  160. }
  161. StreamReader reader = new StreamReader(response.GetResponseStream());
  162. string responseFromServer = reader.ReadToEnd();
  163. response.Close();
  164. // Extract the rnr field from the HTML.
  165. Match rnrMatch = Regex.Match(responseFromServer, @"name=""_rnr_se"".*?value=""(?<rnrvalue>.*?)""");
  166. if (rnrMatch.Success)
  167. {
  168. return rnrMatch.Result("${rnrvalue}");
  169. }
  170. else
  171. {
  172. throw new ApplicationException("Could not find _rnr_se key on your Google Voice account page, SMS cannot proceed.");
  173. }
  174. }
  175. catch (Exception excp)
  176. {
  177. logger.Error("Exception GoogleVoiceSMS Login. " + excp.Message);
  178. throw;
  179. }
  180. }
  181. private void SendSMS(string destinationNumber, string message)
  182. {
  183. try
  184. {
  185. string callData = "phoneNumber=" + Uri.EscapeDataString(destinationNumber) + "&text=" + Uri.EscapeDataString(message) +
  186. "&_rnr_se=" + Uri.EscapeDataString(m_rnrKey);
  187. //logger.Debug("call data=" + callData + ".");
  188. // Build the call request.
  189. HttpWebRequest callRequest = (HttpWebRequest)WebRequest.Create(SMS_SEND_URL);
  190. callRequest.ConnectionGroupName = "call";
  191. callRequest.CookieContainer = m_cookies;
  192. callRequest.Method = "POST";
  193. callRequest.ContentType = "application/x-www-form-urlencoded;charset=utf-8";
  194. callRequest.ContentLength = callData.Length;
  195. callRequest.GetRequestStream().Write(Encoding.UTF8.GetBytes(callData), 0, callData.Length);
  196. callRequest.Timeout = HTTP_REQUEST_TIMEOUT * 1000;
  197. HttpWebResponse response = (HttpWebResponse)callRequest.GetResponse();
  198. HttpStatusCode responseStatus = response.StatusCode;
  199. response.Close();
  200. if (responseStatus != HttpStatusCode.OK)
  201. {
  202. throw new ApplicationException("The SMS request failed with a " + responseStatus + " response.");
  203. }
  204. else
  205. {
  206. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Google Voice SMS to " + destinationNumber + " successfully sent.", m_username));
  207. }
  208. }
  209. catch (Exception excp)
  210. {
  211. logger.Error("Exception GoogleVoiceSMS SendSMS. " + excp.Message);
  212. throw;
  213. }
  214. }
  215. }
  216. }