Skip to content

Instantly share code, notes, and snippets.

@romeshniriella
Last active August 29, 2015 14:19
Show Gist options
  • Save romeshniriella/328de432e4f86e4ed5d9 to your computer and use it in GitHub Desktop.
Save romeshniriella/328de432e4f86e4ed5d9 to your computer and use it in GitHub Desktop.
Bing-Mail Easy Post Api - Version 1.3
public class SessionObject
{
public string user { get; set; }
public string account { get; set; }
public string session_id { get; set; }
}
public class BingMailConfigOptions
{
public string AuthUserName { get; set; }
public string AuthPassword { get; set; }
public string Account { get; set; }
public string Proxy { get; set; }
public string VerifyCertificate { get; set; }
}
/// <summary>
/// Version 1.3
/// </summary>
public class BingMailEasyPostApi
{
private static ILogger _log;
// session control endpoints
private const string SessionIdUri = "publicinterface/get_session_id.json?account={0}";
private const string SessionEndUri = "publicinterface/end_session.json?session_id={0}";
// upload endpoint prefix
private const string UploadUri = "direct_upload/{0}/{1}";
private readonly List<string> _easypostHosts = new List<string>()
{
"https://easymail.com/",
"https://bingmail.com.au/",
"https://alt.easymail.com/"
};
private readonly BingMailConfigOptions _configOptions;
public BingMailEasyPostApi(BingMailConfigOptions configOptions)
{
_configOptions = configOptions;
_log = CommonServices.GetLogger<BingMailEasyPostApi>();
}
public string Send(string metaDataFile, string pathToFile)
{
_log.Trace("Creating a new session");
var sessionId = GetSessionId();
_log.Trace("RCVD Session ID : " + sessionId);
_log.Trace("Uploading metadata file : " + metaDataFile);
Upload(sessionId, metaDataFile);
_log.Trace("Uploading invoice file : " + pathToFile);
Upload(sessionId, pathToFile);
_log.Trace("Ending Session : " + sessionId);
return EndSession(sessionId);
}
private string GetSessionId()
{
_log.Trace("Trying to get the session id");
string sessionId = "";
Uri uri = new Uri(_easypostHosts[0] + SessionIdUri.FormatWith(_configOptions.Account));
DigestAuthFixer.Create(uri.GetLeftPart(UriPartial.Authority), _configOptions.AuthUserName, _configOptions.AuthPassword);
sessionId = DigestAuthFixer.GrabResponse(uri.PathAndQuery);
_log.Info("Session Info: " + sessionId);
var obj = JsonConvert.DeserializeObject<SessionObject>(sessionId);
return obj.session_id;
}
private string EndSession(string sessionId)
{
_log.Trace("Trying to end the session");
var responseStr = "";
Uri uri = new Uri(_easypostHosts[0] + SessionEndUri.FormatWith(sessionId));
var request = GetWebRequest(uri);
var response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
var stream = response.GetResponseStream();
if (stream != null)
{
var reader = new StreamReader(stream);
responseStr = reader.ReadToEnd();
reader.Close();
}
}
response.Close();
_log.Info("End Response: " + responseStr);
return responseStr;
}
private WebRequest GetWebRequest(Uri uri)
{
WebRequest request = WebRequest.Create(uri);
var credentialCache = GetCredentialCache(uri, _configOptions);
request.Credentials = credentialCache;
request.PreAuthenticate = true;
return request;
}
public static CredentialCache GetCredentialCache(Uri uri, BingMailConfigOptions options)
{
var credentialCache = new CredentialCache
{
{
new Uri(uri.GetLeftPart(UriPartial.Authority)),
"Digest",
new NetworkCredential(options.AuthUserName, options.AuthPassword)
}
};
return credentialCache;
}
private void Upload(string sessionId, string filePath)
{
_log.Trace("Trying to upload the file: " + filePath);
var file = new FileInfo(filePath);
if (file.Exists)
{
var content = "";
var fileName = file.Name.Replace("_", "")
.Replace("-", "")
.Replace("[", "")
.Replace("]", "");
// extracted from http://stackoverflow.com/a/3117042/959245
// mopdified to support whatever HTTP methods.
// PUT in my case
public static class DigestAuthFixer
{
private static ILogger _log;
private static string _host;
private static string _user;
private static string _password;
private static string _realm;
private static string _nonce;
private static string _qop;
private static string _cnonce;
private static string _opaque;
private static DateTime _cnonceDate;
private static int _nc = 0;
private static bool isInitialized = false;
public static void Create(string host, string user, string password)
{
_log = CommonServices.GetLogger("DigestAuthFixer");
_host = host;
_user = user;
_password = password;
isInitialized = true;
}
private static string CalculateMd5Hash(
string input)
{
var inputBytes = Encoding.ASCII.GetBytes(input);
var hash = MD5.Create().ComputeHash(inputBytes);
var sb = new StringBuilder();
foreach (var b in hash)
sb.Append(b.ToString("x2"));
return sb.ToString();
}
private static string GrabHeaderVar(
string varName,
string header)
{
_log.Trace("Gonna grab header : " + varName);
var regHeader = new Regex(string.Format(@"{0}=""([^""]*)""", varName));
var matchHeader = regHeader.Match(header);
if (matchHeader.Success)
return matchHeader.Groups[1].Value;
return string.Empty;
}
// http://en.wikipedia.org/wiki/Digest_access_authentication
public static string GetDigestHeader(
string dir, string method = "GET")
{
_nc = _nc + 1;
var ha1 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", _user, _realm, _password));
var ha2 = CalculateMd5Hash(string.Format("{0}:{1}", method, dir));
var digestResponse =
CalculateMd5Hash(string.Format("{0}:{1}:{2:00000000}:{3}:{4}:{5}", ha1, _nonce, _nc, _cnonce, _qop, ha2));
return string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", " +
"algorithm=MD5, response=\"{4}\", qop=\"{5}\", nc=\"{6:00000000}\", cnonce=\"{7}\"{8}",
_user, _realm, _nonce, dir, digestResponse, _qop, _nc, _cnonce, _opaque.IsNotBlank() ? ", opaque=\"{0}\"".FormatWith(_opaque) : "");
}
public static string GrabResponse(
string dir, string method = "GET")
{
if (!isInitialized)
{
throw new InvalidOperationException("Not initialized");
}
var url = _host + dir;
var uri = new Uri(url);
var request = (HttpWebRequest)WebRequest.Create(uri);
// If we've got a recent Auth header, re-use it!
if (!string.IsNullOrEmpty(_cnonce) &&
DateTime.Now.Subtract(_cnonceDate).TotalHours < 1.0)
{
request.Headers.Add("Authorization", GetDigestHeader(dir, method));
}
HttpWebResponse response;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
// Try to fix a 401 exception by adding a Authorization header
if (ex.Response == null || ((HttpWebResponse)ex.Response).StatusCode != HttpStatusCode.Unauthorized)
throw;
var wwwAuthenticateHeader = ex.Response.Headers["WWW-Authenticate"];
_realm = GrabHeaderVar("realm", wwwAuthenticateHeader);
_nonce = GrabHeaderVar("nonce", wwwAuthenticateHeader);
_qop = GrabHeaderVar("qop", wwwAuthenticateHeader);
_opaque = GrabHeaderVar("opaque", wwwAuthenticateHeader);
_nc = 0;
_cnonce = new Random().Next(123400, 9999999).ToString();
_cnonceDate = DateTime.Now;
var request2 = (HttpWebRequest)WebRequest.Create(uri);
request2.Headers.Add("Authorization", GetDigestHeader(dir, method));
response = (HttpWebResponse)request2.GetResponse();
}
var reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}
}
public class InvoiceOperationsEngine : IInvoiceOperationsEngine
{
private static ILogger _log;
// -- ctor --
public void SendMailout(InvoiceMailout mailout)
{
//....
var metaData = new MailDocumentMetaData(mailout)
{
CustomerEmail = sysSettings.NotificationEmail
};
var fileName = file.Name.Replace("_", "")
.Replace("-", "")
.Replace("[", "")
.Replace("]", "");
var letter = new Letter()
{
FileName = fileName
};
letter.FillAdddress(customer, geoRepo);
metaData.Letters.Add(letter);
var metaFile = WriteMetaDataFile(metaData, invoicePath);
var mailer = new BingMailEasyPostApi(new BingMailConfigOptions()
{
Account = settings.AccountCode,
AuthUserName = settings.UserName,
AuthPassword = settings.Password
});
var response = mailer.Send(metaFile, invoicePath);
//....
}
}
public class MailDocumentMetaData
{
[JsonProperty("duplex")]
public bool IsDuplex { get; set; }
[JsonProperty("colour_model")]
public int ColourModel { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("customer_email")]
public string CustomerEmail { get; set; }
[JsonProperty("confirmation_email")]
public bool ConfirmationEmail { get; set; }
[JsonProperty("department")]
public string Department { get; set; }
[JsonProperty("terminal")]
public string Terminal { get; set; }
[JsonProperty("orientation")]
public int Orientation { get; set; }
[JsonProperty("letters")]
public List<Letter> Letters { get; set; }
public MailDocumentMetaData(CustomerInvoiceMailout mailout)
{
Letters = new List<Letter>();
this.IsDuplex = mailout.IsDuplex;
ColourModel = mailout.ColourModel;
Title = mailout.Title;
ConfirmationEmail = mailout.EmailConfirmation;
Department = mailout.Department;
Terminal = mailout.Terminal;
Orientation = mailout.Orientation.ToSafeInt32();
}
}
public class Letter
{
public Letter()
{
Postal = new List<string>();
Primary = "postal";
}
[JsonProperty("postal")]
public List<string> Postal { get; set; }
[JsonProperty("primary")]
public string Primary { get; set; }
[JsonProperty("file_name")]
public string FileName { get; set; }
internal void FillAdddress(Customer customer, IReadOnlyRepository<GeographicLocation> geoRepo)
{
var locality = "";
if (customer.BillingLocality != null)
{
var geo = geoRepo.Get(customer.BillingLocality.Value);
locality = geo.Name.Replace(",","");
}
Postal.AddIf(s => customer.BillingName.IsNotBlank(), customer.BillingName);
Postal.AddIf(s => customer.BillingAddressA.IsNotBlank(), customer.BillingAddressA);
Postal.AddIf(s => customer.BillingAddressB.IsNotBlank(), customer.BillingAddressB);
Postal.AddIf(s => customer.BillingAddressC.IsNotBlank(), customer.BillingAddressC);
Postal.AddIf(s => locality.IsNotBlank(), locality);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment