From a77e5e68fbf128312dbca2dde80c9af55757440c Mon Sep 17 00:00:00 2001 From: Jordan Wages Date: Sun, 29 Jun 2025 02:42:58 -0500 Subject: [PATCH] clean up --- ai-filter.sln | 8 +-- modules/ExpressionSearchFilter.jsm | 90 ------------------------------ modules/messageUtils.jsm | 89 ----------------------------- 3 files changed, 2 insertions(+), 185 deletions(-) delete mode 100644 modules/ExpressionSearchFilter.jsm delete mode 100644 modules/messageUtils.jsm diff --git a/ai-filter.sln b/ai-filter.sln index 40cec4f..2d171dd 100644 --- a/ai-filter.sln +++ b/ai-filter.sln @@ -29,8 +29,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "options", "options", "{7372 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{75ED3C1E-D3C7-4546-9F2E-AC85859DDF4B}" ProjectSection(SolutionItems) = preProject + modules\AiClassifier.js = modules\AiClassifier.js modules\ExpressionSearchFilter.jsm = modules\ExpressionSearchFilter.jsm modules\logger.jsm = modules\logger.jsm + modules\messageUtils.jsm = modules\messageUtils.jsm EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_locales", "_locales", "{D446E5C6-BDDE-4091-BD1A-EC57170003CF}" @@ -40,11 +42,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "en-US", "en-US", "{8BEA7793 _locales\en-US\messages.json = _locales\en-US\messages.json EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "content", "content", "{028FDA4B-AC3E-4A0E-9291-978E213F9B78}" - ProjectSection(SolutionItems) = preProject - content\filterEditor.js = content\filterEditor.js - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "prompt_templates", "prompt_templates", "{86516D53-50D4-4FE2-9D8A-977A8F5EBDBD}" ProjectSection(SolutionItems) = preProject prompt_templates\mistral.txt = prompt_templates\mistral.txt @@ -79,7 +76,6 @@ Global {75ED3C1E-D3C7-4546-9F2E-AC85859DDF4B} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {D446E5C6-BDDE-4091-BD1A-EC57170003CF} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {8BEA7793-3336-40ED-AB96-7FFB09FEB0F6} = {D446E5C6-BDDE-4091-BD1A-EC57170003CF} - {028FDA4B-AC3E-4A0E-9291-978E213F9B78} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {86516D53-50D4-4FE2-9D8A-977A8F5EBDBD} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {68A87938-5C2B-49F5-8AAA-8A34FBBFD854} = {BCC6E6D2-343B-4C48-854D-5FE3BBC3CB70} {F266602F-1755-4A95-A11B-6C90C701C5BF} = {68A87938-5C2B-49F5-8AAA-8A34FBBFD854} diff --git a/modules/ExpressionSearchFilter.jsm b/modules/ExpressionSearchFilter.jsm deleted file mode 100644 index b9998a9..0000000 --- a/modules/ExpressionSearchFilter.jsm +++ /dev/null @@ -1,90 +0,0 @@ -"use strict"; -var { ExtensionParent } = ChromeUtils.importESModule("resource://gre/modules/ExtensionParent.sys.mjs"); -var { MailServices } = ChromeUtils.importESModule("resource:///modules/MailServices.sys.mjs"); -var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); -var AiClassifier = ChromeUtils.importESModule("resource://aifilter/modules/AiClassifier.js"); -var { getPlainText } = ChromeUtils.import("resource://aifilter/modules/messageUtils.jsm"); - -var EXPORTED_SYMBOLS = ["AIFilter", "ClassificationTerm"]; - -class CustomerTermBase { - constructor(nameId, operators) { - // Lookup our extension instance using the ID from manifest.json - // so locale strings are resolved correctly. - this.extension = ExtensionParent.GlobalManager.getExtension("ai-filter@jordanwages"); - this.id = "aifilter#" + nameId; - this.name = this.extension.localeData.localizeMessage(nameId); - this.operators = operators; - - aiLog(`[ExpressionSearchFilter] Initialized term base "${this.id}"`, {debug: true}); - } - - - getEnabled() { - aiLog(`[ExpressionSearchFilter] getEnabled() called on "${this.id}"`, {debug: true}); - return true; - } - - getAvailable() { - aiLog(`[ExpressionSearchFilter] getAvailable() called on "${this.id}"`, {debug: true}); - return true; - } - - getAvailableOperators() { - aiLog(`[ExpressionSearchFilter] getAvailableOperators() called on "${this.id}"`, {debug: true}); - return this.operators; - } - - getAvailableValues() { - aiLog(`[ExpressionSearchFilter] getAvailableValues() called on "${this.id}"`, {debug: true}); - return null; - } - - get attrib() { - aiLog(`[ExpressionSearchFilter] attrib getter called for "${this.id}"`, {debug: true}); - - //return Ci.nsMsgSearchAttrib.Custom; - } -} - - -class ClassificationTerm extends CustomerTermBase { - constructor() { - super("classification", [Ci.nsMsgSearchOp.Matches, Ci.nsMsgSearchOp.DoesntMatch]); - aiLog(`[ExpressionSearchFilter] ClassificationTerm constructed`, {debug: true}); - } - - needsBody() { return true; } - - match(msgHdr, value, op) { - const opName = op === Ci.nsMsgSearchOp.Matches ? "matches" : - op === Ci.nsMsgSearchOp.DoesntMatch ? "doesn't match" : `unknown (${op})`; - aiLog(`[ExpressionSearchFilter] Matching message ${msgHdr.messageId} using op "${opName}" and value "${value}"`, {debug: true}); - - let key = AiClassifier.buildCacheKeySync(msgHdr.messageId, value); - let body = getPlainText(msgHdr); - - let matched = AiClassifier.classifyTextSync(body, value, key); - - if (op === Ci.nsMsgSearchOp.DoesntMatch) { - matched = !matched; - aiLog(`[ExpressionSearchFilter] Operator is "doesn't match" → inverting to ${matched}`, {debug: true}); - } - - aiLog(`[ExpressionSearchFilter] Final match result: ${matched}`, {debug: true}); - return matched; - } -} - -(function register() { - aiLog(`[ExpressionSearchFilter] Registering custom filter term...`, {debug: true}); - let term = new ClassificationTerm(); - if (!MailServices.filters.getCustomTerm(term.id)) { - MailServices.filters.addCustomTerm(term); - aiLog(`[ExpressionSearchFilter] Registered term: ${term.id}`, {debug: true}); - } else { - aiLog(`[ExpressionSearchFilter] Term already registered: ${term.id}`, {debug: true}); - } -})(); - -var AIFilter = { setConfig: AiClassifier.setConfig }; diff --git a/modules/messageUtils.jsm b/modules/messageUtils.jsm deleted file mode 100644 index a4978a7..0000000 --- a/modules/messageUtils.jsm +++ /dev/null @@ -1,89 +0,0 @@ -"use strict"; -var { NetUtil } = ChromeUtils.importESModule("resource://gre/modules/NetUtil.sys.mjs"); -var { MimeParser } = ChromeUtils.importESModule("resource:///modules/mimeParser.sys.mjs"); -var { aiLog } = ChromeUtils.import("resource://aifilter/modules/logger.jsm"); - -var EXPORTED_SYMBOLS = ["getPlainText"]; - -function getPlainText(msgHdr) { - aiLog(`[ExpressionSearchFilter] Extracting plain text for message ID ${msgHdr.messageId}`, {debug: true}); - let folder = msgHdr.folder; - if (!folder.getMsgInputStream) return ""; - let reusable = {}; - let stream = folder.getMsgInputStream(msgHdr, reusable); - let data = NetUtil.readInputStreamToString(stream, msgHdr.messageSize); - if (!reusable.value) stream.close(); - - let parser = Cc["@mozilla.org/parserutils;1"].getService(Ci.nsIParserUtils); - - try { - let root = MimeParser.parseSync(data, {strformat: "unicode"}); - let parts = []; - - function pushPlaceholder(type, info, bytes) { - bytes = bytes || 0; - let prettyType = type.split("/")[1] || type; - parts.push(`[${info}: ${prettyType}, ${bytes} bytes]`); - } - - function byteSizeFromBase64(str) { - let clean = str.replace(/[^A-Za-z0-9+/=]/g, ""); - return Math.floor(clean.length * 3 / 4); - } - - function replaceInlineBase64(text) { - return text.replace(/[A-Za-z0-9+/]{100,}={0,2}/g, - m => `[base64: ${byteSizeFromBase64(m)} bytes]`); - } - - function walk(node) { - if (node.parts && node.parts.length) { - for (let child of node.parts) { - walk(child); - } - return; - } - - let ct = (node.contentType || "text/plain").toLowerCase(); - let cd = (node.headers?.["content-disposition"]?.[0] || "").toLowerCase(); - let enc = (node.headers?.["content-transfer-encoding"]?.[0] || "").toLowerCase(); - let bodyText = String(node.body || ""); - - if (cd.includes("attachment")) { - pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); - } else if (ct.startsWith("text/plain")) { - if (enc === "base64") { - parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); - } else { - parts.push(replaceInlineBase64(bodyText)); - } - } else if (ct.startsWith("text/html")) { - if (enc === "base64") { - parts.push(`[base64: ${byteSizeFromBase64(bodyText)} bytes]`); - } else { - let txt = parser.convertToPlainText(bodyText, - Ci.nsIDocumentEncoder.OutputLFLineBreak | - Ci.nsIDocumentEncoder.OutputNoScriptContent | - Ci.nsIDocumentEncoder.OutputNoFramesContent | - Ci.nsIDocumentEncoder.OutputBodyOnly, 0); - parts.push(replaceInlineBase64(txt)); - } - } else { - // Other single part types treated as attachments - pushPlaceholder(ct, "binary attachment", byteSizeFromBase64(bodyText)); - } - } - - walk(root); - return parts.join("\n"); - } catch (e) { - // Fallback: convert entire raw message to text - aiLog(`Failed to parse MIME, falling back to raw conversion`, {level: 'warn'}, e); - return parser.convertToPlainText(data, - Ci.nsIDocumentEncoder.OutputLFLineBreak | - Ci.nsIDocumentEncoder.OutputNoScriptContent | - Ci.nsIDocumentEncoder.OutputNoFramesContent | - Ci.nsIDocumentEncoder.OutputBodyOnly, 0); - } -} -