From ca0dc864034a9b18e571b11048b6c541f12770ba Mon Sep 17 00:00:00 2001 From: johnsheehan Date: Fri, 15 Jul 2011 12:06:05 -0700 Subject: [PATCH] new .NET helper library 3.0 --- .gitignore | 32 + LICENSE.txt | 67 + README.md | 55 + Twilio.Mvc.nuspec | 16 + Twilio.TwiML.nuspec | 16 + Twilio.WebMatrix.nuspec | 16 + Twilio.nuspec | 16 + package.cmd | 48 + src/Index.dat | Bin 0 -> 28 bytes src/Local.testsettings | 10 + src/Storage.dat | Bin 0 -> 512 bytes src/TraceAndTestImpact.testsettings | 19 + src/Twilio.Api.Silverlight/Accounts.Async.cs | 97 + .../Applications.Async.cs | 156 + .../AvailablePhoneNumbers.Aysnc.cs | 96 + src/Twilio.Api.Silverlight/Calls.Async.cs | 211 + .../Conference.Async.cs | 189 + src/Twilio.Api.Silverlight/Core.Async.cs | 57 + .../IncomingPhoneNumbers.Async.cs | 166 + .../Notifications.Aysnc.cs | 88 + .../OutgoingCallerIds.Async.cs | 134 + .../Properties/AssemblyInfo.cs | 10 + .../Recordings.Async.cs | 102 + src/Twilio.Api.Silverlight/Sandbox.Async.cs | 60 + src/Twilio.Api.Silverlight/Sms.Async.cs | 175 + .../Transcriptions.Async.cs | 99 + .../Twilio.Api.Silverlight.csproj | 224 + src/Twilio.Api.Silverlight/packages.config | 5 + .../Properties/AssemblyInfo.cs | 10 + .../Twilio.Api.WindowsPhone.csproj | 232 + src/Twilio.Api.WindowsPhone/packages.config | 5 + src/Twilio.Api/Accounts.cs | 91 + src/Twilio.Api/Applications.cs | 151 + src/Twilio.Api/AvailablePhoneNumbers.cs | 77 + src/Twilio.Api/Calls.cs | 158 + src/Twilio.Api/Conference.cs | 168 + src/Twilio.Api/Core.cs | 100 + src/Twilio.Api/IncomingPhoneNumbers.cs | 131 + src/Twilio.Api/Model/Account.cs | 62 + src/Twilio.Api/Model/Application.cs | 95 + src/Twilio.Api/Model/ApplicationOptions.cs | 69 + src/Twilio.Api/Model/ApplicationResult.cs | 30 + src/Twilio.Api/Model/AvailablePhoneNumber.cs | 62 + .../Model/AvailablePhoneNumberListRequest.cs | 62 + .../Model/AvailablePhoneNumberResult.cs | 30 + src/Twilio.Api/Model/Call.cs | 95 + src/Twilio.Api/Model/CallListRequest.cs | 67 + src/Twilio.Api/Model/CallOptions.cs | 73 + src/Twilio.Api/Model/CallResult.cs | 30 + src/Twilio.Api/Model/ComparisonType.cs | 37 + src/Twilio.Api/Model/Conference.cs | 51 + src/Twilio.Api/Model/ConferenceListRequest.cs | 59 + src/Twilio.Api/Model/ConferenceResult.cs | 30 + src/Twilio.Api/Model/DeleteStatus.cs | 13 + src/Twilio.Api/Model/HangupStyle.cs | 18 + src/Twilio.Api/Model/IncomingPhoneNumber.cs | 99 + .../Model/IncomingPhoneNumberResult.cs | 30 + src/Twilio.Api/Model/Notification.cs | 99 + src/Twilio.Api/Model/NotificationResult.cs | 30 + src/Twilio.Api/Model/OutgoingCallerId.cs | 51 + .../Model/OutgoingCallerIdResult.cs | 30 + src/Twilio.Api/Model/Participant.cs | 59 + src/Twilio.Api/Model/ParticipantResult.cs | 30 + src/Twilio.Api/Model/PhoneNumberOptions.cs | 93 + src/Twilio.Api/Model/Recording.cs | 55 + src/Twilio.Api/Model/RecordingResult.cs | 30 + src/Twilio.Api/Model/RestException.cs | 41 + src/Twilio.Api/Model/Sandbox.cs | 63 + src/Twilio.Api/Model/SmsMessage.cs | 75 + src/Twilio.Api/Model/SmsMessageResult.cs | 30 + src/Twilio.Api/Model/SmsShortCode.cs | 58 + src/Twilio.Api/Model/SmsShortCodeResult.cs | 30 + src/Twilio.Api/Model/Transcription.cs | 63 + src/Twilio.Api/Model/TranscriptionResult.cs | 30 + src/Twilio.Api/Model/TwilioBase.cs | 34 + src/Twilio.Api/Model/TwilioListBase.cs | 73 + src/Twilio.Api/Model/ValidationRequest.cs | 41 + src/Twilio.Api/Notifications.cs | 89 + src/Twilio.Api/OutgoingCallerIds.cs | 137 + src/Twilio.Api/Properties/AssemblyInfo.cs | 9 + src/Twilio.Api/Recordings.cs | 105 + src/Twilio.Api/Sandbox.cs | 60 + src/Twilio.Api/SharedAssemblyInfo.cs | 14 + src/Twilio.Api/Sms.cs | 174 + src/Twilio.Api/Transcriptions.cs | 100 + src/Twilio.Api/Twilio.Api.csproj | 171 + src/Twilio.Api/packages.config | 5 + src/Twilio.Mvc/Properties/AssemblyInfo.cs | 10 + src/Twilio.Mvc/TwiMLResult.cs | 48 + src/Twilio.Mvc/Twilio.Mvc.csproj | 70 + src/Twilio.Mvc/TwilioController.cs | 16 + src/Twilio.Mvc/ValidateRequestAttribute.cs | 44 + src/Twilio.Twiml.Tests/DialTests.cs | 121 + .../DocExamples/Sms/Redirect.cs | 26 + src/Twilio.Twiml.Tests/DocExamples/Sms/Sms.cs | 35 + .../DocExamples/Voice/Conference.cs | 78 + .../DocExamples/Voice/Dial.cs | 28 + .../DocExamples/Voice/Gather.cs | 43 + .../DocExamples/Voice/Hangup.cs | 17 + .../DocExamples/Voice/Number.cs | 26 + .../DocExamples/Voice/Pause.cs | 29 + .../DocExamples/Voice/Play.cs | 17 + .../DocExamples/Voice/Record.cs | 36 + .../DocExamples/Voice/Redirect.cs | 27 + .../DocExamples/Voice/Reject.cs | 26 + .../DocExamples/Voice/Say.cs | 26 + .../DocExamples/Voice/Sms.cs | 38 + src/Twilio.Twiml.Tests/GatherTests.cs | 39 + src/Twilio.Twiml.Tests/HangupTests.cs | 22 + src/Twilio.Twiml.Tests/PauseTests.cs | 31 + src/Twilio.Twiml.Tests/PlayTests.cs | 36 + .../Properties/AssemblyInfo.cs | 10 + .../QuickStarts/HelloMonkey.cs | 116 + .../QuickStarts/SmsHelloMonkey.cs | 56 + src/Twilio.Twiml.Tests/RecordTests.cs | 35 + src/Twilio.Twiml.Tests/RedirectTests.cs | 31 + src/Twilio.Twiml.Tests/RejectTests.cs | 31 + src/Twilio.Twiml.Tests/ResponseTests.cs | 21 + src/Twilio.Twiml.Tests/SayTests.cs | 41 + src/Twilio.Twiml.Tests/SmsTests.cs | 31 + src/Twilio.Twiml.Tests/TestBase.cs | 31 + src/Twilio.Twiml.Tests/TwiML.xsd | 170 + .../Twilio.TwiML.Tests.csproj | 111 + src/Twilio.Twiml.Tests/packages.config | 4 + src/Twilio.Twiml/Properties/AssemblyInfo.cs | 9 + src/Twilio.Twiml/RequestValidator.cs | 73 + src/Twilio.Twiml/Twilio.TwiML.csproj | 76 + src/Twilio.Twiml/TwilioResponse.cs | 257 + src/Twilio.Twiml/Verbs/Conference.cs | 33 + src/Twilio.Twiml/Verbs/Dial.cs | 35 + src/Twilio.Twiml/Verbs/ElementBase.cs | 70 + src/Twilio.Twiml/Verbs/Gather.cs | 30 + src/Twilio.Twiml/Verbs/Hangup.cs | 16 + src/Twilio.Twiml/Verbs/IVerb.cs | 13 + src/Twilio.Twiml/Verbs/Number.cs | 23 + src/Twilio.Twiml/Verbs/Pause.cs | 22 + src/Twilio.Twiml/Verbs/Play.cs | 21 + src/Twilio.Twiml/Verbs/Record.cs | 30 + src/Twilio.Twiml/Verbs/Redirect.cs | 24 + src/Twilio.Twiml/Verbs/Reject.cs | 22 + src/Twilio.Twiml/Verbs/Say.cs | 25 + src/Twilio.Twiml/Verbs/Sms.cs | 32 + .../Properties/AssemblyInfo.cs | 10 + src/Twilio.WebMatrix/Twilio.WebMatrix.csproj | 66 + src/Twilio.WebMatrix/Twilio.cs | 92 + src/Twilio.sln | 121 + src/Twilio.vsmdi | 6 + .../Newtonsoft.Json.4.0.2.nupkg | Bin 0 -> 2369113 bytes .../lib/net20/Newtonsoft.Json.Net20.dll | Bin 0 -> 406016 bytes .../lib/net20/Newtonsoft.Json.Net20.xml | 6520 ++++++++++++++++ .../lib/net35/Newtonsoft.Json.Net35.dll | Bin 0 -> 325632 bytes .../lib/net35/Newtonsoft.Json.Net35.xml | 6711 ++++++++++++++++ .../lib/net40/Newtonsoft.Json.dll | Bin 0 -> 348160 bytes .../lib/net40/Newtonsoft.Json.xml | 6862 +++++++++++++++++ .../sl3-wp/Newtonsoft.Json.WindowsPhone.dll | Bin 0 -> 295936 bytes .../sl3-wp/Newtonsoft.Json.WindowsPhone.xml | 6331 +++++++++++++++ .../lib/sl4/Newtonsoft.Json.Silverlight.dll | Bin 0 -> 299520 bytes .../lib/sl4/Newtonsoft.Json.Silverlight.xml | 6361 +++++++++++++++ .../RestSharp.101.3/RestSharp.101.3.nupkg | Bin 0 -> 350612 bytes .../lib/net35-client/RestSharp.dll | Bin 0 -> 121344 bytes .../RestSharp.101.3/lib/net35/RestSharp.dll | Bin 0 -> 121344 bytes .../lib/net4-client/RestSharp.dll | Bin 0 -> 121856 bytes .../RestSharp.101.3/lib/net4/RestSharp.dll | Bin 0 -> 121856 bytes .../lib/sl3-wp/RestSharp.WindowsPhone.dll | Bin 0 -> 73216 bytes .../lib/sl4/RestSharp.Silverlight.dll | Bin 0 -> 72704 bytes src/packages/repositories.config | 7 + src/packages/xunit.1.8.0.1545/lib/xunit.dll | Bin 0 -> 64000 bytes .../xunit.1.8.0.1545/lib/xunit.dll.tdnet | 5 + .../lib/xunit.runner.tdnet.dll | Bin 0 -> 8704 bytes .../lib/xunit.runner.utility.dll | Bin 0 -> 46592 bytes src/packages/xunit.1.8.0.1545/lib/xunit.xml | 2439 ++++++ .../xunit.1.8.0.1545/xunit.1.8.0.1545.nupkg | Bin 0 -> 55212 bytes 172 files changed, 44097 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 Twilio.Mvc.nuspec create mode 100644 Twilio.TwiML.nuspec create mode 100644 Twilio.WebMatrix.nuspec create mode 100644 Twilio.nuspec create mode 100644 package.cmd create mode 100644 src/Index.dat create mode 100644 src/Local.testsettings create mode 100644 src/Storage.dat create mode 100644 src/TraceAndTestImpact.testsettings create mode 100644 src/Twilio.Api.Silverlight/Accounts.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Applications.Async.cs create mode 100644 src/Twilio.Api.Silverlight/AvailablePhoneNumbers.Aysnc.cs create mode 100644 src/Twilio.Api.Silverlight/Calls.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Conference.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Core.Async.cs create mode 100644 src/Twilio.Api.Silverlight/IncomingPhoneNumbers.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Notifications.Aysnc.cs create mode 100644 src/Twilio.Api.Silverlight/OutgoingCallerIds.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Properties/AssemblyInfo.cs create mode 100644 src/Twilio.Api.Silverlight/Recordings.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Sandbox.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Sms.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Transcriptions.Async.cs create mode 100644 src/Twilio.Api.Silverlight/Twilio.Api.Silverlight.csproj create mode 100644 src/Twilio.Api.Silverlight/packages.config create mode 100644 src/Twilio.Api.WindowsPhone/Properties/AssemblyInfo.cs create mode 100644 src/Twilio.Api.WindowsPhone/Twilio.Api.WindowsPhone.csproj create mode 100644 src/Twilio.Api.WindowsPhone/packages.config create mode 100644 src/Twilio.Api/Accounts.cs create mode 100644 src/Twilio.Api/Applications.cs create mode 100644 src/Twilio.Api/AvailablePhoneNumbers.cs create mode 100644 src/Twilio.Api/Calls.cs create mode 100644 src/Twilio.Api/Conference.cs create mode 100644 src/Twilio.Api/Core.cs create mode 100644 src/Twilio.Api/IncomingPhoneNumbers.cs create mode 100644 src/Twilio.Api/Model/Account.cs create mode 100644 src/Twilio.Api/Model/Application.cs create mode 100644 src/Twilio.Api/Model/ApplicationOptions.cs create mode 100644 src/Twilio.Api/Model/ApplicationResult.cs create mode 100644 src/Twilio.Api/Model/AvailablePhoneNumber.cs create mode 100644 src/Twilio.Api/Model/AvailablePhoneNumberListRequest.cs create mode 100644 src/Twilio.Api/Model/AvailablePhoneNumberResult.cs create mode 100644 src/Twilio.Api/Model/Call.cs create mode 100644 src/Twilio.Api/Model/CallListRequest.cs create mode 100644 src/Twilio.Api/Model/CallOptions.cs create mode 100644 src/Twilio.Api/Model/CallResult.cs create mode 100644 src/Twilio.Api/Model/ComparisonType.cs create mode 100644 src/Twilio.Api/Model/Conference.cs create mode 100644 src/Twilio.Api/Model/ConferenceListRequest.cs create mode 100644 src/Twilio.Api/Model/ConferenceResult.cs create mode 100644 src/Twilio.Api/Model/DeleteStatus.cs create mode 100644 src/Twilio.Api/Model/HangupStyle.cs create mode 100644 src/Twilio.Api/Model/IncomingPhoneNumber.cs create mode 100644 src/Twilio.Api/Model/IncomingPhoneNumberResult.cs create mode 100644 src/Twilio.Api/Model/Notification.cs create mode 100644 src/Twilio.Api/Model/NotificationResult.cs create mode 100644 src/Twilio.Api/Model/OutgoingCallerId.cs create mode 100644 src/Twilio.Api/Model/OutgoingCallerIdResult.cs create mode 100644 src/Twilio.Api/Model/Participant.cs create mode 100644 src/Twilio.Api/Model/ParticipantResult.cs create mode 100644 src/Twilio.Api/Model/PhoneNumberOptions.cs create mode 100644 src/Twilio.Api/Model/Recording.cs create mode 100644 src/Twilio.Api/Model/RecordingResult.cs create mode 100644 src/Twilio.Api/Model/RestException.cs create mode 100644 src/Twilio.Api/Model/Sandbox.cs create mode 100644 src/Twilio.Api/Model/SmsMessage.cs create mode 100644 src/Twilio.Api/Model/SmsMessageResult.cs create mode 100644 src/Twilio.Api/Model/SmsShortCode.cs create mode 100644 src/Twilio.Api/Model/SmsShortCodeResult.cs create mode 100644 src/Twilio.Api/Model/Transcription.cs create mode 100644 src/Twilio.Api/Model/TranscriptionResult.cs create mode 100644 src/Twilio.Api/Model/TwilioBase.cs create mode 100644 src/Twilio.Api/Model/TwilioListBase.cs create mode 100644 src/Twilio.Api/Model/ValidationRequest.cs create mode 100644 src/Twilio.Api/Notifications.cs create mode 100644 src/Twilio.Api/OutgoingCallerIds.cs create mode 100644 src/Twilio.Api/Properties/AssemblyInfo.cs create mode 100644 src/Twilio.Api/Recordings.cs create mode 100644 src/Twilio.Api/Sandbox.cs create mode 100644 src/Twilio.Api/SharedAssemblyInfo.cs create mode 100644 src/Twilio.Api/Sms.cs create mode 100644 src/Twilio.Api/Transcriptions.cs create mode 100644 src/Twilio.Api/Twilio.Api.csproj create mode 100644 src/Twilio.Api/packages.config create mode 100644 src/Twilio.Mvc/Properties/AssemblyInfo.cs create mode 100644 src/Twilio.Mvc/TwiMLResult.cs create mode 100644 src/Twilio.Mvc/Twilio.Mvc.csproj create mode 100644 src/Twilio.Mvc/TwilioController.cs create mode 100644 src/Twilio.Mvc/ValidateRequestAttribute.cs create mode 100644 src/Twilio.Twiml.Tests/DialTests.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Sms/Redirect.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Sms/Sms.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Conference.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Dial.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Gather.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Hangup.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Number.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Pause.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Play.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Record.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Redirect.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Reject.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Say.cs create mode 100644 src/Twilio.Twiml.Tests/DocExamples/Voice/Sms.cs create mode 100644 src/Twilio.Twiml.Tests/GatherTests.cs create mode 100644 src/Twilio.Twiml.Tests/HangupTests.cs create mode 100644 src/Twilio.Twiml.Tests/PauseTests.cs create mode 100644 src/Twilio.Twiml.Tests/PlayTests.cs create mode 100644 src/Twilio.Twiml.Tests/Properties/AssemblyInfo.cs create mode 100644 src/Twilio.Twiml.Tests/QuickStarts/HelloMonkey.cs create mode 100644 src/Twilio.Twiml.Tests/QuickStarts/SmsHelloMonkey.cs create mode 100644 src/Twilio.Twiml.Tests/RecordTests.cs create mode 100644 src/Twilio.Twiml.Tests/RedirectTests.cs create mode 100644 src/Twilio.Twiml.Tests/RejectTests.cs create mode 100644 src/Twilio.Twiml.Tests/ResponseTests.cs create mode 100644 src/Twilio.Twiml.Tests/SayTests.cs create mode 100644 src/Twilio.Twiml.Tests/SmsTests.cs create mode 100644 src/Twilio.Twiml.Tests/TestBase.cs create mode 100644 src/Twilio.Twiml.Tests/TwiML.xsd create mode 100644 src/Twilio.Twiml.Tests/Twilio.TwiML.Tests.csproj create mode 100644 src/Twilio.Twiml.Tests/packages.config create mode 100644 src/Twilio.Twiml/Properties/AssemblyInfo.cs create mode 100644 src/Twilio.Twiml/RequestValidator.cs create mode 100644 src/Twilio.Twiml/Twilio.TwiML.csproj create mode 100644 src/Twilio.Twiml/TwilioResponse.cs create mode 100644 src/Twilio.Twiml/Verbs/Conference.cs create mode 100644 src/Twilio.Twiml/Verbs/Dial.cs create mode 100644 src/Twilio.Twiml/Verbs/ElementBase.cs create mode 100644 src/Twilio.Twiml/Verbs/Gather.cs create mode 100644 src/Twilio.Twiml/Verbs/Hangup.cs create mode 100644 src/Twilio.Twiml/Verbs/IVerb.cs create mode 100644 src/Twilio.Twiml/Verbs/Number.cs create mode 100644 src/Twilio.Twiml/Verbs/Pause.cs create mode 100644 src/Twilio.Twiml/Verbs/Play.cs create mode 100644 src/Twilio.Twiml/Verbs/Record.cs create mode 100644 src/Twilio.Twiml/Verbs/Redirect.cs create mode 100644 src/Twilio.Twiml/Verbs/Reject.cs create mode 100644 src/Twilio.Twiml/Verbs/Say.cs create mode 100644 src/Twilio.Twiml/Verbs/Sms.cs create mode 100644 src/Twilio.WebMatrix/Properties/AssemblyInfo.cs create mode 100644 src/Twilio.WebMatrix/Twilio.WebMatrix.csproj create mode 100644 src/Twilio.WebMatrix/Twilio.cs create mode 100644 src/Twilio.sln create mode 100644 src/Twilio.vsmdi create mode 100644 src/packages/Newtonsoft.Json.4.0.2/Newtonsoft.Json.4.0.2.nupkg create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/net20/Newtonsoft.Json.Net20.dll create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/net20/Newtonsoft.Json.Net20.xml create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/net35/Newtonsoft.Json.Net35.dll create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/net35/Newtonsoft.Json.Net35.xml create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/net40/Newtonsoft.Json.dll create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/net40/Newtonsoft.Json.xml create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/sl3-wp/Newtonsoft.Json.WindowsPhone.dll create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/sl3-wp/Newtonsoft.Json.WindowsPhone.xml create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/sl4/Newtonsoft.Json.Silverlight.dll create mode 100644 src/packages/Newtonsoft.Json.4.0.2/lib/sl4/Newtonsoft.Json.Silverlight.xml create mode 100644 src/packages/RestSharp.101.3/RestSharp.101.3.nupkg create mode 100644 src/packages/RestSharp.101.3/lib/net35-client/RestSharp.dll create mode 100644 src/packages/RestSharp.101.3/lib/net35/RestSharp.dll create mode 100644 src/packages/RestSharp.101.3/lib/net4-client/RestSharp.dll create mode 100644 src/packages/RestSharp.101.3/lib/net4/RestSharp.dll create mode 100644 src/packages/RestSharp.101.3/lib/sl3-wp/RestSharp.WindowsPhone.dll create mode 100644 src/packages/RestSharp.101.3/lib/sl4/RestSharp.Silverlight.dll create mode 100644 src/packages/repositories.config create mode 100644 src/packages/xunit.1.8.0.1545/lib/xunit.dll create mode 100644 src/packages/xunit.1.8.0.1545/lib/xunit.dll.tdnet create mode 100644 src/packages/xunit.1.8.0.1545/lib/xunit.runner.tdnet.dll create mode 100644 src/packages/xunit.1.8.0.1545/lib/xunit.runner.utility.dll create mode 100644 src/packages/xunit.1.8.0.1545/lib/xunit.xml create mode 100644 src/packages/xunit.1.8.0.1545/xunit.1.8.0.1545.nupkg diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..54d41c513 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ + +#ignore thumbnails created by windows +Thumbs.db +#Ignore files build by Visual Studio +*.obj +*.exe +*.pdb +*.user +*.aps +*.pch +*.vspscc +*_i.c +*_p.c +*.ncb +*.suo +*.tlb +*.tlh +*.bak +*.cache +*.ilk +*.log +[Bb]in +[Dd]ebug*/ +*.lib +*.sbr +obj/ +[Rr]elease*/ +_ReSharper*/ +[Tt]est[Rr]esult* +TwilioTest/ +TwilioTestPhone/ +download/ \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..9aa0a58ae --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,67 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 000000000..850e64602 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +This library replaces https://github.com/johnsheehan/TwilioApi. If you are migrating from TwilioApi 2.1 to this project, there are minor breaking changes (TwilioApi renamed to TwilioRestClient and some methods have changed names slightly). + +
+ +# Twilio REST API and TwiML Libraries for .NET, ASP.NET, ASP.NET MVC and WebMatrix + +Twilio provides a simple HTTP-based API for sending and receiving phone calls and text messages. Learn more at [http://www.twilio.com][0] + +## [.NET Helper Library Documentation][3] +#### [Twilio REST API Documentation][1] - [Twilio TwiML Documentation][2] + +### Sample Usage + + using Twilio; + var twilio = new TwilioRestClient("accountSid", "authToken"); + var call = twilio.InitiateOutboundCall("+1555456790", "+15551112222", "http://example.com/handleCall"); + var msg = twilio.SendSmsMessage("+15551112222", "+15553334444", "Can you believe it's this easy to send an SMS?!"); + +### Silverlight/Windows Phone 7/Asynchronous Requests Sample + + using Twilio; + var twilio = new TwilioClient("accountSid", "authToken"); + twilio.InitiateOutboundCall("+1123456790", "+15555551212", "http://example.com/handleCall", (call) => { + // Console.WriteLog(call.Sid); + }); + + twilio.SendSmsMessage("+15555551212", "+11234567890", "Hello!", (msg) => { + // Console.WriteLine(msg.Sid); + }); + +### TwiML Generation with ASP.NET Sample + + var response = new TwilioResponse(); + response.Say("Hello Monkey"); + response.Play("http://demo.twilio.com/hellomonkey/monkey.mp3"); + response.BeginGather(new { numDigits = 1, action = "hello-monkey-handle-key.php", method = "POST" }); + response.Say("To speak to a real monkey, press 1. Press 2 to record your own monkey howl. Press any other key to start over."); + response.EndGather(); + + // ASP.NET MVC when controller inherits from TwilioController + return TwiML(response); + + // ASP.NET MVC regular controller + return new TwiMLResult(response); + + // ASP.NET Webforms + var doc = response.ToXDocument(); + Response.ContentType = "application/xml"; + doc.Save(Response.Output); + + +[0]: http://www.twilio.com +[1]: http://www.twilio.com/docs/api/rest +[2]: http://www.twilio.com/docs/api/twiml +[3]: https://github.com/johnsheehan/Twilio/wiki diff --git a/Twilio.Mvc.nuspec b/Twilio.Mvc.nuspec new file mode 100644 index 000000000..30f0fbd6c --- /dev/null +++ b/Twilio.Mvc.nuspec @@ -0,0 +1,16 @@ + + + + Twilio.Mvc + 3.0 + Twilio + Twilio helpers for ASP.NET MVC + en-US + http://github.com/johnsheehan/Twilio + http://www.twilio.com/packages/company/img/logos_downloadable_round.png + REST SMS voice telephony phone + + + + + \ No newline at end of file diff --git a/Twilio.TwiML.nuspec b/Twilio.TwiML.nuspec new file mode 100644 index 000000000..05a8329e1 --- /dev/null +++ b/Twilio.TwiML.nuspec @@ -0,0 +1,16 @@ + + + + Twilio.TwiML + 3.0 + Twilio + Twilio TwiML generator. If using ASP.NET MVC, install Twilio.Mvc instead. + en-US + http://github.com/johnsheehan/Twilio + http://www.twilio.com/packages/company/img/logos_downloadable_round.png + REST SMS voice telephony phone + + + + + \ No newline at end of file diff --git a/Twilio.WebMatrix.nuspec b/Twilio.WebMatrix.nuspec new file mode 100644 index 000000000..34436bf7d --- /dev/null +++ b/Twilio.WebMatrix.nuspec @@ -0,0 +1,16 @@ + + + + Twilio.WebMatrix + 3.0 + Twilio + Twilio helpers for WebMatrix and ASP.NET Web Pages + en-US + http://github.com/johnsheehan/Twilio + http://www.twilio.com/packages/company/img/logos_downloadable_round.png + REST SMS voice telephony phone ASPNETWEBPAGES + + + + + \ No newline at end of file diff --git a/Twilio.nuspec b/Twilio.nuspec new file mode 100644 index 000000000..61baa0ae5 --- /dev/null +++ b/Twilio.nuspec @@ -0,0 +1,16 @@ + + + + Twilio + 3.0 + Twilio + Twilio REST API wrapper + en-US + http://github.com/johnsheehan/Twilio + http://www.twilio.com/packages/company/img/logos_downloadable_round.png + REST SMS voice telephony phone + + + + + \ No newline at end of file diff --git a/package.cmd b/package.cmd new file mode 100644 index 000000000..095677820 --- /dev/null +++ b/package.cmd @@ -0,0 +1,48 @@ +tools\nuget.exe update -self + +if not exist download mkdir download +if not exist download\WindowsPhone mkdir download\WindowsPhone +if not exist download\WindowsPhone mkdir download\Silverlight +if not exist download\package mkdir download\package +if not exist download\package\twilio mkdir download\package\twilio +if not exist download\package\twiliomvc mkdir download\package\twiliomvc +if not exist download\package\twiliotwiml mkdir download\package\twiliotwiml +if not exist download\package\twiliowebmatrix mkdir download\package\twiliowebmatrix + +if not exist download\package\twilio\lib mkdir download\package\twilio\lib +if not exist download\package\twilio\lib\3.5 mkdir download\package\twilio\lib\3.5 +if not exist download\package\twilio\lib\SL3-WP7 mkdir download\package\twilio\lib\SL3-WP7 +if not exist download\package\twilio\lib\SL4 mkdir download\package\twilio\lib\SL4 + +if not exist download\package\twiliomvc\lib mkdir download\package\twiliomvc\lib +if not exist download\package\twiliomvc\lib\3.5 mkdir download\package\twiliomvc\lib\3.5 + +if not exist download\package\twiliotwiml\lib mkdir download\package\twiliotwiml\lib +if not exist download\package\twiliotwiml\lib\3.5 mkdir download\package\twiliotwiml\lib\3.5 + +if not exist download\package\twiliowebmatrix\lib mkdir download\package\twiliowebmatrix\lib +if not exist download\package\twiliowebmatrix\lib\3.5 mkdir download\package\twiliowebmatrix\lib\3.5 + +tools\ilmerge.exe /lib:src\Twilio.Api\bin\Release /internalize /ndebug /v2 /out:download\Twilio.Api.dll Twilio.Api.dll RestSharp.dll +tools\ilmerge.exe /lib:src\Twilio.Api.Silverlight\bin\Release /internalize /ndebug /targetplatform:v4,"C:\Program Files (x86)\Microsoft Silverlight\4.0.51204.0" /out:download\Twilio.Api.Silverlight.dll RestSharp.Silverlight.dll + +copy src\Twilio.Api\bin\Release\*.* download +copy src\Twilio.Api.Silverlight\bin\Release\*.* download\Silverlight\ +copy src\Twilio.Api.WindowsPhone\bin\Release\*.* download\WindowsPhone\ +copy src\Twilio.Mvc\bin\Release\*.* download +copy src\Twilio.Twiml\bin\Release\*.* download +copy src\Twilio.WebMatrix\bin\Release\*.* download +copy LICENSE.txt download + +copy src\Twilio.Api\bin\Release\Twilio.Api.* download\package\twilio\lib\3.5\ +copy src\Twilio.Api.Silverlight\bin\Release\Twilio.Api.Silverlight.* download\package\twilio\lib\SL4\ +copy src\Twilio.Api.WindowsPhone\bin\Release\Twilio.Api.WindowsPhone.* download\package\twilio\lib\SL3-WP7\ + +copy src\Twilio.Mvc\bin\Release\Twilio.Mvc.* download\package\twiliomvc\lib\3.5\ +copy src\Twilio.Twiml\bin\Release\Twilio.Twiml.* download\package\twiliotwiml\lib\3.5\ +copy src\Twilio.WebMatrix\bin\Release\Twilio.WebMatrix.* download\package\twiliowebmatrix\lib\3.5\ + +tools\nuget.exe pack Twilio.nuspec -BasePath download\package\twilio -o download +tools\nuget.exe pack Twilio.Mvc.nuspec -BasePath download\package\twiliomvc -o download +tools\nuget.exe pack Twilio.TwiML.nuspec -BasePath download\package\twiliotwiml -o download +tools\nuget.exe pack Twilio.WebMatrix.nuspec -BasePath download\package\twiliowebmatrix -o download \ No newline at end of file diff --git a/src/Index.dat b/src/Index.dat new file mode 100644 index 0000000000000000000000000000000000000000..a94a4c5580b30587b58e8aa38c9418116f872f4c GIT binary patch literal 28 dcmdO7U|`rjPhAB_G5iMt)BQYOSwI{h004LF2fqLS literal 0 HcmV?d00001 diff --git a/src/Local.testsettings b/src/Local.testsettings new file mode 100644 index 000000000..1e56f802f --- /dev/null +++ b/src/Local.testsettings @@ -0,0 +1,10 @@ + + + These are default test settings for a local test run. + + + + + + + \ No newline at end of file diff --git a/src/Storage.dat b/src/Storage.dat new file mode 100644 index 0000000000000000000000000000000000000000..c345a814f1e7d0e774ad1b532e01ce913e623060 GIT binary patch literal 512 QcmZQz7zHCW1pWg701Ng5{Qv*} literal 0 HcmV?d00001 diff --git a/src/TraceAndTestImpact.testsettings b/src/TraceAndTestImpact.testsettings new file mode 100644 index 000000000..b103d0734 --- /dev/null +++ b/src/TraceAndTestImpact.testsettings @@ -0,0 +1,19 @@ + + + These are test settings for Trace and Test Impact. + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Accounts.Async.cs b/src/Twilio.Api.Silverlight/Accounts.Async.cs new file mode 100644 index 000000000..7a4f1da67 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Accounts.Async.cs @@ -0,0 +1,97 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the account details for the currently authenticated account + /// + /// Method to call upon successful completion + public void GetAccount(Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}"; + request.RootElement = "Account"; + + ExecuteAsync(request, (response) => { callback(response); }); + } + + /// + /// Retrieve the account details for a subaccount + /// + /// The Sid of the subaccount to retrieve + /// Method to call upon successful completion + public void GetAccount(string accountSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}"; + request.RootElement = "Account"; + + request.AddUrlSegment("AccountSid", accountSid); + + ExecuteAsync(request, (response) => { callback(response); }); + } + + /// + /// List all subaccounts created for the authenticated account + /// + /// Method to call upon successful completion + public void ListSubAccounts(Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts"; + + ExecuteAsync(request, (response) => { callback(response); }); + } + + /// + /// Creates a new subaccount under the authenticated account + /// + /// Name associated with this account for your own reference (can be empty string) + /// Method to call upon successful completion + public void CreateSubAccount(string friendlyName, Action callback) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts"; + request.RootElement = "Account"; + + request.AddParameter("FriendlyName", friendlyName); + + ExecuteAsync(request, (response) => { callback(response); }); + } + + /// + /// Update the friendly name associated with the currently authenticated account + /// + /// Name to use when updating + /// Method to call upon successful completion + public void UpdateAccountName(string friendlyName, Action callback) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}"; + request.RootElement = "Account"; + request.AddParameter("FriendlyName", friendlyName); + + ExecuteAsync(request, (response) => { callback(response); }); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Applications.Async.cs b/src/Twilio.Api.Silverlight/Applications.Async.cs new file mode 100644 index 000000000..e708ad4b0 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Applications.Async.cs @@ -0,0 +1,156 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details for an application instance. Makes a GET request to an Application Instance resource. + /// + /// The Sid of the application to retrieve + /// Method to call upon successful completion + public void GetApplication(string applicationSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Applications/{ApplicationSid}"; + request.RootElement = "Application"; + + request.AddUrlSegment("ApplicationSid", applicationSid); + + ExecuteAsync(request, (response) => { callback(response); }); + } + + /// + /// List applications on current account + /// + /// Method to call upon successful completion + public void ListApplications(Action callback) + { + ListApplications(null, null, null, callback); + } + + /// + /// List applications on current account with filters + /// + /// Optional friendly name to match + /// Page number to start retrieving results from + /// How many results to return + /// Method to call upon successful completion + public void ListApplications(string friendlyName, int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Applications"; + + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, callback); + } + + /// + /// Create a new application + /// + /// The friendly name to name the application + /// Optional parameters to use when purchasing number + /// Method to call upon successful completion + public void AddApplication(string friendlyName, ApplicationOptions options, Action callback) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Applications"; + request.RootElement = "Application"; + + Require.Argument("FriendlyName", friendlyName); + Validate.IsValidLength(friendlyName, 64); + request.AddParameter("FriendlyName", friendlyName); + + // some check for null. in those cases an empty string is a valid value (to remove a URL assignment) + if (options != null) + { + if (options.VoiceUrl != null) request.AddParameter("VoiceUrl", options.VoiceUrl); + if (options.VoiceMethod.HasValue()) request.AddParameter("VoiceMethod", options.VoiceMethod.ToString()); + if (options.VoiceFallbackUrl != null) request.AddParameter("VoiceFallbackUrl", options.VoiceFallbackUrl); + if (options.VoiceFallbackMethod.HasValue()) request.AddParameter("VoiceFallbackMethod", options.VoiceFallbackMethod.ToString()); + if (options.VoiceCallerIdLookup.HasValue) request.AddParameter("VoiceCallerIdLookup", options.VoiceCallerIdLookup.Value); + if (options.StatusCallback.HasValue()) request.AddParameter("StatusCallbackUrl", options.StatusCallback); + if (options.StatusCallbackMethod.HasValue()) request.AddParameter("StatusCallbackMethod", options.StatusCallbackMethod.ToString()); + if (options.SmsUrl != null) request.AddParameter("SmsUrl", options.SmsUrl); + if (options.SmsMethod.HasValue()) request.AddParameter("SmsMethod", options.SmsMethod.ToString()); + if (options.SmsFallbackUrl != null) request.AddParameter("SmsFallbackUrl", options.SmsFallbackUrl); + if (options.SmsFallbackMethod.HasValue()) request.AddParameter("SmsFallbackMethod", options.SmsFallbackMethod.ToString()); + } + + ExecuteAsync(request, (response) => { callback(response); }); + } + + /// + /// Tries to update the application's properties, and returns the updated resource representation if successful. + /// + /// The Sid of the application to update + /// The friendly name to rename the application to (optional, null to leave as-is) + /// Which settings to update. Only properties with values set will be updated. + /// Method to call upon successful completion + public void UpdateApplication(string applicationSid, string friendlyName, ApplicationOptions options, Action callback) + { + Require.Argument("ApplicationSid", applicationSid); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Applications/{ApplicationSid}"; + request.AddUrlSegment("ApplicationSid", applicationSid); + request.RootElement = "Application"; + + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (options != null) + { + if (options.VoiceUrl != null) request.AddParameter("VoiceUrl", options.VoiceUrl); + if (options.VoiceMethod.HasValue()) request.AddParameter("VoiceMethod", options.VoiceMethod.ToString()); + if (options.VoiceFallbackUrl != null) request.AddParameter("VoiceFallbackUrl", options.VoiceFallbackUrl); + if (options.VoiceFallbackMethod.HasValue()) request.AddParameter("VoiceFallbackMethod", options.VoiceFallbackMethod.ToString()); + if (options.VoiceCallerIdLookup.HasValue) request.AddParameter("VoiceCallerIdLookup", options.VoiceCallerIdLookup.Value); + if (options.StatusCallback.HasValue()) request.AddParameter("StatusCallbackUrl", options.StatusCallback); + if (options.StatusCallbackMethod.HasValue()) request.AddParameter("StatusCallbackMethod", options.StatusCallbackMethod.ToString()); + if (options.SmsUrl != null) request.AddParameter("SmsUrl", options.SmsUrl); + if (options.SmsMethod.HasValue()) request.AddParameter("SmsMethod", options.SmsMethod.ToString()); + if (options.SmsFallbackUrl != null) request.AddParameter("SmsFallbackUrl", options.SmsFallbackUrl); + if (options.SmsFallbackMethod.HasValue()) request.AddParameter("SmsFallbackMethod", options.SmsFallbackMethod.ToString()); + } + + ExecuteAsync(request, (response) => { callback(response); }); + } + + /// + /// Delete this application. If this application's sid is assigned to any IncomingPhoneNumber resources as a VoiceApplicationSid or SmsApplicationSid it will be removed. + /// + /// The Sid of the number to remove + /// Method to call upon successful completion + public void DeleteApplication(string applicationSid, Action callback) + { + Require.Argument("ApplicationSid", applicationSid); + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/Applications/{ApplicationSid}"; + + request.AddUrlSegment("ApplicationSid", applicationSid); + + ExecuteAsync(request, (response) => { callback(response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed); }); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/AvailablePhoneNumbers.Aysnc.cs b/src/Twilio.Api.Silverlight/AvailablePhoneNumbers.Aysnc.cs new file mode 100644 index 000000000..3b99a97d5 --- /dev/null +++ b/src/Twilio.Api.Silverlight/AvailablePhoneNumbers.Aysnc.cs @@ -0,0 +1,96 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Search available local phone numbers + /// + /// Two-character ISO country code (US or CA) + /// Search filter options. Only properties with values set will be used. + /// Method to call upon successful completion + public void ListAvailableLocalPhoneNumbers(string isoCountryCode, AvailablePhoneNumberListRequest options, Action callback) + { + Require.Argument("isoCountryCode", isoCountryCode); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/AvailablePhoneNumbers/{IsoCountryCode}/Local"; + request.AddUrlSegment("IsoCountryCode", isoCountryCode); + + AddNumberSearchParameters(options, request); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Search available toll-free phone numbers + /// + /// Two-character ISO country code (US or CA) + /// Method to call upon successful completion + public void ListAvailableTollFreePhoneNumbers(string isoCountryCode, Action callback) + { + Require.Argument("isoCountryCode", isoCountryCode); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/AvailablePhoneNumbers/{IsoCountryCode}/TollFree"; + request.AddUrlSegment("IsoCountryCode", isoCountryCode); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Search available toll-free phone numbers + /// + /// Two-character ISO country code (US or CA) + /// Value to use when filtering search. Accepts numbers or characters. + /// Method to call upon successful completion + public void ListAvailableTollFreePhoneNumbers(string isoCountryCode, string contains, Action callback) + { + Require.Argument("isoCountryCode", isoCountryCode); + Require.Argument("contains", contains); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/AvailablePhoneNumbers/{IsoCountryCode}/TollFree"; + request.AddUrlSegment("IsoCountryCode", isoCountryCode); + + request.AddParameter("Contains", contains); + + ExecuteAsync(request, (response) => callback(response)); + } + + private void AddNumberSearchParameters(AvailablePhoneNumberListRequest options, RestRequest request) + { + if (options.AreaCode.HasValue()) request.AddParameter("AreaCode", options.AreaCode); + if (options.Contains.HasValue()) request.AddParameter("Contains", options.Contains); + if (options.Distance.HasValue) request.AddParameter("Distance", options.Distance); + if (options.InLata.HasValue()) request.AddParameter("InLata", options.InLata); + if (options.InPostalCode.HasValue()) request.AddParameter("InPostalCode", options.InPostalCode); + if (options.InRateCenter.HasValue()) request.AddParameter("InRateCenter", options.InRateCenter); + if (options.InRegion.HasValue()) request.AddParameter("InRegion", options.InRegion); + if (options.NearLatLong.HasValue()) request.AddParameter("NearLatLong", options.NearLatLong); + if (options.NearNumber.HasValue()) request.AddParameter("NearNumber", options.NearNumber); + } + + } +} diff --git a/src/Twilio.Api.Silverlight/Calls.Async.cs b/src/Twilio.Api.Silverlight/Calls.Async.cs new file mode 100644 index 000000000..afc90cc79 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Calls.Async.cs @@ -0,0 +1,211 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns a paged list of phone calls made to and from the account. + /// Sorted by DateUpdated with most-recent calls first. + /// + /// Method to call upon successful completion + public void ListCalls(Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Calls"; + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Returns a paged list of phone calls made to and from the account. + /// Sorted by DateUpdated with most-recent calls first. + /// + /// List filter options. If an property is set the list will be filtered by that value. + /// Method to call upon successful completion + public void ListCalls(CallListRequest options, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Calls"; + + AddCallListOptions(options, request); + + ExecuteAsync(request, (response) => callback(response)); + } + + private void AddCallListOptions(CallListRequest options, RestRequest request) + { + if (options.From.HasValue()) request.AddParameter("From", options.From); + if (options.To.HasValue()) request.AddParameter("To", options.To); + if (options.Status.HasValue()) request.AddParameter("Status", options.Status); + if (options.StartTime.HasValue) request.AddParameter("StartTime", options.StartTime.Value.ToString("yyyy-MM-dd")); + if (options.EndTime.HasValue) request.AddParameter("EndTime", options.EndTime.Value.ToString("yyyy-MM-dd")); + + var startTimeParameterName = GetParameterNameWithEquality(options.StartTimeComparison, "StartTime"); + var endTimeParameterName = GetParameterNameWithEquality(options.EndTimeComparison, "EndTime"); + + if (options.StartTime.HasValue) request.AddParameter(startTimeParameterName, options.StartTime.Value.ToString("yyyy-MM-dd")); + if (options.EndTime.HasValue) request.AddParameter(endTimeParameterName, options.EndTime.Value.ToString("yyyy-MM-dd")); + + if (options.Count.HasValue) request.AddParameter("num", options.Count.Value); + if (options.PageNumber.HasValue) request.AddParameter("page", options.PageNumber.Value); + + if (options.ParentCallSid.HasValue()) request.AddParameter("ParentCallSid", options.ParentCallSid); + } + + /// + /// Returns the single Call resource identified by {CallSid} + /// + /// The Sid of the Call resource to retrieve + /// Method to call upon successful completion + public void GetCall(string callSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Calls/{CallSid}"; + request.RootElement = "Call"; + + request.AddParameter("CallSid", callSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Initiates a new phone call. + /// + /// The phone number to use as the caller id. Format with a '+' and country code e.g., +16175551212 (E.164 format). Must be a Twilio number or a valid outgoing caller id for your account. + /// The number to call formatted with a '+' and country code e.g., +16175551212 (E.164 format). Twilio will also accept unformatted US numbers e.g., (415) 555-1212, 415-555-1212. + /// The fully qualified URL that should be consulted when the call connects. Just like when you set a URL for your inbound calls. URL should return TwiML. + /// Method to call upon successful completion + public void InitiateOutboundCall(string from, string to, string url, Action callback) + { + InitiateOutboundCall(from, to, url, null, callback); + } + + /// + /// Initiates a new phone call. + /// + /// The phone number to use as the caller id. Format with a '+' and country code e.g., +16175551212 (E.164 format). Must be a Twilio number or a valid outgoing caller id for your account. + /// The number to call formatted with a '+' and country code e.g., +16175551212 (E.164 format). Twilio will also accept unformatted US numbers e.g., (415) 555-1212, 415-555-1212. + /// The fully qualified URL that should be consulted when the call connects. Just like when you set a URL for your inbound calls. URL should return TwiML. + /// A URL that Twilio will request when the call ends to notify your app. + /// Method to call upon successful completion + public void InitiateOutboundCall(string from, string to, string url, string statusCallback, Action callback) + { + InitiateOutboundCall(new CallOptions + { + From = from, + To = to, + Url = url, + StatusCallback = statusCallback + }, + callback); + } + + /// + /// Initiates a new phone call. + /// + /// Call settings. Only properties with values set will be used. + /// Method to call upon successful completion + public void InitiateOutboundCall(CallOptions options, Action callback) + { + Require.Argument("From", options.From); + Require.Argument("To", options.To); + Require.Argument("Url", options.Url); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Calls"; + request.RootElement = "Call"; + + AddCallOptions(options, request); + + ExecuteAsync(request, (response) => callback(response)); + } + + private static void AddCallOptions(CallOptions options, RestRequest request) + { + request.AddParameter("From", options.From); + request.AddParameter("To", options.To); + + if (options.ApplicationSid.HasValue()) + { + request.AddParameter("ApplicationSid", options.ApplicationSid); + } + else + { + request.AddParameter("Url", options.Url); + } + + if (options.StatusCallback.HasValue()) request.AddParameter("StatusCallback", options.StatusCallback); + if (options.StatusCallbackMethod.HasValue()) request.AddParameter("StatusCallbackMethod", options.StatusCallbackMethod); + if (options.FallbackUrl.HasValue()) request.AddParameter("FallbackUrl", options.FallbackUrl); + if (options.FallbackMethod.HasValue()) request.AddParameter("FallbackMethod", options.FallbackMethod); + if (options.Method.HasValue()) request.AddParameter("Method", options.Method); + if (options.SendDigits.HasValue()) request.AddParameter("SendDigits", options.SendDigits); + if (options.IfMachine.HasValue()) request.AddParameter("IfMachine", options.IfMachine); + if (options.Timeout.HasValue) request.AddParameter("Timeout", options.Timeout.Value); + } + + /// + /// Hangs up a call in progress. + /// + /// The Sid of the call to hang up. + /// 'Canceled' will attempt to hangup calls that are queued or ringing but not affect calls already in progress. 'Completed' will attempt to hang up a call even if it's already in progress. + /// Method to call upon successful completion + public void HangupCall(string callSid, HangupStyle style, Action callback) + { + Require.Argument("CallSid", callSid); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Calls/{CallSid}"; + request.RootElement = "Call"; + + request.AddUrlSegment("CallSid", callSid); + request.AddParameter("Status", style.ToString().ToLower()); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Redirect a call in progress to a new TwiML URL + /// + /// The Sid of the call to redirect + /// The URL to redirect the call to. + /// The HTTP method to use when requesting the redirectUrl + /// Method to call upon successful completion + public void RedirectCall(string callSid, string redirectUrl, string redirectMethod, Action callback) + { + Require.Argument("CallSid", callSid); + Require.Argument("Url", redirectUrl); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Calls/{CallSid}"; + request.RootElement = "Call"; + + request.AddParameter("CallSid", callSid, ParameterType.UrlSegment); + request.AddParameter("Url", redirectUrl); + if (redirectMethod.HasValue()) request.AddParameter("Method", redirectMethod); + + ExecuteAsync(request, (response) => callback(response)); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Conference.Async.cs b/src/Twilio.Api.Silverlight/Conference.Async.cs new file mode 100644 index 000000000..cee2b69d2 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Conference.Async.cs @@ -0,0 +1,189 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns a list of conferences within an account. The list includes paging information and is sorted by DateUpdated, with most recent conferences first. + /// + /// Method to call upon successful completion + public void ListConferences(Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences"; + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Returns a list of conferences within an account. The list includes paging information and is sorted by DateUpdated, with most recent conferences first. + /// + /// List filter options. Only properties with values are included in request. + /// Method to call upon successful completion + public void ListConferences(ConferenceListRequest options, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences"; + + AddConferenceListOptions(options, request); + + ExecuteAsync(request, (response) => callback(response)); + } + + private void AddConferenceListOptions(ConferenceListRequest options, RestRequest request) + { + if (options.Status.HasValue) request.AddParameter("Status", options.Status); + if (options.FriendlyName.HasValue()) request.AddParameter("FriendlyName", options.FriendlyName); + + var dateCreatedParameterName = GetParameterNameWithEquality(options.DateCreatedComparison, "DateCreated"); + var dateUpdatedParameterName = GetParameterNameWithEquality(options.DateUpdatedComparison, "DateUpdated"); + + if (options.DateCreated.HasValue) request.AddParameter(dateCreatedParameterName, options.DateCreated.Value.ToString("yyyy-MM-dd")); + if (options.DateUpdated.HasValue) request.AddParameter(dateUpdatedParameterName, options.DateUpdated.Value.ToString("yyyy-MM-dd")); + + if (options.Count.HasValue) request.AddParameter("num", options.Count.Value); + if (options.PageNumber.HasValue) request.AddParameter("page", options.PageNumber.Value); + } + + /// + /// Retrieve details for specific conference + /// + /// The Sid of the conference to retrieve + /// Method to call upon successful completion + public void GetConference(string conferenceSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}"; + request.RootElement = "Conference"; + + request.AddParameter("ConferenceSid", conferenceSid); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Retrieve a list of conference participants + /// + /// The Sid of the conference + /// Set to null to retrieve all, true to retrieve muted, false to retrieve unmuted + /// Method to call upon successful completion + public void ListConferenceParticipants(string conferenceSid, bool? muted, Action callback) + { + ListConferenceParticipants(conferenceSid, muted, null, null, callback); + } + + /// + /// Retrieve a list of conference participants + /// + /// The Sid of the conference + /// Set to null to retrieve all, true to retrieve muted, false to retrieve unmuted + /// Which page number to start retrieving from + /// How many participants to retrieve + /// Method to call upon successful completion + public void ListConferenceParticipants(string conferenceSid, bool? muted, int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants"; + + request.AddParameter("ConferenceSid", conferenceSid); + + if (muted.HasValue) request.AddParameter("Muted", muted.Value); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Retrieve a single conference participant by their CallSid + /// + /// The Sid of the conference + /// The Sid of the call instance + /// Method to call upon successful completion + public void GetConferenceParticipant(string conferenceSid, string callSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}"; + request.RootElement = "Participant"; + + request.AddParameter("ConferenceSid", conferenceSid); + request.AddParameter("CallSid", callSid); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Change a participant of a conference to be muted + /// + /// The Sid of the conference + /// The Sid of the call to mute + /// Method to call upon successful completion + public void MuteConferenceParticipant(string conferenceSid, string callSid, Action callback) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}"; + request.RootElement = "Participant"; + + request.AddParameter("ConferenceSid", conferenceSid); + request.AddParameter("CallSid", callSid); + request.AddParameter("Muted", true); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Change a participant of a conference to be unmuted + /// + /// The Sid of the conference + /// The Sid of the call to unmute + /// Method to call upon successful completion + public void UnmuteConferenceParticipant(string conferenceSid, string callSid, Action callback) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}"; + request.RootElement = "Participant"; + + request.AddParameter("ConferenceSid", conferenceSid); + request.AddParameter("CallSid", callSid); + request.AddParameter("Muted", false); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Remove a caller from a conference + /// + /// The Sid of the conference + /// The Sid of the call to remove + /// Method to call upon successful completion + public void KickConferenceParticipant(string conferenceSid, string callSid, Action callback) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}"; + request.AddParameter("ConferenceSid", conferenceSid); + request.AddParameter("CallSid", callSid); + + ExecuteAsync(request, (response) => callback(response.StatusCode == System.Net.HttpStatusCode.NoContent)); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Core.Async.cs b/src/Twilio.Api.Silverlight/Core.Async.cs new file mode 100644 index 000000000..9aba3337a --- /dev/null +++ b/src/Twilio.Api.Silverlight/Core.Async.cs @@ -0,0 +1,57 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using System.Linq; +using RestSharp; + + +#if WINDOWS_PHONE +using System.Windows; +#endif + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Execute a manual REST request + /// + /// The type of object to create and populate with the returned data. + /// The RestRequest to execute (will use client credentials) + /// The callback function to execute when the async request completes + public void ExecuteAsync(RestRequest request, Action callback) where T : new() + { + _client.ExecuteAsync(request, (response) => + { + callback(response.Data); + }); + } + + /// + /// Execute a manual REST request + /// + /// The RestRequest to execute (will use client credentials) + /// The callback function to execute when the async request completes + public void ExecuteAsync(RestRequest request, Action callback) + { + _client.ExecuteAsync(request, (response) => + { + callback(response); + }); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/IncomingPhoneNumbers.Async.cs b/src/Twilio.Api.Silverlight/IncomingPhoneNumbers.Async.cs new file mode 100644 index 000000000..d0452e6b6 --- /dev/null +++ b/src/Twilio.Api.Silverlight/IncomingPhoneNumbers.Async.cs @@ -0,0 +1,166 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details for an incoming phone number. Makes a GET request to a IncomingPhoneNumber instance resource. + /// + /// The Sid of the number to retrieve + /// Method to call upon successful completion + public void GetIncomingPhoneNumber(string incomingPhoneNumberSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers/{IncomingPhoneNumberSid}"; + request.RootElement = "IncomingPhoneNumber"; + + request.AddParameter("IncomingPhoneNumberSid", incomingPhoneNumberSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// List all incoming phone numbers on current account. Makes a GET request to the IncomingPhoneNumber List resource. + /// + /// Method to call upon successful completion + public void ListIncomingPhoneNumbers(Action callback) + { + ListIncomingPhoneNumbers(null, null, null, null, callback); + } + + /// + /// List incoming phone numbers on current account with filters. Makes a GET request to the IncomingPhoneNumber List resource. + /// + /// Optional phone number to match + /// Optional friendly name to match + /// Page number to start retrieving results from + /// How many results to return + /// Method to call upon successful completion + public void ListIncomingPhoneNumbers(string phoneNumber, string friendlyName, int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers"; + + if (phoneNumber.HasValue()) request.AddParameter("PhoneNumber", phoneNumber); + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Purchase/provision a local phone number. Makes a POST request to the IncomingPhoneNumber List resource. + /// + /// Optional parameters to use when purchasing number + /// Method to call upon successful completion + public void AddIncomingPhoneNumber(PhoneNumberOptions options, Action callback) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers"; + request.RootElement = "IncomingPhoneNumber"; + + if (options.PhoneNumber.HasValue()) + { + request.AddParameter("PhoneNumber", options.PhoneNumber); + } + else + { + if (options.AreaCode.HasValue()) request.AddParameter("AreaCode", options.AreaCode); + } + + AddPhoneNumberOptionsToRequest(request, options); + AddSmsOptionsToRequest(request, options); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Update the settings of an incoming phone number. Makes a POST request to an IncomingPhoneNumber Instance resource. + /// + /// The Sid of the phone number to update + /// Which settings to update. Only properties with values set will be updated. + /// Method to call upon successful completion + public void UpdateIncomingPhoneNumber(string incomingPhoneNumberSid, PhoneNumberOptions options, Action callback) + { + Require.Argument("IncomingPhoneNumberSid", incomingPhoneNumberSid); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers/{IncomingPhoneNumberSid}"; + request.RootElement = "IncomingPhoneNumber"; + + request.AddParameter("IncomingPhoneNumberSid", incomingPhoneNumberSid, ParameterType.UrlSegment); + AddPhoneNumberOptionsToRequest(request, options); + AddSmsOptionsToRequest(request, options); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Remove (deprovision) a phone number from the current account. Makes a DELETE request to an IncomingPhoneNumber Instance resource. + /// + /// The Sid of the number to remove + /// Method to call upon successful completion + public void DeleteIncomingPhoneNumber(string incomingPhoneNumberSid, Action callback) + { + Require.Argument("IncomingPhoneNumberSid", incomingPhoneNumberSid); + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers/{IncomingPhoneNumberSid}"; + + request.AddParameter("IncomingPhoneNumberSid", incomingPhoneNumberSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => { callback(response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed); }); + } + + private void AddPhoneNumberOptionsToRequest(RestRequest request, PhoneNumberOptions options) + { + if (options.FriendlyName.HasValue()) + { + Validate.IsValidLength(options.FriendlyName, 64); + request.AddParameter("FriendlyName", options.FriendlyName); + } + // some check for null. in those cases an empty string is a valid value (to remove a URL assignment) + if (options.VoiceApplicationSid != null) request.AddParameter("VoiceApplicationSid", options.VoiceApplicationSid); + + if (options.VoiceUrl != null) request.AddParameter("VoiceUrl", options.VoiceUrl); + if (options.VoiceMethod.HasValue()) request.AddParameter("VoiceMethod", options.VoiceMethod.ToString()); + if (options.VoiceFallbackUrl != null) request.AddParameter("VoiceFallbackUrl", options.VoiceFallbackUrl); + if (options.VoiceFallbackMethod.HasValue()) request.AddParameter("VoiceFallbackMethod", options.VoiceFallbackMethod.ToString()); + if (options.VoiceCallerIdLookup.HasValue) request.AddParameter("VoiceCallerIdLookup", options.VoiceCallerIdLookup.Value); + if (options.StatusCallback.HasValue()) request.AddParameter("StatusCallbackUrl", options.StatusCallback); + if (options.StatusCallbackMethod.HasValue()) request.AddParameter("StatusCallbackMethod", options.StatusCallbackMethod.ToString()); + } + + private void AddSmsOptionsToRequest(RestRequest request, PhoneNumberOptions options) + { + // some check for null. in those cases an empty string is a valid value (to remove a URL assignment) + if (options.SmsApplicationSid != null) request.AddParameter("SmsApplicationSid", options.SmsApplicationSid); + if (options.SmsUrl != null) request.AddParameter("SmsUrl", options.SmsUrl); + if (options.SmsMethod.HasValue()) request.AddParameter("SmsMethod", options.SmsMethod.ToString()); + if (options.SmsFallbackUrl != null) request.AddParameter("SmsFallbackUrl", options.SmsFallbackUrl); + if (options.SmsFallbackMethod.HasValue()) request.AddParameter("SmsFallbackMethod", options.SmsFallbackMethod.ToString()); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Notifications.Aysnc.cs b/src/Twilio.Api.Silverlight/Notifications.Aysnc.cs new file mode 100644 index 000000000..a038ab3d9 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Notifications.Aysnc.cs @@ -0,0 +1,88 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details of a specific notification + /// + /// The Sid of the notification to retrieve + /// Method to call upon successful completion + public void GetNotification(string notificationSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Notifications/{NotificationSid}"; + request.RootElement = "Notification"; + + request.AddParameter("NotificationSid", notificationSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Returns a list of notifications generated for an account. The list includes paging information and is sorted by DateUpdated, with most recent notifications first. + /// + /// Method to call upon successful completion + public void ListNotifications(Action callback) + { + ListNotifications(null, null, null, null, callback); + } + + /// + /// Returns a filtered list of notifications generated for an account. The list includes paging information and is sorted by DateUpdated, with most recent notifications first. + /// + /// Only show notifications for this log, using the integer log values: 0 is ERROR, 1 is WARNING + /// Only show notifications for this date (in GMT) + /// The page number to start retrieving results from + /// How many notifications to return + /// Method to call upon successful completion + public void ListNotifications(int? log, DateTime? messageDate, int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Notifications"; + + if (log.HasValue) request.AddParameter("Log", log); + if (messageDate.HasValue) request.AddParameter("MessageDate", messageDate.Value.ToString("yyyy-MM-dd")); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Deletes a notification from your account + /// + /// The Sid of the notification to delete + /// Method to call upon successful completion + public void DeleteNotification(string notificationSid, Action callback) + { + Require.Argument("NotificationSid", notificationSid); + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/Notifications/{NotificationSid}"; + + request.AddParameter("NotificationSid", notificationSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => { callback(response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed); }); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/OutgoingCallerIds.Async.cs b/src/Twilio.Api.Silverlight/OutgoingCallerIds.Async.cs new file mode 100644 index 000000000..e8bc267a4 --- /dev/null +++ b/src/Twilio.Api.Silverlight/OutgoingCallerIds.Async.cs @@ -0,0 +1,134 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details for an existing validated Outgoing Caller ID entry + /// + /// The Sid of the entry to retrieve + /// Method to call upon successful completion + public void GetOutgoingCallerId(string outgoingCallerIdSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds/{OutgoingCallerIdSid}"; + request.RootElement = "OutgoingCallerId"; + request.AddParameter("OutgoingCallerIdSid", outgoingCallerIdSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Returns a list of validated outgoing caller IDs. The list includes paging information. + /// + /// Method to call upon successful completion + public void ListOutgoingCallerIds(Action callback) + { + ListOutgoingCallerIds(null, null, null, null, callback); + } + + /// + /// Returns a filtered list of validated outgoing caller IDs. The list includes paging information. + /// + /// If present, filter the list by the value provided + /// If present, filter the list by the value provided + /// If present, start the results from the specified page + /// If present, return the specified number of results, up to 1000 + /// Method to call upon successful completion + public void ListOutgoingCallerIds(string phoneNumber, string friendlyName, int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds"; + //request.RootElement = "OutgoingCallerIds"; + + if (phoneNumber.HasValue()) request.AddParameter("PhoneNumber", phoneNumber); + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Adds a new validated CallerID to your account. After making this request, Twilio will return to you a validation code and dial the phone number given to perform validation. The code returned must be entered via the phone before the CallerID will be added to your account. + /// + /// The phone number to verify. Should be formatted with a '+' and country code e.g., +16175551212 (E.164 format). Twilio will also accept unformatted US numbers e.g., (415) 555-1212, 415-555-1212. + /// A human readable description for the new caller ID with maximum length 64 characters. Defaults to a nicely formatted version of the number. + /// The number of seconds, between 0 and 60, to delay before initiating the validation call. Defaults to 0. + /// Method to call upon successful completion + public void AddOutgoingCallerId(string phoneNumber, string friendlyName, int? callDelay, Action callback) + { + Require.Argument("PhoneNumber", phoneNumber); + if (callDelay.HasValue) Validate.IsBetween(callDelay.Value, 0, 60); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds"; + request.RootElement = "ValidationRequest"; + request.AddParameter("PhoneNumber", phoneNumber); + + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (callDelay.HasValue) request.AddParameter("CallDelay", callDelay.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Update the FriendlyName associated with a validated outgoing caller ID entry + /// + /// The Sid of the outgoing caller ID entry + /// The name to update the FriendlyName to + /// Method to call upon successful completion + public void UpdateOutgoingCallerIdName(string outgoingCallerIdSid, string friendlyName, Action callback) + { + Require.Argument("OutgoingCallerIdSid", outgoingCallerIdSid); + Require.Argument("FriendlyName", friendlyName); + Validate.IsValidLength(friendlyName, 64); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds/{OutgoingCallerIdSid}"; + request.RootElement = "OutgoingCallerId"; + + request.AddParameter("OutgoingCallerIdSid", outgoingCallerIdSid, ParameterType.UrlSegment); + request.AddParameter("FriendlyName", friendlyName); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Remove a validated outgoing caller ID from the current account + /// + /// The Sid to remove + /// Method to call upon successful completion + public void DeleteOutgoingCallerId(string outgoingCallerIdSid, Action callback) + { + Require.Argument("OutgoingCallerIdSid", outgoingCallerIdSid); + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds/{OutgoingCallerIdSid}"; + + request.AddParameter("OutgoingCallerIdSid", outgoingCallerIdSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => { callback(response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed); }); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Properties/AssemblyInfo.cs b/src/Twilio.Api.Silverlight/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..7cbb95aa3 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Twilio.Api.Silverlight")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7cbe85be-1eec-4de2-9838-b5c6df4c55b0")] \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Recordings.Async.cs b/src/Twilio.Api.Silverlight/Recordings.Async.cs new file mode 100644 index 000000000..e021806d6 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Recordings.Async.cs @@ -0,0 +1,102 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns a list of Recordings, each representing a recording generated during the course of a phone call. The list includes paging information. + /// + /// Method to call upon successful completion + public void ListRecordings(Action callback) + { + ListRecordings(null, null, null, null, callback); + } + + /// + /// Returns a filtered list of Recordings, each representing a recording generated during the course of a phone call. The list includes paging information. + /// + /// (Optional) The CallSid to retrieve recordings for + /// (Optional) The date the recording was created (GMT) + /// The page to start retrieving results from + /// How many results to retrieve + /// Method to call upon successful completion + public void ListRecordings(string callSid, DateTime? dateCreated, int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Recordings"; + + if (callSid.HasValue()) request.AddParameter("CallSid", callSid); + if (dateCreated.HasValue) request.AddParameter("DateCreated", dateCreated.Value.ToString("yyyy-MM-dd")); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Retrieve the details for the specified recording instance + /// + /// The Sid of the recording to retrieve + /// Method to call upon successful completion + public void GetRecording(string recordingSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Recordings/{RecordingSid}.xml"; + request.RootElement = "Recording"; + + request.AddParameter("RecordingSid", recordingSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Delete the specified recording instance + /// + /// The Sid of the recording to delete + /// Method to call upon successful completion + public void DeleteRecording(string recordingSid, Action callback) + { + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/Recordings/{RecordingSid}.xml"; + request.RootElement = "Recording"; + + request.AddParameter("RecordingSid", recordingSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => { callback(response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed); }); + } + + /// + /// Retrieves the transcription text for the specified recording, if it was transcribed + /// + /// The Sid of the recording to retreive the transcription for + /// Method to call upon successful completion + public void GetRecordingText(string recordingSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Recordings/{RecordingSid}.txt"; + request.AddParameter("RecordingSid", recordingSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => callback(response.Content)); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Sandbox.Async.cs b/src/Twilio.Api.Silverlight/Sandbox.Async.cs new file mode 100644 index 000000000..708fc7146 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Sandbox.Async.cs @@ -0,0 +1,60 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns the Sandbox resource associated with the account identified by {YourAccountSid}. Twilio accounts upgraded prior to February 2010 may not have a Sandbox resource, and in this case you will receive a 404 (Not Found) response. + /// + /// Method to call upon successful completion + public void GetSandbox(Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Sandbox"; + + ExecuteAsync(request, callback); + } + + /// + /// Update the TwiML voice and SMS URLs associated with the sandbox number + /// + /// The URL to use for incoming calls to your sandbox number. + /// The HTTP method to use for incoming calls to your sandbox number. + /// The URL to use for incoming SMS text messages sent to your sandbox number. + /// The HTTP method to use for incoming text messages sent to your sandbox number. + /// Method to call upon successful completion + public void UpdateSandbox(string voiceUrl, string voiceMethod, string smsUrl, string smsMethod, Action callback) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Sandbox"; + + request.AddParameter("VoiceUrl", voiceUrl); + request.AddParameter("VoiceMethod", voiceMethod); + request.AddParameter("SmsUrl", smsUrl); + request.AddParameter("SmsMethod", smsMethod); + + ExecuteAsync(request, callback); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Sms.Async.cs b/src/Twilio.Api.Silverlight/Sms.Async.cs new file mode 100644 index 000000000..bd4cb196f --- /dev/null +++ b/src/Twilio.Api.Silverlight/Sms.Async.cs @@ -0,0 +1,175 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details for a specific SMS message instance + /// + /// The Sid of the message to retrieve + /// Method to call upon successful completion + public void GetSmsMessage(string smsMessageSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/Messages/{SMSMessageSid}"; + request.RootElement = "SMSMessage"; + request.AddUrlSegment("SMSMessageSid", smsMessageSid); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Returns a list of SMS messages. The list includes paging information and is sorted by DateSent, with most recent messages first. + /// + /// Method to call upon successful completion + public void ListSmsMessages(Action callback) + { + ListSmsMessages(null, null, null, null, null, callback); + } + + /// + /// Returns a filtered list of SMS messages. The list includes paging information and is sorted by DateSent, with most recent messages first. + /// + /// (Optional) The phone number of the message recipient + /// (Optional) The phone number of the message sender + /// (Optional) The date the message was sent (GMT) + /// (Optional) The page to start retrieving results from + /// (Optional) The number of results to retrieve + /// Method to call upon successful completion + public void ListSmsMessages(string to, string from, DateTime? dateSent, int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/Messages"; + + if (to.HasValue()) request.AddParameter("To", to); + if (from.HasValue()) request.AddParameter("From", from); + if (dateSent.HasValue) request.AddParameter("DateSent", dateSent.Value.ToString("yyyy-MM-dd")); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Send a new SMS message to the specified recipients + /// + /// The phone number to send the message from. Must be a Twilio-provided or ported local (not toll-free) number. Validated outgoing caller IDs cannot be used. + /// The phone number to send the message to. If using the Sandbox, this number must be a validated outgoing caller ID + /// The message to send. Must be 160 characters or less. + /// Method to call upon successful completion + public void SendSmsMessage(string from, string to, string body, Action callback) + { + SendSmsMessage(from, to, body, null, callback); + } + + /// + /// Send a new SMS message to the specified recipients + /// + /// The phone number to send the message from. Must be a Twilio-provided or ported local (not toll-free) number. Validated outgoing caller IDs cannot be used. + /// The phone number to send the message to. If using the Sandbox, this number must be a validated outgoing caller ID + /// The message to send. Must be 160 characters or less. + /// A URL that Twilio will POST to when your message is processed. Twilio will POST the SmsSid as well as SmsStatus=sent or SmsStatus=failed + /// Method to call upon successful completion + public void SendSmsMessage(string from, string to, string body, string statusCallback, Action callback) + { + Validate.IsValidLength(body, 160); + Require.Argument("from", from); + Require.Argument("to", to); + Require.Argument("body", body); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/SMS/Messages"; + request.AddParameter("From", from); + request.AddParameter("To", to); + request.AddParameter("Body", body); + if (statusCallback.HasValue()) request.AddParameter("StatusCallback", statusCallback); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Retrieve the details for a specific ShortCode instance. + /// Makes a GET request to a ShortCode Instance resource. + /// + /// The Sid of the ShortCode resource to return + /// Method to call upon successful completion + public void GetShortCode(string shortCodeSid, Action callback) + { + Require.Argument("shortCodeSid", shortCodeSid); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/ShortCodes/{ShortCodeSid}"; + request.AddParameter("ShortCodeSid", shortCodeSid); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Tries to update the shortcode's properties, and returns the updated resource representation if successful. + /// Makes a POST request to the ShortCode instance resource. + /// + /// The Sid of the ShortCode instance to update + /// A human readable description of the short code, with maximum length 64 characters. + /// SMSs to this short code will start a new TwiML session with this API version. + /// The URL that Twilio should request when somebody sends an SMS to the short code. + /// The HTTP method that should be used to request the SmsUrl. Either GET or POST. + /// A URL that Twilio will request if an error occurs requesting or executing the TwiML at the SmsUrl. + /// The HTTP method that should be used to request the SmsFallbackUrl. Either GET or POST. + /// Method to call upon successful completion + public void UpdateShortCode(string shortCodeSid, string friendlyName, string apiVersion, string smsUrl, string smsMethod, string smsFallbackUrl, string smsFallbackMethod, Action callback) + { + Require.Argument("shortCodeSid", shortCodeSid); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/ShortCodes/{ShortCodeSid}"; + request.AddParameter("ShortCodeSid", shortCodeSid); + + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (apiVersion.HasValue()) request.AddParameter("ApiVersion", apiVersion); + if (smsUrl.HasValue()) request.AddParameter("SmsUrl", smsUrl); + if (smsMethod.HasValue()) request.AddParameter("SmsMethod", smsMethod); + if (smsFallbackUrl.HasValue()) request.AddParameter("SmsFallbackUrl", smsFallbackUrl); + if (smsFallbackMethod.HasValue()) request.AddParameter("SmsFallbackMethod", smsFallbackMethod); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Returns a list of ShortCode resource representations, each representing a short code within your account. + /// + /// Only show the ShortCode resources that match this pattern. You can specify partial numbers and use '*' as a wildcard for any digit. + /// Only show the ShortCode resources with friendly names that exactly match this name. + /// Method to call upon successful completion + public void ListShortCodes(string shortCode, string friendlyName, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/ShortCodes}"; + + if (shortCode.HasValue()) request.AddParameter("ShortCode", shortCode); + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + + ExecuteAsync(request, (response) => callback(response)); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Transcriptions.Async.cs b/src/Twilio.Api.Silverlight/Transcriptions.Async.cs new file mode 100644 index 000000000..3ce1763b2 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Transcriptions.Async.cs @@ -0,0 +1,99 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns a set of Transcriptions that includes paging information, sorted by 'DateUpdated', with most recent transcripts first. + /// + /// The method to call upon the completion of the request + public void ListTranscriptions(Action callback) + { + ListTranscriptions(null, null, null, callback); + } + + /// + /// Returns a paged set of Transcriptions that includes paging information, sorted by 'DateUpdated', with most recent transcripts first. + /// + /// The page to start retrieving results from + /// The number of results to retrieve + /// The method to call upon the completion of the request + public void ListTranscriptions(int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Transcriptions"; + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Returns a set of Transcriptions for a specific recording that includes paging information, sorted by 'DateUpdated', with most recent transcripts first. + /// + /// The Sid of the recording to retrieve transcriptions for + /// The page to start retrieving results from + /// The number of results to retrieve + /// Method to call upon completion of request + public void ListTranscriptions(string recordingSid, int? pageNumber, int? count, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Recordings/{RecordingSid}/Transcriptions"; + request.AddUrlSegment("RecordingSid", recordingSid); + + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Retrieve the details of a single transcription + /// + /// The Sid of the transcription to retrieve + /// Method to call upon completion of request + public void GetTranscription(string transcriptionSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Transcriptions/{TranscriptionSid}"; + request.RootElement = "Transcription"; + request.AddParameter("TranscriptionSid", transcriptionSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => callback(response)); + } + + /// + /// Retrieve the text of a single transcription + /// + /// The Sid of the transcription to retrieve + /// Method to call upon completion of the request + public void GetTranscriptionText(string transcriptionSid, Action callback) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Transcriptions/{TranscriptionSid}.txt"; + request.AddParameter("TranscriptionSid", transcriptionSid, ParameterType.UrlSegment); + + ExecuteAsync(request, (response) => callback(response.Content)); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/Twilio.Api.Silverlight.csproj b/src/Twilio.Api.Silverlight/Twilio.Api.Silverlight.csproj new file mode 100644 index 000000000..4abd458c9 --- /dev/null +++ b/src/Twilio.Api.Silverlight/Twilio.Api.Silverlight.csproj @@ -0,0 +1,224 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD} + {A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Twilio.Silverlight + Twilio.Api.Silverlight + Silverlight + v4.0 + $(TargetFrameworkVersion) + false + true + true + + + + v3.5 + + + true + full + false + Bin\Debug + DEBUG;TRACE;SILVERLIGHT + true + true + prompt + 4 + Bin\Debug\Twilio.Api.Silverlight.xml + + + pdbonly + true + Bin\Release + TRACE;SILVERLIGHT + true + true + prompt + 4 + Bin\Release\Twilio.Api.Silverlight.xml + + + + + False + ..\packages\Newtonsoft.Json.4.0.2\lib\sl4\Newtonsoft.Json.Silverlight.dll + + + False + ..\packages\RestSharp.101.3\lib\sl4\RestSharp.Silverlight.dll + + + + + + + + + + + Core.cs + + + Model\Account.cs + + + Model\Application.cs + + + Model\ApplicationOptions.cs + + + Model\ApplicationResult.cs + + + Model\AvailablePhoneNumber.cs + + + Model\AvailablePhoneNumberListRequest.cs + + + Model\AvailablePhoneNumberResult.cs + + + Model\Call.cs + + + Model\CallListRequest.cs + + + Model\CallOptions.cs + + + Model\CallResult.cs + + + Model\ComparisonType.cs + + + Model\Conference.cs + + + Model\ConferenceListRequest.cs + + + Model\ConferenceResult.cs + + + Model\DeleteStatus.cs + + + Model\HangupStyle.cs + + + Model\IncomingPhoneNumber.cs + + + Model\IncomingPhoneNumberResult.cs + + + Model\Notification.cs + + + Model\NotificationResult.cs + + + Model\OutgoingCallerId.cs + + + Model\OutgoingCallerIdResult.cs + + + Model\Participant.cs + + + Model\ParticipantResult.cs + + + Model\PhoneNumberOptions.cs + + + Model\Recording.cs + + + Model\RecordingResult.cs + + + Model\RestException.cs + + + Model\Sandbox.cs + + + Model\SmsMessage.cs + + + Model\SmsMessageResult.cs + + + Model\SmsShortCode.cs + + + Model\SmsShortCodeResult.cs + + + Model\Transcription.cs + + + Model\TranscriptionResult.cs + + + Model\TwilioBase.cs + + + Model\TwilioListBase.cs + + + Model\ValidationRequest.cs + + + SharedAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Twilio.Api.Silverlight/packages.config b/src/Twilio.Api.Silverlight/packages.config new file mode 100644 index 000000000..ce8b75be1 --- /dev/null +++ b/src/Twilio.Api.Silverlight/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/Twilio.Api.WindowsPhone/Properties/AssemblyInfo.cs b/src/Twilio.Api.WindowsPhone/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..406fc36f6 --- /dev/null +++ b/src/Twilio.Api.WindowsPhone/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Twilio.Api.WindowsPhone")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2ba020cf-06c2-4e96-a83d-1dc261156a25")] \ No newline at end of file diff --git a/src/Twilio.Api.WindowsPhone/Twilio.Api.WindowsPhone.csproj b/src/Twilio.Api.WindowsPhone/Twilio.Api.WindowsPhone.csproj new file mode 100644 index 000000000..1019fe037 --- /dev/null +++ b/src/Twilio.Api.WindowsPhone/Twilio.Api.WindowsPhone.csproj @@ -0,0 +1,232 @@ + + + + Debug + AnyCPU + 10.0.20506 + 2.0 + {21E25E45-A334-4178-BD5C-5B875A2911FD} + {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + Twilio.WindowsPhone + Twilio.Api.WindowsPhone + v4.0 + $(TargetFrameworkVersion) + WindowsPhone + Silverlight + false + true + true + + + true + full + false + Bin\Debug + TRACE;DEBUG;WINDOWS_PHONE + true + true + prompt + 4 + Bin\Debug\Twilio.Api.WindowsPhone.xml + + + pdbonly + true + Bin\Release + TRACE;WINDOWS_PHONE + true + true + prompt + 4 + Bin\Release\Twilio.Api.WindowsPhone.xml + + + + + ..\packages\Newtonsoft.Json.4.0.2\lib\sl3-wp\Newtonsoft.Json.WindowsPhone.dll + + + False + ..\packages\RestSharp.101.3\lib\sl3-wp\RestSharp.WindowsPhone.dll + + + + + + + + + + Sandbox.Async.cs + + + Core.cs + + + Model\Account.cs + + + Model\Application.cs + + + Model\ApplicationOptions.cs + + + Model\ApplicationResult.cs + + + Model\AvailablePhoneNumber.cs + + + Model\AvailablePhoneNumberListRequest.cs + + + Model\AvailablePhoneNumberResult.cs + + + Model\Call.cs + + + Model\CallListRequest.cs + + + Model\CallOptions.cs + + + Model\CallResult.cs + + + Model\ComparisonType.cs + + + Model\Conference.cs + + + Model\ConferenceListRequest.cs + + + Model\ConferenceResult.cs + + + Model\DeleteStatus.cs + + + Model\HangupStyle.cs + + + Model\IncomingPhoneNumber.cs + + + Model\IncomingPhoneNumberResult.cs + + + Model\Notification.cs + + + Model\NotificationResult.cs + + + Model\OutgoingCallerId.cs + + + Model\OutgoingCallerIdResult.cs + + + Model\Participant.cs + + + Model\ParticipantResult.cs + + + Model\PhoneNumberOptions.cs + + + Model\Recording.cs + + + Model\RecordingResult.cs + + + Model\RestException.cs + + + Model\Sandbox.cs + + + Model\SmsMessage.cs + + + Model\SmsMessageResult.cs + + + Model\SmsShortCode.cs + + + Model\SmsShortCodeResult.cs + + + Model\Transcription.cs + + + Model\TranscriptionResult.cs + + + Model\TwilioBase.cs + + + Model\TwilioListBase.cs + + + Model\ValidationRequest.cs + + + Accounts.Async.cs + + + Calls.Async.cs + + + Conference.Async.cs + + + Core.Async.cs + + + IncomingPhoneNumbers.Async.cs + + + Notifications.Aysnc.cs + + + OutgoingCallerIds.Async.cs + + + Recordings.Async.cs + + + Sms.Async.cs + + + Transcriptions.Async.cs + + + SharedAssemblyInfo.cs + + + + + + + + + + + \ No newline at end of file diff --git a/src/Twilio.Api.WindowsPhone/packages.config b/src/Twilio.Api.WindowsPhone/packages.config new file mode 100644 index 000000000..ce8b75be1 --- /dev/null +++ b/src/Twilio.Api.WindowsPhone/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/Twilio.Api/Accounts.cs b/src/Twilio.Api/Accounts.cs new file mode 100644 index 000000000..ba8fc3c0c --- /dev/null +++ b/src/Twilio.Api/Accounts.cs @@ -0,0 +1,91 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using RestSharp; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the account details for the currently authenticated account. Makes a GET request to an Account Instance resource. + /// + public Account GetAccount() + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}"; + request.RootElement = "Account"; + + return Execute(request); + } + + /// + /// Retrieve the account details for a subaccount. Makes a GET request to an Account Instance resource. + /// + /// The Sid of the subaccount to retrieve + public Account GetAccount(string accountSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}"; + request.RootElement = "Account"; + + request.AddUrlSegment("AccountSid", accountSid); + + return Execute(request); + } + + /// + /// List all subaccounts created for the authenticated account. Makes a GET request to the Account List resource. + /// + public AccountResult ListSubAccounts() + { + var request = new RestRequest(); + request.Resource = "Accounts"; + + return Execute(request); + } + + /// + /// Creates a new subaccount under the authenticated account. Makes a POST request to the Account List resource. + /// + /// Name associated with this account for your own reference (can be empty string) + public Account CreateSubAccount(string friendlyName) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts"; + request.RootElement = "Account"; + + request.AddParameter("FriendlyName", friendlyName); + + return Execute(request); + } + + /// + /// Update the friendly name associated with the currently authenticated account. Makes a POST request to an Account Instance resource. + /// + /// Name to use when updating + public Account UpdateAccountName(string friendlyName) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}"; + request.RootElement = "Account"; + request.AddParameter("FriendlyName", friendlyName); + + return Execute(request); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Applications.cs b/src/Twilio.Api/Applications.cs new file mode 100644 index 000000000..db200fd6e --- /dev/null +++ b/src/Twilio.Api/Applications.cs @@ -0,0 +1,151 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details for an application instance. Makes a GET request to an Application Instance resource. + /// + /// The Sid of the application to retrieve + public Application GetApplication(string applicationSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Applications/{ApplicationSid}"; + request.RootElement = "Application"; + + request.AddUrlSegment("ApplicationSid", applicationSid); + + return Execute(request); + } + + /// + /// List applications on current account + /// + public ApplicationResult ListApplications() + { + return ListApplications(null, null, null); + } + + /// + /// List applications on current account with filters + /// + /// Optional friendly name to match + /// Page number to start retrieving results from + /// How many results to return + public ApplicationResult ListApplications(string friendlyName, int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Applications"; + + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Create a new application + /// + /// The friendly name to name the application + /// Optional parameters to use when purchasing number + public Application AddApplication(string friendlyName, ApplicationOptions options) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Applications"; + request.RootElement = "Application"; + + Require.Argument("FriendlyName", friendlyName); + Validate.IsValidLength(friendlyName, 64); + request.AddParameter("FriendlyName", friendlyName); + + // some check for null. in those cases an empty string is a valid value (to remove a URL assignment) + if (options != null) + { + if (options.VoiceUrl != null) request.AddParameter("VoiceUrl", options.VoiceUrl); + if (options.VoiceMethod.HasValue()) request.AddParameter("VoiceMethod", options.VoiceMethod.ToString()); + if (options.VoiceFallbackUrl != null) request.AddParameter("VoiceFallbackUrl", options.VoiceFallbackUrl); + if (options.VoiceFallbackMethod.HasValue()) request.AddParameter("VoiceFallbackMethod", options.VoiceFallbackMethod.ToString()); + if (options.VoiceCallerIdLookup.HasValue) request.AddParameter("VoiceCallerIdLookup", options.VoiceCallerIdLookup.Value); + if (options.StatusCallback.HasValue()) request.AddParameter("StatusCallbackUrl", options.StatusCallback); + if (options.StatusCallbackMethod.HasValue()) request.AddParameter("StatusCallbackMethod", options.StatusCallbackMethod.ToString()); + if (options.SmsUrl != null) request.AddParameter("SmsUrl", options.SmsUrl); + if (options.SmsMethod.HasValue()) request.AddParameter("SmsMethod", options.SmsMethod.ToString()); + if (options.SmsFallbackUrl != null) request.AddParameter("SmsFallbackUrl", options.SmsFallbackUrl); + if (options.SmsFallbackMethod.HasValue()) request.AddParameter("SmsFallbackMethod", options.SmsFallbackMethod.ToString()); + } + + return Execute(request); + } + + /// + /// Tries to update the application's properties, and returns the updated resource representation if successful. + /// + /// The Sid of the application to update + /// The friendly name to rename the application to (optional, null to leave as-is) + /// Which settings to update. Only properties with values set will be updated. + public Application UpdateApplication(string applicationSid, string friendlyName, ApplicationOptions options) + { + Require.Argument("ApplicationSid", applicationSid); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Applications/{ApplicationSid}"; + request.AddUrlSegment("ApplicationSid", applicationSid); + request.RootElement = "Application"; + + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (options != null) + { + if (options.VoiceUrl != null) request.AddParameter("VoiceUrl", options.VoiceUrl); + if (options.VoiceMethod.HasValue()) request.AddParameter("VoiceMethod", options.VoiceMethod.ToString()); + if (options.VoiceFallbackUrl != null) request.AddParameter("VoiceFallbackUrl", options.VoiceFallbackUrl); + if (options.VoiceFallbackMethod.HasValue()) request.AddParameter("VoiceFallbackMethod", options.VoiceFallbackMethod.ToString()); + if (options.VoiceCallerIdLookup.HasValue) request.AddParameter("VoiceCallerIdLookup", options.VoiceCallerIdLookup.Value); + if (options.StatusCallback.HasValue()) request.AddParameter("StatusCallbackUrl", options.StatusCallback); + if (options.StatusCallbackMethod.HasValue()) request.AddParameter("StatusCallbackMethod", options.StatusCallbackMethod.ToString()); + if (options.SmsUrl != null) request.AddParameter("SmsUrl", options.SmsUrl); + if (options.SmsMethod.HasValue()) request.AddParameter("SmsMethod", options.SmsMethod.ToString()); + if (options.SmsFallbackUrl != null) request.AddParameter("SmsFallbackUrl", options.SmsFallbackUrl); + if (options.SmsFallbackMethod.HasValue()) request.AddParameter("SmsFallbackMethod", options.SmsFallbackMethod.ToString()); + } + + return Execute(request); + } + + /// + /// Delete this application. If this application's sid is assigned to any IncomingPhoneNumber resources as a VoiceApplicationSid or SmsApplicationSid it will be removed. + /// + /// The Sid of the number to remove + public DeleteStatus DeleteApplication(string applicationSid) + { + Require.Argument("ApplicationSid", applicationSid); + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/Applications/{ApplicationSid}"; + + request.AddUrlSegment("ApplicationSid", applicationSid); + + var response = Execute(request); + return response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed; + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/AvailablePhoneNumbers.cs b/src/Twilio.Api/AvailablePhoneNumbers.cs new file mode 100644 index 000000000..98887b4bb --- /dev/null +++ b/src/Twilio.Api/AvailablePhoneNumbers.cs @@ -0,0 +1,77 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using RestSharp; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Search available local phone numbers. Makes a GET request to the AvailablePhoneNumber List resource. + /// + /// Two-character ISO country code (US or CA) + /// Search filter options. Only properties with values set will be used. + public AvailablePhoneNumberResult ListAvailableLocalPhoneNumbers(string isoCountryCode, AvailablePhoneNumberListRequest options) + { + Require.Argument("isoCountryCode", isoCountryCode); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/AvailablePhoneNumbers/{IsoCountryCode}/Local"; + request.AddUrlSegment("IsoCountryCode", isoCountryCode); + + AddNumberSearchParameters(options, request); + + return Execute(request); + } + + /// + /// Search available toll-free phone numbers. Makes a GET request to the AvailablePhoneNumber List resource. + /// + /// Two-character ISO country code (US or CA) + public AvailablePhoneNumberResult ListAvailableTollFreePhoneNumbers(string isoCountryCode) + { + Require.Argument("isoCountryCode", isoCountryCode); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/AvailablePhoneNumbers/{IsoCountryCode}/TollFree"; + request.AddUrlSegment("IsoCountryCode", isoCountryCode); + + return Execute(request); + } + + /// + /// Search available toll-free phone numbers. Makes a GET request to the AvailablePhoneNumber List resource. + /// + /// Two-character ISO country code (US or CA) + /// Value to use when filtering search. Accepts numbers or characters. + public AvailablePhoneNumberResult ListAvailableTollFreePhoneNumbers(string isoCountryCode, string contains) + { + Require.Argument("isoCountryCode", isoCountryCode); + Require.Argument("contains", contains); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/AvailablePhoneNumbers/{IsoCountryCode}/TollFree"; + request.AddUrlSegment("IsoCountryCode", isoCountryCode); + + request.AddParameter("Contains", contains); + + return Execute(request); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Calls.cs b/src/Twilio.Api/Calls.cs new file mode 100644 index 000000000..524001193 --- /dev/null +++ b/src/Twilio.Api/Calls.cs @@ -0,0 +1,158 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns a paged list of phone calls made to and from the account. + /// Sorted by DateUpdated with most-recent calls first. + /// Makes a GET request to the Calls List resource. + /// + public CallResult ListCalls() + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Calls"; + + return Execute(request); + } + + /// + /// Returns a paged list of phone calls made to and from the account. + /// Sorted by DateUpdated with most-recent calls first. + /// Makes a GET request to the Calls List resource. + /// + /// List filter options. If an property is set the list will be filtered by that value. + public CallResult ListCalls(CallListRequest options) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Calls"; + + AddCallListOptions(options, request); + + return Execute(request); + } + + /// + /// Returns the single Call resource identified by {CallSid} + /// Makes a GET request to a Call Instance resource. + /// + /// The Sid of the Call resource to retrieve + public Call GetCall(string callSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Calls/{CallSid}"; + request.RootElement = "Call"; + + request.AddParameter("CallSid", callSid, ParameterType.UrlSegment); + + return Execute(request); + } + + /// + /// Initiates a new phone call. Makes a POST request to the Calls List resource. + /// + /// The phone number to use as the caller id. Format with a '+' and country code e.g., +16175551212 (E.164 format). Must be a Twilio number or a valid outgoing caller id for your account. + /// The number to call formatted with a '+' and country code e.g., +16175551212 (E.164 format). Twilio will also accept unformatted US numbers e.g., (415) 555-1212, 415-555-1212. + /// The fully qualified URL that should be consulted when the call connects. Just like when you set a URL for your inbound calls. URL should return TwiML. + public Call InitiateOutboundCall(string from, string to, string url) + { + return InitiateOutboundCall(from, to, url, string.Empty); + } + + /// + /// Initiates a new phone call. Makes a POST request to the Calls List resource. + /// + /// The phone number to use as the caller id. Format with a '+' and country code e.g., +16175551212 (E.164 format). Must be a Twilio number or a valid outgoing caller id for your account. + /// The number to call formatted with a '+' and country code e.g., +16175551212 (E.164 format). Twilio will also accept unformatted US numbers e.g., (415) 555-1212, 415-555-1212. + /// The fully qualified URL that should be consulted when the call connects. Just like when you set a URL for your inbound calls. URL should return TwiML. + /// A URL that Twilio will request when the call ends to notify your app. + public Call InitiateOutboundCall(string from, string to, string url, string statusCallback) + { + return InitiateOutboundCall(new CallOptions + { + From = from, + To = to, + Url = url, + StatusCallback = statusCallback + }); + } + + /// + /// Initiates a new phone call. Makes a POST request to the Calls List resource. + /// + /// Call settings. Only properties with values set will be used. + public Call InitiateOutboundCall(CallOptions options) + { + Require.Argument("From", options.From); + Require.Argument("To", options.To); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Calls"; + request.RootElement = "Call"; + + AddCallOptions(options, request); + + return Execute(request); + } + + /// + /// Hangs up a call in progress. Makes a POST request to a Call Instance resource. + /// + /// The Sid of the call to hang up. + /// 'Canceled' will attempt to hangup calls that are queued or ringing but not affect calls already in progress. 'Completed' will attempt to hang up a call even if it's already in progress. + public Call HangupCall(string callSid, HangupStyle style) + { + Require.Argument("CallSid", callSid); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Calls/{CallSid}"; + request.RootElement = "Call"; + + request.AddUrlSegment("CallSid", callSid); + request.AddParameter("Status", style.ToString().ToLower()); + + return Execute(request); + } + + /// + /// Redirect a call in progress to a new TwiML URL. Makes a POST request to a Call Instance resource. + /// + /// The Sid of the call to redirect + /// The URL to redirect the call to. + /// The HTTP method to use when requesting the redirectUrl + public Call RedirectCall(string callSid, string redirectUrl, string redirectMethod) + { + Require.Argument("CallSid", callSid); + Require.Argument("Url", redirectUrl); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Calls/{CallSid}"; + request.RootElement = "Call"; + + request.AddParameter("CallSid", callSid, ParameterType.UrlSegment); + request.AddParameter("Url", redirectUrl); + if (redirectMethod.HasValue()) request.AddParameter("Method", redirectMethod); + + return Execute(request); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Conference.cs b/src/Twilio.Api/Conference.cs new file mode 100644 index 000000000..447e7dfd0 --- /dev/null +++ b/src/Twilio.Api/Conference.cs @@ -0,0 +1,168 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using RestSharp; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns a list of conferences within an account. + /// The list includes paging information and is sorted by DateUpdated, with most recent conferences first. + /// Makes a GET request to the Conferences List resource. + /// + public ConferenceResult ListConferences() + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences"; + + return Execute(request); + } + + /// + /// Returns a list of conferences within an account. + /// The list includes paging information and is sorted by DateUpdated, with most recent conferences first. + /// Makes a POST request to the Conferences List resource. + /// + /// List filter options. Only properties with values are included in request. + public ConferenceResult ListConferences(ConferenceListRequest options) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences"; + + AddConferenceListOptions(options, request); + + return Execute(request); + } + + /// + /// Retrieve details for specific conference. Makes a GET request to a Conference Instance resource. + /// + /// The Sid of the conference to retrieve + public Conference GetConference(string conferenceSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}"; + request.RootElement = "Conference"; + + request.AddParameter("ConferenceSid", conferenceSid); + + return Execute(request); + } + + /// + /// Retrieve a list of conference participants. Makes a GET request to a Conference Participants List resource. + /// + /// The Sid of the conference + /// Set to null to retrieve all, true to retrieve muted, false to retrieve unmuted + public ParticipantResult ListConferenceParticipants(string conferenceSid, bool? muted) + { + return ListConferenceParticipants(conferenceSid, muted, null, null); + } + + /// + /// Retrieve a list of conference participants. Makes a GET request to a Conference Participants List resource. + /// + /// The Sid of the conference + /// Set to null to retrieve all, true to retrieve muted, false to retrieve unmuted + /// Which page number to start retrieving from + /// How many participants to retrieve + public ParticipantResult ListConferenceParticipants(string conferenceSid, bool? muted, int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants"; + + request.AddParameter("ConferenceSid", conferenceSid); + + if (muted.HasValue) request.AddParameter("Muted", muted.Value); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Retrieve a single conference participant by their CallSid. Makes a GET request to a Conference Participant Instance resource. + /// + /// The Sid of the conference + /// The Sid of the call instance + public Participant GetConferenceParticipant(string conferenceSid, string callSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}"; + request.RootElement = "Participant"; + + request.AddParameter("ConferenceSid", conferenceSid); + request.AddParameter("CallSid", callSid); + + return Execute(request); + } + + /// + /// Change a participant of a conference to be muted. Makes a GET request to a Conference Participant Instance resource. + /// + /// The Sid of the conference + /// The Sid of the call to mute + public Participant MuteConferenceParticipant(string conferenceSid, string callSid) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}"; + request.RootElement = "Participant"; + + request.AddParameter("ConferenceSid", conferenceSid); + request.AddParameter("CallSid", callSid); + request.AddParameter("Muted", true); + + return Execute(request); + } + + /// + /// Change a participant of a conference to be unmuted. Makes a GET request to a Conference Participant Instance resource. + /// + /// The Sid of the conference + /// The Sid of the call to unmute + public Participant UnmuteConferenceParticipant(string conferenceSid, string callSid) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}"; + request.RootElement = "Participant"; + + request.AddParameter("ConferenceSid", conferenceSid); + request.AddParameter("CallSid", callSid); + request.AddParameter("Muted", false); + + return Execute(request); + } + + /// + /// Remove a caller from a conference. Makes a DELETE request to a Conference Participant Instance resource. + /// + /// The Sid of the conference + /// The Sid of the call to remove + public bool KickConferenceParticipant(string conferenceSid, string callSid) + { + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/Conferences/{ConferenceSid}/Participants/{CallSid}"; + request.AddParameter("ConferenceSid", conferenceSid); + request.AddParameter("CallSid", callSid); + + var response = Execute(request); + return response.StatusCode == System.Net.HttpStatusCode.NoContent; + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Core.cs b/src/Twilio.Api/Core.cs new file mode 100644 index 000000000..5cb15b393 --- /dev/null +++ b/src/Twilio.Api/Core.cs @@ -0,0 +1,100 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using RestSharp; + + +namespace Twilio +{ + /// + /// REST API wrapper. + /// + public partial class TwilioRestClient + { + /// + /// Twilio API version to use when making requests + /// + public string ApiVersion { get; set; } + /// + /// Base URL of API (defaults to https://api.twilio.com) + /// + public string BaseUrl { get; set; } + private string AccountSid { get; set; } + private string AuthToken { get; set; } + + private RestClient _client; + + /// + /// Initializes a new client with the specified credentials. + /// + /// The AccountSid to authenticate with + /// The AuthToken to authenticate with + public TwilioRestClient(string accountSid, string authToken) + { + ApiVersion = "2010-04-01"; + BaseUrl = "https://api.twilio.com/"; + AccountSid = accountSid; + AuthToken = authToken; + + _client = new RestClient(); + _client.Authenticator = new HttpBasicAuthenticator(AccountSid, AuthToken); + _client.BaseUrl = string.Format("{0}{1}", BaseUrl, ApiVersion); + + // if acting on a subaccount, use request.AddUrlSegment("AccountSid", "value") + // to override for that request. + _client.AddDefaultUrlSegment("AccountSid", AccountSid); + } + +#if FRAMEWORK + /// + /// Execute a manual REST request + /// + /// The type of object to create and populate with the returned data. + /// The RestRequest to execute (will use client credentials) + public T Execute(RestRequest request) where T : new() + { + var response = _client.Execute(request); + return response.Data; + } + + /// + /// Execute a manual REST request + /// + /// The RestRequest to execute (will use client credentials) + public RestResponse Execute(RestRequest request) + { + return _client.Execute(request); + } +#endif + + private string GetParameterNameWithEquality(ComparisonType? comparisonType, string parameterName) + { + if (comparisonType.HasValue) + { + switch (comparisonType) + { + case ComparisonType.GreaterThanOrEqualTo: + parameterName += ">"; + break; + case ComparisonType.LessThanOrEqualTo: + parameterName += "<"; + break; + } + } + return parameterName; + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/IncomingPhoneNumbers.cs b/src/Twilio.Api/IncomingPhoneNumbers.cs new file mode 100644 index 000000000..21911374a --- /dev/null +++ b/src/Twilio.Api/IncomingPhoneNumbers.cs @@ -0,0 +1,131 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details for an incoming phone number + /// + /// The Sid of the number to retrieve + public IncomingPhoneNumber GetIncomingPhoneNumber(string incomingPhoneNumberSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers/{IncomingPhoneNumberSid}"; + request.RootElement = "IncomingPhoneNumber"; + + request.AddUrlSegment("IncomingPhoneNumberSid", incomingPhoneNumberSid); + + return Execute(request); + } + + /// + /// List all incoming phone numbers on current account + /// + public IncomingPhoneNumberResult ListIncomingPhoneNumbers() + { + return ListIncomingPhoneNumbers(null, null, null, null); + } + + /// + /// List incoming phone numbers on current account with filters + /// + /// Optional phone number to match + /// Optional friendly name to match + /// Page number to start retrieving results from + /// How many results to return + public IncomingPhoneNumberResult ListIncomingPhoneNumbers(string phoneNumber, string friendlyName, int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers"; + + if (phoneNumber.HasValue()) request.AddParameter("PhoneNumber", phoneNumber); + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Purchase/provision a local phone number + /// + /// Optional parameters to use when purchasing number + public IncomingPhoneNumber AddIncomingPhoneNumber(PhoneNumberOptions options) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers"; + request.RootElement = "IncomingPhoneNumber"; + + if (options.PhoneNumber.HasValue()) + { + request.AddParameter("PhoneNumber", options.PhoneNumber); + } + else + { + if (options.AreaCode.HasValue()) request.AddParameter("AreaCode", options.AreaCode); + } + + AddPhoneNumberOptionsToRequest(request, options); + AddSmsOptionsToRequest(request, options); + + return Execute(request); + } + + /// + /// Update the settings of an incoming phone number + /// + /// The Sid of the phone number to update + /// Which settings to update. Only properties with values set will be updated. + public IncomingPhoneNumber UpdateIncomingPhoneNumber(string incomingPhoneNumberSid, PhoneNumberOptions options) + { + Require.Argument("IncomingPhoneNumberSid", incomingPhoneNumberSid); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers/{IncomingPhoneNumberSid}"; + request.RootElement = "IncomingPhoneNumber"; + + request.AddParameter("IncomingPhoneNumberSid", incomingPhoneNumberSid, ParameterType.UrlSegment); + AddPhoneNumberOptionsToRequest(request, options); + AddSmsOptionsToRequest(request, options); + + return Execute(request); + } + + /// + /// Remove (deprovision) a phone number from the current account + /// + /// The Sid of the number to remove + public DeleteStatus DeleteIncomingPhoneNumber(string incomingPhoneNumberSid) + { + Require.Argument("IncomingPhoneNumberSid", incomingPhoneNumberSid); + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/IncomingPhoneNumbers/{IncomingPhoneNumberSid}"; + + request.AddParameter("IncomingPhoneNumberSid", incomingPhoneNumberSid, ParameterType.UrlSegment); + + var response = Execute(request); + return response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed; + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Account.cs b/src/Twilio.Api/Model/Account.cs new file mode 100644 index 000000000..35876fc0b --- /dev/null +++ b/src/Twilio.Api/Model/Account.cs @@ -0,0 +1,62 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Account instance resource represents a single Twilio Account. + /// + public class Account : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this account. + /// + public string Sid { get; set; } + /// + /// The date that this account was created, given as GMT + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this account was last updated, given in as GMT + /// + public DateTime DateUpdated { get; set; } + /// + /// A human readable description of this account, up to 64 characters long. By default the FriendlyName is your email address. + /// + public string FriendlyName { get; set; } + /// + /// The status of this account. Usually active, but can be suspended if you've been bad. + /// + public string Status { get; set; } + /// + /// The authorization token for this account. This token should be kept a secret, so no sharing. + /// + public string AuthToken { get; set; } + } + + /// + /// Twilio API call result with paging information + /// + public class AccountResult + { + /// + /// List of accounts returned by API + /// + public TwilioList Accounts { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Application.cs b/src/Twilio.Api/Model/Application.cs new file mode 100644 index 000000000..a3639abab --- /dev/null +++ b/src/Twilio.Api/Model/Application.cs @@ -0,0 +1,95 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Application instance resource represents a single Twilio Application. + /// + public class Application : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this account. + /// + public string Sid { get; set; } + /// + /// The date that this account was created, given as GMT + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this account was last updated, given in as GMT + /// + public DateTime DateUpdated { get; set; } + /// + /// A human readable description of this account, up to 64 characters long. By default the FriendlyName is your email address. + /// + public string FriendlyName { get; set; } + /// + /// The unique id of the Account responsible for this phone number. + /// + public string AccountSid { get; set; } + /// + /// Calls to this phone number will start a new TwiML session with this API version. + /// + public string ApiVersion { get; set; } + /// + /// Look up the caller's caller-ID name from the CNAM database (additional charges apply) + /// + public bool VoiceCallerIdLookup { get; set; } + /// + /// The URL Twilio will request when this phone number receives a call. + /// + public string VoiceUrl { get; set; } + /// + /// The HTTP method Twilio will use when requesting the above Url. Either GET or POST. + /// + public string VoiceMethod { get; set; } + /// + /// The URL that Twilio will request if an error occurs retrieving or executing the TwiML requested by Url. + /// + public string VoiceFallbackUrl { get; set; } + /// + /// The HTTP method Twilio will use when requesting the VoiceFallbackUrl. Either GET or POST. + /// + public string VoiceFallbackMethod { get; set; } + /// + /// The URL that Twilio will request to pass status parameters (such as call ended) to your application. + /// + public string StatusCallback { get; set; } + /// + /// The HTTP method Twilio will use to make requests to the StatusCallbackUrl. Either GET or POST. + /// + public string StatusCallbackMethod { get; set; } + /// + /// The URL Twilio will request when receiving an incoming SMS message to this number. + /// + public string SmsUrl { get; set; } + /// + /// The HTTP method Twilio will use when making requests to the SmsUrl. Either GET or POST. + /// + public string SmsMethod { get; set; } + /// + /// The URL that Twilio will request if an error occurs retrieving or executing the TwiML from SmsUrl. + /// + public string SmsFallbackUrl { get; set; } + /// + /// The HTTP method Twilio will use when requesting the above URL. Either GET or POST. + /// + public string SmsFallbackMethod { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/ApplicationOptions.cs b/src/Twilio.Api/Model/ApplicationOptions.cs new file mode 100644 index 000000000..a2dc7ce5d --- /dev/null +++ b/src/Twilio.Api/Model/ApplicationOptions.cs @@ -0,0 +1,69 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace Twilio +{ + /// + /// Available options when creating a Twilio Application via the API. + /// + public class ApplicationOptions + { + /// + /// The URL that Twilio should request when somebody dials the a phone number using this application. + /// + public string VoiceUrl { get; set; } + /// + /// The HTTP method that should be used to request the VoiceUrl. Must be either GET or POST. Defaults to POST. + /// + public string VoiceMethod { get; set; } + /// + /// A URL that Twilio will request if an error occurs requesting or executing the TwiML at Url. + /// + public string VoiceFallbackUrl { get; set; } + /// + /// The HTTP method that should be used to request the VoiceFallbackUrl. Either GET or POST. Defaults to POST. + /// + public string VoiceFallbackMethod { get; set; } + /// + /// The URL that Twilio should request when somebody sends an SMS to the phone number using this application. + /// + public string SmsUrl { get; set; } + /// + /// The HTTP method that should be used to request the SmsUrl. Must be either GET or POST. Defaults to POST. + /// + public string SmsMethod { get; set; } + /// + /// A URL that Twilio will request if an error occurs requesting or executing the TwiML defined by SmsUrl. + /// + public string SmsFallbackUrl { get; set; } + /// + /// The HTTP method that should be used to request the SmsFallbackUrl. Must be either GET or POST. Defaults to POST. + /// + public string SmsFallbackMethod { get; set; } + /// + /// Do a lookup of a caller's name from the CNAM database and post it to your app. Either true or false. Defaults to false. + /// + public bool? VoiceCallerIdLookup { get; set; } + /// + /// The URL that Twilio will request to pass status parameters (such as call ended) to your application. + /// + public string StatusCallback { get; set; } + /// + /// The HTTP method Twilio will use to make requests to the StatusCallback URL. Either GET or POST. Defaults to POST. + /// + public string StatusCallbackMethod { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/ApplicationResult.cs b/src/Twilio.Api/Model/ApplicationResult.cs new file mode 100644 index 000000000..dcf9e9dfb --- /dev/null +++ b/src/Twilio.Api/Model/ApplicationResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class ApplicationResult + { + /// + /// List of Application instances returned by API + /// + public TwilioList Applications { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/AvailablePhoneNumber.cs b/src/Twilio.Api/Model/AvailablePhoneNumber.cs new file mode 100644 index 000000000..d660f6572 --- /dev/null +++ b/src/Twilio.Api/Model/AvailablePhoneNumber.cs @@ -0,0 +1,62 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// An AvailablePhoneNumber instance resource represents a single AvailablePhoneNumber. + /// + public class AvailablePhoneNumber : TwilioBase + { + /// + /// A nicely-formatted version of the phone number. + /// + public string FriendlyName { get; set; } + /// + /// The phone number, in E.164 (i.e. "+1") format. + /// + public string PhoneNumber { get; set; } + /// + /// The LATA of this phone number. + /// + public string Lata { get; set; } + /// + /// The rate center of this phone number. + /// + public string RateCenter { get; set; } + /// + /// The latitude coordinate of this phone number. + /// + public decimal? Latitude { get; set; } + /// + /// The longitude coordinate of this phone number. + /// + public decimal? Longitude { get; set; } + /// + /// The two-letter state or province abbreviation of this phone number. + /// + public string Region { get; set; } + /// + /// The postal (zip) code of this phone number. + /// + public string PostalCode { get; set; } + /// + /// The ISO country code of this phone number. + /// + public string IsoCountry { get; set; } + } +} diff --git a/src/Twilio.Api/Model/AvailablePhoneNumberListRequest.cs b/src/Twilio.Api/Model/AvailablePhoneNumberListRequest.cs new file mode 100644 index 000000000..4d8a43f41 --- /dev/null +++ b/src/Twilio.Api/Model/AvailablePhoneNumberListRequest.cs @@ -0,0 +1,62 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Search filter options for AvailablePhoneNumber search + /// + public class AvailablePhoneNumberListRequest + { + /// + /// Find phone numbers in the specified Area Code. Only available for North American numbers. + /// + public string AreaCode { get; set; } + /// + /// A pattern to match phone numbers on. Valid characters are '*' and [0-9a-zA-Z]. The '*' character will match any single digit. + /// + public string Contains { get; set; } + /// + /// Limit results to a particular region (i.e. State/Province). Given a phone number, search within the same Region as that number. + /// + public string InRegion { get; set; } + /// + /// Limit results to a particular postal code. Given a phone number, search within the same postal code as that number. + /// + public string InPostalCode { get; set; } + /// + /// Given a latitude/longitude pair lat,long find geographically close numbers within Distance miles. + /// + public string NearLatLong { get; set; } + /// + /// Specifies the search radius for a Near- query in miles. If not specified this defaults to 25 miles. + /// + public int? Distance { get; set; } + /// + /// Given a phone number, find a geographically close number within Distance miles. Distance defaults to 25 miles. + /// + public string NearNumber { get; set; } + /// + /// Limit results to a specific Local access and transport area (LATA). Given a phone number, search within the same LATA as that number. + /// + public string InLata { get; set; } + /// + /// Limit results to a specific rate center, or given a phone number search within the same rate center as that number. Requires InLata to be set as well. + /// + public string InRateCenter { get; set; } + } +} diff --git a/src/Twilio.Api/Model/AvailablePhoneNumberResult.cs b/src/Twilio.Api/Model/AvailablePhoneNumberResult.cs new file mode 100644 index 000000000..1758ff68a --- /dev/null +++ b/src/Twilio.Api/Model/AvailablePhoneNumberResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class AvailablePhoneNumberResult + { + /// + /// List of AvailablePhoneNumbers search results + /// + public TwilioList AvailablePhoneNumbers { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Call.cs b/src/Twilio.Api/Model/Call.cs new file mode 100644 index 000000000..6a8c41e87 --- /dev/null +++ b/src/Twilio.Api/Model/Call.cs @@ -0,0 +1,95 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Call instance resource represents a single Twilio Call. + /// + public class Call : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this resource. + /// + public string Sid { get; set; } + /// + /// A 34 character string that uniquely identifies the call that created this leg. + /// + public string ParentCallSid { get; set; } + /// + /// The date that this resource was created, given as GMT + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource was last updated, given as GMT + /// + public DateTime DateUpdated { get; set; } + /// + /// The unique Sid of the Account responsible for creating this call. + /// + public string AccountSid { get; set; } + /// + /// The phone number that received this call. e.g., +16175551212 (E.164 format) + /// + public string To { get; set; } + /// + /// The phone number that made this call. e.g., +16175551212 (E.164 format) + /// + public string From { get; set; } + /// + /// If the call was inbound, this is the Sid of the IncomingPhoneNumber that received the call. If the call was outbound, it is the Sid of the OutgoingCallerId from which the call was placed. + /// + public string PhoneNumberSid { get; set; } + /// + /// A string representing the status of the call. May be queued, ringing, in-progress, completed, failed, busy or no-answer. + /// + public string Status { get; set; } + /// + /// The start time of the call, given as GMT in RFC 2822 format. Empty if the call has not yet been dialed. + /// + public DateTime? StartTime { get; set; } + /// + /// The end time of the call, given as GMT in RFC 2822 format. Empty if the call did not complete successfully. + /// + public DateTime? EndTime { get; set; } + /// + /// The length of the call in seconds. This value is empty for busy, failed, unanswered or ongoing calls. + /// + public int? Duration { get; set; } + /// + /// The charge for this call in USD. Populated after the call is completed. May not be immediately available. + /// + public decimal? Price { get; set; } + /// + /// A string describing the direction of the call. inbound for inbound calls, outbound-api for calls initiated via the REST API or outbound-dial for calls initiated by a Dial verb. + /// + public string Direction { get; set; } + /// + /// If this call was initiated with answering machine detection, either human or machine. Empty otherwise. + /// + public string AnsweredBy { get; set; } + /// + /// If this call was an incoming call forwarded from another number, the forwarding phone number (depends on carrier supporting forwarding). Empty otherwise. + /// + public string ForwardedFrom { get; set; } + /// + /// If this call was an incoming call from a phone number with Caller ID Lookup enabled, the caller's name. Empty otherwise. + /// + public string CallerName { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/CallListRequest.cs b/src/Twilio.Api/Model/CallListRequest.cs new file mode 100644 index 000000000..b04336be3 --- /dev/null +++ b/src/Twilio.Api/Model/CallListRequest.cs @@ -0,0 +1,67 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// Search filter options for Call list request + /// + public class CallListRequest + { + /// + /// Only show calls from this phone number. + /// + public string From { get; set; } + /// + /// Only show calls to this phone number. + /// + public string To { get; set; } + /// + /// Only show calls currently in this status. May be queued, ringing, in-progress, completed, failed, busy, or no-answer. + /// + public string Status { get; set; } + /// + /// Only show calls that started on this date + /// + public DateTime? StartTime { get; set; } + /// + /// Comparison type for start time + /// + public ComparisonType StartTimeComparison { get; set; } + /// + /// Only show calls that ended on this date + /// + public DateTime? EndTime { get; set; } + /// + /// Comparison type for end time + /// + public ComparisonType EndTimeComparison { get; set; } + /// + /// What page number to start retrieving results from + /// + public int? PageNumber { get; set; } + /// + /// How many results to retrieve + /// + public int? Count { get; set; } + /// + /// Only show calls that belong to this parent call (e.g. Dial legs) + /// + public string ParentCallSid { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/CallOptions.cs b/src/Twilio.Api/Model/CallOptions.cs new file mode 100644 index 000000000..b99fe86d1 --- /dev/null +++ b/src/Twilio.Api/Model/CallOptions.cs @@ -0,0 +1,73 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace Twilio +{ + /// + /// Available options to include when initiating a phone call + /// + public class CallOptions + { + /// + /// The phone number to use as the caller id. Format with a '+' and country code e.g., +16175551212 (E.164 format). Must be a Twilio number or a valid outgoing caller id for your account. + /// + public string From { get; set; } + /// + /// The number to call formatted with a '+' and country code e.g., +16175551212 (E.164 format). Twilio will also accept unformatted US numbers e.g., (415) 555-1212, 415-555-1212. + /// + public string To { get; set; } + /// + /// The fully qualified URL that should be consulted when the call connects. Just like when you set a URL for your inbound calls. + /// + public string Url { get; set; } + /// + /// The 34 character sid of the application Twilio should use to handle this phone call. If this parameter is present, Twilio will ignore all of the voice URLs passed and use the URLs set on the application. + /// + public string ApplicationSid { get; set; } + /// + /// A URL that Twilio will request when the call ends to notify your app. + /// + public string StatusCallback { get; set; } + /// + /// The HTTP method Twilio should use when requesting the above URL. Defaults to POST. + /// + public string StatusCallbackMethod { get; set; } + /// + /// The HTTP method Twilio should use when requesting the required Url parameter's value above. Defaults to POST. + /// + public string Method { get; set; } + /// + /// A string of keys to dial after connecting to the number. Valid digits in the string include: any digit (0-9), '#' and '*'. For example, if you connected to a company phone number, and wanted to dial extension 1234 and then the pound key, use SendDigits=1234#. Remember to URL-encode this string, since the '#' character has special meaning in a URL. + /// + public string SendDigits { get; set; } + /// + /// Tell Twilio to try and determine if a machine (like voicemail) or a human has answered the call. Possible values are Continue and Hangup. + /// + public string IfMachine { get; set; } + /// + /// The integer number of seconds that Twilio should allow the phone to ring before assuming there is no answer. Default is 60 seconds, the maximum is 999 seconds. Note, you could set this to a low value, such as 15, to hangup before reaching an answering machine or voicemail. + /// + public int? Timeout { get; set; } + /// + /// A URL that Twilio will request if an error occurs requesting or executing the TwiML at Url. + /// + public string FallbackUrl { get; set; } + /// + /// The HTTP method that Twilio should use to request the FallbackUrl. Must be either GET or POST. Defaults to POST. + /// + public string FallbackMethod { get; set; } + } +} diff --git a/src/Twilio.Api/Model/CallResult.cs b/src/Twilio.Api/Model/CallResult.cs new file mode 100644 index 000000000..e4bad6e66 --- /dev/null +++ b/src/Twilio.Api/Model/CallResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class CallResult + { + /// + /// List of Calls returned from API request + /// + public TwilioList Calls { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/ComparisonType.cs b/src/Twilio.Api/Model/ComparisonType.cs new file mode 100644 index 000000000..6580bbcd2 --- /dev/null +++ b/src/Twilio.Api/Model/ComparisonType.cs @@ -0,0 +1,37 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace Twilio +{ + /// + /// Available types of range selections + /// + public enum ComparisonType + { + /// + /// Selects items equal to value + /// + EqualTo, + /// + /// Selects items greater than or equal to value + /// + GreaterThanOrEqualTo, + /// + /// Selects items less than or equal to value + /// + LessThanOrEqualTo + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Conference.cs b/src/Twilio.Api/Model/Conference.cs new file mode 100644 index 000000000..df311aa12 --- /dev/null +++ b/src/Twilio.Api/Model/Conference.cs @@ -0,0 +1,51 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Conference instance resource represents a single Twilio Conference. + /// + public class Conference : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this conference. + /// + public string Sid { get; set; } + /// + /// The unique id of the Account responsible for creating this conference. + /// + public string AccountSid { get; set; } + /// + /// A user provided string that identifies this conference room. + /// + public string FriendlyName { get; set; } + /// + /// A string representing the status of the conference. May be init, in-progress, or completed. + /// + public string Status { get; set; } + /// + /// The date that this conference was created, given as GMT + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this conference was last updated, given as GMT + /// + public DateTime DateUpdated { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/ConferenceListRequest.cs b/src/Twilio.Api/Model/ConferenceListRequest.cs new file mode 100644 index 000000000..b08c400d9 --- /dev/null +++ b/src/Twilio.Api/Model/ConferenceListRequest.cs @@ -0,0 +1,59 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// Options for filtering list of Conference instances from API + /// + public class ConferenceListRequest + { + /// + /// Only show conferences currently in with this status. May be init, in-progress, or completed. + /// + public int? Status { get; set; } + /// + /// List conferences who's FriendlyName is the exact match of this string. + /// + public string FriendlyName { get; set; } + /// + /// Only show conferences that started on this date. For comparison options, specify DateCreatedComparison value. + /// + public DateTime? DateCreated { get; set; } + /// + /// Type of comparison to perform with DateCreated filter parameter + /// + public ComparisonType DateCreatedComparison { get; set; } + /// + /// Only show conferences that were last updated on this date. For comparison options, specify DateUpdatedComparison value. + /// + public DateTime? DateUpdated { get; set; } + /// + /// Type of comparison to perform with DateUpdated filter parameter + /// + public ComparisonType DateUpdatedComparison { get; set; } + /// + /// Which page to view. Zero-indexed, so the first page is 0. The default is 0. + /// + public int? PageNumber { get; set; } + /// + /// How many resources to return in each list page. The default is 50, and the maximum is 1000. + /// + public int? Count { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/ConferenceResult.cs b/src/Twilio.Api/Model/ConferenceResult.cs new file mode 100644 index 000000000..df186e72d --- /dev/null +++ b/src/Twilio.Api/Model/ConferenceResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class ConferenceResult + { + /// + /// List of Conference instances returned from API call + /// + public TwilioList Conferences { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/DeleteStatus.cs b/src/Twilio.Api/Model/DeleteStatus.cs new file mode 100644 index 000000000..b77c64bd9 --- /dev/null +++ b/src/Twilio.Api/Model/DeleteStatus.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Twilio +{ + public enum DeleteStatus + { + Success, + Failed + } +} diff --git a/src/Twilio.Api/Model/HangupStyle.cs b/src/Twilio.Api/Model/HangupStyle.cs new file mode 100644 index 000000000..b257c1fb5 --- /dev/null +++ b/src/Twilio.Api/Model/HangupStyle.cs @@ -0,0 +1,18 @@ + +namespace Twilio +{ + /// + /// Options for handling call hangups + /// + public enum HangupStyle + { + /// + /// Specifying canceled will attempt to hangup calls that are queued or ringing but not affect calls already in progress. + /// + Canceled, + /// + /// Specifying completed will attempt to hang up a call even if it's already in progress. + /// + Completed + } +} diff --git a/src/Twilio.Api/Model/IncomingPhoneNumber.cs b/src/Twilio.Api/Model/IncomingPhoneNumber.cs new file mode 100644 index 000000000..f7ec77f28 --- /dev/null +++ b/src/Twilio.Api/Model/IncomingPhoneNumber.cs @@ -0,0 +1,99 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An IncomingPhoneNumber instance resource represents a single Twilio IncomingPhoneNumber. + /// + public class IncomingPhoneNumber : TwilioBase + { + /// + /// A 34 character string that uniquely idetifies this resource. + /// + public string Sid { get; set; } + /// + /// The date that this resource was created, given as GMT + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource was last updated, given as GMT + /// + public DateTime DateUpdated { get; set; } + /// + /// A human readable descriptive text for this resource, up to 64 characters long. By default, the FriendlyName is a nicely formatted version of the phone number. + /// + public string FriendlyName { get; set; } + /// + /// The unique id of the Account responsible for this phone number. + /// + public string AccountSid { get; set; } + /// + /// The incoming phone number. e.g., +16175551212 (E.164 format) + /// + public string PhoneNumber { get; set; } + /// + /// Calls to this phone number will start a new TwiML session with this API version. + /// + public string ApiVersion { get; set; } + /// + /// Look up the caller's caller-ID name from the CNAM database (additional charges apply) + /// + public bool VoiceCallerIdLookup { get; set; } + /// + /// The URL Twilio will request when this phone number receives a call. + /// + public string VoiceUrl { get; set; } + /// + /// The HTTP method Twilio will use when requesting the above Url. Either GET or POST. + /// + public string VoiceMethod { get; set; } + /// + /// The URL that Twilio will request if an error occurs retrieving or executing the TwiML requested by Url. + /// + public string VoiceFallbackUrl { get; set; } + /// + /// The HTTP method Twilio will use when requesting the VoiceFallbackUrl. Either GET or POST. + /// + public string VoiceFallbackMethod { get; set; } + /// + /// The URL that Twilio will request to pass status parameters (such as call ended) to your application. + /// + public string StatusCallback { get; set; } + /// + /// The HTTP method Twilio will use to make requests to the StatusCallbackUrl. Either GET or POST. + /// + public string StatusCallbackMethod { get; set; } + /// + /// The URL Twilio will request when receiving an incoming SMS message to this number. + /// + public string SmsUrl { get; set; } + /// + /// The HTTP method Twilio will use when making requests to the SmsUrl. Either GET or POST. + /// + public string SmsMethod { get; set; } + /// + /// The URL that Twilio will request if an error occurs retrieving or executing the TwiML from SmsUrl. + /// + public string SmsFallbackUrl { get; set; } + /// + /// The HTTP method Twilio will use when requesting the above URL. Either GET or POST. + /// + public string SmsFallbackMethod { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/IncomingPhoneNumberResult.cs b/src/Twilio.Api/Model/IncomingPhoneNumberResult.cs new file mode 100644 index 000000000..d41fd658c --- /dev/null +++ b/src/Twilio.Api/Model/IncomingPhoneNumberResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class IncomingPhoneNumberResult + { + /// + /// List of IncomingPhoneNumber instances returned by API + /// + public TwilioList IncomingPhoneNumbers { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Notification.cs b/src/Twilio.Api/Model/Notification.cs new file mode 100644 index 000000000..9d9845b10 --- /dev/null +++ b/src/Twilio.Api/Model/Notification.cs @@ -0,0 +1,99 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Notification instance resource represents a single Twilio Notification. + /// + public class Notification : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this resource. + /// + public string Sid { get; set; } + /// + /// The date that this resource was created. + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource was last updated. + /// + public DateTime DateUpdated { get; set; } + /// + /// The unique id of the Account responsible for this notification. + /// + public string AccountSid { get; set; } + /// + /// CallSid is the unique id of the call during which the notification was generated. Empty if the notification was generated by the REST API without regard to a specific phone call. + /// + public string CallSid { get; set; } + /// + /// The version of the Twilio in use when this notification was generated. + /// + public string ApiVersion { get; set; } + /// + /// An integer log level corresponding to the type of notification: 0 is ERROR, 1 is WARNING. + /// + public int Log { get; set; } + /// + /// A unique error code for the error condition. + /// + public string ErrorCode { get; set; } + /// + /// A URL for more information about the error condition. + /// + public string MoreInfo { get; set; } + /// + /// The text of the notification. + /// + public string MessageText { get; set; } + /// + /// The date the notification was actually generated. Due to buffering, this may be slightly different than the DateCreated date. + /// + public DateTime MessageDate { get; set; } + /// + /// The URL of the resource that generated the notification. + /// If the notification was generated during a phone call: + /// This is the URL of the resource on YOUR SERVER that caused the notification. + /// If the notification was generated by your use of the REST API: + /// This is the URL of the REST resource you were attempting to request on Twilio's servers. + /// + public string RequestUrl { get; set; } + /// + /// The HTTP method in use for the request that generated the notification. + /// If the notification was generated during a phone call: + /// The HTTP Method use to request the resource on your server. + /// If the notification was generated by your use of the REST API: + /// This is the HTTP method used in your request to the REST resource on Twilio's servers. + /// + public string RequestMethod { get; set; } + /// + /// The Twilio-generated HTTP GET or POST variables sent to your server. Alternatively, if the notification was generated by the REST API, this field will include any HTTP POST or PUT variables you sent to the REST API. + /// + public string RequestVariables { get; set; } + /// + /// The HTTP headers returned by your server. + /// + public string ResponseHeaders { get; set; } + /// + /// The HTTP body returned by your server. + /// + public string ResponseBody { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/NotificationResult.cs b/src/Twilio.Api/Model/NotificationResult.cs new file mode 100644 index 000000000..df27422d1 --- /dev/null +++ b/src/Twilio.Api/Model/NotificationResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class NotificationResult + { + /// + /// List of Notification instances returned by API + /// + public TwilioList Notifications { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/OutgoingCallerId.cs b/src/Twilio.Api/Model/OutgoingCallerId.cs new file mode 100644 index 000000000..caa20a1f3 --- /dev/null +++ b/src/Twilio.Api/Model/OutgoingCallerId.cs @@ -0,0 +1,51 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An OutgoingCallerId instance resource represents a single Twilio OutgoingCallerId. + /// + public class OutgoingCallerId : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this resource. + /// + public string Sid { get; set; } + /// + /// The date that this resource was created + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource last updated + /// + public DateTime DateUpdated { get; set; } + /// + /// A human readable descriptive text for this resource, up to 64 characters long. By default, the FriendlyName is a nicely formatted version of the phone number. + /// + public string FriendlyName { get; set; } + /// + /// The unique id of the Account responsible for this Caller Id. + /// + public string AccountSid { get; set; } + /// + /// The incoming phone number. Formatted with a '+' and country code e.g., +16175551212 (E.164 format). + /// + public string PhoneNumber { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/OutgoingCallerIdResult.cs b/src/Twilio.Api/Model/OutgoingCallerIdResult.cs new file mode 100644 index 000000000..7720f2750 --- /dev/null +++ b/src/Twilio.Api/Model/OutgoingCallerIdResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class OutgoingCallerIdResult + { + /// + /// List of OutgoingCallerId instances returned by API + /// + public TwilioList OutgoingCallerIds { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Participant.cs b/src/Twilio.Api/Model/Participant.cs new file mode 100644 index 000000000..1349e5200 --- /dev/null +++ b/src/Twilio.Api/Model/Participant.cs @@ -0,0 +1,59 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Participant instance resource represents a single Twilio conference Participant. + /// + public class Participant : TwilioBase + { + /// + /// A 34 character string that identifies the conference this participant is in + /// + public string ConferenceSid { get; set; } + /// + /// The unique id of the Account that created this conference + /// + public string AccountSid { get; set; } + /// + /// A 34 character string that uniquely identifies the call that is connected to this conference + /// + public string CallSid { get; set; } + /// + /// true if this participant is currently muted. false otherwise. + /// + public bool Muted { get; set; } + /// + /// Was the startConferenceOnEnter attribute set on this participant (true or false)? + /// + public bool StartConferenceOnEnter { get; set; } + /// + /// Was the endConferenceOnExit attribute set on this participant (true or false)? + /// + public bool EndConferenceOnExit { get; set; } + /// + /// The date that this resource was created + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource was last updated + /// + public DateTime DateUpdated { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/ParticipantResult.cs b/src/Twilio.Api/Model/ParticipantResult.cs new file mode 100644 index 000000000..f398c74d6 --- /dev/null +++ b/src/Twilio.Api/Model/ParticipantResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class ParticipantResult + { + /// + /// List of conference Participant resources returned by API + /// + public TwilioList Participants { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/PhoneNumberOptions.cs b/src/Twilio.Api/Model/PhoneNumberOptions.cs new file mode 100644 index 000000000..d316d10cc --- /dev/null +++ b/src/Twilio.Api/Model/PhoneNumberOptions.cs @@ -0,0 +1,93 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace Twilio +{ + /// + /// Available options when purchasing phone numbers via the API. NOTE: you can only request phone numbers with a full Twilio account, not in the Twilio Free Trial. If you would like to buy a Twilio phone number, you must upgrade your account. + /// + public class PhoneNumberOptions + { + /// + /// The AccountSid to assign this number to. Only used for moving phone numbers betweeen subaccounts. + /// + public string AccountSid { get; set; } + /// + /// The area code in which you'd like a new incoming phone number. Any three digit, US area code is valid. Twilio will provision a random phone number within this area code for you. You must include either this or a PhoneNumber parameter to have your POST succeed. + /// + public string AreaCode { get; set; } + /// + /// The phone number you want to purchase. The number should be formated starting with a '+' followed by the country code and the number in E.164 format e.g., '+15105555555'. You must include either this or an AreaCode parameter to have your POST succeed. + /// + public string PhoneNumber { get; set; } + /// + /// A human readable description of the new incoming phone number. Maximum 64 characters. Defaults to a formatted version of the number. + /// + public string FriendlyName { get; set; } + /// + /// The 34 character sid of the application Twilio should use to handle SMSs sent to this number. If a SmsApplicationSid is present, Twilio will ignore all of the SMS urls above and use those set on the application. + /// + public string SmsApplicationSid { get; set; } + /// + /// The 34 character sid of the application Twilio should use to handle phone calls to this number. If a VoiceApplicationSid is present, Twilio will ignore all of the voice urls above and use those set on the application. + /// + public string VoiceApplicationSid { get; set; } + /// + /// The URL that Twilio should request when somebody dials the new phone number. + /// + public string VoiceUrl { get; set; } + /// + /// The HTTP method that should be used to request the VoiceUrl. Must be either GET or POST. Defaults to POST. + /// + public string VoiceMethod { get; set; } + /// + /// A URL that Twilio will request if an error occurs requesting or executing the TwiML at Url. + /// + public string VoiceFallbackUrl { get; set; } + /// + /// The HTTP method that should be used to request the VoiceFallbackUrl. Either GET or POST. Defaults to POST. + /// + public string VoiceFallbackMethod { get; set; } + /// + /// The URL that Twilio should request when somebody sends an SMS to the phone number. + /// + public string SmsUrl { get; set; } + /// + /// The HTTP method that should be used to request the SmsUrl. Must be either GET or POST. Defaults to POST. + /// + public string SmsMethod { get; set; } + /// + /// A URL that Twilio will request if an error occurs requesting or executing the TwiML defined by SmsUrl. + /// + public string SmsFallbackUrl { get; set; } + /// + /// The HTTP method that should be used to request the SmsFallbackUrl. Must be either GET or POST. Defaults to POST. + /// + public string SmsFallbackMethod { get; set; } + /// + /// Do a lookup of a caller's name from the CNAM database and post it to your app. Either true or false. Defaults to false. + /// + public bool? VoiceCallerIdLookup { get; set; } + /// + /// The URL that Twilio will request to pass status parameters (such as call ended) to your application. + /// + public string StatusCallback { get; set; } + /// + /// The HTTP method Twilio will use to make requests to the StatusCallback URL. Either GET or POST. Defaults to POST. + /// + public string StatusCallbackMethod { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Recording.cs b/src/Twilio.Api/Model/Recording.cs new file mode 100644 index 000000000..6f631a63b --- /dev/null +++ b/src/Twilio.Api/Model/Recording.cs @@ -0,0 +1,55 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Recording instance resource represents a single Twilio Recording. + /// + public class Recording : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this resource. + /// + public string Sid { get; set; } + /// + /// The date that this resource was created + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource was last updated + /// + public DateTime DateUpdated { get; set; } + /// + /// The unique id of the Account responsible for this recording. + /// + public string AccountSid { get; set; } + /// + /// The call during which the recording was made. + /// + public string CallSid { get; set; } + /// + /// The length of the recording, in seconds. + /// + public int Duration { get; set; } + /// + /// The version of the API in use during the recording. + /// + public string ApiVersion { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/RecordingResult.cs b/src/Twilio.Api/Model/RecordingResult.cs new file mode 100644 index 000000000..4c5b38308 --- /dev/null +++ b/src/Twilio.Api/Model/RecordingResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class RecordingResult + { + /// + /// List of Recording instances returned by API + /// + public TwilioList Recordings { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/RestException.cs b/src/Twilio.Api/Model/RestException.cs new file mode 100644 index 000000000..a833c7829 --- /dev/null +++ b/src/Twilio.Api/Model/RestException.cs @@ -0,0 +1,41 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace Twilio +{ + /// + /// Exceptions returned in the HTTP response body when something goes wrong. + /// + public class RestException + { + /// + /// The HTTP status code for the exception. + /// + public string Status { get; set; } + /// + /// (Conditional) The URL of Twilio's documentation for the error code. + /// + public string MoreInfo { get; set; } + /// + /// (Conditional) An error code to find help for the exception. + /// + public string Code { get; set; } + /// + /// A more descriptive message regarding the exception. + /// + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Sandbox.cs b/src/Twilio.Api/Model/Sandbox.cs new file mode 100644 index 000000000..87ace5ba0 --- /dev/null +++ b/src/Twilio.Api/Model/Sandbox.cs @@ -0,0 +1,63 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Call instance resource represents a single Twilio Call. + /// + public class Sandbox : TwilioBase + { + /// + /// The unique Sid of the Account responsible for creating this call. + /// + public string AccountSid { get; set; } + /// + /// An 8 digit number that gives access to this sandbox. + /// + public string Pin { get; set; } + /// + /// The phone number of the sandbox. Formatted with a '+' and country code e.g., +16175551212 (E.164 format). + /// + public string PhoneNumber { get; set; } + /// + /// The URL Twilio will request when the sandbox number is called. + /// + public string VoiceUrl { get; set; } + /// + /// The HTTP method to use when requesting the above URL. Either GET or POST. + /// + public string VoiceMethod { get; set; } + /// + /// The URL Twilio will request when receiving an incoming SMS message to the sandbox number. + /// + public string SmsUrl { get; set; } + /// + /// The HTTP method to use when requesting the sms URL. Either GET or POST. + /// + public string SmsMethod { get; set; } + /// + /// The date that this resource was created + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource was last updated + /// + public DateTime DateUpdated { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/SmsMessage.cs b/src/Twilio.Api/Model/SmsMessage.cs new file mode 100644 index 000000000..f73d3da0b --- /dev/null +++ b/src/Twilio.Api/Model/SmsMessage.cs @@ -0,0 +1,75 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An SMSMessage instance resource represents a single Twilio SMSMessage. + /// + public class SmsMessage : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this resource. + /// + public string Sid { get; set; } + /// + /// The date that this resource was created + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource was last updated + /// + public DateTime DateUpdated { get; set; } + /// + /// The date that the SMS was sent + /// + public DateTime DateSent { get; set; } + /// + /// The unique id of the Account that sent this SMS message. + /// + public string AccountSid { get; set; } + /// + /// The phone number that initiated the message in E.164 format. For incoming messages, this will be the remote phone. For outgoing messages, this will be one of your Twilio phone numbers. + /// + public string From { get; set; } + /// + /// The phone number that received the message in E.164 format. For incoming messages, this will be one of your Twilio phone numbers. For outgoing messages, this will be the remote phone. + /// + public string To { get; set; } + /// + /// The text body of the SMS message. Up to 160 characters long. + /// + public string Body { get; set; } + /// + /// The status of this SMS message. Either queued, sending, sent, or failed. + /// + public string Status { get; set; } + /// + /// The direction of this SMS message. incoming for incoming messages, outbound-api for messages initiated via the REST API, outbound-call for messages initiated during a call or outbound-reply for messages initiated in response to an incoming SMS. + /// + public string Direction { get; set; } + /// + /// The amount billed for the message. + /// + public decimal Price { get; set; } + /// + /// The version of the Twilio API used to process the SMS message. + /// + public string ApiVersion { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/SmsMessageResult.cs b/src/Twilio.Api/Model/SmsMessageResult.cs new file mode 100644 index 000000000..0e90ce561 --- /dev/null +++ b/src/Twilio.Api/Model/SmsMessageResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class SmsMessageResult + { + /// + /// List of SMSMessage resources returned by API + /// + public TwilioList SmsMessages { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/SmsShortCode.cs b/src/Twilio.Api/Model/SmsShortCode.cs new file mode 100644 index 000000000..a84dd1ebf --- /dev/null +++ b/src/Twilio.Api/Model/SmsShortCode.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Twilio +{ + /// + /// Represents a single ShortCode Instance resource + /// + public class SmsShortCode : TwilioBase + { + /// + /// A 34 character string that uniquely idetifies this resource. + /// + public string Sid { get; set; } + /// + /// The unique id of the Account that owns this short code. + /// + public string AccountSid { get; set; } + /// + /// A human readable descriptive text for this resource, up to 64 characters long. By default, the FriendlyName is just the short code. + /// + public string FriendlyName { get; set; } + /// + /// The short code. e.g., 894546. + /// + public string ShortCode { get; set; } + /// + /// The date that this resource was created. + /// + public string DateCreated { get; set; } + /// + /// The date that this resource was last updated. + /// + public string DateUpdated { get; set; } + /// + /// The URL Twilio will request when receiving an incoming SMS message to this short code. + /// + public string SmsUrl { get; set; } + /// + /// The HTTP method Twilio will use when making requests to the SmsUrl. Either GET or POST. + /// + public string SmsMethod { get; set; } + /// + /// The URL that Twilio will request if an error occurs retrieving or executing the TwiML from SmsUrl. + /// + public string SmsFallbackUrl { get; set; } + /// + /// The HTTP method Twilio will use when requesting the above URL. Either GET or POST. + /// + public string SmsFallbackMethod { get; set; } + /// + /// SMSs to this short code will start a new TwiML session with this API version. + /// + public string ApiVersion { get; set; } + } +} diff --git a/src/Twilio.Api/Model/SmsShortCodeResult.cs b/src/Twilio.Api/Model/SmsShortCodeResult.cs new file mode 100644 index 000000000..f98ce5268 --- /dev/null +++ b/src/Twilio.Api/Model/SmsShortCodeResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class SmsShortCodeResult + { + /// + /// List of ShortCode resources returned by API + /// + public TwilioList ShortCodes { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/Transcription.cs b/src/Twilio.Api/Model/Transcription.cs new file mode 100644 index 000000000..2a54e95ab --- /dev/null +++ b/src/Twilio.Api/Model/Transcription.cs @@ -0,0 +1,63 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; + +namespace Twilio +{ + /// + /// An Transcription instance resource represents a single Twilio Transcription. + /// + public class Transcription : TwilioBase + { + /// + /// A 34 character string that uniquely identifies this resource. + /// + public string Sid { get; set; } + /// + /// The date that this resource was created + /// + public DateTime DateCreated { get; set; } + /// + /// The date that this resource was last updated + /// + public DateTime DateUpdated { get; set; } + /// + /// The unique id of the Account responsible for this transcription. + /// + public string AccountSid { get; set; } + /// + /// A string representing the status of the transcription: in-progress, completed or failed. + /// + public string Status { get; set; } + /// + /// The unique id of the Recording this Transcription was made of. + /// + public string RecordingSid { get; set; } + /// + /// The duration of the transcribed audio, in seconds. + /// + public int Duration { get; set; } + /// + /// The text content of the transcription. + /// + public string TranscriptionText { get; set; } + /// + /// The charge for this transcript in USD. Populated after the transcript is completed. Note, this value may not be immediately available. + /// + public decimal? Price { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/TranscriptionResult.cs b/src/Twilio.Api/Model/TranscriptionResult.cs new file mode 100644 index 000000000..8348a5308 --- /dev/null +++ b/src/Twilio.Api/Model/TranscriptionResult.cs @@ -0,0 +1,30 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + + +namespace Twilio +{ + /// + /// Twilio API call result with paging information + /// + public class TranscriptionResult + { + /// + /// List of Transcription resources returned by API + /// + public TwilioList Transcriptions { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/TwilioBase.cs b/src/Twilio.Api/Model/TwilioBase.cs new file mode 100644 index 000000000..857ad4743 --- /dev/null +++ b/src/Twilio.Api/Model/TwilioBase.cs @@ -0,0 +1,34 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +namespace Twilio +{ + /// + /// Base class for all Twilio resource types + /// + public abstract class TwilioBase + { + /// + /// Exception encountered during API request + /// + public RestException Exception { get; set; } + /// + /// The URI for this resource, relative to https://api.twilio.com + /// + public Uri Uri { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/TwilioListBase.cs b/src/Twilio.Api/Model/TwilioListBase.cs new file mode 100644 index 000000000..9905ef31c --- /dev/null +++ b/src/Twilio.Api/Model/TwilioListBase.cs @@ -0,0 +1,73 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using System.Collections.Generic; + +namespace Twilio +{ + /// + /// List with paging information + /// + /// + public class TwilioList : List + { + /// + /// The current page number. Zero-indexed, so the first page is 0. + /// + public int Page { get; set; } + /// + /// The total number of pages. + /// + public int NumPages { get; set; } + /// + /// How many items are in each page + /// + public int PageSize { get; set; } + /// + /// The total number of items in the list. + /// + public int Total { get; set; } + /// + /// The position in the overall list of the first item in this page. + /// + public int Start { get; set; } + /// + /// The position in the overall list of the last item in this page. + /// + public int End { get; set; } + /// + /// The URI of the current page. + /// + public Uri Uri { get; set; } + /// + /// The URI for the first page of this list. + /// + public Uri FirstPageUri { get; set; } + /// + /// The URI for the next page of this list. + /// + public Uri NextPageUri { get; set; } + /// + /// The URI for the previous page of this list. + /// + public Uri PreviousPageUri { get; set; } + /// + /// The URI for the last page of this list. + /// + public Uri LastPageUri { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Model/ValidationRequest.cs b/src/Twilio.Api/Model/ValidationRequest.cs new file mode 100644 index 000000000..a8820aa3d --- /dev/null +++ b/src/Twilio.Api/Model/ValidationRequest.cs @@ -0,0 +1,41 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace Twilio +{ + /// + /// Result of making a request to validate an OutgoingCallerId + /// + public class ValidationRequestResult : TwilioBase + { + /// + /// The unique id of the Account to which the Validation Request belongs. + /// + public string AccountSid { get; set; } + /// + /// The friendly name you provided, if any. + /// + public string FriendlyName { get; set; } + /// + /// The incoming phone number being validated, formatted with a '+' and country code e.g., +16175551212 (E.164 format). + /// + public string PhoneNumber { get; set; } + /// + /// The 6 digit validation code that must be entered via the phone to validate this phone number for Caller ID. + /// + public string ValidationCode { get; set; } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Notifications.cs b/src/Twilio.Api/Notifications.cs new file mode 100644 index 000000000..63f5b7e19 --- /dev/null +++ b/src/Twilio.Api/Notifications.cs @@ -0,0 +1,89 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details of a specific notification. Makes a GET request to a Notification Instance resource. + /// + /// The Sid of the notification to retrieve + public Notification GetNotification(string notificationSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Notifications/{NotificationSid}"; + request.RootElement = "Notification"; + + request.AddParameter("NotificationSid", notificationSid, ParameterType.UrlSegment); + + return Execute(request); + } + + /// + /// Returns a list of notifications generated for an account. + /// The list includes paging information and is sorted by DateUpdated, with most recent notifications first. + /// Makes a GET request to a Notifications List resource. + /// + public NotificationResult ListNotifications() + { + return ListNotifications(null, null, null, null); + } + + /// + /// Returns a filtered list of notifications generated for an account. + /// The list includes paging information and is sorted by DateUpdated, with most recent notifications first. + /// Makes a GET request to a Notifications List resource. + /// + /// Only show notifications for this log, using the integer log values: 0 is ERROR, 1 is WARNING + /// Only show notifications for this date (in GMT) + /// The page number to start retrieving results from + /// How many notifications to return + public NotificationResult ListNotifications(int? log, DateTime? messageDate, int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Notifications"; + + if (log.HasValue) request.AddParameter("Log", log); + if (messageDate.HasValue) request.AddParameter("MessageDate", messageDate.Value.ToString("yyyy-MM-dd")); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Deletes a notification from your account. Makes a DELETE request to a Notification Instance resource. + /// + /// The Sid of the notification to delete + public DeleteStatus DeleteNotification(string notificationSid) + { + Require.Argument("NotificationSid", notificationSid); + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/Notifications/{NotificationSid}"; + + request.AddParameter("NotificationSid", notificationSid, ParameterType.UrlSegment); + + var response = Execute(request); + return response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed; + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/OutgoingCallerIds.cs b/src/Twilio.Api/OutgoingCallerIds.cs new file mode 100644 index 000000000..c2f5297eb --- /dev/null +++ b/src/Twilio.Api/OutgoingCallerIds.cs @@ -0,0 +1,137 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details for an existing validated Outgoing Caller ID entry. + /// Makes a GET request to an OutgoingCallerId Instance resource. + /// + /// The Sid of the entry to retrieve + public OutgoingCallerId GetOutgoingCallerId(string outgoingCallerIdSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds/{OutgoingCallerIdSid}"; + request.RootElement = "OutgoingCallerId"; + request.AddParameter("OutgoingCallerIdSid", outgoingCallerIdSid, ParameterType.UrlSegment); + + return Execute(request); + } + + /// + /// Returns a list of validated outgoing caller IDs. The list includes paging information. + /// Makes a GET request to an OutgoingCallerIds List resource. + /// + public OutgoingCallerIdResult ListOutgoingCallerIds() + { + return ListOutgoingCallerIds(null, null, null, null); + } + + /// + /// Returns a filtered list of validated outgoing caller IDs. The list includes paging information. + /// Makes a GET request to an OutgoingCallerIds List resource. + /// + /// If present, filter the list by the value provided + /// If present, filter the list by the value provided + /// If present, start the results from the specified page + /// If present, return the specified number of results, up to 1000 + /// + public OutgoingCallerIdResult ListOutgoingCallerIds(string phoneNumber, string friendlyName, int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds"; + request.RootElement = "OutgoingCallerIds"; + + if (phoneNumber.HasValue()) request.AddParameter("PhoneNumber", phoneNumber); + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Adds a new validated CallerID to your account. + /// After making this request, Twilio will return to you a validation code and dial the phone number given to perform validation. + /// The code returned must be entered via the phone before the CallerID will be added to your account. + /// Makes a POST request to an OutgoingCallerIds List resource. + /// + /// The phone number to verify. Should be formatted with a '+' and country code e.g., +16175551212 (E.164 format). Twilio will also accept unformatted US numbers e.g., (415) 555-1212, 415-555-1212. + /// A human readable description for the new caller ID with maximum length 64 characters. Defaults to a nicely formatted version of the number. + /// The number of seconds, between 0 and 60, to delay before initiating the validation call. Defaults to 0. + public ValidationRequestResult AddOutgoingCallerId(string phoneNumber, string friendlyName, int? callDelay) + { + Require.Argument("PhoneNumber", phoneNumber); + if (callDelay.HasValue) Validate.IsBetween(callDelay.Value, 0, 60); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds"; + request.RootElement = "ValidationRequest"; + request.AddParameter("PhoneNumber", phoneNumber); + + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (callDelay.HasValue) request.AddParameter("CallDelay", callDelay.Value); + + return Execute(request); + } + + /// + /// Update the FriendlyName associated with a validated outgoing caller ID entry. + /// Makes a POST request to an OutgoingCallerId Instance resource. + /// + /// The Sid of the outgoing caller ID entry + /// The name to update the FriendlyName to + public OutgoingCallerId UpdateOutgoingCallerIdName(string outgoingCallerIdSid, string friendlyName) + { + Require.Argument("OutgoingCallerIdSid", outgoingCallerIdSid); + Require.Argument("FriendlyName", friendlyName); + Validate.IsValidLength(friendlyName, 64); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds/{OutgoingCallerIdSid}"; + request.RootElement = "OutgoingCallerId"; + + request.AddParameter("OutgoingCallerIdSid", outgoingCallerIdSid, ParameterType.UrlSegment); + request.AddParameter("FriendlyName", friendlyName); + + return Execute(request); + } + + /// + /// Remove a validated outgoing caller ID from the current account. + /// Makes a DELETE request to an OutgoingCallerId Instance resource. + /// + /// The Sid to remove + public DeleteStatus DeleteOutgoingCallerId(string outgoingCallerIdSid) + { + Require.Argument("OutgoingCallerIdSid", outgoingCallerIdSid); + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/OutgoingCallerIds/{OutgoingCallerIdSid}"; + + request.AddParameter("OutgoingCallerIdSid", outgoingCallerIdSid, ParameterType.UrlSegment); + + var response = Execute(request); + return response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed; + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Properties/AssemblyInfo.cs b/src/Twilio.Api/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0de9ec9588 --- /dev/null +++ b/src/Twilio.Api/Properties/AssemblyInfo.cs @@ -0,0 +1,9 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Twilio.Api")] +[assembly: AssemblyDescription("API wrapper for the Twilio REST API")] +[assembly: AssemblyConfiguration("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c2354ee7-e275-4969-9cdb-21cfcdd4c0b0")] \ No newline at end of file diff --git a/src/Twilio.Api/Recordings.cs b/src/Twilio.Api/Recordings.cs new file mode 100644 index 000000000..d1c94bee6 --- /dev/null +++ b/src/Twilio.Api/Recordings.cs @@ -0,0 +1,105 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns a list of Recordings, each representing a recording generated during the course of a phone call. + /// The list includes paging information. + /// Makes a GET request to the Recordings List resource. + /// + public RecordingResult ListRecordings() + { + return ListRecordings(null, null, null, null); + } + + /// + /// Returns a filtered list of Recordings, each representing a recording generated during the course of a phone call. + /// The list includes paging information. + /// Makes a GET request to the Recordings List resource. + /// + /// (Optional) The CallSid to retrieve recordings for + /// (Optional) The date the recording was created (GMT) + /// The page to start retrieving results from + /// How many results to retrieve + public RecordingResult ListRecordings(string callSid, DateTime? dateCreated, int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Recordings"; + + if (callSid.HasValue()) request.AddParameter("CallSid", callSid); + if (dateCreated.HasValue) request.AddParameter("DateCreated", dateCreated.Value.ToString("yyyy-MM-dd")); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Retrieve the details for the specified recording instance. + /// Makes a GET request to a Recording Instance resource. + /// + /// The Sid of the recording to retrieve + public Recording GetRecording(string recordingSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Recordings/{RecordingSid}.xml"; + request.RootElement = "Recording"; + + request.AddParameter("RecordingSid", recordingSid, ParameterType.UrlSegment); + + return Execute(request); + } + + /// + /// Delete the specified recording instance. Makes a DELETE request to a Recording Instance resource. + /// + /// The Sid of the recording to delete + public DeleteStatus DeleteRecording(string recordingSid) + { + var request = new RestRequest(Method.DELETE); + request.Resource = "Accounts/{AccountSid}/Recordings/{RecordingSid}.xml"; + request.RootElement = "Recording"; + + request.AddParameter("RecordingSid", recordingSid, ParameterType.UrlSegment); + + var response = Execute(request); + return response.StatusCode == System.Net.HttpStatusCode.NoContent ? DeleteStatus.Success : DeleteStatus.Failed; + } + + /// + /// Retrieves the transcription text for the specified recording, if it was transcribed. + /// Makes a GET request to a Recording Instance resource. + /// + /// The Sid of the recording to retreive the transcription for + public string GetRecordingText(string recordingSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Recordings/{RecordingSid}.txt"; + request.AddParameter("RecordingSid", recordingSid, ParameterType.UrlSegment); + + var response = Execute(request); + return response.Content; + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Sandbox.cs b/src/Twilio.Api/Sandbox.cs new file mode 100644 index 000000000..d21ae8065 --- /dev/null +++ b/src/Twilio.Api/Sandbox.cs @@ -0,0 +1,60 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns the Sandbox resource associated with the account identified by {YourAccountSid}. + /// Twilio accounts upgraded prior to February 2010 may not have a Sandbox resource, and in this case you will receive a 404 (Not Found) response. + /// Makes a GET request to the Sandbox Instance resource. + /// + public Sandbox GetSandbox() + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Sandbox"; + + return Execute(request); + } + + /// + /// Update the TwiML voice and SMS URLs associated with the sandbox number. + /// Makes a POST request to the Sandbox Instance resource. + /// + /// The URL to use for incoming calls to your sandbox number. + /// The HTTP method to use for incoming calls to your sandbox number. + /// The URL to use for incoming SMS text messages sent to your sandbox number. + /// The HTTP method to use for incoming text messages sent to your sandbox number. + public Sandbox UpdateSandbox(string voiceUrl, string voiceMethod, string smsUrl, string smsMethod) + { + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/Sandbox"; + + request.AddParameter("VoiceUrl", voiceUrl); + request.AddParameter("VoiceMethod", voiceMethod); + request.AddParameter("SmsUrl", smsUrl); + request.AddParameter("SmsMethod", smsMethod); + + return Execute(request); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/SharedAssemblyInfo.cs b/src/Twilio.Api/SharedAssemblyInfo.cs new file mode 100644 index 000000000..cc2d7e5ae --- /dev/null +++ b/src/Twilio.Api/SharedAssemblyInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyCompany("Twilio")] +[assembly: AssemblyProduct("Twilio")] +[assembly: AssemblyCopyright("Copyright Twilio")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: AssemblyVersion("2.1.0.0")] +[assembly: AssemblyFileVersion("2.1.0.0")] diff --git a/src/Twilio.Api/Sms.cs b/src/Twilio.Api/Sms.cs new file mode 100644 index 000000000..04ec520f0 --- /dev/null +++ b/src/Twilio.Api/Sms.cs @@ -0,0 +1,174 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; +using RestSharp.Validation; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Retrieve the details for a specific SMS message instance. + /// Makes a GET request to an SMSMessage Instance resource. + /// + /// The Sid of the message to retrieve + public SmsMessage GetSmsMessage(string smsMessageSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/Messages/{SMSMessageSid}"; + request.RootElement = "SMSMessage"; + request.AddUrlSegment("SMSMessageSid", smsMessageSid); + + return Execute(request); + } + + /// + /// Returns a list of SMS messages. + /// The list includes paging information and is sorted by DateSent, with most recent messages first. + /// Makes a GET request to the SMSMessage List resource. + /// + public SmsMessageResult GetSmsMessages() + { + return GetSmsMessages(null, null, null, null, null); + } + + /// + /// Returns a filtered list of SMS messages. The list includes paging information and is sorted by DateSent, with most recent messages first. + /// Makes a GET request to the SMSMessages List resource. + /// + /// (Optional) The phone number of the message recipient + /// (Optional) The phone number of the message sender + /// (Optional) The date the message was sent (GMT) + /// (Optional) The page to start retrieving results from + /// (Optional) The number of results to retrieve + public SmsMessageResult GetSmsMessages(string to, string from, DateTime? dateSent, int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/Messages"; + request.RootElement = "SMSMessages"; + + if (to.HasValue()) request.AddParameter("To", to); + if (from.HasValue()) request.AddParameter("From", from); + if (dateSent.HasValue) request.AddParameter("DateSent", dateSent.Value.ToString("yyyy-MM-dd")); + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Send a new SMS message to the specified recipients. + /// Makes a POST request to the SMSMessages List resource. + /// + /// The phone number to send the message from. Must be a Twilio-provided or ported local (not toll-free) number. Validated outgoing caller IDs cannot be used. + /// The phone number to send the message to. If using the Sandbox, this number must be a validated outgoing caller ID + /// The message to send. Must be 160 characters or less. + public SmsMessage SendSmsMessage(string from, string to, string body) + { + return SendSmsMessage(from, to, body, string.Empty); + } + + /// + /// Send a new SMS message to the specified recipients + /// Makes a POST request to the SMSMessages List resource. + /// + /// The phone number to send the message from. Must be a Twilio-provided or ported local (not toll-free) number. Validated outgoing caller IDs cannot be used. + /// The phone number to send the message to. If using the Sandbox, this number must be a validated outgoing caller ID + /// The message to send. Must be 160 characters or less. + /// A URL that Twilio will POST to when your message is processed. Twilio will POST the SmsSid as well as SmsStatus=sent or SmsStatus=failed + public SmsMessage SendSmsMessage(string from, string to, string body, string statusCallback) + { + Validate.IsValidLength(body, 160); + Require.Argument("from", from); + Require.Argument("to", to); + Require.Argument("body", body); + + var request = new RestRequest(Method.POST); + request.Resource = "Accounts/{AccountSid}/SMS/Messages"; + request.AddParameter("From", from); + request.AddParameter("To", to); + request.AddParameter("Body", body); + if (statusCallback.HasValue()) request.AddParameter("StatusCallback", statusCallback); + + return Execute(request); + } + + /// + /// Retrieve the details for a specific ShortCode instance. + /// Makes a GET request to a ShortCode Instance resource. + /// + /// The Sid of the ShortCode resource to return + public SmsShortCode GetShortCode(string shortCodeSid) + { + Require.Argument("shortCodeSid", shortCodeSid); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/ShortCodes/{ShortCodeSid}"; + request.AddParameter("ShortCodeSid", shortCodeSid); + + return Execute(request); + } + + /// + /// Tries to update the shortcode's properties, and returns the updated resource representation if successful. + /// Makes a POST request to the ShortCode instance resource. + /// + /// The Sid of the ShortCode instance to update + /// A human readable description of the short code, with maximum length 64 characters. + /// SMSs to this short code will start a new TwiML session with this API version. + /// The URL that Twilio should request when somebody sends an SMS to the short code. + /// The HTTP method that should be used to request the SmsUrl. Either GET or POST. + /// A URL that Twilio will request if an error occurs requesting or executing the TwiML at the SmsUrl. + /// The HTTP method that should be used to request the SmsFallbackUrl. Either GET or POST. + public SmsShortCode UpdateShortCode(string shortCodeSid, string friendlyName, string apiVersion, string smsUrl, string smsMethod, string smsFallbackUrl, string smsFallbackMethod) + { + Require.Argument("shortCodeSid", shortCodeSid); + + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/ShortCodes/{ShortCodeSid}"; + request.AddParameter("ShortCodeSid", shortCodeSid); + + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + if (apiVersion.HasValue()) request.AddParameter("ApiVersion", apiVersion); + if (smsUrl.HasValue()) request.AddParameter("SmsUrl", smsUrl); + if (smsMethod.HasValue()) request.AddParameter("SmsMethod", smsMethod); + if (smsFallbackUrl.HasValue()) request.AddParameter("SmsFallbackUrl", smsFallbackUrl); + if (smsFallbackMethod.HasValue()) request.AddParameter("SmsFallbackMethod", smsFallbackMethod); + + return Execute(request); + } + + /// + /// Returns a list of ShortCode resource representations, each representing a short code within your account. + /// + /// Only show the ShortCode resources that match this pattern. You can specify partial numbers and use '*' as a wildcard for any digit. + /// Only show the ShortCode resources with friendly names that exactly match this name. + public SmsShortCodeResult ListShortCodes(string shortCode, string friendlyName) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/SMS/ShortCodes}"; + + if (shortCode.HasValue()) request.AddParameter("ShortCode", shortCode); + if (friendlyName.HasValue()) request.AddParameter("FriendlyName", friendlyName); + + return Execute(request); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Transcriptions.cs b/src/Twilio.Api/Transcriptions.cs new file mode 100644 index 000000000..068791c9f --- /dev/null +++ b/src/Twilio.Api/Transcriptions.cs @@ -0,0 +1,100 @@ +#region License +// Copyright 2010 John Sheehan +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +using System; +using RestSharp; +using RestSharp.Extensions; + + +namespace Twilio +{ + public partial class TwilioRestClient + { + /// + /// Returns a set of Transcriptions that includes paging information, sorted by 'DateUpdated', with most recent transcripts first. + /// Makes a GET request to the Transcriptions List resource. + /// + public TranscriptionResult ListTranscriptions() + { + return ListTranscriptions(null, null); + } + + /// + /// Returns a paged set of Transcriptions that includes paging information, sorted by 'DateUpdated', with most recent transcripts first. + /// Makes a GET request to the Transcriptions List resource. + /// + /// The page to start retrieving results from + /// The number of results to retrieve + public TranscriptionResult ListTranscriptions(int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Transcriptions"; + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Returns a set of Transcriptions for a specific recording that includes paging information, sorted by 'DateUpdated', + /// with most recent transcripts first. Makes a GET request to a Recording Transcriptions List resource. + /// + /// The Sid of the recording to retrieve transcriptions for + /// The page to start retrieving results from + /// The number of results to retrieve + public TranscriptionResult ListTranscriptions(string recordingSid, int? pageNumber, int? count) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Recordings/{RecordingSid}/Transcriptions"; + request.AddUrlSegment("RecordingSid", recordingSid); + + if (pageNumber.HasValue) request.AddParameter("page", pageNumber.Value); + if (count.HasValue) request.AddParameter("num", count.Value); + + return Execute(request); + } + + /// + /// Retrieve the details of a single transcription. + /// Makes a GET request to a Transcription Instance resource. + /// + /// The Sid of the transcription to retrieve + public Transcription GetTranscription(string transcriptionSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Transcriptions/{TranscriptionSid}"; + request.RootElement = "Transcription"; + request.AddParameter("TranscriptionSid", transcriptionSid, ParameterType.UrlSegment); + + return Execute(request); + } + + /// + /// Retrieve the text of a single transcription. + /// Makes a GET request to a Transcription Instance resource. + /// + /// The Sid of the transcription to retrieve + public string GetTranscriptionText(string transcriptionSid) + { + var request = new RestRequest(); + request.Resource = "Accounts/{AccountSid}/Transcriptions/{TranscriptionSid}.txt"; + request.AddParameter("TranscriptionSid", transcriptionSid, ParameterType.UrlSegment); + + var response = Execute(request); + return response.Content; + } + } +} \ No newline at end of file diff --git a/src/Twilio.Api/Twilio.Api.csproj b/src/Twilio.Api/Twilio.Api.csproj new file mode 100644 index 000000000..bf2f23ef4 --- /dev/null +++ b/src/Twilio.Api/Twilio.Api.csproj @@ -0,0 +1,171 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B} + Library + Properties + Twilio + Twilio.Api + v3.5 + 512 + + + 3.5 + + Client + + + true + full + false + bin\Debug\ + TRACE;DEBUG;FRAMEWORK + prompt + 4 + AllRules.ruleset + bin\Debug\Twilio.Api.xml + + + pdbonly + true + bin\Release\ + TRACE;FRAMEWORK + prompt + 4 + AllRules.ruleset + bin\Release\Twilio.Api.xml + + + + ..\packages\Newtonsoft.Json.4.0.2\lib\net35\Newtonsoft.Json.Net35.dll + + + False + ..\packages\RestSharp.101.3\lib\net35-client\RestSharp.dll + + + + 3.5 + + + 3.5 + + + + + + + Accounts.Async.cs + + + Applications.Async.cs + + + AvailablePhoneNumbers.Aysnc.cs + + + Calls.Async.cs + + + Conference.Async.cs + + + Core.Async.cs + + + IncomingPhoneNumbers.Async.cs + + + Notifications.Aysnc.cs + + + OutgoingCallerIds.Async.cs + + + Recordings.Async.cs + + + Sandbox.Async.cs + + + Sms.Async.cs + + + Transcriptions.Async.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Twilio.Api/packages.config b/src/Twilio.Api/packages.config new file mode 100644 index 000000000..ce8b75be1 --- /dev/null +++ b/src/Twilio.Api/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/Twilio.Mvc/Properties/AssemblyInfo.cs b/src/Twilio.Mvc/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ea8ece82f --- /dev/null +++ b/src/Twilio.Mvc/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Twilio.Mvc")] +[assembly: AssemblyDescription("ASP.NET MVC Helpers for Twilio")] +[assembly: AssemblyConfiguration("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cdecab7a-0a8f-4dfe-898c-1647f63132b2")] \ No newline at end of file diff --git a/src/Twilio.Mvc/TwiMLResult.cs b/src/Twilio.Mvc/TwiMLResult.cs new file mode 100644 index 000000000..d5c5875cf --- /dev/null +++ b/src/Twilio.Mvc/TwiMLResult.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; +using System.Xml.Linq; + +namespace Twilio.TwiML.Mvc +{ + public class TwiMLResult : ActionResult + { + XDocument data; + + public TwiMLResult() + { + } + + public TwiMLResult(string twiml) + { + data = XDocument.Parse(twiml); + } + + public TwiMLResult(XDocument twiml) + { + data = twiml; + } + + public TwiMLResult(TwilioResponse response) + { + data = response.ToXDocument(); + } + + public override void ExecuteResult(ControllerContext controllerContext) + { + var context = controllerContext.RequestContext.HttpContext; + context.Response.ContentType = "application/xml"; + + if (data == null) + { + data = new XDocument(new XElement("Response")); + } + + data.Save(context.Response.Output); + } + } +} diff --git a/src/Twilio.Mvc/Twilio.Mvc.csproj b/src/Twilio.Mvc/Twilio.Mvc.csproj new file mode 100644 index 000000000..29f5e3f59 --- /dev/null +++ b/src/Twilio.Mvc/Twilio.Mvc.csproj @@ -0,0 +1,70 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3} + Library + Properties + Twilio.Mvc + Twilio.Mvc + v3.5 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Twilio.Mvc.xml + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Twilio.Mvc.xml + + + + + + + + + + + + + + + SharedAssemblyInfo.cs + + + + + + + + + {D810C485-249B-499D-B5BA-8D6507E11DED} + Twilio.TwiML + + + + + \ No newline at end of file diff --git a/src/Twilio.Mvc/TwilioController.cs b/src/Twilio.Mvc/TwilioController.cs new file mode 100644 index 000000000..2a3ee1f6e --- /dev/null +++ b/src/Twilio.Mvc/TwilioController.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web.Mvc; + +namespace Twilio.TwiML.Mvc +{ + public class TwilioController : Controller + { + public TwiMLResult TwiML(TwilioResponse response) + { + return new TwiMLResult(response); + } + } +} diff --git a/src/Twilio.Mvc/ValidateRequestAttribute.cs b/src/Twilio.Mvc/ValidateRequestAttribute.cs new file mode 100644 index 000000000..ac5fb613d --- /dev/null +++ b/src/Twilio.Mvc/ValidateRequestAttribute.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web.Mvc; +using System.Security.Cryptography; +using System.Net; +using System.Web; + +namespace Twilio.TwiML.Mvc +{ + public class ValidateRequestAttribute : ActionFilterAttribute + { + public string AuthToken { get; set; } + public string UrlOverride { get; set; } + + public ValidateRequestAttribute(string authToken) + { + AuthToken = authToken; + } + + public ValidateRequestAttribute(string authToken, string urlOverride) + { + AuthToken = authToken; + UrlOverride = urlOverride; + } + + public override void OnActionExecuting(ActionExecutingContext filterContext) + { + var validator = new RequestValidator(); + + var context = ((HttpApplication)filterContext.HttpContext.GetService(typeof(HttpApplication))).Context; + + if (!validator.IsValidRequest(context, AuthToken, UrlOverride)) + { + filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; + filterContext.HttpContext.Response.SuppressContent = true; + filterContext.HttpContext.ApplicationInstance.CompleteRequest(); + } + + base.OnActionExecuting(filterContext); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DialTests.cs b/src/Twilio.Twiml.Tests/DialTests.cs new file mode 100644 index 000000000..d4053d34f --- /dev/null +++ b/src/Twilio.Twiml.Tests/DialTests.cs @@ -0,0 +1,121 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +using System.Xml.Linq; +using System.Xml.Schema; +using System.IO; +using System.Xml; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class DialTests : TestBase + { + [Fact] + public void Can_Generate_Dial_Conference_And_Attributes() + { + var response = new TwilioResponse(); + response.DialConference("room1", new { muted = true, beep = false, waitUrl = "wait.xml", waitMethod = "GET" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_Conference_And_Attributes_And_Dial_Attributes() + { + var response = new TwilioResponse(); + response.DialConference("room1", + new { muted = true, beep = false, waitUrl = "wait.xml", waitMethod = "GET" }, + new { timeLimit = 30, action = "http://example.com" } + ); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_Conference() + { + var response = new TwilioResponse(); + response.DialConference("room1"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_Multiple_Numbers() + { + var response = new TwilioResponse(); + response.DialNumbers("555-111-1111", "555-222-2222", "555-333-3333"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_And_Attributes_And_Number_Attributes() + { + var response = new TwilioResponse(); + response.Dial("555-111-2222", + new { action = "dial.xml", method = "GET", timeout = "30", hangupOnStar = "true", timeLimit = "1000", callerId = "555-111-2222" }, + new { url = "whisper.xml", sendDigits = 1234 } + ); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_And_Attributes() + { + var response = new TwilioResponse(); + response.Dial("555-111-2222", new { action = "dial.xml", method = "GET", timeout = "30", hangupOnStar = "true", timeLimit = "1000", callerId = "555-111-2222" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial() + { + var response = new TwilioResponse(); + response.Dial("555-111-2222"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_And_Number_Object_Param() + { + var response = new TwilioResponse(); + response.Dial(new Number("555-111-2222")); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_And_Conf_Object_Param() + { + var response = new TwilioResponse(); + response.Dial(new Conference("room1")); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_And_Number_Object_Param_And_Dial_Attributes() + { + var response = new TwilioResponse(); + response.Dial(new Number("555-111-2222"), new { action = "dial.xml", method = "GET", timeout = "30", hangupOnStar = "true", timeLimit = "1000", callerId = "555-111-2222" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Dial_And_Conf_Object_Param_And_Dial_Attributes() + { + var response = new TwilioResponse(); + response.Dial(new Conference("room1"), new { action = "dial.xml", method = "GET", timeout = "30", hangupOnStar = "true", timeLimit = "1000", callerId = "555-111-2222" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} diff --git a/src/Twilio.Twiml.Tests/DocExamples/Sms/Redirect.cs b/src/Twilio.Twiml.Tests/DocExamples/Sms/Redirect.cs new file mode 100644 index 000000000..ac683f565 --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Sms/Redirect.cs @@ -0,0 +1,26 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples.Sms +{ + public class RedirectTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Redirect("http://www.foo.com/nextInstructions"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Redirect("../nextInstructions"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Sms/Sms.cs b/src/Twilio.Twiml.Tests/DocExamples/Sms/Sms.cs new file mode 100644 index 000000000..32d3afbff --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Sms/Sms.cs @@ -0,0 +1,35 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples.Sms +{ + public class SmsTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Sms("Store Location: 123 Easy St."); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Sms("Store Location: 123 Easy St.", new { action = "/SmsHandler.php", method = "POST" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_3() + { + var response = new TwilioResponse(); + response.Sms("Store Location: 123 Easy St.", new { statusCallback = "/SMSHandler.php" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Conference.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Conference.cs new file mode 100644 index 000000000..71f6ffa1c --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Conference.cs @@ -0,0 +1,78 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class ConferenceTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.DialConference("1234"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2a() + { + var response = new TwilioResponse(); + response.DialConference("1234", new { startConferenceOnEnter = "false" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2b() + { + var response = new TwilioResponse(); + response.DialConference("1234", new { startConferenceOnEnter = false, endConferenceOnExit = true }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_3() + { + var response = new TwilioResponse(); + response.DialConference("SimpleRoom", new { muted = true }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_4() + { + var response = new TwilioResponse(); + response.DialConference("NoMusicNoBeepRoom", new { beep = false, waitUrl = "", startConferenceOnEnter = true, endConferenceOnExit = false }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_5a() + { + var response = new TwilioResponse(); + response.DialConference("Customer Waiting Room", new { beep = false }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_5b() + { + var response = new TwilioResponse(); + response.DialConference("Customer Waiting Room", new { beep = false, endConferenceOnExit = true }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_6() + { + var response = new TwilioResponse(); + response.Dial(new Conference("LoveTwilio"), new { action = "handleLeaveConference.php", method = "POST", hangupOnStar = "true", timeLimit = 30 }); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Dial.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Dial.cs new file mode 100644 index 000000000..ac6560886 --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Dial.cs @@ -0,0 +1,28 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class DialTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Dial("515-123-4567"); + response.Say("Goodbye"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Dial("415-123-4567", new { action = "/handleDialCallStatus.php", method = "GET" }); + response.Say("I am unreachable"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Gather.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Gather.cs new file mode 100644 index 000000000..95233796a --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Gather.cs @@ -0,0 +1,43 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class GatherTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Gather(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + // http://www.twilio.com/docs/api/twiml/gather#examples-2 + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.BeginGather(new { action = "/process_gather.php", method = "GET" }); + response.Say("Please enter your account number, followed by the pound sign"); + response.EndGather(); + response.Say("We didn't receive any input. Goodbye!"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + // http://www.twilio.com/docs/api/twiml/gather#hints + [Fact] + public void Advanced() + { + var response = new TwilioResponse(); + response.BeginGather(new { action = "/process_gather.php", method = "GET" }); + response.Say("Enter something, or not"); + response.EndGather(); + response.Redirect("/process_gather.php?Digits=TIMEOUT", "GET"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Hangup.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Hangup.cs new file mode 100644 index 000000000..3f6f0cd2d --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Hangup.cs @@ -0,0 +1,17 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class HangupTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Hangup(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Number.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Number.cs new file mode 100644 index 000000000..0798983e1 --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Number.cs @@ -0,0 +1,26 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class NumberTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Dial(new Number("415-123-4567", new { sendDigits = "wwww1928" })); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.DialNumbers("858-987-6543", "415-123-4567", "619-765-4321"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Pause.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Pause.cs new file mode 100644 index 000000000..36076c3c8 --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Pause.cs @@ -0,0 +1,29 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class PauseTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Say("I will pause 10 seconds starting now!"); + response.Pause(10); + response.Say("I just paused 10 seconds"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Pause(5); + response.Say("Hi there."); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Play.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Play.cs new file mode 100644 index 000000000..919b267b1 --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Play.cs @@ -0,0 +1,17 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class PlayTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Play("http://foo.com/cowbell.mp3"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Record.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Record.cs new file mode 100644 index 000000000..1c8b99728 --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Record.cs @@ -0,0 +1,36 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class RecordTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Record(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Say("Please leave a message at the beep. Press the star key when finished."); + response.Record(new { action = "http://foo.edu/handleRecording.php", method = "GET", maxLength = 20, finishOnKey = "*" }); + response.Say("I did not receive a recording"); + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_3() + { + var response = new TwilioResponse(); + response.Record(new { transcribe = true, transcribeCallback = "/handle_transcribe.php" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Redirect.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Redirect.cs new file mode 100644 index 000000000..0d0622823 --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Redirect.cs @@ -0,0 +1,27 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class RedirectTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Dial("415-123-4567"); + response.Redirect("http://www.foo.com/nextInstructions"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Redirect("../nextInstructions"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Reject.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Reject.cs new file mode 100644 index 000000000..75d43c12a --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Reject.cs @@ -0,0 +1,26 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class RejectTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Reject(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Reject("busy"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Say.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Say.cs new file mode 100644 index 000000000..0275abb0c --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Say.cs @@ -0,0 +1,26 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class SayTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Say("Hello world"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Say("Hello world", new { voice = "woman", loop = 2 }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/DocExamples/Voice/Sms.cs b/src/Twilio.Twiml.Tests/DocExamples/Voice/Sms.cs new file mode 100644 index 000000000..54daca915 --- /dev/null +++ b/src/Twilio.Twiml.Tests/DocExamples/Voice/Sms.cs @@ -0,0 +1,38 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests.DocExamples +{ + public class SmsTests : TestBase + { + [Fact] + public void Example_1() + { + var response = new TwilioResponse(); + response.Say("Our store is located at 123 Easy St."); + response.Sms("Store Location: 123 Easy St."); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_2() + { + var response = new TwilioResponse(); + response.Say("Our store is located at 123 Easy St."); + response.Sms("Store Location: 123 Easy St.", new { action = "/smsHandler.php", method = "POST" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Example_3() + { + var response = new TwilioResponse(); + response.Say("Our store is located at 123 Easy St."); + response.Sms("Store Location: 123 Easy St.", new { statusCallback = "/smsHandler.php" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/GatherTests.cs b/src/Twilio.Twiml.Tests/GatherTests.cs new file mode 100644 index 000000000..bc352d61d --- /dev/null +++ b/src/Twilio.Twiml.Tests/GatherTests.cs @@ -0,0 +1,39 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class GatherTests : TestBase + { + [Fact] + public void Can_Generate_Gather_With_No_Options() + { + var response = new TwilioResponse(); + response.Gather(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Gather_With_All_Options() + { + var response = new TwilioResponse(); + response.Gather(new { action = "example.xml", timeout = 10, method = "GET", finishOnKey = "#", numDigits = 3 }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Gather_With_All_Options_and_Nested_Verbs_With_Begin_End() + { + var response = new TwilioResponse(); + response.BeginGather(new { action = "example.xml", timeout = 10, method = "GET", finishOnKey = "#", numDigits = 3 }) + .Say("hello") + .Play("example.mp3") + .Pause(10) + .EndGather(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} diff --git a/src/Twilio.Twiml.Tests/HangupTests.cs b/src/Twilio.Twiml.Tests/HangupTests.cs new file mode 100644 index 000000000..f8f282aac --- /dev/null +++ b/src/Twilio.Twiml.Tests/HangupTests.cs @@ -0,0 +1,22 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +using System.Xml.Linq; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class HangupTests : TestBase + { + [Fact] + public void Can_Generate_Single_Hangup() + { + var response = new TwilioResponse(); + response.Hangup(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/PauseTests.cs b/src/Twilio.Twiml.Tests/PauseTests.cs new file mode 100644 index 000000000..562d3724f --- /dev/null +++ b/src/Twilio.Twiml.Tests/PauseTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +using System.Xml.Linq; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class PauseTests : TestBase + { + [Fact] + public void Can_Generate_Single_Pause_With_Length() + { + var response = new TwilioResponse(); + response.Pause(10); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Single_Pause() + { + var response = new TwilioResponse(); + response.Pause(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/PlayTests.cs b/src/Twilio.Twiml.Tests/PlayTests.cs new file mode 100644 index 000000000..34493607d --- /dev/null +++ b/src/Twilio.Twiml.Tests/PlayTests.cs @@ -0,0 +1,36 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class PlayTests : TestBase + { + [Fact] + public void Can_Generate_Single_Play() + { + var response = new TwilioResponse(); + response.Play("Hello world"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Single_Play_And_Attributes() + { + var response = new TwilioResponse(); + response.Play("Hello world", new { loop = 3 }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Consecutive_Mixed_Plays() + { + var response = new TwilioResponse(); + response.Play("Hello world"); + response.Play("Hello world2", new { loop = 3 }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/Properties/AssemblyInfo.cs b/src/Twilio.Twiml.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..d95d2cffe --- /dev/null +++ b/src/Twilio.Twiml.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Twilio.TwiML.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("797d6e40-5226-4731-8a0e-7fd7e572da6e")] \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/QuickStarts/HelloMonkey.cs b/src/Twilio.Twiml.Tests/QuickStarts/HelloMonkey.cs new file mode 100644 index 000000000..f568fff8c --- /dev/null +++ b/src/Twilio.Twiml.Tests/QuickStarts/HelloMonkey.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Xunit; + +namespace Twilio.TwiML.Tests.QuickStarts +{ + public class HelloMonkey : TestBase + { + [Fact] + public void _1_0() + { + var response = new TwilioResponse(); + response.Say("Hello monkey"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _1_1() + { + var name = "Monkey"; + + var response = new TwilioResponse(); + response.Say("Hello " + name); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _1_2() + { + var name = "Monkey"; + + var response = new TwilioResponse(); + response.Say("Hello " + name); + response.Play("http://demo.twilio.com/hellomonkey/monkey.mp3"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _1_3a() + { + var name = "Monkey"; + + var response = new TwilioResponse(); + response.Say("Hello " + name); + response.Play("http://demo.twilio.com/hellomonkey/monkey.mp3"); + response.BeginGather(new { numDigits = 1, action = "hello-monkey-handle-key.php", method = "POST" }); + response.Say("To speak to a real monkey, press 1. Press any other key to start over."); + response.EndGather(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _1_3b() + { + var response = new TwilioResponse(); + response.Dial("+13105551212"); + response.Say("The call failed or the remote party hung up. Goodbye."); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _1_4a() + { + var name = "Monkey"; + + var response = new TwilioResponse(); + response.Say("Hello " + name); + response.Play("http://demo.twilio.com/hellomonkey/monkey.mp3"); + response.BeginGather(new { numDigits = 1, action = "hello-monkey-handle-key.php", method = "POST" }); + response.Say("To speak to a real monkey, press 1. Press 2 to record your own monkey howl. Press any other key to start over."); + response.EndGather(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _1_4b() + { + var digits = 1; + + var response = new TwilioResponse(); + if (digits == 1) + { + response.Dial("+13105551212"); + response.Say("The call failed or the remote party hung up. Goodbye."); + } + else if (digits == 2) + { + response.Say("Record your monkey howl after the tone."); + response.Record(new { maxLength = 30, action = "hello-monkey-handle-recording.php" }); + } + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _1_4c() + { + var recordingUrl = "http://example.com/example.mp3"; + + var response = new TwilioResponse(); + response.Say("Thanks for howling... take a listen to what you howled."); + response.Play(recordingUrl); + response.Say("Goodbye"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} diff --git a/src/Twilio.Twiml.Tests/QuickStarts/SmsHelloMonkey.cs b/src/Twilio.Twiml.Tests/QuickStarts/SmsHelloMonkey.cs new file mode 100644 index 000000000..0851ded75 --- /dev/null +++ b/src/Twilio.Twiml.Tests/QuickStarts/SmsHelloMonkey.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Xunit; + +namespace Twilio.TwiML.Tests.QuickStarts +{ + public class SmsHelloMonkey : TestBase + { + [Fact] + public void _1_0() + { + var response = new TwilioResponse(); + response.Sms("Hello, Mobile Monkey"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _2_0() + { + var name = "Monkey"; + + var response = new TwilioResponse(); + response.Sms(name + ", thanks for the message!"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _4_0() + { + var name = "Monkey"; + var to = "+15558675309"; + var counter = 2; + + var response = new TwilioResponse(); + response.Sms(name + " has messaged " + to + " " + counter + " times"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void _5_0() + { + var name = "Monkey"; + + var response = new TwilioResponse(); + response.Say("Hello " + name); + response.Say(name + ", thanks for the call!"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} diff --git a/src/Twilio.Twiml.Tests/RecordTests.cs b/src/Twilio.Twiml.Tests/RecordTests.cs new file mode 100644 index 000000000..bab43e3e3 --- /dev/null +++ b/src/Twilio.Twiml.Tests/RecordTests.cs @@ -0,0 +1,35 @@ +using System; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class RecordTests : TestBase + { + [Fact] + public void Can_Generate_Single_Record() + { + var response = new TwilioResponse(); + response.Record(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Record_And_Attributes() + { + var response = new TwilioResponse(); + response.Record(new { action = "record.php" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Record_With_All_Attributes() + { + var response = new TwilioResponse(); + response.Record(new { action = "record.php", method = "GET", timeout = 10, finishOnKey = "#", maxLength = 90, transcribe = true, transcribeCallback = "transcribe.php", playBeep = false }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/RedirectTests.cs b/src/Twilio.Twiml.Tests/RedirectTests.cs new file mode 100644 index 000000000..012f2c76f --- /dev/null +++ b/src/Twilio.Twiml.Tests/RedirectTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +using System.Xml.Linq; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class RedirectTests : TestBase + { + [Fact] + public void Can_Generate_Single_Redirect() + { + var response = new TwilioResponse(); + response.Redirect("url"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Single_Redirect_With_Method() + { + var response = new TwilioResponse(); + response.Redirect("url", "GET"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/RejectTests.cs b/src/Twilio.Twiml.Tests/RejectTests.cs new file mode 100644 index 000000000..7b1f66490 --- /dev/null +++ b/src/Twilio.Twiml.Tests/RejectTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +using System.Xml.Linq; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class RejectTests : TestBase + { + [Fact] + public void Can_Generate_Empty_Reject() + { + var response = new TwilioResponse(); + response.Reject(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Reject_With_Reason() + { + var response = new TwilioResponse(); + response.Reject("busy"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/ResponseTests.cs b/src/Twilio.Twiml.Tests/ResponseTests.cs new file mode 100644 index 000000000..3805ed7a1 --- /dev/null +++ b/src/Twilio.Twiml.Tests/ResponseTests.cs @@ -0,0 +1,21 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +using System.Xml.Linq; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class ResponseTests : TestBase + { + [Fact] + public void Can_Generate_Empty_Response() + { + var response = new TwilioResponse(); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} diff --git a/src/Twilio.Twiml.Tests/SayTests.cs b/src/Twilio.Twiml.Tests/SayTests.cs new file mode 100644 index 000000000..a029cc095 --- /dev/null +++ b/src/Twilio.Twiml.Tests/SayTests.cs @@ -0,0 +1,41 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +using System.Xml.Linq; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class SayTests : TestBase + { + [Fact] + public void Can_Generate_Single_Say() + { + var response = new TwilioResponse(); + response.Say("Hello world"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Single_Say_And_Attributes() + { + var response = new TwilioResponse(); + response.Say("Hello world", new { language = "en" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Consecutive_Mixed_Says() + { + var response = new TwilioResponse(); + response.Say("Hello world", new { voice = "woman" }); + response.Say("Hello world2", new { loop = 3 }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/SmsTests.cs b/src/Twilio.Twiml.Tests/SmsTests.cs new file mode 100644 index 000000000..5910eb0b9 --- /dev/null +++ b/src/Twilio.Twiml.Tests/SmsTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; + +using System.Xml.Linq; +using Xunit; + +namespace Twilio.TwiML.Tests +{ + public class SmsTests : TestBase + { + [Fact] + public void Can_Generate_Single_Sms() + { + var response = new TwilioResponse(); + response.Sms("Hello world"); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + + [Fact] + public void Can_Generate_Single_Sms_And_Attributes() + { + var response = new TwilioResponse(); + response.Sms("Hello world", new { to = "+15551111111", from = "+15552222222", action = "sms.php", method = "GET", statusCallback = "status.php" }); + + Assert.True(IsValidTwiML(response.ToXDocument())); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/TestBase.cs b/src/Twilio.Twiml.Tests/TestBase.cs new file mode 100644 index 000000000..8761132d9 --- /dev/null +++ b/src/Twilio.Twiml.Tests/TestBase.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using System.IO; +using System.Xml.Schema; +using System.Xml; + +namespace Twilio.TwiML.Tests +{ + public class TestBase + { + public XmlSchemaSet Schemas { get; set; } + + public TestBase() + { + Schemas = new XmlSchemaSet(); + Schemas.Add("", XmlReader.Create("TwiML.xsd")); + } + + public bool IsValidTwiML(XDocument doc) + { + Console.Write(doc.ToString()); + + var valid = true; + doc.Validate(Schemas, (o, e) => { valid = false; }); + return valid; + } + } +} diff --git a/src/Twilio.Twiml.Tests/TwiML.xsd b/src/Twilio.Twiml.Tests/TwiML.xsd new file mode 100644 index 000000000..f79fe5ea0 --- /dev/null +++ b/src/Twilio.Twiml.Tests/TwiML.xsd @@ -0,0 +1,170 @@ + + + + + Twilio API TwiML XML Schema Copyright Twilio Inc. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/Twilio.TwiML.Tests.csproj b/src/Twilio.Twiml.Tests/Twilio.TwiML.Tests.csproj new file mode 100644 index 000000000..20d7ae90d --- /dev/null +++ b/src/Twilio.Twiml.Tests/Twilio.TwiML.Tests.csproj @@ -0,0 +1,111 @@ + + + + Debug + AnyCPU + + + 2.0 + {35E6CB68-D17E-4E16-960D-75D638335FAF} + Library + Properties + Twilio.Twiml.Tests + Twilio.Twiml.Tests + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Twilio.Twiml.Tests.xml + + + + + + + 3.5 + + + + + ..\packages\xunit.1.8.0.1545\lib\xunit.dll + + + + + False + + + + + SharedAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {D810C485-249B-499D-B5BA-8D6507E11DED} + Twilio.TwiML + + + + + Designer + PreserveNewest + + + + + + + + \ No newline at end of file diff --git a/src/Twilio.Twiml.Tests/packages.config b/src/Twilio.Twiml.Tests/packages.config new file mode 100644 index 000000000..6626b0747 --- /dev/null +++ b/src/Twilio.Twiml.Tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Twilio.Twiml/Properties/AssemblyInfo.cs b/src/Twilio.Twiml/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..f0eb5ca73 --- /dev/null +++ b/src/Twilio.Twiml/Properties/AssemblyInfo.cs @@ -0,0 +1,9 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Twilio.TwiML")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a17cd566-d258-4df9-a873-0193c137b842")] \ No newline at end of file diff --git a/src/Twilio.Twiml/RequestValidator.cs b/src/Twilio.Twiml/RequestValidator.cs new file mode 100644 index 000000000..a393554a2 --- /dev/null +++ b/src/Twilio.Twiml/RequestValidator.cs @@ -0,0 +1,73 @@ +using System; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Web; + +namespace Twilio.TwiML +{ + /// + /// Class used to validate incoming requests from Twilio using 'Request Validation' as described + /// in the Security section of the Twilio TwiML API documentation. + /// + public class RequestValidator + { + /// + /// Performs request validation using the current HTTP context passed in manually or from + /// the ASP.NET MVC ValidateRequestAttribute + /// + /// HttpContext to use for validation + /// AuthToken for the account used to sign the request + public bool IsValidRequest(HttpContext context, string authToken) + { + return IsValidRequest(context, authToken, null); + } + + /// + /// Performs request validation using the current HTTP context passed in manually or from + /// the ASP.NET MVC ValidateRequestAttribute + /// + /// HttpContext to use for validation + /// AuthToken for the account used to sign the request + /// The URL to use for validation, if different from Request.Url (sometimes needed if web site is behind a proxy or load-balancer) + public bool IsValidRequest(HttpContext context, string authToken, string urlOverride) + { + if (context.Request.IsLocal) + { + return true; + } + + // validate request + // http://www.twilio.com/docs/security-reliability/security + // Take the full URL of the request, from the protocol (http...) through the end of the query string (everything after the ?) + var value = new StringBuilder(); + var fullUrl = string.IsNullOrEmpty(urlOverride) ? context.Request.Url.ToString() : urlOverride; + + value.Append(fullUrl); + + // If the request is a POST, take all of the POST parameters and sort them alphabetically. + if (context.Request.HttpMethod == "POST") + { + // Iterate through that sorted list of POST parameters, and append the variable name and value (with no delimiters) to the end of the URL string + var sortedKeys = context.Request.Form.AllKeys.OrderBy(k => k, StringComparer.Ordinal).ToList(); + foreach (var key in sortedKeys) + { + value.Append(key); + value.Append(context.Request.Form[key]); + } + } + + // Sign the resulting value with HMAC-SHA1 using your AuthToken as the key (remember, your AuthToken's case matters!). + var sha1 = new HMACSHA1(Encoding.UTF8.GetBytes(authToken)); + var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(value.ToString())); + + // Base64 encode the hash + var encoded = Convert.ToBase64String(hash); + + // Compare your hash to ours, submitted in the X-Twilio-Signature header. If they match, then you're good to go. + var sig = context.Request.Headers["X-Twilio-Signature"]; + + return sig == encoded; + } + } +} diff --git a/src/Twilio.Twiml/Twilio.TwiML.csproj b/src/Twilio.Twiml/Twilio.TwiML.csproj new file mode 100644 index 000000000..72cb36838 --- /dev/null +++ b/src/Twilio.Twiml/Twilio.TwiML.csproj @@ -0,0 +1,76 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {D810C485-249B-499D-B5BA-8D6507E11DED} + Library + Properties + Twilio.Twiml + Twilio.Twiml + v3.5 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Twilio.Twiml.xml + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Twilio.Twiml.xml + + + + + + + + + + + + SharedAssemblyInfo.cs + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Twilio.Twiml/TwilioResponse.cs b/src/Twilio.Twiml/TwilioResponse.cs new file mode 100644 index 000000000..24acbcd6a --- /dev/null +++ b/src/Twilio.Twiml/TwilioResponse.cs @@ -0,0 +1,257 @@ +using System; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class TwilioResponse : ElementBase + { + public TwilioResponse() + { + Element = new XElement("Response"); + + AllowedChildren.Add("Say"); + AllowedChildren.Add("Play"); + AllowedChildren.Add("Gather"); + AllowedChildren.Add("Dial"); + AllowedChildren.Add("Record"); + AllowedChildren.Add("Reject"); + AllowedChildren.Add("Redirect"); + AllowedChildren.Add("Sms"); + AllowedChildren.Add("Hangup"); + AllowedChildren.Add("Pause"); + } + + public TwilioResponse Dial(string number) + { + Add(new Dial(number)); + return this; + } + + public TwilioResponse Dial(string number, object attributes) + { + Add(new Dial(number, attributes)); + return this; + } + + public TwilioResponse Dial(string number, object dialAttributes, object numberAttributes) + { + BeginDial(dialAttributes); + Add(new Number(number, numberAttributes)); + return EndDial(); + } + + public TwilioResponse Dial(Number number) + { + BeginDial(); + Add(number); + return EndDial(); + } + + public TwilioResponse Dial(Number number, object dialAttributes) + { + BeginDial(dialAttributes); + Add(number); + return EndDial(); + } + + public TwilioResponse Dial(Conference conf) + { + BeginDial(); + Add(conf); + return EndDial(); + } + + public TwilioResponse Dial(Conference conf, object dialAttributes) + { + BeginDial(dialAttributes); + Add(conf); + return EndDial(); + } + + public TwilioResponse DialConference(string room) + { + BeginDial(); + Add(new Conference(room)); + return EndDial(); + } + + public TwilioResponse DialConference(string room, object attributes) + { + BeginDial(); + Add(new Conference(room, attributes)); + return EndDial(); + } + + public TwilioResponse DialConference(string room, object conferenceAttributes, object dialAttributes) + { + BeginDial(dialAttributes); + Add(new Conference(room, conferenceAttributes)); + return EndDial(); + } + + public TwilioResponse DialNumbers(params string[] numbers) + { + BeginDial(); + var dial = new Dial(); + foreach (var number in numbers) + { + Add(new Number(number)); + } + return EndDial(); + } + + protected TwilioResponse BeginDial() + { + Current.Push(new Dial()); + return this; + } + + protected TwilioResponse BeginDial(object attributes) + { + Current.Push(new Dial(null, attributes)); + return this; + } + + protected TwilioResponse EndDial() + { + Add(Current.Pop()); + return this; + } + + public TwilioResponse BeginGather() + { + Current.Push(new Gather()); + return this; + } + + public TwilioResponse BeginGather(object attributes) + { + Current.Push(new Gather(attributes)); + return this; + } + + public TwilioResponse EndGather() + { + Add(Current.Pop()); + return this; + } + + public TwilioResponse Gather() + { + Add(new Gather()); + return this; + } + + public TwilioResponse Gather(object attributes) + { + Add(new Gather(attributes)); + return this; + } + + public TwilioResponse Hangup() + { + Add(new Hangup()); + return this; + } + + public TwilioResponse Pause() + { + Add(new Pause()); + return this; + } + + public TwilioResponse Pause(int length) + { + Add(new Pause(length)); + return this; + } + + public TwilioResponse Play(string url) + { + Add(new Play(url)); + return this; + } + + public TwilioResponse Play(string url, object attributes) + { + Add(new Play(url, attributes)); + return this; + } + + public TwilioResponse Record() + { + Add(new Record()); + return this; + } + + public TwilioResponse Record(object attributes) + { + Add(new Record(attributes)); + return this; + } + + public TwilioResponse Redirect() + { + Add(new Redirect()); + return this; + } + + public TwilioResponse Redirect(string url) + { + Add(new Redirect(url)); + return this; + } + + public TwilioResponse Redirect(string url, string method) + { + Add(new Redirect(url, method)); + return this; + } + + public TwilioResponse Reject() + { + Add(new Reject()); + return this; + } + + public TwilioResponse Reject(string reason) + { + Add(new Reject(reason)); + return this; + } + + public TwilioResponse Say(string text) + { + Add(new Say(text)); + return this; + } + + public TwilioResponse Say(string text, object attributes) + { + Add(new Say(text, attributes)); + return this; + } + + public TwilioResponse Sms(string text) + { + Add(new Sms(text)); + return this; + } + + public TwilioResponse Sms(string text, object attributes) + { + Add(new Sms(text, attributes)); + return this; + } + + public override string ToString() + { + return ToXDocument().ToString(); + } + + public XDocument ToXDocument() + { + return new XDocument(Element); + } + } +} diff --git a/src/Twilio.Twiml/Verbs/Conference.cs b/src/Twilio.Twiml/Verbs/Conference.cs new file mode 100644 index 000000000..0f69c2325 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Conference.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Conference : ElementBase + { + public Conference() + { + Element = new XElement("Conference"); + + AllowedAttributes.Add("muted"); + AllowedAttributes.Add("beep"); + AllowedAttributes.Add("waitUrl"); + AllowedAttributes.Add("waitMethod"); + AllowedAttributes.Add("startConferenceOnEnter"); + AllowedAttributes.Add("endConferenceOnExit"); + } + + public Conference(string room) : this() + { + Element = new XElement("Conference", room); + } + + public Conference(string room, object attributes) : this(room) + { + AddAttributesFromObject(attributes); + } + } +} diff --git a/src/Twilio.Twiml/Verbs/Dial.cs b/src/Twilio.Twiml/Verbs/Dial.cs new file mode 100644 index 000000000..4d567b112 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Dial.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Dial : ElementBase + { + public Dial() + { + Element = new XElement("Dial"); + AllowedChildren.Add("Number"); + AllowedChildren.Add("Conference"); + + AllowedAttributes.Add("timeout"); + AllowedAttributes.Add("callerId"); + AllowedAttributes.Add("action"); + AllowedAttributes.Add("method"); + AllowedAttributes.Add("hangupOnStar"); + AllowedAttributes.Add("timeLimit"); + } + + public Dial(string number) : this() + { + Element.Add(number); + } + + public Dial(string number, object attributes) : this(number) + { + AddAttributesFromObject(attributes); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml/Verbs/ElementBase.cs b/src/Twilio.Twiml/Verbs/ElementBase.cs new file mode 100644 index 000000000..aa8fcd4aa --- /dev/null +++ b/src/Twilio.Twiml/Verbs/ElementBase.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; +using Twilio.TwiML.Verbs; + +namespace Twilio.TwiML +{ + public abstract class ElementBase + { + public List AllowedChildren { get; set; } + public List AllowedAttributes { get; set; } + public XElement Element { get; set; } + protected Stack Current { get; set; } + + public ElementBase() + { + AllowedAttributes = new List(); + AllowedChildren = new List(); + Current = new Stack(); + } + + protected ElementBase Add(ElementBase verb) + { + var root = Element; + var elementToAdd = verb.Element; + var allowed = AllowedChildren; + + if (Current.Any()) + { + root = Current.Peek().Element; + allowed = Current.Peek().AllowedChildren; + } + + if (allowed.Contains(verb.Element.Name.ToString())) + { + root.Add(elementToAdd); + } + + return this; + } + + public void AddAttributesFromObject(object attributes) + { + foreach (var prop in attributes.GetType().GetProperties()) + { + Element.SetAttributeValue(prop.Name, prop.GetValue(attributes, null)); + } + } + + public T GetAttributeValue(string key) + { + if (Element.Attributes(key) != null) + { + return (T)Element.Attributes(key); + } + + return default(T); + } + + public void SetAttributeValue(string key, object value) + { + if (AllowedAttributes.Contains(key)) + { + Element.Add(new XAttribute(key, value)); + } + } + } +} diff --git a/src/Twilio.Twiml/Verbs/Gather.cs b/src/Twilio.Twiml/Verbs/Gather.cs new file mode 100644 index 000000000..b1a07aa90 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Gather.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Gather : ElementBase + { + public Gather() + { + Element = new XElement("Gather"); + AllowedChildren.Add("Say"); + AllowedChildren.Add("Play"); + AllowedChildren.Add("Pause"); + + AllowedAttributes.Add("action"); + AllowedAttributes.Add("finishOnKey"); + AllowedAttributes.Add("method"); + AllowedAttributes.Add("numDigits"); + AllowedAttributes.Add("timeout"); + } + + public Gather(object attributes) : this() + { + AddAttributesFromObject(attributes); + } + } +} diff --git a/src/Twilio.Twiml/Verbs/Hangup.cs b/src/Twilio.Twiml/Verbs/Hangup.cs new file mode 100644 index 000000000..bc90a9612 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Hangup.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Hangup : ElementBase + { + public Hangup() + { + Element = new XElement("Hangup"); + } + } +} diff --git a/src/Twilio.Twiml/Verbs/IVerb.cs b/src/Twilio.Twiml/Verbs/IVerb.cs new file mode 100644 index 000000000..721e91aae --- /dev/null +++ b/src/Twilio.Twiml/Verbs/IVerb.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Twilio.TwiML.Verbs +{ + public interface IVerb + { + void Add(IVerb child); + IVerb With(IVerb child); + } +} diff --git a/src/Twilio.Twiml/Verbs/Number.cs b/src/Twilio.Twiml/Verbs/Number.cs new file mode 100644 index 000000000..097d629bc --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Number.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Number : ElementBase + { + public Number(string number) + { + Element = new XElement("Number", number); + AllowedAttributes.Add("url"); + AllowedAttributes.Add("sendDigits"); + } + + public Number(string number, object attributes) : this(number) + { + AddAttributesFromObject(attributes); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml/Verbs/Pause.cs b/src/Twilio.Twiml/Verbs/Pause.cs new file mode 100644 index 000000000..e046142e7 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Pause.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Pause : ElementBase + { + public Pause() + { + Element = new XElement("Pause"); + AllowedAttributes.Add("length"); + } + + public Pause(int seconds) : this() + { + SetAttributeValue("length", seconds); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml/Verbs/Play.cs b/src/Twilio.Twiml/Verbs/Play.cs new file mode 100644 index 000000000..7be39c871 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Play.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Play : ElementBase + { + public Play(string url) + { + Element = new XElement("Play", url); + } + + public Play(string url, object attributes) : this(url) + { + AddAttributesFromObject(attributes); + } + } +} diff --git a/src/Twilio.Twiml/Verbs/Record.cs b/src/Twilio.Twiml/Verbs/Record.cs new file mode 100644 index 000000000..423338d20 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Record.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Record : ElementBase + { + public Record() + { + Element = new XElement("Record"); + + AllowedAttributes.Add("action"); + AllowedAttributes.Add("method"); + AllowedAttributes.Add("timeout"); + AllowedAttributes.Add("finishOnKey"); + AllowedAttributes.Add("maxlength"); + AllowedAttributes.Add("transcribe"); + AllowedAttributes.Add("transcribeCallback"); + AllowedAttributes.Add("playBeep"); + } + + public Record(object attributes) : this() + { + AddAttributesFromObject(attributes); + } + } +} \ No newline at end of file diff --git a/src/Twilio.Twiml/Verbs/Redirect.cs b/src/Twilio.Twiml/Verbs/Redirect.cs new file mode 100644 index 000000000..415511e4a --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Redirect.cs @@ -0,0 +1,24 @@ +using System; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Redirect : ElementBase + { + public Redirect() + { + Element = new XElement("Redirect"); + AllowedAttributes.Add("method"); + } + + public Redirect(string url) : this() + { + Element.Add(url); + } + + public Redirect(string url, string method) : this(url) + { + SetAttributeValue("method", method); + } + } +} diff --git a/src/Twilio.Twiml/Verbs/Reject.cs b/src/Twilio.Twiml/Verbs/Reject.cs new file mode 100644 index 000000000..54bec8875 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Reject.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Reject : ElementBase + { + public Reject() + { + Element = new XElement("Reject"); + AllowedAttributes.Add("reason"); + } + + public Reject(string reason) : this() + { + SetAttributeValue("reason", reason); + } + } +} diff --git a/src/Twilio.Twiml/Verbs/Say.cs b/src/Twilio.Twiml/Verbs/Say.cs new file mode 100644 index 000000000..a9788088a --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Say.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Say : ElementBase + { + public Say(string text) + { + Element = new XElement("Say", text); + + AllowedAttributes.Add("voice"); + AllowedAttributes.Add("language"); + AllowedAttributes.Add("loop"); + } + + public Say(string text, object attributes) : this(text) + { + AddAttributesFromObject(attributes); + } + } +} diff --git a/src/Twilio.Twiml/Verbs/Sms.cs b/src/Twilio.Twiml/Verbs/Sms.cs new file mode 100644 index 000000000..5403a6dc6 --- /dev/null +++ b/src/Twilio.Twiml/Verbs/Sms.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Xml.Linq; + +namespace Twilio.TwiML +{ + public class Sms : ElementBase + { + public Sms() + { + Element = new XElement("Sms"); + + AllowedAttributes.Add("to"); + AllowedAttributes.Add("from"); + AllowedAttributes.Add("action"); + AllowedAttributes.Add("method"); + AllowedAttributes.Add("statusCallback"); + } + + public Sms(string message) : this() + { + Element.Add(message); + } + + public Sms(string message, object attributes) : this(message) + { + AddAttributesFromObject(attributes); + } + } +} diff --git a/src/Twilio.WebMatrix/Properties/AssemblyInfo.cs b/src/Twilio.WebMatrix/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..7046d8454 --- /dev/null +++ b/src/Twilio.WebMatrix/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Twilio.WebMatrix")] +[assembly: AssemblyDescription("WebMatrix helpers for sending SMS and initiating phone calls using Twilio")] +[assembly: AssemblyConfiguration("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9d06702c-5cb7-412e-ab98-4ff416ff4142")] \ No newline at end of file diff --git a/src/Twilio.WebMatrix/Twilio.WebMatrix.csproj b/src/Twilio.WebMatrix/Twilio.WebMatrix.csproj new file mode 100644 index 000000000..1e9ec84e1 --- /dev/null +++ b/src/Twilio.WebMatrix/Twilio.WebMatrix.csproj @@ -0,0 +1,66 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {D4EC9211-7F9B-45A0-B620-909C02841E60} + Library + Properties + Twilio.WebMatrix + Twilio.WebMatrix + v4.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Twilio.WebMatrix.xml + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Twilio.WebMatrix.xml + + + + + + + + + + + + + SharedAssemblyInfo.cs + + + + + + + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B} + Twilio.Api + + + + + \ No newline at end of file diff --git a/src/Twilio.WebMatrix/Twilio.cs b/src/Twilio.WebMatrix/Twilio.cs new file mode 100644 index 000000000..ec86f9932 --- /dev/null +++ b/src/Twilio.WebMatrix/Twilio.cs @@ -0,0 +1,92 @@ +using System; +using System.Web; +using Twilio; + +namespace Twilio.WebMatrix +{ + /// + /// A set of Twilio helpers for WebMatrix sites + /// + public class Twilio + { + /// + /// The AccountSid to authenticate with when making requests + /// + public static string AccountSid { get; set; } + /// + /// The AuthToken to authenticate with when making requests + /// + public static string AuthToken { get; set; } + + /// + /// Send an SMS message + /// + /// The number to send the message from + /// The number to send the message to + /// The contents of the message, up to 160 characters + /// The URL to notify of the message status + /// An SMSMessage Instance resource + public static SmsMessage SendSms(string from, string to, string body, string statusCallbackUrl) + { + CheckForCredentials(); + + var twilio = new TwilioRestClient(AccountSid, AuthToken); + return twilio.SendSmsMessage(from, to, body, statusCallbackUrl); + } + + /// + /// Initiate a new outgoing call + /// + /// The phone number to call from + /// The phone number to call to + /// The TwiML URL to use for controlling this call + /// The URL to notify upon completion of the call + /// The HTTP method to use when requesting the statusCallback URL + /// The URL to request upon encountering an in-call error + /// The HTTP method to use when requesting the fallbackUrl + /// The action to take when encountering an answering machine + /// The DTMF touch tone digits to transmit when the call is answered + /// The amount of time to allow a call to ring before ending + /// A Call Instance resource + public static Call MakeCall(string from, string to, string url, string statusCallback, + string statusCallbackMethod, string fallbackUrl, string fallbackMethod, + string ifMachine, string sendDigits, int? timeout = null) + { + CheckForCredentials(); + + var twilio = new TwilioRestClient(AccountSid, AuthToken); + + var options = new CallOptions(); + options.From = from; + options.To = to; + + if (!string.IsNullOrEmpty(url)) + { + options.Url = url; + } + else + { + options.Url = HttpContext.Current.Request.Url.ToString(); + } + + options.StatusCallback = statusCallback; + options.StatusCallbackMethod = statusCallbackMethod; + options.FallbackUrl = fallbackUrl; + options.FallbackMethod = fallbackMethod; + options.IfMachine = ifMachine; + options.SendDigits = sendDigits; + options.Timeout = timeout; + + return twilio.InitiateOutboundCall(options); + } + + private static void CheckForCredentials() + { + if (string.IsNullOrEmpty(AccountSid) || string.IsNullOrEmpty(AuthToken)) + { + throw new ApplicationException(@"Twilio credentials have not been specified. Verify Twilio.AccountSid + and Twilio.AuthToken have been set to the values from your account dashboard."); + } + } + } +} diff --git a/src/Twilio.sln b/src/Twilio.sln new file mode 100644 index 000000000..679b8042a --- /dev/null +++ b/src/Twilio.sln @@ -0,0 +1,121 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twilio.Api", "Twilio.Api\Twilio.Api.csproj", "{894FF9E8-4DBF-4472-8AE2-1A6A988E105B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twilio.Api.WindowsPhone", "Twilio.Api.WindowsPhone\Twilio.Api.WindowsPhone.csproj", "{21E25E45-A334-4178-BD5C-5B875A2911FD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{36CA862C-F8AB-4362-81F0-7B2116AF27FD}" + ProjectSection(SolutionItems) = preProject + ..\LICENSE.txt = ..\LICENSE.txt + ..\Twilio.Mvc.nuspec = ..\Twilio.Mvc.nuspec + ..\Twilio.nuspec = ..\Twilio.nuspec + ..\Twilio.TwiML.nuspec = ..\Twilio.TwiML.nuspec + ..\Twilio.WebMatrix.nuspec = ..\Twilio.WebMatrix.nuspec + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twilio.TwiML", "Twilio.Twiml\Twilio.TwiML.csproj", "{D810C485-249B-499D-B5BA-8D6507E11DED}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twilio.TwiML.Tests", "Twilio.Twiml.Tests\Twilio.TwiML.Tests.csproj", "{35E6CB68-D17E-4E16-960D-75D638335FAF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{86AE3CC1-5BB7-4438-AB08-732292C3754C}" + ProjectSection(SolutionItems) = preProject + Local.testsettings = Local.testsettings + TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings + Twilio.vsmdi = Twilio.vsmdi + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twilio.Api.Silverlight", "Twilio.Api.Silverlight\Twilio.Api.Silverlight.csproj", "{08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twilio.WebMatrix", "Twilio.WebMatrix\Twilio.WebMatrix.csproj", "{D4EC9211-7F9B-45A0-B620-909C02841E60}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Twilio.Mvc", "Twilio.Mvc\Twilio.Mvc.csproj", "{5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = Twilio.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Debug|x86.ActiveCfg = Debug|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Release|Any CPU.Build.0 = Release|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {894FF9E8-4DBF-4472-8AE2-1A6A988E105B}.Release|x86.ActiveCfg = Release|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Debug|x86.ActiveCfg = Debug|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Release|Any CPU.Build.0 = Release|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {21E25E45-A334-4178-BD5C-5B875A2911FD}.Release|x86.ActiveCfg = Release|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Debug|x86.ActiveCfg = Debug|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Release|Any CPU.Build.0 = Release|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D810C485-249B-499D-B5BA-8D6507E11DED}.Release|x86.ActiveCfg = Release|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Debug|x86.ActiveCfg = Debug|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Release|Any CPU.Build.0 = Release|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {35E6CB68-D17E-4E16-960D-75D638335FAF}.Release|x86.ActiveCfg = Release|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Debug|x86.ActiveCfg = Debug|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Release|Any CPU.Build.0 = Release|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {08218C33-9EE0-4B7B-874B-83CCEB8FE4DD}.Release|x86.ActiveCfg = Release|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Debug|x86.ActiveCfg = Debug|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Release|Any CPU.Build.0 = Release|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D4EC9211-7F9B-45A0-B620-909C02841E60}.Release|x86.ActiveCfg = Release|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Debug|x86.ActiveCfg = Debug|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Release|Any CPU.Build.0 = Release|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {5D0AFE27-1CBE-4E63-ADBC-A778B598E7B3}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Twilio.vsmdi b/src/Twilio.vsmdi new file mode 100644 index 000000000..c2dd210b9 --- /dev/null +++ b/src/Twilio.vsmdi @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/packages/Newtonsoft.Json.4.0.2/Newtonsoft.Json.4.0.2.nupkg b/src/packages/Newtonsoft.Json.4.0.2/Newtonsoft.Json.4.0.2.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..684a6f2cc77997e5229421fe3af073faac9f59b0 GIT binary patch literal 2369113 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

- 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