using System; using System.Collections.Specialized; using System.IO; using System.Net; using System.Reflection; using System.Runtime.InteropServices; using System.Text; [assembly: AssemblyTitle("WABusiness")] [assembly: AssemblyDescription("WhatsApp From Tally")] [assembly: AssemblyCompany("Fusion Technology")] [assembly: AssemblyProduct("WABusiness")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: ComVisible(true)] [assembly: Guid("6506a303-4758-4975-ae22-0f6259ba5226")] [assembly: AssemblyVersion("2.0.0.0")] [assembly: AssemblyFileVersion("2.0.0.0")] namespace WABusiness { [ComVisible(true)] [Guid("6506a303-4758-4975-ae22-0f6259ba5227")] [ProgId("WABusiness.Transporter")] [ClassInterface(ClassInterfaceType.AutoDual)] public class Transporter { private const int RequestTimeout = 120000; public int Sum(int x, int y) { return x + y; } // Sends multipart/form-data fields and optional files. public string SendHttpRequest( string url, NameValueCollection values, NameValueCollection files) { if (string.IsNullOrWhiteSpace(url)) return "ERROR: URL is empty"; string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "multipart/form-data; boundary=" + boundary; request.KeepAlive = false; request.Timeout = RequestTimeout; request.ReadWriteTimeout = RequestTimeout; request.AllowWriteStreamBuffering = true; request.Credentials = CredentialCache.DefaultCredentials; using (Stream requestStream = request.GetRequestStream()) { if (values != null) { foreach (string key in values.AllKeys) { if (key == null) continue; WriteTextPart( requestStream, boundary, key, values[key] ?? ""); } } if (files != null) { foreach (string key in files.AllKeys) { if (key == null) continue; string filePath = files[key]; if (string.IsNullOrWhiteSpace(filePath)) continue; if (!File.Exists(filePath)) return "ERROR: file not found - " + filePath; WriteFilePart( requestStream, boundary, key, filePath); } } byte[] closingBoundary = Encoding.UTF8.GetBytes( "--" + boundary + "--\r\n"); requestStream.Write( closingBoundary, 0, closingBoundary.Length); } using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (Stream responseStream = response.GetResponseStream()) { using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8)) { return reader.ReadToEnd(); } } } } catch (WebException ex) { return ReadWebException(ex); } catch (Exception ex) { return "ERROR: " + ex.Message; } } private static void WriteTextPart( Stream stream, string boundary, string name, string value) { string header = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + EscapeHeaderValue(name) + "\"\r\n\r\n"; byte[] headerBytes = Encoding.UTF8.GetBytes(header); byte[] valueBytes = Encoding.UTF8.GetBytes(value); byte[] newLine = Encoding.UTF8.GetBytes("\r\n"); stream.Write(headerBytes, 0, headerBytes.Length); stream.Write(valueBytes, 0, valueBytes.Length); stream.Write(newLine, 0, newLine.Length); } private static void WriteFilePart( Stream stream, string boundary, string fieldName, string filePath) { string fileName = Path.GetFileName(filePath); string contentType = string.Equals( Path.GetExtension(filePath), ".pdf", StringComparison.OrdinalIgnoreCase) ? "application/pdf" : "application/octet-stream"; string header = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"" + EscapeHeaderValue(fieldName) + "\"; filename=\"" + EscapeHeaderValue(fileName) + "\"\r\n" + "Content-Type: " + contentType + "\r\n\r\n"; byte[] headerBytes = Encoding.UTF8.GetBytes(header); byte[] newLine = Encoding.UTF8.GetBytes("\r\n"); stream.Write(headerBytes, 0, headerBytes.Length); using (FileStream fileStream = new FileStream( filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = fileStream.Read( buffer, 0, buffer.Length)) > 0) { stream.Write(buffer, 0, bytesRead); } } stream.Write(newLine, 0, newLine.Length); } private static string EscapeHeaderValue(string value) { if (value == null) return ""; return value.Replace("\\", "_") .Replace("\"", "_") .Replace("\r", "") .Replace("\n", ""); } private static string ReadWebException(WebException ex) { string body = ""; string status = ""; try { if (ex.Response != null) { using (WebResponse response = ex.Response) { HttpWebResponse httpResponse = response as HttpWebResponse; if (httpResponse != null) { status = ((int)httpResponse.StatusCode).ToString() + " " + httpResponse.StatusDescription; } using (Stream responseStream = response.GetResponseStream()) { if (responseStream != null) { using (StreamReader reader = new StreamReader(responseStream, Encoding.UTF8)) { body = reader.ReadToEnd(); } } } } } } catch { // Keep the original HTTP error details. } if (status.Length > 0) { return "HTTP ERROR: " + status + (body.Length > 0 ? " | Server response: " + body : ""); } return "ERROR: " + ex.Message + (body.Length > 0 ? " | Server response: " + body : ""); } // Uploads one PDF/file and an APIKey field. // PHP does not need to validate the APIKey. public string UploadPdf( string url, string filePath, string apiKey) { if (string.IsNullOrWhiteSpace(url)) return "ERROR: URL is empty"; if (string.IsNullOrWhiteSpace(filePath) || !File.Exists(filePath)) { return "ERROR: file not found - " + (filePath ?? ""); } if (!string.Equals( Path.GetExtension(filePath), ".pdf", StringComparison.OrdinalIgnoreCase)) { return "ERROR: Only PDF files are allowed"; } NameValueCollection values = new NameValueCollection(); NameValueCollection files = new NameValueCollection(); values.Add("APIKey", apiKey ?? ""); files.Add("wafile", filePath); return SendHttpRequest( CleanUrl(url), values, files); } // Called from Tally TDL. // Uses a 12-parameter COM signature. // Uploads FileName as the actual PDF under field name "wafile". public string SendingTest( string APIKey, string licenseno, string CmpMailName, string mobileNo, string VoucherNumber, string Amount, string ClosingBalance, string VoucherDate, string FileName, string serverurl, string wamsgtype, string ledgername) { string cleanServer = CleanUrl(serverurl); if (cleanServer.Length == 0) return "ERROR: serverurl is empty"; if (string.IsNullOrWhiteSpace(FileName)) return "ERROR: PDF file path is empty"; if (!File.Exists(FileName)) return "ERROR: PDF file not found - " + FileName; if (!string.Equals( Path.GetExtension(FileName), ".pdf", StringComparison.OrdinalIgnoreCase)) { return "ERROR: Only PDF files are allowed"; } try { NameValueCollection values = new NameValueCollection(); NameValueCollection files = new NameValueCollection(); // Retained for compatibility. PHP ignores APIKey validation. values.Add("APIKey", APIKey ?? ""); values.Add("licenseno", licenseno ?? ""); values.Add("CmpMailName", CmpMailName ?? ""); values.Add("mobileNo", mobileNo ?? ""); values.Add("VoucherNumber", VoucherNumber ?? ""); values.Add("Amount", Amount ?? ""); values.Add("ClosingBalance", ClosingBalance ?? ""); values.Add("VoucherDate", VoucherDate ?? ""); values.Add("FileName", FileName ?? ""); values.Add("serverurl", cleanServer); values.Add("wamsgtype", wamsgtype ?? ""); values.Add("ledgername", ledgername ?? ""); // IMPORTANT: this uploads the PDF bytes to PHP. // The PHP endpoint must read $_FILES['wafile']. files.Add("wafile", FileName); return SendHttpRequest( cleanServer, values, files); } catch (WebException ex) { return ReadWebException(ex); } catch (Exception ex) { return "ERROR: " + ex.ToString(); } } private static string CleanUrl(string url) { return (url ?? "").Trim().Trim('"').Trim(); } } }