public void SendMessage(int personID, int communicationID, string toNumber, string fromNumber, string fromName, string message, string userID) { PersonCommunication pc; TwilioRestClient twilio = new TwilioRestClient(_username, _password); LookupCollection validNumbers = new LookupCollection(new Guid("11B4ADEC-CB8C-4D01-B99E-7A0FFE2007B5")); Message msg; SmsHistory history; String twilioNumber = null; String callback; // // Check if this message has already been sent. The agent seems to be broken and // will send each SMS message twice in rapid succession. If the communication is // no longer pending or queued, assume it has already been sent and silently ignore. // if (personID != -1 && communicationID != -1) { pc = new PersonCommunication(personID, communicationID); if (pc.CommunicationID != -1) { if (pc.Status != "Pending" && pc.Status != "Queued") return; } } // // Get the first enabled twilio number, use that as the default. // foreach (Lookup lk in validNumbers) { if (lk.Active) { twilioNumber = CleanPhone(lk.Qualifier); break; } } // // Check if the fromNumber is a valid Twilio number, if it isn't then use the default Twilio Number. // fromNumber = CleanPhone(fromNumber); foreach (Lookup lk in validNumbers) { string cleaned = CleanPhone(lk.Qualifier); if (lk.Active && fromNumber == cleaned) { twilioNumber = cleaned; break; } } // // Verify that we have our default twilio number defined. // if (String.IsNullOrEmpty(twilioNumber)) { if (communicationID != -1 && personID != -1) new PersonCommunicationData().SavePersonCommunication(communicationID, personID, DateTime.Now, "Failed -- Invalid from number specified", ArenaContext.Current.Organization.OrganizationID); return; } // // If we don't have a valid outgoing number, fail. // toNumber = CleanPhone(toNumber); if (String.IsNullOrEmpty(toNumber)) { if (communicationID != -1 && personID != -1) new PersonCommunicationData().SavePersonCommunication(communicationID, personID, DateTime.Now, "Failed -- No SMS number available", ArenaContext.Current.Organization.OrganizationID); return; } // // Construct the callback URL. // callback = ArenaContext.Current.AppSettings["ApplicationURLPath"]; if (!callback.EndsWith("/")) callback = callback + "/"; callback = callback + "UserControls/Custom/HDC/Twilio/SmsStatus.aspx"; // // Update the person communication history to show that we have attempted to send, since this is an // asynchronous operation we don't want to chance the callback not working and the message gets // sent over and over again. // if (communicationID != -1 && personID != -1) { new PersonCommunicationData().SavePersonCommunication(communicationID, personID, DateTime.Now, "Pushed", ArenaContext.Current.Organization.OrganizationID); } // // Verify that the twilio object exists. // if (twilio == null) { new PersonCommunicationData().SavePersonCommunication(communicationID, personID, DateTime.Now, "Failed -- Could not initialize Twilio library.", ArenaContext.Current.Organization.OrganizationID); return; } // // Send the message. // msg = twilio.SendMessage(twilioNumber, toNumber, message, callback); if (personID != -1 && communicationID != -1) { if (msg == null) { new PersonCommunicationData().SavePersonCommunication(communicationID, personID, DateTime.Now, "Failed -- Could not contact Twilio API.", ArenaContext.Current.Organization.OrganizationID); return; } if (String.IsNullOrEmpty(msg.Sid)) { if (communicationID != -1 && personID != -1) { String reason; if (msg.RestException != null && !String.IsNullOrEmpty(msg.RestException.Message)) reason = String.Format("Failed -- SMS provider did not accept message ({0}).", msg.RestException.Message); else if (!String.IsNullOrEmpty(msg.Status)) reason = String.Format("Failed -- SMS provider did not accept message ({0}).", msg.Status); else reason = String.Format("Failed -- SMS provider did not accept message (Unknown Error)."); new PersonCommunicationData().SavePersonCommunication(communicationID, personID, DateTime.Now, reason, ArenaContext.Current.Organization.OrganizationID); } } else { history = new SmsHistory(); history.CommunicationId = communicationID; history.PersonId = personID; history.SmsSid = msg.Sid; history.Save(userID); } } }
protected void Page_Load(object sender, EventArgs e) { String smsSid = Request.Form["SmsSid"].ToString(); String status = Request.Form["SmsStatus"].ToString().ToLower(); SmsHistory history; // // Check if this is a received message. // if (status == "received") { OrganizationData orgData = new OrganizationData(); LookupCollection validNumbers = new LookupCollection(new Guid("11B4ADEC-CB8C-4D01-B99E-7A0FFE2007B5")); LookupCollection twilioHandlers = new LookupCollection(new Guid("FC1BA7E8-C22A-48CF-8A30-5DF640049373")); String body = Request.Form["Body"].ToString(); String from = Request.Form["From"].ToString(); String to = Request.Form["To"].ToString(); String baseUrl; StringBuilder sb = new StringBuilder(); List<String> possiblyFrom = new List<String>(); Boolean handled = false; PersonCollection col = new PersonCollection(); Lookup lkTo = null; // // Look for the twilio phone number, if not found ignore the incoming message. // to = TwilioSMS.CleanPhone(to); foreach (Lookup lk in validNumbers) { if (lk.Active && to == TwilioSMS.CleanPhone(lk.Qualifier)) { lkTo = lk; break; } } if (lkTo == null) return; // // Load all person records that match the phone number. // from = TwilioSMS.CleanPhone(from); if (from.StartsWith("1")) col.LoadByPhone(from.Substring(1)); else col.LoadByPhone(from); // // Build a list of ID numbers for the person IDs that this could be from. // foreach (Person p in col) { possiblyFrom.Add(p.PersonID.ToString()); } // // See if we can find a stored procedure that wants to handle this message. // try { foreach (Lookup handler in twilioHandlers) { ArrayList parms = new ArrayList(); SqlParameter outStatus = new SqlParameter("@OutStatus", SqlDbType.Int); SqlParameter outMessage = new SqlParameter("@OutMessage", SqlDbType.VarChar, 2000); if (handler.Active == false) continue; // // Check if this handler is for us. // if (Convert.ToInt32(handler.Qualifier) != lkTo.LookupID && lkTo.LookupID != -1) continue; // // Check if there is a match on the regular expression. // if (!Regex.IsMatch(body, handler.Qualifier2, RegexOptions.IgnoreCase)) continue; outStatus.Direction = ParameterDirection.Output; outMessage.Direction = ParameterDirection.Output; parms.Add(new SqlParameter("@FromNumber", from)); parms.Add(new SqlParameter("@PossiblyFrom", String.Join(",", possiblyFrom.ToArray()))); parms.Add(new SqlParameter("@ToNumber", to)); parms.Add(new SqlParameter("@ToNumberID", lkTo.LookupID)); parms.Add(new SqlParameter("@Message", body)); parms.Add(outStatus); parms.Add(outMessage); orgData.ExecuteNonQuery(handler.Qualifier3, parms); // // See if a response should be sent. // if ((int)outStatus.Value == 1) { if (!String.IsNullOrEmpty((String)outMessage.Value)) { int len = outMessage.Value.ToString().Length; if (len > 160) len = 160; Response.Clear(); Response.ContentType = "text/plain"; Response.Write(outMessage.Value.ToString().Substring(0, len)); // // Set the base url. // baseUrl = ArenaContext.Current.AppSettings["ApplicationURLPath"]; if (!baseUrl.EndsWith("/")) baseUrl = baseUrl + "/"; baseUrl = String.Format("{0}default.aspx?page={1}", baseUrl, personDetailPageId); // // If there is a valid e-mail address to forward the text to then build up an e-mail // message and send an e-mail. // if (!String.IsNullOrEmpty(handler.Qualifier4)) { try { sb.AppendFormat("<p>Received a text message from {0} to {1} ({2})</p>", from, to, lkTo.Value); sb.AppendFormat("<p>Message: {0}</p>", body); if (col.Count > 0) { sb.Append("<p>Possibly received from:<br /><ul>"); foreach (Person p in col) { sb.AppendFormat("<li><a href=\"{0}&guid={1}\">{2}</a></li>", baseUrl, p.PersonGUID.ToString(), Server.HtmlEncode(p.FullName)); } sb.Append("</ul></p>"); } ArenaSendMail.SendMail(String.Empty, String.Empty, handler.Qualifier4, "Received SMS message", sb.ToString()); } catch (System.Exception ex) { try { new Arena.DataLayer.Core.ExceptionHistoryData().AddUpdate_Exception(ex, ArenaContext.Current.Organization.OrganizationID, "HDC.Twilio", ArenaContext.Current.ServerUrl); } catch { } } } Response.End(); } handled = true; break; } } } catch (System.Exception ex) { if (ex.Message != "Thread was being aborted.") { new Arena.DataLayer.Core.ExceptionHistoryData().AddUpdate_Exception(ex, ArenaContext.Current.Organization.OrganizationID, "HDC.Twilio", ArenaContext.Current.ServerUrl); } } // // If the message has already been handled, we don't need to send any replies or // e-mail anybody. // if (!handled) { // // Set the base url. // baseUrl = ArenaContext.Current.AppSettings["ApplicationURLPath"]; if (!baseUrl.EndsWith("/")) baseUrl = baseUrl + "/"; baseUrl = String.Format("{0}default.aspx?page={1}", baseUrl, personDetailPageId); // // If there is a valid e-mail address to forward the text to then build up an e-mail // message and send an e-mail. // if (!String.IsNullOrEmpty(lkTo.Qualifier2)) { try { sb.AppendFormat("<p>Received a text message from {0} to {1} ({2})</p>", from, to, lkTo.Value); sb.AppendFormat("<p>Message: {0}</p>", body); if (col.Count > 0) { sb.Append("<p>Possibly received from:<br /><ul>"); foreach (Person p in col) { sb.AppendFormat("<li><a href=\"{0}&guid={1}\">{2}</a></li>", baseUrl, p.PersonGUID.ToString(), Server.HtmlEncode(p.FullName)); } sb.Append("</ul></p>"); } ArenaSendMail.SendMail(String.Empty, String.Empty, lkTo.Qualifier2, "Received SMS message", sb.ToString()); } catch (System.Exception ex) { try { new Arena.DataLayer.Core.ExceptionHistoryData().AddUpdate_Exception(ex, ArenaContext.Current.Organization.OrganizationID, "HDC.Twilio", ArenaContext.Current.ServerUrl); } catch { } } } // // If there is an auto-reply message in the lookup then send back that message. // if (!String.IsNullOrEmpty(lkTo.Qualifier8)) { try { int len = lkTo.Qualifier8.Length; if (len > 160) len = 160; Response.Clear(); Response.ContentType = "text/plain"; Response.Write(lkTo.Qualifier8.Substring(0, len)); Response.End(); } catch (System.Exception ex) { try { if (ex.Message != "Thread was being aborted.") { new Arena.DataLayer.Core.ExceptionHistoryData().AddUpdate_Exception(ex, ArenaContext.Current.Organization.OrganizationID, "HDC.Twilio", ArenaContext.Current.ServerUrl); } } catch { } } } } } else { // // This (should be) a status response to an outgoing message. // history = new SmsHistory(smsSid); if (history.SmsHistoryId != -1) { try { if (status == "sent") { new PersonCommunicationData().SavePersonCommunication(history.CommunicationId, history.PersonId, DateTime.Now, "Success"); } else { new PersonCommunicationData().SavePersonCommunication(history.CommunicationId, history.PersonId, DateTime.Now, "Failed"); } } catch (System.Exception) { } history.Delete(); } } }