using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Globalization; namespace bdf { public class MegaT { // A class to hold the extracted data for a single row of INSIS data public class INSISData { public string Item { get; set; } public string Code { get; set; } public string Description { get; set; } public string Period { get; set; } public string UnitPrice { get; set; } public string Quantity { get; set; } public string Amount { get; set; } public string BillingType { get; set; } public string Currency { get; set; } public string StartDate { get; set; } public string EndDate { get; set; } public override string ToString() { return $"Code: {Code}, Description: {Description}, Unit Price: {UnitPrice}, Qty: {Quantity}, Amount: {Amount}, Start Date: {StartDate}"; } } public static List GetRVNUDetails_bySCHED(string sched, ref CookieContainer cookies) { bool success = false; byte[] webResp = null; List rvnu_items = new List { }; success = Web.MakeRequest( "GET", "http://megatool.rogers.com/megatool/megatool/INSIS/insisMainwindow.asp?serv_id=" + sched, false, "", ref webResp, ref cookies); if (!success) { Logger.Log(5, "Get INSIS RVNU TopLevel Details FAIL {0}", sched); } string html = Encoding.ASCII.GetString(webResp); if (html.Length > 5000) // valid SCHED, seek RVNU items for SIP data { try { HashSet rvnu_links = RVNU_item_links(html); foreach (var link in rvnu_links) { success = false; webResp = null; success = Web.MakeRequest( "GET", "http://megatool.rogers.com/megatool/megatool/INSIS/" + link.ToString(), false, "", ref webResp, ref cookies); if (!success) { Logger.Log(5, "Get INSIS RVNU Details FAIL {0}-{1} {2}", sched, link, webResp); } string html2 = Encoding.ASCII.GetString(webResp); INSISData x = ExtractINSISData(html2); if (!x.BillingType.Contains("Delete")) // Feb 12 2026 rvnu_items.Add(x); Logger.Log(6, "Desc: {0} | rvnu_items size={1}", x.Description, rvnu_items.Count); } } catch (Exception e) { Logger.Log(0, "Error SCHED {0} - SIP HTML={0}", sched, e.Message); } } return rvnu_items; } public static HashSet RVNU_item_links(string html) { HashSet result = new HashSet(System.StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(html)) return result; string trPattern = @"]*id\s*=\s*['""]R\d+['""][^>]*>(.*?)"; System.Text.RegularExpressions.MatchCollection trMatches = System.Text.RegularExpressions.Regex.Matches( html, trPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline ); foreach (System.Text.RegularExpressions.Match trMatch in trMatches) { string trContent = trMatch.Groups[1].Value; System.Text.RegularExpressions.MatchCollection tdMatches = System.Text.RegularExpressions.Regex.Matches( trContent, @"]*>(.*?)", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline ); if (tdMatches.Count < 5) continue; // ----- Extract openIt('...') from 4th ----- string fourthTd = tdMatches[3].Groups[1].Value; //Logger.Log(6,"4th [{0}]", fourthTd); string openItValue = ""; if (fourthTd.IndexOf("RVNU", System.StringComparison.OrdinalIgnoreCase) >= 0) { System.Text.RegularExpressions.Match onclickMatch = System.Text.RegularExpressions.Regex.Match( fourthTd, @"openIt\('(?[^']+)'\)", System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Singleline ); if (!onclickMatch.Success) { Logger.Log(3,"no rvnu match"); continue; } openItValue = onclickMatch.Groups["openit"].Value.Trim(); } else // Skip non-RVNU rows { Logger.Log(4,"non-revenue [{0}]", fourthTd); continue; } result.Add(openItValue); } return result; } public static INSISData ExtractINSISData(string html) { var extractedData = new INSISData(); // Regex to find table rows () within a specific table structure (adjust if needed, e.g., using a table ID) // The pattern uses capturing groups for each content // It assumes tags might have extra spaces or attributes, but the content inside is the target. Dictionary result = new Dictionary(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrWhiteSpace(html)) return null; string pattern = @"]*class\s*=\s*""heading""[^>]*>\s*(?[^<]+)\s*[\s\S]*?" + @"value\s*=\s*""(?[^""]*)"""; System.Text.RegularExpressions.MatchCollection matches = System.Text.RegularExpressions.Regex.Matches( html, pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase); foreach (System.Text.RegularExpressions.Match match in matches) { string heading = match.Groups["heading"].Value.Trim(); string value = match.Groups["value"].Value.Trim().Replace("$","").Replace("/", "-"); // FIXME convert to SSC style date if (!result.ContainsKey(heading)) { result.Add(heading.Replace(" ", ""), value); //Remove field label spaces to make them valid dictionary entries Logger.Log(5, "Found: {0}={1}", heading, value); } } System.Type type = typeof(INSISData); foreach (System.Reflection.PropertyInfo prop in type.GetProperties( System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)) { Logger.Log(6,"a4n {0} : {1}", prop.PropertyType.Name, prop.Name); if (prop.PropertyType != typeof(string)) continue; if (!prop.CanWrite) continue; if (result.TryGetValue(prop.Name, out string value)) { Logger.Log(6,"a5 {0}", value); try { prop.SetValue( extractedData, (string)value); } catch (Exception e) { Logger.Log(0, "Error prop.SetValue {0}:{1}\n{2}", prop.Name, value, e.Message); } } } return extractedData; } // Takes MM-d-yyyy and converts to yyyyMMdd public static string ConvertDate(string input) { System.DateTime date = System.DateTime.ParseExact( input, "M-d-yyyy", System.Globalization.CultureInfo.InvariantCulture ); return date.ToString("yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture); } //------------------------------------ // SCHED-A Info Extraction from "Schedule Details" Megatool page, most import is SO<->SCHED mapping public static Dictionary GetParms(string sched, ref CookieContainer cookies) { string token = ""; bool success = false; byte[] webResp = null; string html = ""; Dictionary parms = new Dictionary { }; //if (sched != "dummy") if ( sched.Length != 3 ) // not a 'dummy' request { success = Web.MakeRequest( "GET", "http://megatool.rogers.com/megatool/megatool/INSIS/schedule.asp?logo=N&serv_id=" + sched, false, "", ref webResp, ref cookies); if (!success) { Logger.Log(0, "GetParms fail{0}", token); } //Console.WriteLine(Encoding.ASCII.GetString(webResp)); html = Encoding.ASCII.GetString(webResp); } else { success = true; html = ""; } //following builds the columns in order, one IF per column try { // SO + up to 5 non-digits + six digits var regex = new Regex(@"SO(?:\D{0,5})(\d{6})", RegexOptions.IgnoreCase); Match m = regex.Match(html); if (m.Success) { // m.Value = the entire match parms.Add("SO", m.Groups[1].ToString()); // = the 6-digit number } else { parms.Add("SO", "XXX"); } // TA + up to 5 non-digits + R + nine digits regex = new Regex(@"TA(?:\D{0,5})(\d{9})", RegexOptions.IgnoreCase); m = regex.Match(html); if (m.Success) { // m.Value = the entire match parms.Add("TA", "R"+m.Groups[1].ToString()); // = the 6-digit number } else { parms.Add("TA", "XXX"); } // COP + up to 5 non-digits + six digits regex = new Regex(@"COP(?:\D{0,5})(\d{6})", RegexOptions.IgnoreCase); m = regex.Match(html); if (m.Success) { // m.Value = the entire match parms.Add("COP", m.Groups[1].ToString()); // = the 6-digit number } else { parms.Add("COP", "XXX"); } // PRID + up to 5 non-digits + four digits //regex = new Regex(@"PR.*ID(?:\D{0,5})(\d{4})", RegexOptions.IgnoreCase); regex = new Regex(@"PR(?:\s?ID)?(?:\D{0,5})(\d{4})", RegexOptions.IgnoreCase); m = regex.Match(html); if (m.Success) { // m.Value = the entire match parms.Add("PRID", m.Groups[1].ToString()); // = the 6-digit number } else { parms.Add("PRID", "XXX"); } // Contract + up to 5 non-digits + letter + 9 digits regex = new Regex(@"CONTRACT(?:\D{0,5})([a-zA-Z]\d{9})", RegexOptions.IgnoreCase); m = regex.Match(html); if (m.Success) { // m.Value = the entire match parms.Add("CONTRACT", m.Groups[1].ToString()); // = the alpha+9-digit number } else { parms.Add("CONTRACT", "XXX"); } // parms.Add("SCHED", sched); // needed to build that datatable correctly in MAIN // // Billing Start Date; seems to come in Mon D, YYYY format, need to convert to YYYYMMDD //regex = new Regex(@"
Bill Start Date:\s+([a-zA-Z0-9,\s]+[0-9]{4})[.]?\s*
", RegexOptions.IgnoreCase); // Bill(?:ing|in)?\sStart(?: Date)?:\s regex = new Regex(@"
Bill(?:ing|in)?\sStart(?: Date)?:\s+([a-zA-Z0-9,\s]+[0-9]{4})[.]?\s*
", RegexOptions.IgnoreCase); m = regex.Match(html); if (m.Success) { Logger.Log(5, "raw BSD = |{0}|", m.Groups[1].ToString()); try { // m.Value = the entire match string input = m.Groups[1].ToString(); string iformat = "MMM d, yyyy"; string oformat = "yyyyMMdd"; DateTime fdate = DateTime.ParseExact(input, iformat, CultureInfo.InvariantCulture); parms.Add("BSD", fdate.ToString(oformat)); // = the alpha+9-digit number Logger.Log(4, "BSD = >{0}<", fdate.ToString(oformat)); } catch (Exception e) { Logger.Log(0, "Error converting date from SchedA->Schedule details {0}", e.Message); } } else { parms.Add("BSD", "XXX"); } // MRR+ up to 5 non-digits + $XXX.XX //regex = new Regex(@"(?Order Type ("; const string endKey = ")(); int index = 0; while (true) { // Find "serv_id=" int start = html.IndexOf(startKey, index, StringComparison.OrdinalIgnoreCase); if (start == -1) break; // no more matches start += startKey.Length; // Find "')" int end = html.IndexOf(endKey, start, StringComparison.Ordinal); if (end == -1) break; string value = html.Substring(start, end - start); if ((value == "XL") || (value == "XP") || (value == "NX")) return true; index = end + endKey.Length; } } return false; } public static bool GetSchedAs(string serv_id, ref List scheds, ref CookieContainer cookies) { bool success = false; string token = ""; byte[] webResp = null; success = Web.MakeRequest( "POST", "http://megatool.rogers.com/megatool/megatool/INSIS/SearchSites.asp?query=Y&exportFlag=N", "service_id="+serv_id, false, "", ref webResp, ref cookies); if (!success) { Logger.Log(0, "Get SchedA's Fail {0}", token); } //Console.WriteLine(Encoding.ASCII.GetString(webResp)); else { string html = Encoding.ASCII.GetString(webResp); const string startKey = "serv_id="; const string endKey = "')"; //var results = new List(); int index = 0; while (true) { // Find "serv_id=" int start = html.IndexOf(startKey, index, StringComparison.OrdinalIgnoreCase); if (start == -1) break; // no more matches start += startKey.Length; // Find "')" int end = html.IndexOf(endKey, start, StringComparison.Ordinal); if (end == -1) break; string value = html.Substring(start, end - start); if ( !scheds.Exists(s => s == value) ) // skip any duplicate SCHEDA entries, such as with WAVs scheds.Add(value); index = end + endKey.Length; } } return success; } //perform NTLM authentication for MegaTool with users LAN ID public static bool Auth(string user, string pass, ref CookieContainer cookies) { string url = "http://megatool.rogers.com/megatool/megatool/"; bool success = false; // Explicit credentials (domain\user) // var creds = new NetworkCredential(user, pass, "RCI"); // Add to global cred cache for NTLM auth - Needed to survive Windows 11 / .NET481. Works fine in Mono or with Fiddler, but not straight .exe bdf.cache.Add(new Uri(url), "NTLM", CredentialCache.DefaultNetworkCredentials); // A cookie container is REQUIRED to capture session cookies var request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; request.AllowAutoRedirect = false; // Required for NTLM handshake request.PreAuthenticate = true; //request.PreAuthenticate = false; // NTLM cannot pre-authenticate request.UseDefaultCredentials = false; request.Credentials = bdf.cache; //request.Credentials = creds; // Enables SSPI NTLM handshake request.CookieContainer = cookies; // Store session cookies request.KeepAlive = true; // NTLM requires same connection //request.UnsafeAuthenticatedConnectionSharing = true; request.UserAgent = "NTLMClient/.NET4.8"; Logger.Log(1, "Megatool authentication for ({0})...", user); HttpWebResponse response; try { response = (HttpWebResponse)request.GetResponse(); } catch (WebException wex) when (wex.Response is HttpWebResponse) { response = (HttpWebResponse)wex.Response; } // If server demands NTLM, the framework automatically: // • sends Type1 // • receives Type2 // • sends Type3 // • then returns the real authenticated page response Logger.Log(5, "HTTP Status: " + (int)response.StatusCode + " " + response.StatusCode); // Read response body string body; using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) { body = reader.ReadToEnd(); } foreach (Cookie ck in cookies.GetCookies(request.RequestUri)) { Logger.Log(5, $"{ck.Name} = {ck.Value}; Domain={ck.Domain}; Path={ck.Path}"); success = true; } response.Close(); return success; } } }