spamscanner 7.0.9 → 7.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1624,6 +1624,286 @@ var init_homograph = __esm({
1624
1624
  }
1625
1625
  });
1626
1626
 
1627
+ // src/entities.js
1628
+ var NAMED, NAMED_REFERENCES;
1629
+ var init_entities = __esm({
1630
+ "src/entities.js"() {
1631
+ NAMED = [
1632
+ "AElig=c6,AMP=26,Aacute=c1,Abreve=102,Acirc=c2,Acy=410,Afr=1d504,Agrave=c0,Alpha=391,Amacr=100,And=2a",
1633
+ "53,Aogon=104,Aopf=1d538,ApplyFunction=2061,Aring=c5,Ascr=1d49c,Assign=2254,Atilde=c3,Auml=c4,Backsla",
1634
+ "sh=2216,Barv=2ae7,Barwed=2306,Bcy=411,Because=2235,Bernoullis=212c,Beta=392,Bfr=1d505,Bopf=1d539,Bre",
1635
+ "ve=2d8,Bscr=212c,Bumpeq=224e,CHcy=427,COPY=a9,Cacute=106,Cap=22d2,CapitalDifferentialD=2145,Cayleys=",
1636
+ "212d,Ccaron=10c,Ccedil=c7,Ccirc=108,Cconint=2230,Cdot=10a,Cedilla=b8,CenterDot=b7,Cfr=212d,Chi=3a7,C",
1637
+ "ircleDot=2299,CircleMinus=2296,CirclePlus=2295,CircleTimes=2297,ClockwiseContourIntegral=2232,CloseC",
1638
+ "urlyDoubleQuote=201d,CloseCurlyQuote=2019,Colon=2237,Colone=2a74,Congruent=2261,Conint=222f,ContourI",
1639
+ "ntegral=222e,Copf=2102,Coproduct=2210,CounterClockwiseContourIntegral=2233,Cross=2a2f,Cscr=1d49e,Cup",
1640
+ "=22d3,CupCap=224d,DD=2145,DDotrahd=2911,DJcy=402,DScy=405,DZcy=40f,Dagger=2021,Darr=21a1,Dashv=2ae4,",
1641
+ "Dcaron=10e,Dcy=414,Del=2207,Delta=394,Dfr=1d507,DiacriticalAcute=b4,DiacriticalDot=2d9,DiacriticalDo",
1642
+ "ubleAcute=2dd,DiacriticalGrave=60,DiacriticalTilde=2dc,Diamond=22c4,DifferentialD=2146,Dopf=1d53b,Do",
1643
+ "t=a8,DotDot=20dc,DotEqual=2250,DoubleContourIntegral=222f,DoubleDot=a8,DoubleDownArrow=21d3,DoubleLe",
1644
+ "ftArrow=21d0,DoubleLeftRightArrow=21d4,DoubleLeftTee=2ae4,DoubleLongLeftArrow=27f8,DoubleLongLeftRig",
1645
+ "htArrow=27fa,DoubleLongRightArrow=27f9,DoubleRightArrow=21d2,DoubleRightTee=22a8,DoubleUpArrow=21d1,",
1646
+ "DoubleUpDownArrow=21d5,DoubleVerticalBar=2225,DownArrow=2193,DownArrowBar=2913,DownArrowUpArrow=21f5",
1647
+ ",DownBreve=311,DownLeftRightVector=2950,DownLeftTeeVector=295e,DownLeftVector=21bd,DownLeftVectorBar",
1648
+ "=2956,DownRightTeeVector=295f,DownRightVector=21c1,DownRightVectorBar=2957,DownTee=22a4,DownTeeArrow",
1649
+ "=21a7,Downarrow=21d3,Dscr=1d49f,Dstrok=110,ENG=14a,ETH=d0,Eacute=c9,Ecaron=11a,Ecirc=ca,Ecy=42d,Edot",
1650
+ "=116,Efr=1d508,Egrave=c8,Element=2208,Emacr=112,EmptySmallSquare=25fb,EmptyVerySmallSquare=25ab,Eogo",
1651
+ "n=118,Eopf=1d53c,Epsilon=395,Equal=2a75,EqualTilde=2242,Equilibrium=21cc,Escr=2130,Esim=2a73,Eta=397",
1652
+ ",Euml=cb,Exists=2203,ExponentialE=2147,Fcy=424,Ffr=1d509,FilledSmallSquare=25fc,FilledVerySmallSquar",
1653
+ "e=25aa,Fopf=1d53d,ForAll=2200,Fouriertrf=2131,Fscr=2131,GJcy=403,GT=3e,Gamma=393,Gammad=3dc,Gbreve=1",
1654
+ "1e,Gcedil=122,Gcirc=11c,Gcy=413,Gdot=120,Gfr=1d50a,Gg=22d9,Gopf=1d53e,GreaterEqual=2265,GreaterEqual",
1655
+ "Less=22db,GreaterFullEqual=2267,GreaterGreater=2aa2,GreaterLess=2277,GreaterSlantEqual=2a7e,GreaterT",
1656
+ "ilde=2273,Gscr=1d4a2,Gt=226b,HARDcy=42a,Hacek=2c7,Hat=5e,Hcirc=124,Hfr=210c,HilbertSpace=210b,Hopf=2",
1657
+ "10d,HorizontalLine=2500,Hscr=210b,Hstrok=126,HumpDownHump=224e,HumpEqual=224f,IEcy=415,IJlig=132,IOc",
1658
+ "y=401,Iacute=cd,Icirc=ce,Icy=418,Idot=130,Ifr=2111,Igrave=cc,Im=2111,Imacr=12a,ImaginaryI=2148,Impli",
1659
+ "es=21d2,Int=222c,Integral=222b,Intersection=22c2,InvisibleComma=2063,InvisibleTimes=2062,Iogon=12e,I",
1660
+ "opf=1d540,Iota=399,Iscr=2110,Itilde=128,Iukcy=406,Iuml=cf,Jcirc=134,Jcy=419,Jfr=1d50d,Jopf=1d541,Jsc",
1661
+ "r=1d4a5,Jsercy=408,Jukcy=404,KHcy=425,KJcy=40c,Kappa=39a,Kcedil=136,Kcy=41a,Kfr=1d50e,Kopf=1d542,Ksc",
1662
+ "r=1d4a6,LJcy=409,LT=3c,Lacute=139,Lambda=39b,Lang=27ea,Laplacetrf=2112,Larr=219e,Lcaron=13d,Lcedil=1",
1663
+ "3b,Lcy=41b,LeftAngleBracket=27e8,LeftArrow=2190,LeftArrowBar=21e4,LeftArrowRightArrow=21c6,LeftCeili",
1664
+ "ng=2308,LeftDoubleBracket=27e6,LeftDownTeeVector=2961,LeftDownVector=21c3,LeftDownVectorBar=2959,Lef",
1665
+ "tFloor=230a,LeftRightArrow=2194,LeftRightVector=294e,LeftTee=22a3,LeftTeeArrow=21a4,LeftTeeVector=29",
1666
+ "5a,LeftTriangle=22b2,LeftTriangleBar=29cf,LeftTriangleEqual=22b4,LeftUpDownVector=2951,LeftUpTeeVect",
1667
+ "or=2960,LeftUpVector=21bf,LeftUpVectorBar=2958,LeftVector=21bc,LeftVectorBar=2952,Leftarrow=21d0,Lef",
1668
+ "trightarrow=21d4,LessEqualGreater=22da,LessFullEqual=2266,LessGreater=2276,LessLess=2aa1,LessSlantEq",
1669
+ "ual=2a7d,LessTilde=2272,Lfr=1d50f,Ll=22d8,Lleftarrow=21da,Lmidot=13f,LongLeftArrow=27f5,LongLeftRigh",
1670
+ "tArrow=27f7,LongRightArrow=27f6,Longleftarrow=27f8,Longleftrightarrow=27fa,Longrightarrow=27f9,Lopf=",
1671
+ "1d543,LowerLeftArrow=2199,LowerRightArrow=2198,Lscr=2112,Lsh=21b0,Lstrok=141,Lt=226a,Map=2905,Mcy=41",
1672
+ "c,MediumSpace=205f,Mellintrf=2133,Mfr=1d510,MinusPlus=2213,Mopf=1d544,Mscr=2133,Mu=39c,NJcy=40a,Nacu",
1673
+ "te=143,Ncaron=147,Ncedil=145,Ncy=41d,NegativeMediumSpace=200b,NegativeThickSpace=200b,NegativeThinSp",
1674
+ "ace=200b,NegativeVeryThinSpace=200b,NestedGreaterGreater=226b,NestedLessLess=226a,NewLine=a,Nfr=1d51",
1675
+ "1,NoBreak=2060,NonBreakingSpace=a0,Nopf=2115,Not=2aec,NotCongruent=2262,NotCupCap=226d,NotDoubleVert",
1676
+ "icalBar=2226,NotElement=2209,NotEqual=2260,NotEqualTilde=2242.338,NotExists=2204,NotGreater=226f,Not",
1677
+ "GreaterEqual=2271,NotGreaterFullEqual=2267.338,NotGreaterGreater=226b.338,NotGreaterLess=2279,NotGre",
1678
+ "aterSlantEqual=2a7e.338,NotGreaterTilde=2275,NotHumpDownHump=224e.338,NotHumpEqual=224f.338,NotLeftT",
1679
+ "riangle=22ea,NotLeftTriangleBar=29cf.338,NotLeftTriangleEqual=22ec,NotLess=226e,NotLessEqual=2270,No",
1680
+ "tLessGreater=2278,NotLessLess=226a.338,NotLessSlantEqual=2a7d.338,NotLessTilde=2274,NotNestedGreater",
1681
+ "Greater=2aa2.338,NotNestedLessLess=2aa1.338,NotPrecedes=2280,NotPrecedesEqual=2aaf.338,NotPrecedesSl",
1682
+ "antEqual=22e0,NotReverseElement=220c,NotRightTriangle=22eb,NotRightTriangleBar=29d0.338,NotRightTria",
1683
+ "ngleEqual=22ed,NotSquareSubset=228f.338,NotSquareSubsetEqual=22e2,NotSquareSuperset=2290.338,NotSqua",
1684
+ "reSupersetEqual=22e3,NotSubset=2282.20d2,NotSubsetEqual=2288,NotSucceeds=2281,NotSucceedsEqual=2ab0.",
1685
+ "338,NotSucceedsSlantEqual=22e1,NotSucceedsTilde=227f.338,NotSuperset=2283.20d2,NotSupersetEqual=2289",
1686
+ ",NotTilde=2241,NotTildeEqual=2244,NotTildeFullEqual=2247,NotTildeTilde=2249,NotVerticalBar=2224,Nscr",
1687
+ "=1d4a9,Ntilde=d1,Nu=39d,OElig=152,Oacute=d3,Ocirc=d4,Ocy=41e,Odblac=150,Ofr=1d512,Ograve=d2,Omacr=14",
1688
+ "c,Omega=3a9,Omicron=39f,Oopf=1d546,OpenCurlyDoubleQuote=201c,OpenCurlyQuote=2018,Or=2a54,Oscr=1d4aa,",
1689
+ "Oslash=d8,Otilde=d5,Otimes=2a37,Ouml=d6,OverBar=203e,OverBrace=23de,OverBracket=23b4,OverParenthesis",
1690
+ "=23dc,PartialD=2202,Pcy=41f,Pfr=1d513,Phi=3a6,Pi=3a0,PlusMinus=b1,Poincareplane=210c,Popf=2119,Pr=2a",
1691
+ "bb,Precedes=227a,PrecedesEqual=2aaf,PrecedesSlantEqual=227c,PrecedesTilde=227e,Prime=2033,Product=22",
1692
+ "0f,Proportion=2237,Proportional=221d,Pscr=1d4ab,Psi=3a8,QUOT=22,Qfr=1d514,Qopf=211a,Qscr=1d4ac,RBarr",
1693
+ "=2910,REG=ae,Racute=154,Rang=27eb,Rarr=21a0,Rarrtl=2916,Rcaron=158,Rcedil=156,Rcy=420,Re=211c,Revers",
1694
+ "eElement=220b,ReverseEquilibrium=21cb,ReverseUpEquilibrium=296f,Rfr=211c,Rho=3a1,RightAngleBracket=2",
1695
+ "7e9,RightArrow=2192,RightArrowBar=21e5,RightArrowLeftArrow=21c4,RightCeiling=2309,RightDoubleBracket",
1696
+ "=27e7,RightDownTeeVector=295d,RightDownVector=21c2,RightDownVectorBar=2955,RightFloor=230b,RightTee=",
1697
+ "22a2,RightTeeArrow=21a6,RightTeeVector=295b,RightTriangle=22b3,RightTriangleBar=29d0,RightTriangleEq",
1698
+ "ual=22b5,RightUpDownVector=294f,RightUpTeeVector=295c,RightUpVector=21be,RightUpVectorBar=2954,Right",
1699
+ "Vector=21c0,RightVectorBar=2953,Rightarrow=21d2,Ropf=211d,RoundImplies=2970,Rrightarrow=21db,Rscr=21",
1700
+ "1b,Rsh=21b1,RuleDelayed=29f4,SHCHcy=429,SHcy=428,SOFTcy=42c,Sacute=15a,Sc=2abc,Scaron=160,Scedil=15e",
1701
+ ",Scirc=15c,Scy=421,Sfr=1d516,ShortDownArrow=2193,ShortLeftArrow=2190,ShortRightArrow=2192,ShortUpArr",
1702
+ "ow=2191,Sigma=3a3,SmallCircle=2218,Sopf=1d54a,Sqrt=221a,Square=25a1,SquareIntersection=2293,SquareSu",
1703
+ "bset=228f,SquareSubsetEqual=2291,SquareSuperset=2290,SquareSupersetEqual=2292,SquareUnion=2294,Sscr=",
1704
+ "1d4ae,Star=22c6,Sub=22d0,Subset=22d0,SubsetEqual=2286,Succeeds=227b,SucceedsEqual=2ab0,SucceedsSlant",
1705
+ "Equal=227d,SucceedsTilde=227f,SuchThat=220b,Sum=2211,Sup=22d1,Superset=2283,SupersetEqual=2287,Supse",
1706
+ "t=22d1,THORN=de,TRADE=2122,TSHcy=40b,TScy=426,Tab=9,Tau=3a4,Tcaron=164,Tcedil=162,Tcy=422,Tfr=1d517,",
1707
+ "Therefore=2234,Theta=398,ThickSpace=205f.200a,ThinSpace=2009,Tilde=223c,TildeEqual=2243,TildeFullEqu",
1708
+ "al=2245,TildeTilde=2248,Topf=1d54b,TripleDot=20db,Tscr=1d4af,Tstrok=166,Uacute=da,Uarr=219f,Uarrocir",
1709
+ "=2949,Ubrcy=40e,Ubreve=16c,Ucirc=db,Ucy=423,Udblac=170,Ufr=1d518,Ugrave=d9,Umacr=16a,UnderBar=5f,Und",
1710
+ "erBrace=23df,UnderBracket=23b5,UnderParenthesis=23dd,Union=22c3,UnionPlus=228e,Uogon=172,Uopf=1d54c,",
1711
+ "UpArrow=2191,UpArrowBar=2912,UpArrowDownArrow=21c5,UpDownArrow=2195,UpEquilibrium=296e,UpTee=22a5,Up",
1712
+ "TeeArrow=21a5,Uparrow=21d1,Updownarrow=21d5,UpperLeftArrow=2196,UpperRightArrow=2197,Upsi=3d2,Upsilo",
1713
+ "n=3a5,Uring=16e,Uscr=1d4b0,Utilde=168,Uuml=dc,VDash=22ab,Vbar=2aeb,Vcy=412,Vdash=22a9,Vdashl=2ae6,Ve",
1714
+ "e=22c1,Verbar=2016,Vert=2016,VerticalBar=2223,VerticalLine=7c,VerticalSeparator=2758,VerticalTilde=2",
1715
+ "240,VeryThinSpace=200a,Vfr=1d519,Vopf=1d54d,Vscr=1d4b1,Vvdash=22aa,Wcirc=174,Wedge=22c0,Wfr=1d51a,Wo",
1716
+ "pf=1d54e,Wscr=1d4b2,Xfr=1d51b,Xi=39e,Xopf=1d54f,Xscr=1d4b3,YAcy=42f,YIcy=407,YUcy=42e,Yacute=dd,Ycir",
1717
+ "c=176,Ycy=42b,Yfr=1d51c,Yopf=1d550,Yscr=1d4b4,Yuml=178,ZHcy=416,Zacute=179,Zcaron=17d,Zcy=417,Zdot=1",
1718
+ "7b,ZeroWidthSpace=200b,Zeta=396,Zfr=2128,Zopf=2124,Zscr=1d4b5,aacute=e1,abreve=103,ac=223e,acE=223e.",
1719
+ "333,acd=223f,acirc=e2,acute=b4,acy=430,aelig=e6,af=2061,afr=1d51e,agrave=e0,alefsym=2135,aleph=2135,",
1720
+ "alpha=3b1,amacr=101,amalg=2a3f,amp=26,and=2227,andand=2a55,andd=2a5c,andslope=2a58,andv=2a5a,ang=222",
1721
+ "0,ange=29a4,angle=2220,angmsd=2221,angmsdaa=29a8,angmsdab=29a9,angmsdac=29aa,angmsdad=29ab,angmsdae=",
1722
+ "29ac,angmsdaf=29ad,angmsdag=29ae,angmsdah=29af,angrt=221f,angrtvb=22be,angrtvbd=299d,angsph=2222,ang",
1723
+ "st=c5,angzarr=237c,aogon=105,aopf=1d552,ap=2248,apE=2a70,apacir=2a6f,ape=224a,apid=224b,apos=27,appr",
1724
+ "ox=2248,approxeq=224a,aring=e5,ascr=1d4b6,ast=2a,asymp=2248,asympeq=224d,atilde=e3,auml=e4,awconint=",
1725
+ "2233,awint=2a11,bNot=2aed,backcong=224c,backepsilon=3f6,backprime=2035,backsim=223d,backsimeq=22cd,b",
1726
+ "arvee=22bd,barwed=2305,barwedge=2305,bbrk=23b5,bbrktbrk=23b6,bcong=224c,bcy=431,bdquo=201e,becaus=22",
1727
+ "35,because=2235,bemptyv=29b0,bepsi=3f6,bernou=212c,beta=3b2,beth=2136,between=226c,bfr=1d51f,bigcap=",
1728
+ "22c2,bigcirc=25ef,bigcup=22c3,bigodot=2a00,bigoplus=2a01,bigotimes=2a02,bigsqcup=2a06,bigstar=2605,b",
1729
+ "igtriangledown=25bd,bigtriangleup=25b3,biguplus=2a04,bigvee=22c1,bigwedge=22c0,bkarow=290d,blackloze",
1730
+ "nge=29eb,blacksquare=25aa,blacktriangle=25b4,blacktriangledown=25be,blacktriangleleft=25c2,blacktria",
1731
+ "ngleright=25b8,blank=2423,blk12=2592,blk14=2591,blk34=2593,block=2588,bne=3d.20e5,bnequiv=2261.20e5,",
1732
+ "bnot=2310,bopf=1d553,bot=22a5,bottom=22a5,bowtie=22c8,boxDL=2557,boxDR=2554,boxDl=2556,boxDr=2553,bo",
1733
+ "xH=2550,boxHD=2566,boxHU=2569,boxHd=2564,boxHu=2567,boxUL=255d,boxUR=255a,boxUl=255c,boxUr=2559,boxV",
1734
+ "=2551,boxVH=256c,boxVL=2563,boxVR=2560,boxVh=256b,boxVl=2562,boxVr=255f,boxbox=29c9,boxdL=2555,boxdR",
1735
+ "=2552,boxdl=2510,boxdr=250c,boxh=2500,boxhD=2565,boxhU=2568,boxhd=252c,boxhu=2534,boxminus=229f,boxp",
1736
+ "lus=229e,boxtimes=22a0,boxuL=255b,boxuR=2558,boxul=2518,boxur=2514,boxv=2502,boxvH=256a,boxvL=2561,b",
1737
+ "oxvR=255e,boxvh=253c,boxvl=2524,boxvr=251c,bprime=2035,breve=2d8,brvbar=a6,bscr=1d4b7,bsemi=204f,bsi",
1738
+ "m=223d,bsime=22cd,bsol=5c,bsolb=29c5,bsolhsub=27c8,bull=2022,bullet=2022,bump=224e,bumpE=2aae,bumpe=",
1739
+ "224f,bumpeq=224f,cacute=107,cap=2229,capand=2a44,capbrcup=2a49,capcap=2a4b,capcup=2a47,capdot=2a40,c",
1740
+ "aps=2229.fe00,caret=2041,caron=2c7,ccaps=2a4d,ccaron=10d,ccedil=e7,ccirc=109,ccups=2a4c,ccupssm=2a50",
1741
+ ",cdot=10b,cedil=b8,cemptyv=29b2,cent=a2,centerdot=b7,cfr=1d520,chcy=447,check=2713,checkmark=2713,ch",
1742
+ "i=3c7,cir=25cb,cirE=29c3,circ=2c6,circeq=2257,circlearrowleft=21ba,circlearrowright=21bb,circledR=ae",
1743
+ ",circledS=24c8,circledast=229b,circledcirc=229a,circleddash=229d,cire=2257,cirfnint=2a10,cirmid=2aef",
1744
+ ",cirscir=29c2,clubs=2663,clubsuit=2663,colon=3a,colone=2254,coloneq=2254,comma=2c,commat=40,comp=220",
1745
+ "1,compfn=2218,complement=2201,complexes=2102,cong=2245,congdot=2a6d,conint=222e,copf=1d554,coprod=22",
1746
+ "10,copy=a9,copysr=2117,crarr=21b5,cross=2717,cscr=1d4b8,csub=2acf,csube=2ad1,csup=2ad0,csupe=2ad2,ct",
1747
+ "dot=22ef,cudarrl=2938,cudarrr=2935,cuepr=22de,cuesc=22df,cularr=21b6,cularrp=293d,cup=222a,cupbrcap=",
1748
+ "2a48,cupcap=2a46,cupcup=2a4a,cupdot=228d,cupor=2a45,cups=222a.fe00,curarr=21b7,curarrm=293c,curlyeqp",
1749
+ "rec=22de,curlyeqsucc=22df,curlyvee=22ce,curlywedge=22cf,curren=a4,curvearrowleft=21b6,curvearrowrigh",
1750
+ "t=21b7,cuvee=22ce,cuwed=22cf,cwconint=2232,cwint=2231,cylcty=232d,dArr=21d3,dHar=2965,dagger=2020,da",
1751
+ "leth=2138,darr=2193,dash=2010,dashv=22a3,dbkarow=290f,dblac=2dd,dcaron=10f,dcy=434,dd=2146,ddagger=2",
1752
+ "021,ddarr=21ca,ddotseq=2a77,deg=b0,delta=3b4,demptyv=29b1,dfisht=297f,dfr=1d521,dharl=21c3,dharr=21c",
1753
+ "2,diam=22c4,diamond=22c4,diamondsuit=2666,diams=2666,die=a8,digamma=3dd,disin=22f2,div=f7,divide=f7,",
1754
+ "divideontimes=22c7,divonx=22c7,djcy=452,dlcorn=231e,dlcrop=230d,dollar=24,dopf=1d555,dot=2d9,doteq=2",
1755
+ "250,doteqdot=2251,dotminus=2238,dotplus=2214,dotsquare=22a1,doublebarwedge=2306,downarrow=2193,downd",
1756
+ "ownarrows=21ca,downharpoonleft=21c3,downharpoonright=21c2,drbkarow=2910,drcorn=231f,drcrop=230c,dscr",
1757
+ "=1d4b9,dscy=455,dsol=29f6,dstrok=111,dtdot=22f1,dtri=25bf,dtrif=25be,duarr=21f5,duhar=296f,dwangle=2",
1758
+ "9a6,dzcy=45f,dzigrarr=27ff,eDDot=2a77,eDot=2251,eacute=e9,easter=2a6e,ecaron=11b,ecir=2256,ecirc=ea,",
1759
+ "ecolon=2255,ecy=44d,edot=117,ee=2147,efDot=2252,efr=1d522,eg=2a9a,egrave=e8,egs=2a96,egsdot=2a98,el=",
1760
+ "2a99,elinters=23e7,ell=2113,els=2a95,elsdot=2a97,emacr=113,empty=2205,emptyset=2205,emptyv=2205,emsp",
1761
+ "=2003,emsp13=2004,emsp14=2005,eng=14b,ensp=2002,eogon=119,eopf=1d556,epar=22d5,eparsl=29e3,eplus=2a7",
1762
+ "1,epsi=3b5,epsilon=3b5,epsiv=3f5,eqcirc=2256,eqcolon=2255,eqsim=2242,eqslantgtr=2a96,eqslantless=2a9",
1763
+ "5,equals=3d,equest=225f,equiv=2261,equivDD=2a78,eqvparsl=29e5,erDot=2253,erarr=2971,escr=212f,esdot=",
1764
+ "2250,esim=2242,eta=3b7,eth=f0,euml=eb,euro=20ac,excl=21,exist=2203,expectation=2130,exponentiale=214",
1765
+ "7,fallingdotseq=2252,fcy=444,female=2640,ffilig=fb03,fflig=fb00,ffllig=fb04,ffr=1d523,filig=fb01,fjl",
1766
+ "ig=66.6a,flat=266d,fllig=fb02,fltns=25b1,fnof=192,fopf=1d557,forall=2200,fork=22d4,forkv=2ad9,fparti",
1767
+ "nt=2a0d,frac12=bd,frac13=2153,frac14=bc,frac15=2155,frac16=2159,frac18=215b,frac23=2154,frac25=2156,",
1768
+ "frac34=be,frac35=2157,frac38=215c,frac45=2158,frac56=215a,frac58=215d,frac78=215e,frasl=2044,frown=2",
1769
+ "322,fscr=1d4bb,gE=2267,gEl=2a8c,gacute=1f5,gamma=3b3,gammad=3dd,gap=2a86,gbreve=11f,gcirc=11d,gcy=43",
1770
+ "3,gdot=121,ge=2265,gel=22db,geq=2265,geqq=2267,geqslant=2a7e,ges=2a7e,gescc=2aa9,gesdot=2a80,gesdoto",
1771
+ "=2a82,gesdotol=2a84,gesl=22db.fe00,gesles=2a94,gfr=1d524,gg=226b,ggg=22d9,gimel=2137,gjcy=453,gl=227",
1772
+ "7,glE=2a92,gla=2aa5,glj=2aa4,gnE=2269,gnap=2a8a,gnapprox=2a8a,gne=2a88,gneq=2a88,gneqq=2269,gnsim=22",
1773
+ "e7,gopf=1d558,grave=60,gscr=210a,gsim=2273,gsime=2a8e,gsiml=2a90,gt=3e,gtcc=2aa7,gtcir=2a7a,gtdot=22",
1774
+ "d7,gtlPar=2995,gtquest=2a7c,gtrapprox=2a86,gtrarr=2978,gtrdot=22d7,gtreqless=22db,gtreqqless=2a8c,gt",
1775
+ "rless=2277,gtrsim=2273,gvertneqq=2269.fe00,gvnE=2269.fe00,hArr=21d4,hairsp=200a,half=bd,hamilt=210b,",
1776
+ "hardcy=44a,harr=2194,harrcir=2948,harrw=21ad,hbar=210f,hcirc=125,hearts=2665,heartsuit=2665,hellip=2",
1777
+ "026,hercon=22b9,hfr=1d525,hksearow=2925,hkswarow=2926,hoarr=21ff,homtht=223b,hookleftarrow=21a9,hook",
1778
+ "rightarrow=21aa,hopf=1d559,horbar=2015,hscr=1d4bd,hslash=210f,hstrok=127,hybull=2043,hyphen=2010,iac",
1779
+ "ute=ed,ic=2063,icirc=ee,icy=438,iecy=435,iexcl=a1,iff=21d4,ifr=1d526,igrave=ec,ii=2148,iiiint=2a0c,i",
1780
+ "iint=222d,iinfin=29dc,iiota=2129,ijlig=133,imacr=12b,image=2111,imagline=2110,imagpart=2111,imath=13",
1781
+ "1,imof=22b7,imped=1b5,in=2208,incare=2105,infin=221e,infintie=29dd,inodot=131,int=222b,intcal=22ba,i",
1782
+ "ntegers=2124,intercal=22ba,intlarhk=2a17,intprod=2a3c,iocy=451,iogon=12f,iopf=1d55a,iota=3b9,iprod=2",
1783
+ "a3c,iquest=bf,iscr=1d4be,isin=2208,isinE=22f9,isindot=22f5,isins=22f4,isinsv=22f3,isinv=2208,it=2062",
1784
+ ",itilde=129,iukcy=456,iuml=ef,jcirc=135,jcy=439,jfr=1d527,jmath=237,jopf=1d55b,jscr=1d4bf,jsercy=458",
1785
+ ",jukcy=454,kappa=3ba,kappav=3f0,kcedil=137,kcy=43a,kfr=1d528,kgreen=138,khcy=445,kjcy=45c,kopf=1d55c",
1786
+ ",kscr=1d4c0,lAarr=21da,lArr=21d0,lAtail=291b,lBarr=290e,lE=2266,lEg=2a8b,lHar=2962,lacute=13a,laempt",
1787
+ "yv=29b4,lagran=2112,lambda=3bb,lang=2329,langd=2991,langle=27e8,lap=2a85,laquo=ab,larr=2190,larrb=21",
1788
+ "e4,larrbfs=291f,larrfs=291d,larrhk=21a9,larrlp=21ab,larrpl=2939,larrsim=2973,larrtl=21a2,lat=2aab,la",
1789
+ "tail=2919,late=2aad,lates=2aad.fe00,lbarr=290c,lbbrk=2772,lbrace=7b,lbrack=5b,lbrke=298b,lbrksld=298",
1790
+ "f,lbrkslu=298d,lcaron=13e,lcedil=13c,lceil=2308,lcub=7b,lcy=43b,ldca=2936,ldquo=201c,ldquor=201e,ldr",
1791
+ "dhar=2967,ldrushar=294b,ldsh=21b2,le=2264,leftarrow=2190,leftarrowtail=21a2,leftharpoondown=21bd,lef",
1792
+ "tharpoonup=21bc,leftleftarrows=21c7,leftrightarrow=2194,leftrightarrows=21c6,leftrightharpoons=21cb,",
1793
+ "leftrightsquigarrow=21ad,leftthreetimes=22cb,leg=22da,leq=2264,leqq=2266,leqslant=2a7d,les=2a7d,lesc",
1794
+ "c=2aa8,lesdot=2a7f,lesdoto=2a81,lesdotor=2a83,lesg=22da.fe00,lesges=2a93,lessapprox=2a85,lessdot=22d",
1795
+ "6,lesseqgtr=22da,lesseqqgtr=2a8b,lessgtr=2276,lesssim=2272,lfisht=297c,lfloor=230a,lfr=1d529,lg=2276",
1796
+ ",lgE=2a91,lhard=21bd,lharu=21bc,lharul=296a,lhblk=2584,ljcy=459,ll=226a,llarr=21c7,llcorner=231e,llh",
1797
+ "ard=296b,lltri=25fa,lmidot=140,lmoust=23b0,lmoustache=23b0,lnE=2268,lnap=2a89,lnapprox=2a89,lne=2a87",
1798
+ ",lneq=2a87,lneqq=2268,lnsim=22e6,loang=27ec,loarr=21fd,lobrk=27e6,longleftarrow=27f5,longleftrightar",
1799
+ "row=27f7,longmapsto=27fc,longrightarrow=27f6,looparrowleft=21ab,looparrowright=21ac,lopar=2985,lopf=",
1800
+ "1d55d,loplus=2a2d,lotimes=2a34,lowast=2217,lowbar=5f,loz=25ca,lozenge=25ca,lozf=29eb,lpar=28,lparlt=",
1801
+ "2993,lrarr=21c6,lrcorner=231f,lrhar=21cb,lrhard=296d,lrm=200e,lrtri=22bf,lsaquo=2039,lscr=1d4c1,lsh=",
1802
+ "21b0,lsim=2272,lsime=2a8d,lsimg=2a8f,lsqb=5b,lsquo=2018,lsquor=201a,lstrok=142,lt=3c,ltcc=2aa6,ltcir",
1803
+ "=2a79,ltdot=22d6,lthree=22cb,ltimes=22c9,ltlarr=2976,ltquest=2a7b,ltrPar=2996,ltri=25c3,ltrie=22b4,l",
1804
+ "trif=25c2,lurdshar=294a,luruhar=2966,lvertneqq=2268.fe00,lvnE=2268.fe00,mDDot=223a,macr=af,male=2642",
1805
+ ",malt=2720,maltese=2720,map=21a6,mapsto=21a6,mapstodown=21a7,mapstoleft=21a4,mapstoup=21a5,marker=25",
1806
+ "ae,mcomma=2a29,mcy=43c,mdash=2014,measuredangle=2221,mfr=1d52a,mho=2127,micro=b5,mid=2223,midast=2a,",
1807
+ "midcir=2af0,middot=b7,minus=2212,minusb=229f,minusd=2238,minusdu=2a2a,mlcp=2adb,mldr=2026,mnplus=221",
1808
+ "3,models=22a7,mopf=1d55e,mp=2213,mscr=1d4c2,mstpos=223e,mu=3bc,multimap=22b8,mumap=22b8,nGg=22d9.338",
1809
+ ",nGt=226b.20d2,nGtv=226b.338,nLeftarrow=21cd,nLeftrightarrow=21ce,nLl=22d8.338,nLt=226a.20d2,nLtv=22",
1810
+ "6a.338,nRightarrow=21cf,nVDash=22af,nVdash=22ae,nabla=2207,nacute=144,nang=2220.20d2,nap=2249,napE=2",
1811
+ "a70.338,napid=224b.338,napos=149,napprox=2249,natur=266e,natural=266e,naturals=2115,nbsp=a0,nbump=22",
1812
+ "4e.338,nbumpe=224f.338,ncap=2a43,ncaron=148,ncedil=146,ncong=2247,ncongdot=2a6d.338,ncup=2a42,ncy=43",
1813
+ "d,ndash=2013,ne=2260,neArr=21d7,nearhk=2924,nearr=2197,nearrow=2197,nedot=2250.338,nequiv=2262,nesea",
1814
+ "r=2928,nesim=2242.338,nexist=2204,nexists=2204,nfr=1d52b,ngE=2267.338,nge=2271,ngeq=2271,ngeqq=2267.",
1815
+ "338,ngeqslant=2a7e.338,nges=2a7e.338,ngsim=2275,ngt=226f,ngtr=226f,nhArr=21ce,nharr=21ae,nhpar=2af2,",
1816
+ "ni=220b,nis=22fc,nisd=22fa,niv=220b,njcy=45a,nlArr=21cd,nlE=2266.338,nlarr=219a,nldr=2025,nle=2270,n",
1817
+ "leftarrow=219a,nleftrightarrow=21ae,nleq=2270,nleqq=2266.338,nleqslant=2a7d.338,nles=2a7d.338,nless=",
1818
+ "226e,nlsim=2274,nlt=226e,nltri=22ea,nltrie=22ec,nmid=2224,nopf=1d55f,not=ac,notin=2209,notinE=22f9.3",
1819
+ "38,notindot=22f5.338,notinva=2209,notinvb=22f7,notinvc=22f6,notni=220c,notniva=220c,notnivb=22fe,not",
1820
+ "nivc=22fd,npar=2226,nparallel=2226,nparsl=2afd.20e5,npart=2202.338,npolint=2a14,npr=2280,nprcue=22e0",
1821
+ ",npre=2aaf.338,nprec=2280,npreceq=2aaf.338,nrArr=21cf,nrarr=219b,nrarrc=2933.338,nrarrw=219d.338,nri",
1822
+ "ghtarrow=219b,nrtri=22eb,nrtrie=22ed,nsc=2281,nsccue=22e1,nsce=2ab0.338,nscr=1d4c3,nshortmid=2224,ns",
1823
+ "hortparallel=2226,nsim=2241,nsime=2244,nsimeq=2244,nsmid=2224,nspar=2226,nsqsube=22e2,nsqsupe=22e3,n",
1824
+ "sub=2284,nsubE=2ac5.338,nsube=2288,nsubset=2282.20d2,nsubseteq=2288,nsubseteqq=2ac5.338,nsucc=2281,n",
1825
+ "succeq=2ab0.338,nsup=2285,nsupE=2ac6.338,nsupe=2289,nsupset=2283.20d2,nsupseteq=2289,nsupseteqq=2ac6",
1826
+ ".338,ntgl=2279,ntilde=f1,ntlg=2278,ntriangleleft=22ea,ntrianglelefteq=22ec,ntriangleright=22eb,ntria",
1827
+ "nglerighteq=22ed,nu=3bd,num=23,numero=2116,numsp=2007,nvDash=22ad,nvHarr=2904,nvap=224d.20d2,nvdash=",
1828
+ "22ac,nvge=2265.20d2,nvgt=3e.20d2,nvinfin=29de,nvlArr=2902,nvle=2264.20d2,nvlt=3c.20d2,nvltrie=22b4.2",
1829
+ "0d2,nvrArr=2903,nvrtrie=22b5.20d2,nvsim=223c.20d2,nwArr=21d6,nwarhk=2923,nwarr=2196,nwarrow=2196,nwn",
1830
+ "ear=2927,oS=24c8,oacute=f3,oast=229b,ocir=229a,ocirc=f4,ocy=43e,odash=229d,odblac=151,odiv=2a38,odot",
1831
+ "=2299,odsold=29bc,oelig=153,ofcir=29bf,ofr=1d52c,ogon=2db,ograve=f2,ogt=29c1,ohbar=29b5,ohm=3a9,oint",
1832
+ "=222e,olarr=21ba,olcir=29be,olcross=29bb,oline=203e,olt=29c0,omacr=14d,omega=3c9,omicron=3bf,omid=29",
1833
+ "b6,ominus=2296,oopf=1d560,opar=29b7,operp=29b9,oplus=2295,or=2228,orarr=21bb,ord=2a5d,order=2134,ord",
1834
+ "erof=2134,ordf=aa,ordm=ba,origof=22b6,oror=2a56,orslope=2a57,orv=2a5b,oscr=2134,oslash=f8,osol=2298,",
1835
+ "otilde=f5,otimes=2297,otimesas=2a36,ouml=f6,ovbar=233d,par=2225,para=b6,parallel=2225,parsim=2af3,pa",
1836
+ "rsl=2afd,part=2202,pcy=43f,percnt=25,period=2e,permil=2030,perp=22a5,pertenk=2031,pfr=1d52d,phi=3c6,",
1837
+ "phiv=3d5,phmmat=2133,phone=260e,pi=3c0,pitchfork=22d4,piv=3d6,planck=210f,planckh=210e,plankv=210f,p",
1838
+ "lus=2b,plusacir=2a23,plusb=229e,pluscir=2a22,plusdo=2214,plusdu=2a25,pluse=2a72,plusmn=b1,plussim=2a",
1839
+ "26,plustwo=2a27,pm=b1,pointint=2a15,popf=1d561,pound=a3,pr=227a,prE=2ab3,prap=2ab7,prcue=227c,pre=2a",
1840
+ "af,prec=227a,precapprox=2ab7,preccurlyeq=227c,preceq=2aaf,precnapprox=2ab9,precneqq=2ab5,precnsim=22",
1841
+ "e8,precsim=227e,prime=2032,primes=2119,prnE=2ab5,prnap=2ab9,prnsim=22e8,prod=220f,profalar=232e,prof",
1842
+ "line=2312,profsurf=2313,prop=221d,propto=221d,prsim=227e,prurel=22b0,pscr=1d4c5,psi=3c8,puncsp=2008,",
1843
+ "qfr=1d52e,qint=2a0c,qopf=1d562,qprime=2057,qscr=1d4c6,quaternions=210d,quatint=2a16,quest=3f,questeq",
1844
+ "=225f,quot=22,rAarr=21db,rArr=21d2,rAtail=291c,rBarr=290f,rHar=2964,race=223d.331,racute=155,radic=2",
1845
+ "21a,raemptyv=29b3,rang=232a,rangd=2992,range=29a5,rangle=27e9,raquo=bb,rarr=2192,rarrap=2975,rarrb=2",
1846
+ "1e5,rarrbfs=2920,rarrc=2933,rarrfs=291e,rarrhk=21aa,rarrlp=21ac,rarrpl=2945,rarrsim=2974,rarrtl=21a3",
1847
+ ",rarrw=219d,ratail=291a,ratio=2236,rationals=211a,rbarr=290d,rbbrk=2773,rbrace=7d,rbrack=5d,rbrke=29",
1848
+ "8c,rbrksld=298e,rbrkslu=2990,rcaron=159,rcedil=157,rceil=2309,rcub=7d,rcy=440,rdca=2937,rdldhar=2969",
1849
+ ",rdquo=201d,rdquor=201d,rdsh=21b3,real=211c,realine=211b,realpart=211c,reals=211d,rect=25ad,reg=ae,r",
1850
+ "fisht=297d,rfloor=230b,rfr=1d52f,rhard=21c1,rharu=21c0,rharul=296c,rho=3c1,rhov=3f1,rightarrow=2192,",
1851
+ "rightarrowtail=21a3,rightharpoondown=21c1,rightharpoonup=21c0,rightleftarrows=21c4,rightleftharpoons",
1852
+ "=21cc,rightrightarrows=21c9,rightsquigarrow=219d,rightthreetimes=22cc,ring=2da,risingdotseq=2253,rla",
1853
+ "rr=21c4,rlhar=21cc,rlm=200f,rmoust=23b1,rmoustache=23b1,rnmid=2aee,roang=27ed,roarr=21fe,robrk=27e7,",
1854
+ "ropar=2986,ropf=1d563,roplus=2a2e,rotimes=2a35,rpar=29,rpargt=2994,rppolint=2a12,rrarr=21c9,rsaquo=2",
1855
+ "03a,rscr=1d4c7,rsh=21b1,rsqb=5d,rsquo=2019,rsquor=2019,rthree=22cc,rtimes=22ca,rtri=25b9,rtrie=22b5,",
1856
+ "rtrif=25b8,rtriltri=29ce,ruluhar=2968,rx=211e,sacute=15b,sbquo=201a,sc=227b,scE=2ab4,scap=2ab8,scaro",
1857
+ "n=161,sccue=227d,sce=2ab0,scedil=15f,scirc=15d,scnE=2ab6,scnap=2aba,scnsim=22e9,scpolint=2a13,scsim=",
1858
+ "227f,scy=441,sdot=22c5,sdotb=22a1,sdote=2a66,seArr=21d8,searhk=2925,searr=2198,searrow=2198,sect=a7,",
1859
+ "semi=3b,seswar=2929,setminus=2216,setmn=2216,sext=2736,sfr=1d530,sfrown=2322,sharp=266f,shchcy=449,s",
1860
+ "hcy=448,shortmid=2223,shortparallel=2225,shy=ad,sigma=3c3,sigmaf=3c2,sigmav=3c2,sim=223c,simdot=2a6a",
1861
+ ",sime=2243,simeq=2243,simg=2a9e,simgE=2aa0,siml=2a9d,simlE=2a9f,simne=2246,simplus=2a24,simrarr=2972",
1862
+ ",slarr=2190,smallsetminus=2216,smashp=2a33,smeparsl=29e4,smid=2223,smile=2323,smt=2aaa,smte=2aac,smt",
1863
+ "es=2aac.fe00,softcy=44c,sol=2f,solb=29c4,solbar=233f,sopf=1d564,spades=2660,spadesuit=2660,spar=2225",
1864
+ ",sqcap=2293,sqcaps=2293.fe00,sqcup=2294,sqcups=2294.fe00,sqsub=228f,sqsube=2291,sqsubset=228f,sqsubs",
1865
+ "eteq=2291,sqsup=2290,sqsupe=2292,sqsupset=2290,sqsupseteq=2292,squ=25a1,square=25a1,squarf=25aa,squf",
1866
+ "=25aa,srarr=2192,sscr=1d4c8,ssetmn=2216,ssmile=2323,sstarf=22c6,star=2606,starf=2605,straightepsilon",
1867
+ "=3f5,straightphi=3d5,strns=af,sub=2282,subE=2ac5,subdot=2abd,sube=2286,subedot=2ac3,submult=2ac1,sub",
1868
+ "nE=2acb,subne=228a,subplus=2abf,subrarr=2979,subset=2282,subseteq=2286,subseteqq=2ac5,subsetneq=228a",
1869
+ ",subsetneqq=2acb,subsim=2ac7,subsub=2ad5,subsup=2ad3,succ=227b,succapprox=2ab8,succcurlyeq=227d,succ",
1870
+ "eq=2ab0,succnapprox=2aba,succneqq=2ab6,succnsim=22e9,succsim=227f,sum=2211,sung=266a,sup=2283,sup1=b",
1871
+ "9,sup2=b2,sup3=b3,supE=2ac6,supdot=2abe,supdsub=2ad8,supe=2287,supedot=2ac4,suphsol=27c9,suphsub=2ad",
1872
+ "7,suplarr=297b,supmult=2ac2,supnE=2acc,supne=228b,supplus=2ac0,supset=2283,supseteq=2287,supseteqq=2",
1873
+ "ac6,supsetneq=228b,supsetneqq=2acc,supsim=2ac8,supsub=2ad4,supsup=2ad6,swArr=21d9,swarhk=2926,swarr=",
1874
+ "2199,swarrow=2199,swnwar=292a,szlig=df,target=2316,tau=3c4,tbrk=23b4,tcaron=165,tcedil=163,tcy=442,t",
1875
+ "dot=20db,telrec=2315,tfr=1d531,there4=2234,therefore=2234,theta=3b8,thetasym=3d1,thetav=3d1,thickapp",
1876
+ "rox=2248,thicksim=223c,thinsp=2009,thkap=2248,thksim=223c,thorn=fe,tilde=2dc,times=d7,timesb=22a0,ti",
1877
+ "mesbar=2a31,timesd=2a30,tint=222d,toea=2928,top=22a4,topbot=2336,topcir=2af1,topf=1d565,topfork=2ada",
1878
+ ",tosa=2929,tprime=2034,trade=2122,triangle=25b5,triangledown=25bf,triangleleft=25c3,trianglelefteq=2",
1879
+ "2b4,triangleq=225c,triangleright=25b9,trianglerighteq=22b5,tridot=25ec,trie=225c,triminus=2a3a,tripl",
1880
+ "us=2a39,trisb=29cd,tritime=2a3b,trpezium=23e2,tscr=1d4c9,tscy=446,tshcy=45b,tstrok=167,twixt=226c,tw",
1881
+ "oheadleftarrow=219e,twoheadrightarrow=21a0,uArr=21d1,uHar=2963,uacute=fa,uarr=2191,ubrcy=45e,ubreve=",
1882
+ "16d,ucirc=fb,ucy=443,udarr=21c5,udblac=171,udhar=296e,ufisht=297e,ufr=1d532,ugrave=f9,uharl=21bf,uha",
1883
+ "rr=21be,uhblk=2580,ulcorn=231c,ulcorner=231c,ulcrop=230f,ultri=25f8,umacr=16b,uml=a8,uogon=173,uopf=",
1884
+ "1d566,uparrow=2191,updownarrow=2195,upharpoonleft=21bf,upharpoonright=21be,uplus=228e,upsi=3c5,upsih",
1885
+ "=3d2,upsilon=3c5,upuparrows=21c8,urcorn=231d,urcorner=231d,urcrop=230e,uring=16f,urtri=25f9,uscr=1d4",
1886
+ "ca,utdot=22f0,utilde=169,utri=25b5,utrif=25b4,uuarr=21c8,uuml=fc,uwangle=29a7,vArr=21d5,vBar=2ae8,vB",
1887
+ "arv=2ae9,vDash=22a8,vangrt=299c,varepsilon=3f5,varkappa=3f0,varnothing=2205,varphi=3d5,varpi=3d6,var",
1888
+ "propto=221d,varr=2195,varrho=3f1,varsigma=3c2,varsubsetneq=228a.fe00,varsubsetneqq=2acb.fe00,varsups",
1889
+ "etneq=228b.fe00,varsupsetneqq=2acc.fe00,vartheta=3d1,vartriangleleft=22b2,vartriangleright=22b3,vcy=",
1890
+ "432,vdash=22a2,vee=2228,veebar=22bb,veeeq=225a,vellip=22ee,verbar=7c,vert=7c,vfr=1d533,vltri=22b2,vn",
1891
+ "sub=2282.20d2,vnsup=2283.20d2,vopf=1d567,vprop=221d,vrtri=22b3,vscr=1d4cb,vsubnE=2acb.fe00,vsubne=22",
1892
+ "8a.fe00,vsupnE=2acc.fe00,vsupne=228b.fe00,vzigzag=299a,wcirc=175,wedbar=2a5f,wedge=2227,wedgeq=2259,",
1893
+ "weierp=2118,wfr=1d534,wopf=1d568,wp=2118,wr=2240,wreath=2240,wscr=1d4cc,xcap=22c2,xcirc=25ef,xcup=22",
1894
+ "c3,xdtri=25bd,xfr=1d535,xhArr=27fa,xharr=27f7,xi=3be,xlArr=27f8,xlarr=27f5,xmap=27fc,xnis=22fb,xodot",
1895
+ "=2a00,xopf=1d569,xoplus=2a01,xotime=2a02,xrArr=27f9,xrarr=27f6,xscr=1d4cd,xsqcup=2a06,xuplus=2a04,xu",
1896
+ "tri=25b3,xvee=22c1,xwedge=22c0,yacute=fd,yacy=44f,ycirc=177,ycy=44b,yen=a5,yfr=1d536,yicy=457,yopf=1",
1897
+ "d56a,yscr=1d4ce,yucy=44e,yuml=ff,zacute=17a,zcaron=17e,zcy=437,zdot=17c,zeetrf=2128,zeta=3b6,zfr=1d5",
1898
+ "37,zhcy=436,zigrarr=21dd,zopf=1d56b,zscr=1d4cf,zwj=200d,zwnj=200c"
1899
+ ].join("");
1900
+ NAMED_REFERENCES = new Map(NAMED.split(",").map((entry) => {
1901
+ const [name, codes] = entry.split("=");
1902
+ return [name, String.fromCodePoint(...codes.split(".").map((code) => Number.parseInt(code, 16)))];
1903
+ }));
1904
+ }
1905
+ });
1906
+
1627
1907
  // src/html.js
1628
1908
  function fromCode(code) {
1629
1909
  if (code === 0 || code > 1114111 || code >= 55296 && code <= 57343) {
@@ -1640,8 +1920,8 @@ function decodeEntities(value, { attribute = false } = {}) {
1640
1920
  if (hex !== void 0 || decimal !== void 0) {
1641
1921
  return fromCode(hex === void 0 ? Number.parseInt(decimal, 10) : Number.parseInt(hex, 16));
1642
1922
  }
1643
- if (semicolon && (ENTITIES.has(name) || LONGER_NAMES.has(name))) {
1644
- return ENTITIES.get(name) ?? match;
1923
+ if (semicolon && NAMED_REFERENCES.has(name)) {
1924
+ return NAMED_REFERENCES.get(name);
1645
1925
  }
1646
1926
  let legacy;
1647
1927
  for (let length = Math.min(name.length, LEGACY_LONGEST); length >= 2 && legacy === void 0; length--) {
@@ -1655,7 +1935,7 @@ function decodeEntities(value, { attribute = false } = {}) {
1655
1935
  if (attribute && /[\da-zA-Z=]/.test(next)) {
1656
1936
  return match;
1657
1937
  }
1658
- return ENTITIES.get(legacy) + rest;
1938
+ return NAMED_REFERENCES.get(legacy) + rest;
1659
1939
  });
1660
1940
  }
1661
1941
  function readTag(html2, start) {
@@ -2296,106 +2576,14 @@ function visibleText(html2) {
2296
2576
  }
2297
2577
  return { text: parts.join(""), hidden };
2298
2578
  }
2299
- var LATIN1, ENTITIES, LEGACY, LEGACY_LONGEST, LONGER_NAMES, WINDOWS_1252, REFERENCE, UNSHOWN, RAW_SHOWN, RAW_END, BREAKS, SPECIAL, SCOPE, FORMATTING, LINE, OWN_PLACE, VOID, CLOSES_PARAGRAPH, PARAGRAPH, IMPLIED, TABLE_PARTS, TABLE_BOXES, HEADINGS, IMPLIED_END, PARTS_OF_TABLE, TABLE_STRUCTURE, IN_TABLE, MAX_FORMATTING, MARKERS, FOSTERED_MARKERS, NOT_REOPENING, LEAVES_FOREIGN, HOLDS_HTML, SVG_UNSHOWN, MAX_OPEN, MAX_ATTRIBUTES, MAX_STYLE, COMMENT_END, WHITESPACE2, NO_WORD_ATTRIBUTES, FIELDS, FIELD_HELP, HINTS, MAX_HELP, LABEL_END, isHelp, MAX_VALUE, LENGTH, UNITS, SIZE_KEYWORDS, ZERO_NUMBER, DISPLAY_INLINE, DISPLAY_BLOCK, isZero, declarationCache, ROOT, DOCTYPE, QUIRKS_PUBLIC, QUIRKS_IF_NO_SYSTEM;
2579
+ var LATIN1, LEGACY, LEGACY_LONGEST, WINDOWS_1252, REFERENCE, UNSHOWN, RAW_SHOWN, RAW_END, BREAKS, SPECIAL, SCOPE, FORMATTING, LINE, OWN_PLACE, VOID, CLOSES_PARAGRAPH, PARAGRAPH, IMPLIED, TABLE_PARTS, TABLE_BOXES, HEADINGS, IMPLIED_END, PARTS_OF_TABLE, TABLE_STRUCTURE, IN_TABLE, MAX_FORMATTING, MARKERS, FOSTERED_MARKERS, NOT_REOPENING, LEAVES_FOREIGN, HOLDS_HTML, SVG_UNSHOWN, MAX_OPEN, MAX_ATTRIBUTES, MAX_STYLE, COMMENT_END, WHITESPACE2, NO_WORD_ATTRIBUTES, FIELDS, FIELD_HELP, HINTS, MAX_HELP, LABEL_END, isHelp, MAX_VALUE, LENGTH, UNITS, SIZE_KEYWORDS, ZERO_NUMBER, DISPLAY_INLINE, DISPLAY_BLOCK, isZero, declarationCache, ROOT, DOCTYPE, QUIRKS_PUBLIC, QUIRKS_IF_NO_SYSTEM;
2300
2580
  var init_html = __esm({
2301
2581
  "src/html.js"() {
2582
+ init_entities();
2302
2583
  init_linear();
2303
2584
  LATIN1 = "nbsp iexcl cent pound curren yen brvbar sect uml copy ordf laquo not shy reg macr deg plusmn sup2 sup3 acute micro para middot cedil sup1 ordm raquo frac14 frac12 frac34 iquest Agrave Aacute Acirc Atilde Auml Aring AElig Ccedil Egrave Eacute Ecirc Euml Igrave Iacute Icirc Iuml ETH Ntilde Ograve Oacute Ocirc Otilde Ouml times Oslash Ugrave Uacute Ucirc Uuml Yacute THORN szlig agrave aacute acirc atilde auml aring aelig ccedil egrave eacute ecirc euml igrave iacute icirc iuml eth ntilde ograve oacute ocirc otilde ouml divide oslash ugrave uacute ucirc uuml yacute thorn yuml".split(" ");
2304
- ENTITIES = new Map([
2305
- ...LATIN1.map((name, index) => [name, String.fromCodePoint(160 + index)]),
2306
- ["amp", "&"],
2307
- ["lt", "<"],
2308
- ["gt", ">"],
2309
- ["quot", '"'],
2310
- ["apos", "'"],
2311
- ["AMP", "&"],
2312
- ["LT", "<"],
2313
- ["GT", ">"],
2314
- ["QUOT", '"'],
2315
- ["COPY", "\xA9"],
2316
- ["REG", "\xAE"],
2317
- ["OElig", "\u0152"],
2318
- ["oelig", "\u0153"],
2319
- ["Scaron", "\u0160"],
2320
- ["scaron", "\u0161"],
2321
- ["Yuml", "\u0178"],
2322
- ["fnof", "\u0192"],
2323
- ["circ", "\u02C6"],
2324
- ["tilde", "\u02DC"],
2325
- ["ensp", "\u2002"],
2326
- ["emsp", "\u2003"],
2327
- ["thinsp", "\u2009"],
2328
- ["zwnj", "\u200C"],
2329
- ["zwj", "\u200D"],
2330
- ["lrm", "\u200E"],
2331
- ["rlm", "\u200F"],
2332
- ["ndash", "\u2013"],
2333
- ["mdash", "\u2014"],
2334
- ["lsquo", "\u2018"],
2335
- ["rsquo", "\u2019"],
2336
- ["sbquo", "\u201A"],
2337
- ["ldquo", "\u201C"],
2338
- ["rdquo", "\u201D"],
2339
- ["bdquo", "\u201E"],
2340
- ["dagger", "\u2020"],
2341
- ["Dagger", "\u2021"],
2342
- ["bull", "\u2022"],
2343
- ["hellip", "\u2026"],
2344
- ["permil", "\u2030"],
2345
- ["prime", "\u2032"],
2346
- ["Prime", "\u2033"],
2347
- ["lsaquo", "\u2039"],
2348
- ["rsaquo", "\u203A"],
2349
- ["euro", "\u20AC"],
2350
- ["trade", "\u2122"],
2351
- ["larr", "\u2190"],
2352
- ["uarr", "\u2191"],
2353
- ["rarr", "\u2192"],
2354
- ["darr", "\u2193"],
2355
- ["hearts", "\u2665"],
2356
- ["check", "\u2713"],
2357
- // The punctuation of a web address, as browsers read these names
2358
- // ("https://bank.example&commat;evil.example/" goes to evil.example)
2359
- ["Tab", " "],
2360
- ["NewLine", "\n"],
2361
- ["excl", "!"],
2362
- ["num", "#"],
2363
- ["dollar", "$"],
2364
- ["percnt", "%"],
2365
- ["lpar", "("],
2366
- ["rpar", ")"],
2367
- ["ast", "*"],
2368
- ["midast", "*"],
2369
- ["plus", "+"],
2370
- ["comma", ","],
2371
- ["period", "."],
2372
- ["sol", "/"],
2373
- ["colon", ":"],
2374
- ["semi", ";"],
2375
- ["equals", "="],
2376
- ["quest", "?"],
2377
- ["commat", "@"],
2378
- ["lsqb", "["],
2379
- ["lbrack", "["],
2380
- ["bsol", "\\"],
2381
- ["rsqb", "]"],
2382
- ["rbrack", "]"],
2383
- ["Hat", "^"],
2384
- ["lowbar", "_"],
2385
- ["UnderBar", "_"],
2386
- ["grave", "`"],
2387
- ["DiacriticalGrave", "`"],
2388
- ["lcub", "{"],
2389
- ["lbrace", "{"],
2390
- ["verbar", "|"],
2391
- ["vert", "|"],
2392
- ["VerticalLine", "|"],
2393
- ["rcub", "}"],
2394
- ["rbrace", "}"]
2395
- ]);
2396
2585
  LEGACY = /* @__PURE__ */ new Set([...LATIN1, "amp", "lt", "gt", "quot", "AMP", "LT", "GT", "QUOT", "COPY", "REG"]);
2397
2586
  LEGACY_LONGEST = Math.max(...[...LEGACY].map((name) => name.length));
2398
- LONGER_NAMES = new Set("centerdot copysr divideontimes gtcc gtcir gtdot gtlPar gtquest gtrapprox gtrarr gtrdot gtreqless gtreqqless gtrless gtrsim ltcc ltcir ltdot lthree ltimes ltlarr ltquest ltrPar ltri ltrie ltrif notin notinE notindot notinva notinvb notinvc notni notniva notnivb notnivc parallel timesb timesbar timesd".split(" "));
2399
2587
  WINDOWS_1252 = [8364, 129, 8218, 402, 8222, 8230, 8224, 8225, 710, 8240, 352, 8249, 338, 141, 381, 143, 144, 8216, 8217, 8220, 8221, 8226, 8211, 8212, 732, 8482, 353, 8250, 339, 157, 382, 376];
2400
2588
  REFERENCE = /&(?:#([xX])([\da-fA-F]+)|#(\d+)|([a-zA-Z][a-zA-Z\d]{0,31}))(;?)/g;
2401
2589
  UNSHOWN = /* @__PURE__ */ new Set(["script", "style", "title", "noembed", "noframes", "iframe"]);
@@ -2790,7 +2978,7 @@ function endsInsideTag(html2, end, link) {
2790
2978
  const joined = trimEndOf(link.replace(/^https?:\/\//i, "") + after, ".-");
2791
2979
  return joined !== host && (!isHost(host) || isHost(joined) && registrableDomain(joined) !== registrableDomain(host));
2792
2980
  }
2793
- function extractLinks(text, html2, { maxLength = 5e5, bareHosts = false } = {}) {
2981
+ function extractLinks(text, html2, { maxLength = 5e5, bareHosts: bareHosts2 = false } = {}) {
2794
2982
  text = typeof text === "string" ? foldToAscii(text) : text;
2795
2983
  html2 = typeof html2 === "string" ? foldToAscii(html2) : html2;
2796
2984
  const links = [];
@@ -2857,7 +3045,7 @@ ${shown || ""}`;
2857
3045
  }
2858
3046
  add(link);
2859
3047
  }
2860
- if (bareHosts && index < 2) {
3048
+ if (bareHosts2 && index < 2) {
2861
3049
  bareLinkHosts(read, (host) => {
2862
3050
  bareFound.push(host);
2863
3051
  });
@@ -3797,7 +3985,16 @@ function shorten(name, max = 100) {
3797
3985
  return characters.length <= max ? name : `${characters.slice(0, max - 41).join("")}\u2026${characters.slice(-40).join("")}`;
3798
3986
  }
3799
3987
  function extensionOf(name) {
3800
- const base = trimEndOf(String(name).toLowerCase().split(/[/\\]/).pop(), ". ");
3988
+ const base = trimEndOf(String(name).toLowerCase().replace(ALL_BIDI_CONTROLS, "").split(/[/\\]/).pop(), ". ");
3989
+ const whole = lastExtension(base);
3990
+ const file = base.replace(/^[a-z]:/, "");
3991
+ const colon = file.indexOf(":");
3992
+ if (colon !== -1 && /^(?::?\$data)?$/.test(file.slice(colon + 1))) {
3993
+ return lastExtension(trimEndOf(file.slice(0, colon), ". "));
3994
+ }
3995
+ return whole;
3996
+ }
3997
+ function lastExtension(base) {
3801
3998
  const dot = base.lastIndexOf(".");
3802
3999
  return dot === -1 ? "" : base.slice(dot + 1).trim();
3803
4000
  }
@@ -3882,7 +4079,7 @@ function inspectAttachments(attachments = []) {
3882
4079
  }
3883
4080
  return findings;
3884
4081
  }
3885
- var import_node_buffer, EXECUTABLE_EXTENSIONS, RISKY_EXTENSIONS, SCRIPT_EXTENSIONS, MACRO_EXTENSIONS, DOCUMENT_EXTENSIONS, TEMPORARY_EXTENSIONS, BIDI_CONTROLS, ARCHIVE_TYPES, ZIP_FAMILY, OFFICE_TYPES, OFFICE_EMBEDDED, ENTRIES, MAX_NAME_LENGTH, MAX_NAME_BYTES, DIRECTORY, isDirectory, VBA_NAMES, PDF_ACTIVE, escaped, WORD_ESCAPE, PDF_ACTIVE_ESCAPED, pdfActive;
4082
+ var import_node_buffer, EXECUTABLE_EXTENSIONS, RISKY_EXTENSIONS, SCRIPT_EXTENSIONS, MACRO_EXTENSIONS, DOCUMENT_EXTENSIONS, TEMPORARY_EXTENSIONS, BIDI_CONTROLS, ALL_BIDI_CONTROLS, ARCHIVE_TYPES, ZIP_FAMILY, OFFICE_TYPES, OFFICE_EMBEDDED, ENTRIES, MAX_NAME_LENGTH, MAX_NAME_BYTES, DIRECTORY, isDirectory, VBA_NAMES, PDF_ACTIVE, escaped, WORD_ESCAPE, PDF_ACTIVE_ESCAPED, pdfActive;
3886
4083
  var init_attachments = __esm({
3887
4084
  "src/attachments.js"() {
3888
4085
  import_node_buffer = require("node:buffer");
@@ -4033,6 +4230,7 @@ var init_attachments = __esm({
4033
4230
  DOCUMENT_EXTENSIONS = /* @__PURE__ */ new Set(["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "rtf", "jpg", "jpeg", "png", "gif", "zip", "csv", "odt", "ods", "html", "htm", "mp3", "mp4", "mov", "wav", "eml", "msg", "xml", "json"]);
4034
4231
  TEMPORARY_EXTENSIONS = /* @__PURE__ */ new Set(["tmp"]);
4035
4232
  BIDI_CONTROLS = characterClass([[8234, 8238], [8294, 8297]], "u");
4233
+ ALL_BIDI_CONTROLS = characterClass([[8234, 8238], [8294, 8297]], "gu");
4036
4234
  ARCHIVE_TYPES = /* @__PURE__ */ new Set(["zip", "rar", "7z", "gz", "bz2", "xz", "cab", "iso", "tar", "zst", "lzh", "ace", "arj"]);
4037
4235
  ZIP_FAMILY = /* @__PURE__ */ new Set(["zip", "docx", "xlsx", "pptx"]);
4038
4236
  OFFICE_TYPES = /* @__PURE__ */ new Set(["docx", "xlsx", "pptx"]);
@@ -4413,7 +4611,8 @@ async function parseWithin(raw, parse = parseMessage, deadline = Date.now() + PA
4413
4611
  }
4414
4612
  }
4415
4613
  }
4416
- async function expandAttachments(attachments = [], errors = [], parse = parseMessage, unopened = []) {
4614
+ async function expandAttachments(attachments = [], errors = [], parse = parseMessage, gets = {}) {
4615
+ const { unopened = [], mails = [] } = Array.isArray(gets) ? { unopened: gets } : gets;
4417
4616
  const all = [];
4418
4617
  const deadline = Date.now() + PARSE_TIMEOUT;
4419
4618
  let budget = MAX_NESTED_BYTES;
@@ -4462,6 +4661,7 @@ async function expandAttachments(attachments = [], errors = [], parse = parseMes
4462
4661
  if (inner.error) {
4463
4662
  errors.push(inner.error);
4464
4663
  }
4664
+ mails.push(inner.mail);
4465
4665
  await visit(inner.mail.attachments, prefix ? `${prefix}/${name}` : name || "attached message", depth + 1);
4466
4666
  }
4467
4667
  }
@@ -6005,6 +6205,924 @@ var init_classifier = __esm({
6005
6205
  }
6006
6206
  });
6007
6207
 
6208
+ // src/links.js
6209
+ function isHostCode2(code) {
6210
+ return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 48 && code <= 57 || code === 45 || code === 46;
6211
+ }
6212
+ function isSpace(code) {
6213
+ return code === 32 || code >= 9 && code <= 13;
6214
+ }
6215
+ function urlOf(value) {
6216
+ let href = value.replaceAll(/[\t\n\r]/g, "");
6217
+ let start = 0;
6218
+ let end = href.length;
6219
+ while (start < end && href.codePointAt(start) <= 32) {
6220
+ start++;
6221
+ }
6222
+ while (end > start && href.codePointAt(end - 1) <= 32) {
6223
+ end--;
6224
+ }
6225
+ while (end > start && TRAILING.has(href[end - 1])) {
6226
+ end--;
6227
+ }
6228
+ href = href.slice(start, end);
6229
+ if (/^[\\/]{2}/.test(href)) {
6230
+ href = `https://${href.slice(2)}`;
6231
+ } else if (/^www\./i.test(href)) {
6232
+ href = `http://${href}`;
6233
+ } else if (!/^https?:/i.test(href)) {
6234
+ return null;
6235
+ }
6236
+ try {
6237
+ return new URL(href);
6238
+ } catch {
6239
+ return null;
6240
+ }
6241
+ }
6242
+ function hostOfUrl(url) {
6243
+ let host = url.hostname.toLowerCase();
6244
+ let dots = host.length;
6245
+ while (dots > 0 && host[dots - 1] === ".") {
6246
+ dots--;
6247
+ }
6248
+ host = host.slice(0, dots);
6249
+ if (host.startsWith("[") && host.endsWith("]")) {
6250
+ host = host.slice(1, -1);
6251
+ }
6252
+ if (!host || NAMESPACES.has(host)) {
6253
+ return null;
6254
+ }
6255
+ return (0, import_node_net4.isIP)(host) ? host : lookupName(host);
6256
+ }
6257
+ function hostsOf(value) {
6258
+ const url = urlOf(value);
6259
+ if (!url) {
6260
+ return [];
6261
+ }
6262
+ const host = hostOfUrl(url);
6263
+ const hosts = host ? [host] : [];
6264
+ const target = unwrapLink(url.href);
6265
+ if (target && target.href !== url.href) {
6266
+ const targetHost = hostOfUrl(target);
6267
+ if (targetHost && targetHost !== host) {
6268
+ hosts.push(targetHost);
6269
+ }
6270
+ const further = unwrapLink(target.href);
6271
+ if (further && further.href !== target.href) {
6272
+ hosts.unresolved = true;
6273
+ }
6274
+ }
6275
+ return hosts;
6276
+ }
6277
+ function* attributesOf(html2) {
6278
+ TAG_START.lastIndex = 0;
6279
+ let match;
6280
+ while ((match = TAG_START.exec(html2)) !== null) {
6281
+ let i = match.index + match[0].length;
6282
+ while (i < html2.length && html2[i] !== ">") {
6283
+ if (isSpace(html2.codePointAt(i)) || html2[i] === "/") {
6284
+ i++;
6285
+ continue;
6286
+ }
6287
+ let j = i;
6288
+ while (j < html2.length && html2[j] !== "=" && html2[j] !== ">" && html2[j] !== "/" && !isSpace(html2.codePointAt(j))) {
6289
+ j++;
6290
+ }
6291
+ const name = html2.slice(i, j).toLowerCase();
6292
+ if (j === i) {
6293
+ j++;
6294
+ }
6295
+ while (j < html2.length && isSpace(html2.codePointAt(j))) {
6296
+ j++;
6297
+ }
6298
+ if (html2[j] !== "=") {
6299
+ i = j;
6300
+ continue;
6301
+ }
6302
+ j++;
6303
+ while (j < html2.length && isSpace(html2.codePointAt(j))) {
6304
+ j++;
6305
+ }
6306
+ let value;
6307
+ if (html2[j] === '"' || html2[j] === "'") {
6308
+ const close = html2.indexOf(html2[j], j + 1);
6309
+ const stop = close === -1 ? html2.length : close;
6310
+ value = html2.slice(j + 1, stop);
6311
+ j = stop + 1;
6312
+ } else {
6313
+ const start = j;
6314
+ while (j < html2.length && html2[j] !== ">" && !isSpace(html2.codePointAt(j))) {
6315
+ j++;
6316
+ }
6317
+ value = html2.slice(start, j);
6318
+ }
6319
+ if (name) {
6320
+ yield [name, value];
6321
+ }
6322
+ i = j;
6323
+ }
6324
+ TAG_START.lastIndex = Math.max(i, match.index + 1);
6325
+ }
6326
+ }
6327
+ function linksOf(name, value, add, embed) {
6328
+ const decoded = decodeEntities(value, { attribute: true });
6329
+ switch (name) {
6330
+ case "srcdoc": {
6331
+ embed(decoded);
6332
+ break;
6333
+ }
6334
+ case "style": {
6335
+ for (const [, link] of decoded.matchAll(CSS_URL)) {
6336
+ add(link);
6337
+ }
6338
+ break;
6339
+ }
6340
+ case "srcset": {
6341
+ for (const candidate of decoded.split(",")) {
6342
+ add(candidate.trim().split(/\s/, 1)[0]);
6343
+ }
6344
+ break;
6345
+ }
6346
+ // (several, separated by spaces)
6347
+ case "ping": {
6348
+ for (const link of decoded.split(/\s+/)) {
6349
+ add(link);
6350
+ }
6351
+ break;
6352
+ }
6353
+ // (only the address of a refresh)
6354
+ case "content": {
6355
+ const match = /(?:^|[\s;,])url\s*=\s*["']?([^\s"';]+)/i.exec(decoded.slice(0, 4096));
6356
+ if (match) {
6357
+ add(match[1]);
6358
+ }
6359
+ break;
6360
+ }
6361
+ default: {
6362
+ add(decoded);
6363
+ }
6364
+ }
6365
+ }
6366
+ function lenientLinks(html2, add, done, embed) {
6367
+ LENIENT.lastIndex = 0;
6368
+ let match;
6369
+ while (!done() && (match = LENIENT.exec(html2)) !== null) {
6370
+ const name = match[1].toLowerCase();
6371
+ let i = LENIENT.lastIndex;
6372
+ let end = i;
6373
+ if (html2[i] === '"' || html2[i] === "'") {
6374
+ const quote = html2[i];
6375
+ i++;
6376
+ end = i;
6377
+ while (end < html2.length && html2[end] !== quote && html2[end] !== "<" && html2[end] !== ">") {
6378
+ end++;
6379
+ }
6380
+ if (end < html2.length && html2[end] !== quote) {
6381
+ const close = html2.indexOf(quote, end);
6382
+ if (close !== -1 && close - i <= MAX_LENIENT_VALUE) {
6383
+ linksOf(name, html2.slice(i, close), add, embed);
6384
+ }
6385
+ }
6386
+ } else {
6387
+ while (end < html2.length && !isSpace(html2.codePointAt(end)) && !UNQUOTED_END.has(html2[end])) {
6388
+ end++;
6389
+ }
6390
+ }
6391
+ linksOf(name, html2.slice(i, end), add, embed);
6392
+ }
6393
+ }
6394
+ function endsLink2(text, i) {
6395
+ const code = text.codePointAt(i);
6396
+ if (code < 128) {
6397
+ return isSpace(code) || code === 34 || code === 39 || code === 60 || code === 62 || code === 96;
6398
+ }
6399
+ return /\s/u.test(text[i]);
6400
+ }
6401
+ function linkReader(text) {
6402
+ let read = 0;
6403
+ let space = -1;
6404
+ let scheme = -1;
6405
+ return (start) => {
6406
+ for (; read < start; read++) {
6407
+ if (endsLink2(text, read)) {
6408
+ space = read;
6409
+ } else if (text[read] === "/" && text[read - 1] === "/" && text[read - 2] === ":") {
6410
+ scheme = read;
6411
+ }
6412
+ }
6413
+ return scheme > space;
6414
+ };
6415
+ }
6416
+ function isSchemeless(text, start) {
6417
+ if (start < 2 || text[start - 2] !== "/") {
6418
+ return false;
6419
+ }
6420
+ if (start === 2) {
6421
+ return true;
6422
+ }
6423
+ const before = text[start - 3];
6424
+ return !(before === ":" || before === "/" || isHostCode2(text.codePointAt(start - 3)));
6425
+ }
6426
+ function bareName(name) {
6427
+ const labels = name.split(".");
6428
+ const tld = labels.pop();
6429
+ if (!/^(?:[a-z]{2,24}|xn--[a-z\d-]{1,59})$/i.test(tld)) {
6430
+ return null;
6431
+ }
6432
+ const names = [];
6433
+ while (labels.length > 0 && names.length < 11) {
6434
+ const label = labels.pop();
6435
+ if (!/^[a-z\d-]{1,63}$/i.test(label)) {
6436
+ break;
6437
+ }
6438
+ names.unshift(label);
6439
+ }
6440
+ if (names.length === 0) {
6441
+ return null;
6442
+ }
6443
+ names[0] = names[0].replace(/^-+/, "");
6444
+ if (!names[0]) {
6445
+ return null;
6446
+ }
6447
+ return `${names.join(".")}.${tld}`.toLowerCase();
6448
+ }
6449
+ function isRealName(host) {
6450
+ const parsed = (0, import_tldts4.parse)(host);
6451
+ return Boolean(parsed.isIcann && parsed.domain);
6452
+ }
6453
+ function bareHosts(text, add, { done, seen, from = 0, cutEnd = false }) {
6454
+ let previous = -1;
6455
+ const inLink = linkReader(text);
6456
+ for (let slash = text.indexOf("/"); slash !== -1; slash = text.indexOf("/", slash + 1)) {
6457
+ if (done()) {
6458
+ return;
6459
+ }
6460
+ const floor = Math.max(previous + 1, slash - MAX_HOST);
6461
+ previous = slash;
6462
+ let end = slash;
6463
+ while (end > floor && text.codePointAt(end - 1) >= 48 && text.codePointAt(end - 1) <= 57) {
6464
+ end--;
6465
+ }
6466
+ end = end > floor && text[end - 1] === ":" ? end - 1 : slash;
6467
+ let start = end;
6468
+ while (start > floor && isHostCode2(text.codePointAt(start - 1))) {
6469
+ start--;
6470
+ }
6471
+ if (start === end || start < from || cutEnd && slash === text.length - 1) {
6472
+ continue;
6473
+ }
6474
+ if (start > 0 && (IN_WORD2.test(text[start - 1]) || text[start - 1] === "/" && !isSchemeless(text, start)) || inLink(start)) {
6475
+ continue;
6476
+ }
6477
+ while (end > start && text[end - 1] === ".") {
6478
+ end--;
6479
+ }
6480
+ const host = bareName(text.slice(start, end));
6481
+ if (!host || seen.has(host)) {
6482
+ continue;
6483
+ }
6484
+ if (seen.size < MAX_SEEN) {
6485
+ seen.add(host);
6486
+ }
6487
+ if (isRealName(host)) {
6488
+ add(`http://${host}/`);
6489
+ }
6490
+ }
6491
+ }
6492
+ function looseHosts(text, add, { from = 0, cutEnd = false, seen, done }) {
6493
+ const inLink = linkReader(text);
6494
+ const { length } = text;
6495
+ let i = 0;
6496
+ while (i < length) {
6497
+ if (!isHostCode2(text.codePointAt(i))) {
6498
+ i++;
6499
+ continue;
6500
+ }
6501
+ const start = i;
6502
+ while (i < length && isHostCode2(text.codePointAt(i))) {
6503
+ i++;
6504
+ }
6505
+ let end = i;
6506
+ if (end - start > MAX_HOST || start < from || cutEnd && end === length) {
6507
+ continue;
6508
+ }
6509
+ while (end > start && text[end - 1] === ".") {
6510
+ end--;
6511
+ }
6512
+ const before = start > 0 ? text[start - 1] : "";
6513
+ const after = end < length ? text[end] : "";
6514
+ if (after === "/" || after === "@" || before === "@") {
6515
+ continue;
6516
+ }
6517
+ if (before && (IN_WORD2.test(before) || before === "/" || before === "\\" || before === "&" || before === "#")) {
6518
+ continue;
6519
+ }
6520
+ if (after && after !== "." && IN_WORD2.test(after)) {
6521
+ continue;
6522
+ }
6523
+ const name = text.slice(start, end);
6524
+ if (!name.includes(".") || inLink(start)) {
6525
+ continue;
6526
+ }
6527
+ const lower = name.toLowerCase();
6528
+ if (seen.has(lower)) {
6529
+ continue;
6530
+ }
6531
+ if (seen.size < MAX_SEEN) {
6532
+ seen.add(lower);
6533
+ }
6534
+ if (done()) {
6535
+ return;
6536
+ }
6537
+ const host = bareName(name);
6538
+ if (host && isRealName(host)) {
6539
+ add(host);
6540
+ }
6541
+ }
6542
+ }
6543
+ function* chunksOf(html2) {
6544
+ let start = 0;
6545
+ let cutStart = false;
6546
+ while (start < html2.length) {
6547
+ const end = Math.min(html2.length, start + DECODE_CHUNK);
6548
+ if (end < html2.length) {
6549
+ let cut = end;
6550
+ while (cut > end - 65536 && cut > start) {
6551
+ if (html2[cut] === "<" || isSpace(html2.codePointAt(cut))) {
6552
+ break;
6553
+ }
6554
+ cut--;
6555
+ }
6556
+ if (cut > start && cut > end - 65536) {
6557
+ yield { text: html2.slice(start, cut), cutStart, cutEnd: false };
6558
+ start = cut;
6559
+ cutStart = false;
6560
+ continue;
6561
+ }
6562
+ yield { text: html2.slice(start, end), cutStart, cutEnd: true };
6563
+ start = end - CHUNK_OVERLAP;
6564
+ cutStart = true;
6565
+ continue;
6566
+ }
6567
+ yield { text: html2.slice(start, end), cutStart, cutEnd: false };
6568
+ start = end;
6569
+ }
6570
+ }
6571
+ function withoutNul(text) {
6572
+ return text.includes("\0") ? `${text}
6573
+ ${text.replaceAll("\0", "")}` : text;
6574
+ }
6575
+ function hexValue(code) {
6576
+ if (code >= 48 && code <= 57) {
6577
+ return code - 48;
6578
+ }
6579
+ if (code >= 65 && code <= 70) {
6580
+ return code - 55;
6581
+ }
6582
+ if (code >= 97 && code <= 102) {
6583
+ return code - 87;
6584
+ }
6585
+ return -1;
6586
+ }
6587
+ function percentDecoded(text) {
6588
+ const input = import_node_buffer7.Buffer.from(text);
6589
+ const output = import_node_buffer7.Buffer.allocUnsafe(input.length);
6590
+ let length = 0;
6591
+ for (let i = 0; i < input.length; i++) {
6592
+ const high = input[i] === 37 ? hexValue(input[i + 1]) : -1;
6593
+ const low = high === -1 ? -1 : hexValue(input[i + 2]);
6594
+ if (low === -1) {
6595
+ output[length++] = input[i];
6596
+ continue;
6597
+ }
6598
+ output[length++] = high * 16 + low;
6599
+ i += 2;
6600
+ }
6601
+ return output.subarray(0, length);
6602
+ }
6603
+ function swapped(bytes) {
6604
+ return import_node_buffer7.Buffer.from(bytes.subarray(0, bytes.length - bytes.length % 2)).swap16().toString("utf16le");
6605
+ }
6606
+ function decodeText(content, charset = "") {
6607
+ if (content[0] === 255 && content[1] === 254) {
6608
+ return content.subarray(2).toString("utf16le");
6609
+ }
6610
+ if (content[0] === 254 && content[1] === 255) {
6611
+ return swapped(content.subarray(2));
6612
+ }
6613
+ if (UTF16LE.has(charset)) {
6614
+ return content.toString("utf16le");
6615
+ }
6616
+ return UTF16BE.has(charset) ? swapped(content) : content.toString("utf8");
6617
+ }
6618
+ function dataDocument(value) {
6619
+ const match = DATA_DOCUMENT.exec(value.slice(0, 1024));
6620
+ if (!match) {
6621
+ return null;
6622
+ }
6623
+ const bytes = percentDecoded(value.slice(match[0].length));
6624
+ const content = /;\s*base64\s*$/i.test(match[1]) ? import_node_buffer7.Buffer.from(bytes.toString("latin1"), "base64") : bytes;
6625
+ const charset = /;\s*charset\s*=\s*"?([^;"\s]+)/i.exec(match[1]);
6626
+ return decodeText(content, charset ? charset[1].toLowerCase() : "");
6627
+ }
6628
+ function readEscapes(text, lenient = false) {
6629
+ let index = text.indexOf("\\");
6630
+ if (index === -1) {
6631
+ return text;
6632
+ }
6633
+ let out = "";
6634
+ let parts = [];
6635
+ let start = 0;
6636
+ while (index !== -1 && index + 1 < text.length) {
6637
+ const next = text[index + 1];
6638
+ if (lenient || "nN,;\\".includes(next)) {
6639
+ parts.push(text.slice(start, index), next === "n" || next === "N" ? "\n" : next);
6640
+ start = index + 2;
6641
+ index = text.indexOf("\\", start);
6642
+ if (parts.length >= 65536) {
6643
+ out += parts.join("");
6644
+ parts = [];
6645
+ }
6646
+ } else {
6647
+ index = text.indexOf("\\", index + 1);
6648
+ }
6649
+ }
6650
+ parts.push(text.slice(start));
6651
+ return out + parts.join("");
6652
+ }
6653
+ function valueColon(line) {
6654
+ let colon = line.indexOf(":");
6655
+ let from = 0;
6656
+ for (; ; ) {
6657
+ const quote = line.indexOf('"', from);
6658
+ if (quote === -1 || colon === -1 || colon < quote) {
6659
+ return colon;
6660
+ }
6661
+ const end = line.indexOf('"', quote + 1);
6662
+ if (end === -1) {
6663
+ return -1;
6664
+ }
6665
+ from = end + 1;
6666
+ if (colon < from) {
6667
+ colon = line.indexOf(":", from);
6668
+ }
6669
+ }
6670
+ }
6671
+ function trimSpaceEnd(text) {
6672
+ let end = text.length;
6673
+ while (end > 0 && (text[end - 1] === " " || text[end - 1] === " ")) {
6674
+ end--;
6675
+ }
6676
+ return end === text.length ? text : text.slice(0, end);
6677
+ }
6678
+ function decodeQuotedPrintable(value, charset) {
6679
+ let decoder;
6680
+ try {
6681
+ decoder = new TextDecoder(charset || "utf8");
6682
+ } catch {
6683
+ decoder = new TextDecoder("utf8");
6684
+ }
6685
+ if (!/[\u0080-\u{10FFFF}]/u.test(value)) {
6686
+ const bytes = import_node_buffer7.Buffer.from(value, "latin1");
6687
+ let length = 0;
6688
+ for (let index = 0; index < bytes.length; index++) {
6689
+ const hex = bytes[index] === 61 ? value.slice(index + 1, index + 3) : "";
6690
+ if (/^[\da-f]{2}$/i.test(hex)) {
6691
+ bytes[length++] = Number.parseInt(hex, 16);
6692
+ index += 2;
6693
+ } else {
6694
+ bytes[length++] = bytes[index];
6695
+ }
6696
+ }
6697
+ return decoder.decode(bytes.subarray(0, length));
6698
+ }
6699
+ return value.replaceAll(/(?:=[\da-f]{2})+/gi, (run) => decoder.decode(import_node_buffer7.Buffer.from(run.replaceAll("=", ""), "hex")));
6700
+ }
6701
+ function quotedPrintableValues(text) {
6702
+ if (!/quoted-printable/i.test(text)) {
6703
+ return text;
6704
+ }
6705
+ const lines2 = text.split(LINE_BREAK);
6706
+ const out = [];
6707
+ for (let i = 0; i < lines2.length; i++) {
6708
+ const line = lines2[i];
6709
+ const colon = valueColon(line);
6710
+ const parameters = colon === -1 ? "" : line.slice(0, colon);
6711
+ if (colon === -1 || !QUOTED_PRINTABLE.test(parameters)) {
6712
+ out.push(line);
6713
+ continue;
6714
+ }
6715
+ const charset = /;\s*charset\s*=\s*"?([\w.:-]+)/i.exec(parameters)?.[1];
6716
+ const parts = [trimSpaceEnd(line.slice(colon + 1))];
6717
+ while (parts.at(-1).endsWith("=") && i + 1 < lines2.length) {
6718
+ parts[parts.length - 1] = parts.at(-1).slice(0, -1);
6719
+ parts.push(trimSpaceEnd(lines2[++i]));
6720
+ }
6721
+ out.push(line.slice(0, colon + 1) + decodeQuotedPrintable(parts.join(""), charset));
6722
+ }
6723
+ return out.join("\n");
6724
+ }
6725
+ function hasQuotedPrintable(text) {
6726
+ const unfolded = text.replaceAll(FOLD, "");
6727
+ if (!/quoted-printable/i.test(unfolded)) {
6728
+ return false;
6729
+ }
6730
+ return unfolded.split(LINE_BREAK).some((line) => {
6731
+ const colon = valueColon(line);
6732
+ return colon !== -1 && QUOTED_PRINTABLE.test(line.slice(0, colon));
6733
+ });
6734
+ }
6735
+ function shownText(text, full = true) {
6736
+ const unfolded = text.replaceAll(FOLD, "");
6737
+ const shown = /* @__PURE__ */ new Set([text, readEscapes(unfolded)]);
6738
+ let decoded = unfolded;
6739
+ if (full) {
6740
+ decoded = quotedPrintableValues(unfolded);
6741
+ if (decoded !== unfolded) {
6742
+ shown.add(readEscapes(decoded));
6743
+ if (unfolded !== text) {
6744
+ shown.add(quotedPrintableValues(text));
6745
+ }
6746
+ }
6747
+ }
6748
+ if (/\\[^nN,;\\]/.test(decoded)) {
6749
+ shown.add(readEscapes(decoded, true));
6750
+ }
6751
+ return [...shown].reverse().join("\n");
6752
+ }
6753
+ function htmlDescriptions(text) {
6754
+ if (!/[<&]|altrep/i.test(text)) {
6755
+ return "";
6756
+ }
6757
+ const html2 = [];
6758
+ for (const line of text.replaceAll(FOLD, "").split(LINE_BREAK)) {
6759
+ const colon = valueColon(line);
6760
+ if (colon === -1) {
6761
+ continue;
6762
+ }
6763
+ const altrep = /;\s*altrep\s*=\s*"([^"]*)"/i.exec(line.slice(0, colon))?.[1];
6764
+ if (altrep) {
6765
+ html2.push(`<iframe src="${altrep.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;")}"></iframe>`);
6766
+ }
6767
+ if (!HTML_PROPERTIES.test(line)) {
6768
+ continue;
6769
+ }
6770
+ const value = readEscapes(line.slice(colon + 1));
6771
+ if (/[<&]/.test(value)) {
6772
+ html2.push(value);
6773
+ }
6774
+ }
6775
+ return html2.join("\n");
6776
+ }
6777
+ function withoutBinaryValues(text) {
6778
+ if (!/base64|binary|encoding\s*=\s*"?b|;\s*b\s*[;:]/i.test(text)) {
6779
+ return text;
6780
+ }
6781
+ const lines2 = text.split(LINE_BREAK);
6782
+ const out = [];
6783
+ for (let i = 0; i < lines2.length; i++) {
6784
+ const line = lines2[i];
6785
+ const colon = valueColon(line);
6786
+ if (colon === -1 || !BINARY.test(line.slice(0, colon))) {
6787
+ out.push(line);
6788
+ continue;
6789
+ }
6790
+ const value = [line.slice(colon + 1)];
6791
+ let next = i + 1;
6792
+ while (next < lines2.length && (lines2[next].startsWith(" ") || lines2[next].startsWith(" "))) {
6793
+ value.push(lines2[next++]);
6794
+ }
6795
+ if (!value.every((part) => /^[\w+/=\s]*$/.test(part))) {
6796
+ for (let index = i; index < next; index++) {
6797
+ out.push(lines2[index]);
6798
+ }
6799
+ i = next - 1;
6800
+ continue;
6801
+ }
6802
+ while (next < lines2.length && lines2[next] !== "" && /^[\w+/=]+$/.test(lines2[next])) {
6803
+ value.push(lines2[next++]);
6804
+ }
6805
+ if (next < lines2.length && lines2[next] === "") {
6806
+ next++;
6807
+ }
6808
+ i = next - 1;
6809
+ const name = line.slice(0, colon).split(";")[0].split(".").pop().trim().toLowerCase();
6810
+ out.push(MEDIA_PROPERTIES.has(name) ? line.slice(0, colon + 1) : line.slice(0, colon + 1) + import_node_buffer7.Buffer.from(value.join("").replaceAll(/\s/g, ""), "base64").toString("utf8"));
6811
+ }
6812
+ return out.join("\n");
6813
+ }
6814
+ function extensionOf2(filename) {
6815
+ let end = filename.length;
6816
+ while (end > 0 && (filename[end - 1] === "." || filename[end - 1] === " ")) {
6817
+ end--;
6818
+ }
6819
+ const name = filename.slice(0, end).trim().toLowerCase();
6820
+ const index = name.lastIndexOf(".");
6821
+ return index !== -1 && index < name.length - 1 ? name.slice(index + 1) : null;
6822
+ }
6823
+ function extensionsOf(attachment) {
6824
+ const names = [];
6825
+ if (typeof attachment.filename === "string") {
6826
+ names.push(attachment.filename);
6827
+ }
6828
+ const { headers } = attachment;
6829
+ if (headers && typeof headers.get === "function") {
6830
+ for (const [field, parameter] of [["content-type", "name"], ["content-disposition", "filename"]]) {
6831
+ const value = headers.get(field)?.params?.[parameter];
6832
+ if (typeof value === "string" && value !== "") {
6833
+ names.push(value);
6834
+ }
6835
+ }
6836
+ }
6837
+ return new Set(names.flatMap((name) => [extensionOf2(name), extensionOf(name)]).filter(Boolean));
6838
+ }
6839
+ function charsetOf(attachment) {
6840
+ const { headers } = attachment;
6841
+ const charset = headers && typeof headers.get === "function" ? headers.get("content-type")?.params?.charset : null;
6842
+ return typeof charset === "string" ? charset.toLowerCase() : "";
6843
+ }
6844
+ function documentsOf(attachments, until) {
6845
+ const documents = [];
6846
+ let bytes = 0;
6847
+ let opened = 0;
6848
+ for (const attachment of attachments) {
6849
+ const { content } = attachment ?? {};
6850
+ if (!import_node_buffer7.Buffer.isBuffer(content) || content.length === 0) {
6851
+ continue;
6852
+ }
6853
+ const type = typeof attachment.contentType === "string" ? attachment.contentType.toLowerCase() : "";
6854
+ const extensions = extensionsOf(attachment);
6855
+ const has = (set) => [...extensions].some((name) => set.has(name));
6856
+ if (MESSAGE_TYPES.has(type) || extensions.has("eml") || extensions.has("u8msg")) {
6857
+ continue;
6858
+ }
6859
+ const isHtml = HTML_TYPES.has(type) || has(HTML_EXTENSIONS);
6860
+ const isCard = !isHtml && (CARD_TYPES.has(type) || has(CARD_EXTENSIONS));
6861
+ const isText = isCard || !isHtml && type === "text/plain";
6862
+ if (!isHtml && !isText) {
6863
+ continue;
6864
+ }
6865
+ if (!isText && ++opened > MAX_ATTACHED || bytes + content.length > MAX_ATTACHED_BYTES) {
6866
+ documents.tooComplex = true;
6867
+ return documents;
6868
+ }
6869
+ if (Date.now() > until) {
6870
+ documents.incomplete = true;
6871
+ return documents;
6872
+ }
6873
+ bytes += content.length;
6874
+ const text = decodeText(content, charsetOf(attachment));
6875
+ if (isHtml) {
6876
+ documents.push({ html: text });
6877
+ continue;
6878
+ }
6879
+ if (!isCard) {
6880
+ documents.push({ text });
6881
+ continue;
6882
+ }
6883
+ const readable = withoutBinaryValues(text);
6884
+ const full = readable.length <= MAX_SHOWN_BYTES;
6885
+ if (!full && hasQuotedPrintable(readable)) {
6886
+ documents.tooComplex = true;
6887
+ continue;
6888
+ }
6889
+ documents.push({ text: shownText(readable, full) });
6890
+ const html2 = htmlDescriptions(readable);
6891
+ if (html2 !== "") {
6892
+ documents.push({ html: html2 });
6893
+ }
6894
+ }
6895
+ return documents;
6896
+ }
6897
+ function carriedLinkHosts(mail, {
6898
+ mails = [],
6899
+ attachments = [],
6900
+ maxHosts = 250,
6901
+ hostsInText = false
6902
+ } = {}) {
6903
+ const hosts = /* @__PURE__ */ new Set();
6904
+ const loose = /* @__PURE__ */ new Set();
6905
+ const seen = /* @__PURE__ */ new Set();
6906
+ const seenBare = /* @__PURE__ */ new Set();
6907
+ const seenLoose = /* @__PURE__ */ new Set();
6908
+ let more = false;
6909
+ let tooComplex = false;
6910
+ const done = () => more;
6911
+ const looseDone = () => more || loose.size > maxHosts;
6912
+ const addLoose = (host) => {
6913
+ if (!looseDone()) {
6914
+ loose.add(host);
6915
+ }
6916
+ };
6917
+ const until = Date.now() + MAX_READ_TIME;
6918
+ let incomplete = false;
6919
+ const late = () => {
6920
+ if (!incomplete && Date.now() > until) {
6921
+ incomplete = true;
6922
+ }
6923
+ return incomplete;
6924
+ };
6925
+ const carried = documentsOf(attachments, until);
6926
+ tooComplex = Boolean(carried.tooComplex);
6927
+ incomplete = Boolean(carried.incomplete);
6928
+ const queue = [mail, ...mails, ...carried].map((document) => ({ document, depth: 0 }));
6929
+ let depth = 0;
6930
+ let embedded = 0;
6931
+ let embeddedLength = 0;
6932
+ const embed = (html2) => {
6933
+ if (depth >= MAX_EMBED_DEPTH || embedded >= MAX_EMBEDDED || embeddedLength + html2.length > MAX_EMBEDDED_LENGTH) {
6934
+ tooComplex = true;
6935
+ return;
6936
+ }
6937
+ embedded++;
6938
+ embeddedLength += html2.length;
6939
+ queue.push({ document: { html: html2 }, depth: depth + 1 });
6940
+ };
6941
+ const add = (value) => {
6942
+ if (more || typeof value !== "string" || value === "" || seen.has(value)) {
6943
+ return;
6944
+ }
6945
+ if (seen.size < MAX_SEEN) {
6946
+ seen.add(value);
6947
+ }
6948
+ if (/^\s*data:/i.test(value)) {
6949
+ const html2 = dataDocument(value);
6950
+ if (html2 !== null) {
6951
+ embed(html2);
6952
+ }
6953
+ return;
6954
+ }
6955
+ const found = hostsOf(value);
6956
+ if (found.unresolved) {
6957
+ tooComplex = true;
6958
+ }
6959
+ for (const host of found) {
6960
+ if (hosts.has(host)) {
6961
+ continue;
6962
+ }
6963
+ if (hosts.size >= maxHosts) {
6964
+ more = true;
6965
+ return;
6966
+ }
6967
+ hosts.add(host);
6968
+ }
6969
+ };
6970
+ const readText = (source, { cutStart = false, cutEnd = false } = {}) => {
6971
+ for (const match of source.matchAll(URL_START)) {
6972
+ if (more) {
6973
+ break;
6974
+ }
6975
+ if (cutStart && match.index === 0) {
6976
+ continue;
6977
+ }
6978
+ if (cutEnd && match.index + match[0].length === source.length) {
6979
+ const value = match[0];
6980
+ const at = /^www\./i.test(value) ? 0 : value.indexOf("//") + 2;
6981
+ if (/[/?#\\]/.test(value.slice(at))) {
6982
+ add(value);
6983
+ } else if (source.length - match.index > CHUNK_OVERLAP) {
6984
+ tooComplex = true;
6985
+ }
6986
+ continue;
6987
+ }
6988
+ add(match[0]);
6989
+ }
6990
+ const from = cutStart ? 1 : 0;
6991
+ bareHosts(source, add, {
6992
+ done,
6993
+ seen: seenBare,
6994
+ from,
6995
+ cutEnd
6996
+ });
6997
+ if (hostsInText && !looseDone()) {
6998
+ looseHosts(source, addLoose, {
6999
+ from,
7000
+ cutEnd,
7001
+ seen: seenLoose,
7002
+ done: looseDone
7003
+ });
7004
+ }
7005
+ };
7006
+ for (const element of queue) {
7007
+ if (more || late()) {
7008
+ break;
7009
+ }
7010
+ ({ depth } = element);
7011
+ const { document } = element;
7012
+ const html2 = withoutNul(typeof document?.html === "string" ? document.html : "");
7013
+ const text = withoutNul(typeof document?.text === "string" ? document.text : "");
7014
+ for (const [name, value] of attributesOf(html2)) {
7015
+ if (more) {
7016
+ break;
7017
+ }
7018
+ if (LINK_ATTRIBUTES.has(name)) {
7019
+ linksOf(name, value, add, embed);
7020
+ }
7021
+ }
7022
+ lenientLinks(html2, add, done, embed);
7023
+ for (const pattern of [CSS_URL, CSS_IMPORT]) {
7024
+ for (const [, link] of html2.matchAll(pattern)) {
7025
+ if (more) {
7026
+ break;
7027
+ }
7028
+ add(decodeEntities(link, { attribute: true }));
7029
+ }
7030
+ }
7031
+ if (!more) {
7032
+ readText(text);
7033
+ }
7034
+ for (const chunk2 of chunksOf(html2)) {
7035
+ if (more || late()) {
7036
+ break;
7037
+ }
7038
+ readText(decodeEntities(chunk2.text), chunk2);
7039
+ }
7040
+ }
7041
+ if (!more && !incomplete) {
7042
+ for (const name of loose) {
7043
+ if (hosts.size >= maxHosts) {
7044
+ break;
7045
+ }
7046
+ const [host] = hostsOf(`http://${name}/`);
7047
+ if (host) {
7048
+ hosts.add(host);
7049
+ }
7050
+ }
7051
+ }
7052
+ return {
7053
+ hosts: [...hosts],
7054
+ more,
7055
+ tooComplex,
7056
+ incomplete
7057
+ };
7058
+ }
7059
+ var import_node_buffer7, import_node_net4, import_tldts4, LINK_ATTRIBUTES, TAG_START, URL_START, CSS_URL, CSS_IMPORT, LENIENT, IN_WORD2, NAMESPACES, MAX_HOST, MAX_SEEN, TRAILING, DECODE_CHUNK, CHUNK_OVERLAP, MAX_EMBED_DEPTH, MAX_EMBEDDED, MAX_EMBEDDED_LENGTH, MAX_ATTACHED, MAX_ATTACHED_BYTES, MAX_READ_TIME, MAX_SHOWN_BYTES, MAX_LENIENT_VALUE, UNQUOTED_END, UTF16LE, UTF16BE, DATA_DOCUMENT, LINE_BREAK, FOLD, QUOTED_PRINTABLE, MEDIA_PROPERTIES, HTML_PROPERTIES, BINARY, HTML_TYPES, HTML_EXTENSIONS, CARD_TYPES, CARD_EXTENSIONS, MESSAGE_TYPES;
7060
+ var init_links = __esm({
7061
+ "src/links.js"() {
7062
+ import_node_buffer7 = require("node:buffer");
7063
+ import_node_net4 = require("node:net");
7064
+ import_tldts4 = require("tldts");
7065
+ init_attachments();
7066
+ init_dnsbl();
7067
+ init_html();
7068
+ init_tokenizer();
7069
+ LINK_ATTRIBUTES = /* @__PURE__ */ new Set([
7070
+ "href",
7071
+ "src",
7072
+ "srcset",
7073
+ "background",
7074
+ "action",
7075
+ "formaction",
7076
+ "poster",
7077
+ "cite",
7078
+ "longdesc",
7079
+ "xlink:href",
7080
+ "style",
7081
+ "data",
7082
+ "ping",
7083
+ // (of a <meta> refresh: "0;url=https://example.com/")
7084
+ "content",
7085
+ // (a document of its own, see linksOf)
7086
+ "srcdoc"
7087
+ ]);
7088
+ TAG_START = /<[a-z][^\s/>]*/gi;
7089
+ URL_START = /\b(?:https?:\/\/|www\.)[^\s<>"'`]+/gi;
7090
+ CSS_URL = /url\(\s*["']?([^()"']*)/gi;
7091
+ CSS_IMPORT = /@import\s+["']([^"'<>]*)/gi;
7092
+ LENIENT = /[\s"'/<](href|src|srcset|background|action|formaction|poster|cite|longdesc|xlink:href|style|data|ping|content|srcdoc)\s*=\s*/gi;
7093
+ IN_WORD2 = /[\p{L}\p{N}\p{M}_%]/u;
7094
+ NAMESPACES = /* @__PURE__ */ new Set(["www.w3.org", "w3.org"]);
7095
+ MAX_HOST = 760;
7096
+ MAX_SEEN = 1e5;
7097
+ TRAILING = /* @__PURE__ */ new Set([")", ".", ",", ";", ":", "!", "?", "'", '"', "]"]);
7098
+ DECODE_CHUNK = 1024 * 1024;
7099
+ CHUNK_OVERLAP = 4096;
7100
+ MAX_EMBED_DEPTH = 3;
7101
+ MAX_EMBEDDED = 1e3;
7102
+ MAX_EMBEDDED_LENGTH = 10 * 1024 * 1024;
7103
+ MAX_ATTACHED = 100;
7104
+ MAX_ATTACHED_BYTES = 50 * 1024 * 1024;
7105
+ MAX_READ_TIME = 5e3;
7106
+ MAX_SHOWN_BYTES = 4 * 1024 * 1024;
7107
+ MAX_LENIENT_VALUE = 4096;
7108
+ UNQUOTED_END = /* @__PURE__ */ new Set(["<", ">", '"', "'", "`", "="]);
7109
+ UTF16LE = /* @__PURE__ */ new Set(["csunicode", "iso-10646-ucs-2", "ucs-2", "unicode", "unicodefeff", "utf-16", "utf-16le"]);
7110
+ UTF16BE = /* @__PURE__ */ new Set(["unicodefffe", "utf-16be"]);
7111
+ DATA_DOCUMENT = /^\s*data:\s*(?:text\/html|application\/xhtml\+xml|image\/svg\+xml|text\/xml|application\/xml)\b([^,]*),/i;
7112
+ LINE_BREAK = /\r\n?|\n/;
7113
+ FOLD = /(?:\r\n?|\n)[ \t]/g;
7114
+ QUOTED_PRINTABLE = /;\s*(?:encoding\s*=\s*)?"?quoted-printable"?\s*(?:;|$)/i;
7115
+ MEDIA_PROPERTIES = /* @__PURE__ */ new Set(["photo", "logo", "sound", "key", "attach"]);
7116
+ HTML_PROPERTIES = /^(?:x-alt-desc|styled-description|description|comment)[;:]/i;
7117
+ BINARY = /;\s*(?:(?:encoding\s*=\s*)?"?(?:b|base64)"?|value\s*=\s*"?binary"?)\s*(?:;|$)/i;
7118
+ HTML_TYPES = /* @__PURE__ */ new Set(["text/html", "application/xhtml+xml", "image/svg+xml", "text/xml", "application/xml"]);
7119
+ HTML_EXTENSIONS = /* @__PURE__ */ new Set(["html", "htm", "shtml", "xhtml", "xht", "svg", "xml"]);
7120
+ CARD_TYPES = /* @__PURE__ */ new Set(["text/calendar", "text/x-vcalendar", "application/ics", "text/vcard", "text/x-vcard", "text/directory"]);
7121
+ CARD_EXTENSIONS = /* @__PURE__ */ new Set(["ics", "ical", "ifb", "vcs", "vcf", "vcard"]);
7122
+ MESSAGE_TYPES = /* @__PURE__ */ new Set(["message/rfc822", "message/global"]);
7123
+ }
7124
+ });
7125
+
6008
7126
  // src/is-arbitrary.js
6009
7127
  function unquoted(text) {
6010
7128
  let start = 0;
@@ -6069,13 +7187,13 @@ function joinsDisplay(brand, display, name) {
6069
7187
  return false;
6070
7188
  }
6071
7189
  function isOfficial({ brand, official }, domain, display, shared = true) {
6072
- const parsed = (0, import_tldts4.parse)(domain);
7190
+ const parsed = (0, import_tldts5.parse)(domain);
6073
7191
  const name = parsed.domainWithoutSuffix ?? "";
6074
7192
  const compact = brand.replaceAll(" ", "");
6075
7193
  if (parsed.publicSuffix === compact || compact.length >= 5 && joinsDisplay(brand, display, name) && !JOINED_WORDS.some((word) => name.slice(compact.length).includes(word))) {
6076
7194
  return true;
6077
7195
  }
6078
- return official.some((entry) => entry instanceof RegExp ? entry.test(registrableDomain(domain)) : entry.includes(".") ? (shared || (0, import_tldts4.parse)(entry).domain !== null) && (domain === entry || domain.endsWith(`.${entry}`)) : name === entry);
7196
+ return official.some((entry) => entry instanceof RegExp ? entry.test(registrableDomain(domain)) : entry.includes(".") ? (shared || (0, import_tldts5.parse)(entry).domain !== null) && (domain === entry || domain.endsWith(`.${entry}`)) : name === entry);
6079
7197
  }
6080
7198
  function headerString(mail, name) {
6081
7199
  const value = mail.headers?.get?.(name);
@@ -6177,7 +7295,7 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
6177
7295
  }
6178
7296
  } else if (claimed && isWholeName(name, claimed)) {
6179
7297
  const domain = claimed[1];
6180
- const brand = MAILBOXES.has((0, import_tldts4.parse)(domain).domainWithoutSuffix) ? null : DISPLAY_BRANDS.find((entry) => isOfficial(entry, domain, "", false) && !isOfficial(entry, session.originalFromAddressDomain, ""));
7298
+ const brand = MAILBOXES.has((0, import_tldts5.parse)(domain).domainWithoutSuffix) ? null : DISPLAY_BRANDS.find((entry) => isOfficial(entry, domain, "", false) && !isOfficial(entry, session.originalFromAddressDomain, ""));
6181
7299
  if (brand) {
6182
7300
  hit("FROM_NAME_BRAND", 2, `Display name is an address of "${brand.brand}" but the message is from ${fromRoot}`, "PHISHING");
6183
7301
  }
@@ -6210,10 +7328,10 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
6210
7328
  category
6211
7329
  };
6212
7330
  }
6213
- var import_tldts4, GTUBE, BLOCKED_SUBJECT, HACKED_SUBJECT, COIN, CODE, CURRENCY, MONEY, CRYPTOCURRENCY, AMOUNT_DEMAND, AMOUNT_GIVEN, HARM_VERB, HARMED, RECORDING, THREAT, HOURS, COUNT, DEADLINE, isPaymentDemand, BITCOIN_ADDRESS, IGNORE_INSTRUCTIONS, AI_ACTION, AI_OBJECT, AI_ACTION_OBJECT, AI_NEAR, VERDICT, VERDICT_WORD, VERDICT_ORDER, VERDICT_CLAIM, CLASSIFY, SYSTEM_PROMPT, YOU_ARE, QUOTE, CONDITION, DISCUSSED, DISCUSSED_SHOWN, DISCUSSED_NEAR, isDiscussed, isInjection, QUOTE_OR_SPACE, SHOWN_NEAR, isOrder, PAYPAL_DOMAIN, PAYPAL_SPAM_TYPE_IDS, PAYPAL_OWN_REQUEST, PAYPAL_INVOICE_SUBJECT, MS_SPAM_VERDICT, MS_SPAM_CATEGORY, APPLE_NEXT, APPLE_FILLER, APPLE_STRONG, APPLE_BUSINESS, APPLE_ALONE, APPLE_BESIDE, APPLE_PART, NEXT_WORD, MAX_AFTER, APPLE, DISPLAY_BRANDS, ADDRESSES, LIST_HOSTS, VIA_LIST, MAILBOXES, BEFORE_ADDRESS, AFTER_ADDRESS, isWholeName, JOINED_WORDS, MAX_DISPLAY;
7331
+ var import_tldts5, GTUBE, BLOCKED_SUBJECT, HACKED_SUBJECT, COIN, CODE, CURRENCY, MONEY, CRYPTOCURRENCY, AMOUNT_DEMAND, AMOUNT_GIVEN, HARM_VERB, HARMED, RECORDING, THREAT, HOURS, COUNT, DEADLINE, isPaymentDemand, BITCOIN_ADDRESS, IGNORE_INSTRUCTIONS, AI_ACTION, AI_OBJECT, AI_ACTION_OBJECT, AI_NEAR, VERDICT, VERDICT_WORD, VERDICT_ORDER, VERDICT_CLAIM, CLASSIFY, SYSTEM_PROMPT, YOU_ARE, QUOTE, CONDITION, DISCUSSED, DISCUSSED_SHOWN, DISCUSSED_NEAR, isDiscussed, isInjection, QUOTE_OR_SPACE, SHOWN_NEAR, isOrder, PAYPAL_DOMAIN, PAYPAL_SPAM_TYPE_IDS, PAYPAL_OWN_REQUEST, PAYPAL_INVOICE_SUBJECT, MS_SPAM_VERDICT, MS_SPAM_CATEGORY, APPLE_NEXT, APPLE_FILLER, APPLE_STRONG, APPLE_BUSINESS, APPLE_ALONE, APPLE_BESIDE, APPLE_PART, NEXT_WORD, MAX_AFTER, APPLE, DISPLAY_BRANDS, ADDRESSES, LIST_HOSTS, VIA_LIST, MAILBOXES, BEFORE_ADDRESS, AFTER_ADDRESS, isWholeName, JOINED_WORDS, MAX_DISPLAY;
6214
7332
  var init_is_arbitrary = __esm({
6215
7333
  "src/is-arbitrary.js"() {
6216
- import_tldts4 = require("tldts");
7334
+ import_tldts5 = require("tldts");
6217
7335
  init_homograph();
6218
7336
  init_html();
6219
7337
  init_linear();
@@ -6464,7 +7582,7 @@ function authHeaders(config) {
6464
7582
  case "basic": {
6465
7583
  const user = config.username ?? "";
6466
7584
  const pass = config.password ?? config.apiKey ?? "";
6467
- headers.authorization = `Basic ${import_node_buffer7.Buffer.from(`${user}:${pass}`).toString("base64")}`;
7585
+ headers.authorization = `Basic ${import_node_buffer8.Buffer.from(`${user}:${pass}`).toString("base64")}`;
6468
7586
  break;
6469
7587
  }
6470
7588
  case "x-api-key": {
@@ -6911,10 +8029,10 @@ function replyText(api, reply2) {
6911
8029
  }
6912
8030
  return reply2?.choices?.[0]?.message?.content || null;
6913
8031
  }
6914
- var import_node_buffer7, import_node_crypto2, import_node_os, import_node_process, PROVIDERS, DECISION_APIS, TOP_LOGPROBS, VERDICTS, VERDICT_CRITERIA, SIGNS, GUIDE, DEFAULT_SYSTEM_PROMPT, DECISION_SYSTEM_PROMPT, DECISION_INSTRUCTIONS, LOCALHOST, PRIVATE_HOST, REDACTIONS, THINK_OPEN, THINK_CLOSE, ANSWER_FIRST, LOCAL_CHARACTER, BREAKS2, VERDICT_WORD2, NOT, DENIED, JOINED, SPAM_LABEL, HAM_WORDS, HAM_LABEL, NOT_HAM_LABEL, UNWANTED, MIN_VERDICT_MASS, percent, MODES, LLMClassifier;
8032
+ var import_node_buffer8, import_node_crypto2, import_node_os, import_node_process, PROVIDERS, DECISION_APIS, TOP_LOGPROBS, VERDICTS, VERDICT_CRITERIA, SIGNS, GUIDE, DEFAULT_SYSTEM_PROMPT, DECISION_SYSTEM_PROMPT, DECISION_INSTRUCTIONS, LOCALHOST, PRIVATE_HOST, REDACTIONS, THINK_OPEN, THINK_CLOSE, ANSWER_FIRST, LOCAL_CHARACTER, BREAKS2, VERDICT_WORD2, NOT, DENIED, JOINED, SPAM_LABEL, HAM_WORDS, HAM_LABEL, NOT_HAM_LABEL, UNWANTED, MIN_VERDICT_MASS, percent, MODES, LLMClassifier;
6915
8033
  var init_llm = __esm({
6916
8034
  "src/llm.js"() {
6917
- import_node_buffer7 = require("node:buffer");
8035
+ import_node_buffer8 = require("node:buffer");
6918
8036
  import_node_crypto2 = require("node:crypto");
6919
8037
  import_node_os = __toESM(require("node:os"), 1);
6920
8038
  import_node_process = __toESM(require("node:process"), 1);
@@ -7666,7 +8784,7 @@ var init_package = __esm({
7666
8784
  package_default = {
7667
8785
  name: "spamscanner",
7668
8786
  description: "Spam, phishing and malware filter for email in any language: a trainable classifier, link and attachment checks, SPF/DKIM/DMARC, and an optional AI second opinion from any LLM, including local Ollama models. Works as a library, CLI, Postfix milter or HTTP API.",
7669
- version: "7.0.9",
8787
+ version: "7.0.11",
7670
8788
  author: "Forward Email (https://forwardemail.net)",
7671
8789
  bin: {
7672
8790
  spamscanner: "./dist/esm/cli.js"
@@ -7855,10 +8973,10 @@ function splitMessage(raw) {
7855
8973
  const match = /^\r?\n|\r?\n\r?\n/.exec(text);
7856
8974
  if (!match) {
7857
8975
  const newline2 = text.includes("\n") && !text.includes("\r\n") ? "\n" : "\r\n";
7858
- return { header: text.replace(/\r?\n$/, ""), body: import_node_buffer8.Buffer.alloc(0), newline: newline2 };
8976
+ return { header: text.replace(/\r?\n$/, ""), body: import_node_buffer9.Buffer.alloc(0), newline: newline2 };
7859
8977
  }
7860
8978
  const newline = match[0].startsWith("\r") ? "\r\n" : "\n";
7861
- return { header: text.slice(0, match.index), body: raw.subarray(import_node_buffer8.Buffer.byteLength(text.slice(0, match.index + match[0].length), "latin1")), newline };
8979
+ return { header: text.slice(0, match.index), body: raw.subarray(import_node_buffer9.Buffer.byteLength(text.slice(0, match.index + match[0].length), "latin1")), newline };
7862
8980
  }
7863
8981
  function subjectTagText(tag, spaceAfter = false) {
7864
8982
  const line = String(tag).replaceAll(new RegExp("\\p{Cc}+", "gu"), " ").trim();
@@ -7868,14 +8986,14 @@ function subjectTagText(tag, spaceAfter = false) {
7868
8986
  const words2 = [];
7869
8987
  let chunk2 = "";
7870
8988
  for (const character of spaceAfter ? `${line} ` : line) {
7871
- if (import_node_buffer8.Buffer.byteLength(chunk2 + character, "utf8") > ENCODED_BYTES) {
8989
+ if (import_node_buffer9.Buffer.byteLength(chunk2 + character, "utf8") > ENCODED_BYTES) {
7872
8990
  words2.push(chunk2);
7873
8991
  chunk2 = "";
7874
8992
  }
7875
8993
  chunk2 += character;
7876
8994
  }
7877
8995
  words2.push(chunk2);
7878
- return words2.map((word) => `=?UTF-8?B?${import_node_buffer8.Buffer.from(word, "utf8").toString("base64")}?=`).join(" ");
8996
+ return words2.map((word) => `=?UTF-8?B?${import_node_buffer9.Buffer.from(word, "utf8").toString("base64")}?=`).join(" ");
7879
8997
  }
7880
8998
  function taggedSubject(tag, current, newline = "\r\n") {
7881
8999
  const unfolded = current.replaceAll(/\r?\n/g, "");
@@ -7906,7 +9024,7 @@ function taggedSubject(tag, current, newline = "\r\n") {
7906
9024
  return lines2.join(newline).slice("Subject: ".length);
7907
9025
  }
7908
9026
  function rewriteMessage(source, headers = [], options = {}) {
7909
- const raw = import_node_buffer8.Buffer.isBuffer(source) ? source : import_node_buffer8.Buffer.from(String(source), "utf8");
9027
+ const raw = import_node_buffer9.Buffer.isBuffer(source) ? source : import_node_buffer9.Buffer.from(String(source), "utf8");
7910
9028
  const { header, body, newline } = splitMessage(raw);
7911
9029
  const remove = options.remove ?? /^x-spam-/i;
7912
9030
  const lines2 = header === "" ? [] : header.split(/\r?\n/);
@@ -7931,15 +9049,15 @@ function rewriteMessage(source, headers = [], options = {}) {
7931
9049
  }
7932
9050
  }
7933
9051
  }
7934
- const added = headers.map(([name, value]) => foldHeader(name, import_node_buffer8.Buffer.from(String(value), "utf8").toString("latin1"), newline));
9052
+ const added = headers.map(([name, value]) => foldHeader(name, import_node_buffer9.Buffer.from(String(value), "utf8").toString("latin1"), newline));
7935
9053
  const mbox = kept.length > 0 && kept[0][0].startsWith("From ") ? kept.shift() : [];
7936
9054
  const head = [...mbox, ...added, ...kept.map((field) => field.join(newline))].join(newline);
7937
- return import_node_buffer8.Buffer.concat([import_node_buffer8.Buffer.from(head === "" && header === "" ? newline : `${head}${newline}${newline}`, "latin1"), body]);
9055
+ return import_node_buffer9.Buffer.concat([import_node_buffer9.Buffer.from(head === "" && header === "" ? newline : `${head}${newline}${newline}`, "latin1"), body]);
7938
9056
  }
7939
- var import_node_buffer8, ENCODED_BYTES, PLAIN_WORD, ENCODED_LINE, MAX_LINE2, ENCODED_WORD, ENCODED_START;
9057
+ var import_node_buffer9, ENCODED_BYTES, PLAIN_WORD, ENCODED_LINE, MAX_LINE2, ENCODED_WORD, ENCODED_START;
7940
9058
  var init_headers = __esm({
7941
9059
  "src/headers.js"() {
7942
- import_node_buffer8 = require("node:buffer");
9060
+ import_node_buffer9 = require("node:buffer");
7943
9061
  ENCODED_BYTES = 39;
7944
9062
  PLAIN_WORD = 64;
7945
9063
  ENCODED_LINE = 76;
@@ -8115,7 +9233,7 @@ async function* readJsonl(file, options = {}) {
8115
9233
  }
8116
9234
  async function* walk(directory) {
8117
9235
  const entries = await import_promises.default.readdir(directory, { withFileTypes: true });
8118
- entries.sort((a, b) => import_node_buffer9.Buffer.compare(import_node_buffer9.Buffer.from(a.name), import_node_buffer9.Buffer.from(b.name)));
9236
+ entries.sort((a, b) => import_node_buffer10.Buffer.compare(import_node_buffer10.Buffer.from(a.name), import_node_buffer10.Buffer.from(b.name)));
8119
9237
  for (const entry of entries) {
8120
9238
  if (SKIP.has(entry.name) || entry.name.startsWith(".")) {
8121
9239
  continue;
@@ -8140,7 +9258,7 @@ async function* readMessages(source) {
8140
9258
  const handle = await import_promises.default.open(file);
8141
9259
  let head;
8142
9260
  try {
8143
- const { buffer, bytesRead } = await handle.read(import_node_buffer9.Buffer.alloc(64), 0, 64, 0);
9261
+ const { buffer, bytesRead } = await handle.read(import_node_buffer10.Buffer.alloc(64), 0, 64, 0);
8144
9262
  head = buffer.subarray(0, bytesRead).toString("latin1");
8145
9263
  } finally {
8146
9264
  await handle.close();
@@ -8152,10 +9270,10 @@ async function* readMessages(source) {
8152
9270
  }
8153
9271
  }
8154
9272
  }
8155
- var import_node_buffer9, import_node_fs3, import_promises, import_node_path2, import_node_readline, import_node_zlib, SKIP, SPAM_LABELS, HAM_LABELS, MAX_RECORD_LINES, MAX_RECORD_LENGTH, TEXT_NAMES, LABEL_NAMES, JSONL_LABEL_NAMES, JSONL_TEXT_NAMES;
9273
+ var import_node_buffer10, import_node_fs3, import_promises, import_node_path2, import_node_readline, import_node_zlib, SKIP, SPAM_LABELS, HAM_LABELS, MAX_RECORD_LINES, MAX_RECORD_LENGTH, TEXT_NAMES, LABEL_NAMES, JSONL_LABEL_NAMES, JSONL_TEXT_NAMES;
8156
9274
  var init_sources = __esm({
8157
9275
  "src/sources.js"() {
8158
- import_node_buffer9 = require("node:buffer");
9276
+ import_node_buffer10 = require("node:buffer");
8159
9277
  import_node_fs3 = require("node:fs");
8160
9278
  import_promises = __toESM(require("node:fs/promises"), 1);
8161
9279
  import_node_path2 = __toESM(require("node:path"), 1);
@@ -8329,8 +9447,8 @@ function sessionFromQuery(query) {
8329
9447
  return session;
8330
9448
  }
8331
9449
  function sameToken(given, expected) {
8332
- const a = import_node_buffer10.Buffer.from(String(given));
8333
- const b = import_node_buffer10.Buffer.from(String(expected));
9450
+ const a = import_node_buffer11.Buffer.from(String(given));
9451
+ const b = import_node_buffer11.Buffer.from(String(expected));
8334
9452
  return a.length === b.length && (0, import_node_crypto5.timingSafeEqual)(a, b);
8335
9453
  }
8336
9454
  function readBody(request, limit) {
@@ -8350,7 +9468,7 @@ function readBody(request, limit) {
8350
9468
  reject(error);
8351
9469
  return;
8352
9470
  }
8353
- resolve(import_node_buffer10.Buffer.concat(chunks));
9471
+ resolve(import_node_buffer11.Buffer.concat(chunks));
8354
9472
  });
8355
9473
  request.on("error", reject);
8356
9474
  });
@@ -8365,7 +9483,7 @@ function createHttpServer(scanner, options = {}) {
8365
9483
  let active = 0;
8366
9484
  const server = import_node_http2.default.createServer(async (request, response) => {
8367
9485
  const send = (status, body, headers = {}) => {
8368
- const isBuffer = import_node_buffer10.Buffer.isBuffer(body);
9486
+ const isBuffer = import_node_buffer11.Buffer.isBuffer(body);
8369
9487
  response.writeHead(status, { "content-type": isBuffer ? "message/rfc822" : "application/json; charset=utf-8", "cache-control": "no-store", ...headers });
8370
9488
  response.end(isBuffer ? body : `${JSON.stringify(body)}
8371
9489
  `);
@@ -8438,14 +9556,14 @@ function createTcpServer(scanner, options = {}) {
8438
9556
  timeout = 6e4,
8439
9557
  maxConnections = MAX_CONNECTIONS
8440
9558
  } = options;
8441
- const server = import_node_net4.default.createServer({ allowHalfOpen: true }, (socket) => {
9559
+ const server = import_node_net5.default.createServer({ allowHalfOpen: true }, (socket) => {
8442
9560
  const chunks = [];
8443
9561
  let size = 0;
8444
9562
  socket.setTimeout(timeout, () => socket.destroy());
8445
9563
  const onEnd = async () => {
8446
9564
  socket.setTimeout(0);
8447
9565
  try {
8448
- const result = await scanner.scan(import_node_buffer10.Buffer.concat(chunks));
9566
+ const result = await scanner.scan(import_node_buffer11.Buffer.concat(chunks));
8449
9567
  socket.end(json ? `${JSON.stringify(serializeResult(result))}
8450
9568
  ` : `${result.isSpam ? "SPAM" : "HAM"} ${result.score.toFixed(1)}/${result.threshold.toFixed(1)} ${result.tests.map((test) => test.name).join(",")}
8451
9569
  `);
@@ -8474,13 +9592,13 @@ function createTcpServer(scanner, options = {}) {
8474
9592
  server.maxConnections = maxConnections;
8475
9593
  return server;
8476
9594
  }
8477
- var import_node_buffer10, import_node_crypto5, import_node_http2, import_node_net4, MAX_MESSAGE_SIZE, MAX_CONNECTIONS;
9595
+ var import_node_buffer11, import_node_crypto5, import_node_http2, import_node_net5, MAX_MESSAGE_SIZE, MAX_CONNECTIONS;
8478
9596
  var init_server = __esm({
8479
9597
  "src/server.js"() {
8480
- import_node_buffer10 = require("node:buffer");
9598
+ import_node_buffer11 = require("node:buffer");
8481
9599
  import_node_crypto5 = require("node:crypto");
8482
9600
  import_node_http2 = __toESM(require("node:http"), 1);
8483
- import_node_net4 = __toESM(require("node:net"), 1);
9601
+ import_node_net5 = __toESM(require("node:net"), 1);
8484
9602
  init_headers();
8485
9603
  init_version();
8486
9604
  MAX_MESSAGE_SIZE = 25 * 1024 * 1024;
@@ -8489,12 +9607,12 @@ var init_server = __esm({
8489
9607
  });
8490
9608
 
8491
9609
  // src/milter.js
8492
- function packet(command, data2 = import_node_buffer11.Buffer.alloc(0)) {
8493
- const payload = import_node_buffer11.Buffer.isBuffer(data2) ? data2 : import_node_buffer11.Buffer.from(data2, "latin1");
8494
- const header = import_node_buffer11.Buffer.alloc(5);
9610
+ function packet(command, data2 = import_node_buffer12.Buffer.alloc(0)) {
9611
+ const payload = import_node_buffer12.Buffer.isBuffer(data2) ? data2 : import_node_buffer12.Buffer.from(data2, "latin1");
9612
+ const header = import_node_buffer12.Buffer.alloc(5);
8495
9613
  header.writeUInt32BE(payload.length + 1);
8496
9614
  header.write(command, 4, "latin1");
8497
- return import_node_buffer11.Buffer.concat([header, payload]);
9615
+ return import_node_buffer12.Buffer.concat([header, payload]);
8498
9616
  }
8499
9617
  function cstrings(data2) {
8500
9618
  const parts = data2.toString("latin1").split("\0");
@@ -8504,19 +9622,19 @@ function cstrings(data2) {
8504
9622
  return parts;
8505
9623
  }
8506
9624
  function cstring(value) {
8507
- return import_node_buffer11.Buffer.from(`${value}\0`, "latin1");
9625
+ return import_node_buffer12.Buffer.from(`${value}\0`, "latin1");
8508
9626
  }
8509
9627
  function address(value) {
8510
9628
  const text = String(value ?? "").trim();
8511
9629
  const match = /^<?([^<>]*)>?$/.exec(text);
8512
9630
  return match ? match[1] : text;
8513
9631
  }
8514
- var import_node_buffer11, import_node_events, import_node_net5, COMMANDS, RESPONSES, ACTIONS, PROTOCOL, MAX_PACKET, MilterSession, MilterServer;
9632
+ var import_node_buffer12, import_node_events, import_node_net6, COMMANDS, RESPONSES, ACTIONS, PROTOCOL, MAX_PACKET, MilterSession, MilterServer;
8515
9633
  var init_milter = __esm({
8516
9634
  "src/milter.js"() {
8517
- import_node_buffer11 = require("node:buffer");
9635
+ import_node_buffer12 = require("node:buffer");
8518
9636
  import_node_events = require("node:events");
8519
- import_node_net5 = __toESM(require("node:net"), 1);
9637
+ import_node_net6 = __toESM(require("node:net"), 1);
8520
9638
  init_headers();
8521
9639
  init_auth();
8522
9640
  init_server();
@@ -8634,7 +9752,7 @@ var init_milter = __esm({
8634
9752
  if (this.buffered < this.needed) {
8635
9753
  return;
8636
9754
  }
8637
- let buffer = this.chunks.length === 1 ? this.chunks[0] : import_node_buffer11.Buffer.concat(this.chunks);
9755
+ let buffer = this.chunks.length === 1 ? this.chunks[0] : import_node_buffer12.Buffer.concat(this.chunks);
8638
9756
  this.needed = 4;
8639
9757
  while (buffer.length >= 4) {
8640
9758
  const length = buffer.readUInt32BE(0);
@@ -8679,7 +9797,7 @@ var init_milter = __esm({
8679
9797
  const protocol = data2.readUInt32BE(8);
8680
9798
  const wanted = ACTIONS.ADDHDRS | ACTIONS.CHGHDRS | ACTIONS.QUARANTINE;
8681
9799
  this.leadingSpace = Boolean(protocol & PROTOCOL.HDR_LEADSPC);
8682
- const reply2 = import_node_buffer11.Buffer.alloc(12);
9800
+ const reply2 = import_node_buffer12.Buffer.alloc(12);
8683
9801
  reply2.writeUInt32BE(Math.min(version, 6), 0);
8684
9802
  reply2.writeUInt32BE(actions & wanted, 4);
8685
9803
  reply2.writeUInt32BE(protocol & (PROTOCOL.HDR_LEADSPC | PROTOCOL.NOUNKNOWN), 8);
@@ -8744,7 +9862,7 @@ var init_milter = __esm({
8744
9862
  if (this.truncated || this.size + data2.length > options.maxSize) {
8745
9863
  this.truncated = true;
8746
9864
  } else {
8747
- this.body.push(import_node_buffer11.Buffer.from(data2));
9865
+ this.body.push(import_node_buffer12.Buffer.from(data2));
8748
9866
  this.size += data2.length;
8749
9867
  }
8750
9868
  this.send(RESPONSES.CONTINUE);
@@ -8779,7 +9897,7 @@ var init_milter = __esm({
8779
9897
  /** @returns {Buffer} */
8780
9898
  rawMessage() {
8781
9899
  const head = this.headers.map(([name, value]) => `${name}:${this.leadingSpace || value.startsWith(" ") || value.startsWith(" ") ? "" : " "}${value}`).join("\r\n");
8782
- return import_node_buffer11.Buffer.concat([import_node_buffer11.Buffer.from(this.headers.length > 0 ? `${head}\r
9900
+ return import_node_buffer12.Buffer.concat([import_node_buffer12.Buffer.from(this.headers.length > 0 ? `${head}\r
8783
9901
  \r
8784
9902
  ` : "\r\n", "latin1"), ...this.body]);
8785
9903
  }
@@ -8790,9 +9908,9 @@ var init_milter = __esm({
8790
9908
  const key = name.toLowerCase();
8791
9909
  counts.set(key, (counts.get(key) || 0) + 1);
8792
9910
  if (key.startsWith("x-spam-")) {
8793
- const index = import_node_buffer11.Buffer.alloc(4);
9911
+ const index = import_node_buffer12.Buffer.alloc(4);
8794
9912
  index.writeUInt32BE(counts.get(key));
8795
- this.send(RESPONSES.CHGHEADER, import_node_buffer11.Buffer.concat([index, cstring(name), cstring("")]));
9913
+ this.send(RESPONSES.CHGHEADER, import_node_buffer12.Buffer.concat([index, cstring(name), cstring("")]));
8796
9914
  }
8797
9915
  }
8798
9916
  }
@@ -8815,7 +9933,7 @@ var init_milter = __esm({
8815
9933
  }
8816
9934
  this.server.report(error);
8817
9935
  this.removeForgedHeaders();
8818
- this.send(RESPONSES.ADDHEADER, import_node_buffer11.Buffer.concat([cstring("X-Spam-Virus-Scan"), cstring(`${this.leadingSpace ? " " : ""}failed`)]));
9936
+ this.send(RESPONSES.ADDHEADER, import_node_buffer12.Buffer.concat([cstring("X-Spam-Virus-Scan"), cstring(`${this.leadingSpace ? " " : ""}failed`)]));
8819
9937
  this.send(RESPONSES.CONTINUE);
8820
9938
  this.resetMessage();
8821
9939
  return;
@@ -8836,15 +9954,15 @@ var init_milter = __esm({
8836
9954
  headers.unshift(["Authentication-Results", formatAuthResultsHeader(result.results.authentication, options.hostname)]);
8837
9955
  }
8838
9956
  for (const [name, value] of headers) {
8839
- this.send(RESPONSES.ADDHEADER, import_node_buffer11.Buffer.concat([cstring(name), cstring(`${this.leadingSpace ? " " : ""}${value}`.replaceAll("\r\n", "\n"))]));
9957
+ this.send(RESPONSES.ADDHEADER, import_node_buffer12.Buffer.concat([cstring(name), cstring(`${this.leadingSpace ? " " : ""}${value}`.replaceAll("\r\n", "\n"))]));
8840
9958
  }
8841
9959
  if (result.isSpam && options.subjectTag) {
8842
9960
  const subject = this.headers.find(([name]) => name.toLowerCase() === "subject");
8843
9961
  const value = taggedSubject(options.subjectTag, subject ? subject[1].trim() : "", "\n");
8844
9962
  if (value !== null) {
8845
- const index = import_node_buffer11.Buffer.alloc(4);
9963
+ const index = import_node_buffer12.Buffer.alloc(4);
8846
9964
  index.writeUInt32BE(1);
8847
- this.send(RESPONSES.CHGHEADER, import_node_buffer11.Buffer.concat([index, cstring("Subject"), cstring(`${this.leadingSpace ? " " : ""}${value}`.replaceAll("\r\n", "\n"))]));
9965
+ this.send(RESPONSES.CHGHEADER, import_node_buffer12.Buffer.concat([index, cstring("Subject"), cstring(`${this.leadingSpace ? " " : ""}${value}`.replaceAll("\r\n", "\n"))]));
8848
9966
  }
8849
9967
  }
8850
9968
  if (result.action === "reject" && options.reject) {
@@ -8895,7 +10013,7 @@ var init_milter = __esm({
8895
10013
  throw new RangeError(`rejectCode must be a 4xx or 5xx SMTP code, not ${this.options.rejectCode}`);
8896
10014
  }
8897
10015
  this.sockets = /* @__PURE__ */ new Set();
8898
- this.server = import_node_net5.default.createServer((socket) => {
10016
+ this.server = import_node_net6.default.createServer((socket) => {
8899
10017
  this.sockets.add(socket);
8900
10018
  socket.on("close", () => this.sockets.delete(socket));
8901
10019
  return new MilterSession(socket, this);
@@ -8971,7 +10089,7 @@ function reply(code, text, headers = [], body = null) {
8971
10089
  lines2.push(`Content-length: ${body.length}`);
8972
10090
  }
8973
10091
  lines2.push(...headers.map(([name, value]) => `${name}: ${value}`), "", "");
8974
- return body === null ? import_node_buffer12.Buffer.from(lines2.join("\r\n")) : import_node_buffer12.Buffer.concat([import_node_buffer12.Buffer.from(lines2.join("\r\n")), body]);
10092
+ return body === null ? import_node_buffer13.Buffer.from(lines2.join("\r\n")) : import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from(lines2.join("\r\n")), body]);
8975
10093
  }
8976
10094
  function report(result) {
8977
10095
  const lines2 = [
@@ -9016,11 +10134,11 @@ async function answer(scanner, request, message, options) {
9016
10134
  return reply(EX_OK, "EX_OK", [verdict]);
9017
10135
  }
9018
10136
  case "SYMBOLS": {
9019
- return reply(EX_OK, "EX_OK", [verdict], import_node_buffer12.Buffer.from(result.tests.map((test) => test.name).join(",")));
10137
+ return reply(EX_OK, "EX_OK", [verdict], import_node_buffer13.Buffer.from(result.tests.map((test) => test.name).join(",")));
9020
10138
  }
9021
10139
  case "REPORT":
9022
10140
  case "REPORT_IFSPAM": {
9023
- return reply(EX_OK, "EX_OK", [verdict], command === "REPORT" || result.isSpam ? import_node_buffer12.Buffer.from(report(result)) : import_node_buffer12.Buffer.alloc(0));
10141
+ return reply(EX_OK, "EX_OK", [verdict], command === "REPORT" || result.isSpam ? import_node_buffer13.Buffer.from(report(result)) : import_node_buffer13.Buffer.alloc(0));
9024
10142
  }
9025
10143
  default: {
9026
10144
  const rewritten = rewriteMessage(message, spamHeaders(result, { version: VERSION }), { subjectTag: result.isSpam ? options.subjectTag : null });
@@ -9028,7 +10146,7 @@ async function answer(scanner, request, message, options) {
9028
10146
  return reply(EX_OK, "EX_OK", [verdict], rewritten);
9029
10147
  }
9030
10148
  const { header, newline } = splitMessage(rewritten);
9031
- return reply(EX_OK, "EX_OK", [verdict], import_node_buffer12.Buffer.from(`${header}${newline}${newline}`, "latin1"));
10149
+ return reply(EX_OK, "EX_OK", [verdict], import_node_buffer13.Buffer.from(`${header}${newline}${newline}`, "latin1"));
9032
10150
  }
9033
10151
  }
9034
10152
  }
@@ -9042,8 +10160,8 @@ function createSpamdServer(scanner, options = {}) {
9042
10160
  maxConnections: MAX_CONNECTIONS,
9043
10161
  ...options
9044
10162
  };
9045
- const server = import_node_net6.default.createServer({ allowHalfOpen: true }, (socket) => {
9046
- let head = import_node_buffer12.Buffer.alloc(0);
10163
+ const server = import_node_net7.default.createServer({ allowHalfOpen: true }, (socket) => {
10164
+ let head = import_node_buffer13.Buffer.alloc(0);
9047
10165
  const chunks = [];
9048
10166
  let size = 0;
9049
10167
  let request = null;
@@ -9069,7 +10187,7 @@ function createSpamdServer(scanner, options = {}) {
9069
10187
  return;
9070
10188
  }
9071
10189
  if (!request) {
9072
- head = import_node_buffer12.Buffer.concat([head, chunk2]);
10190
+ head = import_node_buffer13.Buffer.concat([head, chunk2]);
9073
10191
  const end = head.indexOf("\r\n\r\n");
9074
10192
  if (end === -1) {
9075
10193
  if (head.length > 64 * 1024) {
@@ -9104,7 +10222,7 @@ function createSpamdServer(scanner, options = {}) {
9104
10222
  chunks.push(chunk2);
9105
10223
  size += chunk2.length;
9106
10224
  if (request.length === null ? ["PING", "SKIP"].includes(request.command) : size >= request.length) {
9107
- finish(import_node_buffer12.Buffer.concat(chunks).subarray(0, request.length ?? 0));
10225
+ finish(import_node_buffer13.Buffer.concat(chunks).subarray(0, request.length ?? 0));
9108
10226
  } else if (size > settings.maxSize) {
9109
10227
  fail(EX_DATAERR, `Message larger than ${settings.maxSize} bytes`);
9110
10228
  }
@@ -9116,7 +10234,7 @@ function createSpamdServer(scanner, options = {}) {
9116
10234
  if (!request) {
9117
10235
  fail(EX_PROTOCOL, "Incomplete request");
9118
10236
  } else if (request.length === null) {
9119
- finish(import_node_buffer12.Buffer.concat(chunks));
10237
+ finish(import_node_buffer13.Buffer.concat(chunks));
9120
10238
  } else {
9121
10239
  fail(EX_PROTOCOL, `Message shorter than its Content-length of ${request.length} bytes`);
9122
10240
  }
@@ -9127,11 +10245,11 @@ function createSpamdServer(scanner, options = {}) {
9127
10245
  server.maxConnections = settings.maxConnections;
9128
10246
  return server;
9129
10247
  }
9130
- var import_node_buffer12, import_node_net6, EX_OK, EX_USAGE, EX_DATAERR, EX_SOFTWARE, EX_PROTOCOL, EX_NOPERM, COMMANDS2;
10248
+ var import_node_buffer13, import_node_net7, EX_OK, EX_USAGE, EX_DATAERR, EX_SOFTWARE, EX_PROTOCOL, EX_NOPERM, COMMANDS2;
9131
10249
  var init_spamd = __esm({
9132
10250
  "src/spamd.js"() {
9133
- import_node_buffer12 = require("node:buffer");
9134
- import_node_net6 = __toESM(require("node:net"), 1);
10251
+ import_node_buffer13 = require("node:buffer");
10252
+ import_node_net7 = __toESM(require("node:net"), 1);
9135
10253
  init_headers();
9136
10254
  init_server();
9137
10255
  init_version();
@@ -9343,21 +10461,21 @@ async function withTimeout(promise, ms, fallback) {
9343
10461
  }
9344
10462
  }
9345
10463
  async function toBuffer(source) {
9346
- if (import_node_buffer13.Buffer.isBuffer(source)) {
10464
+ if (import_node_buffer14.Buffer.isBuffer(source)) {
9347
10465
  return source;
9348
10466
  }
9349
10467
  if (typeof source === "string") {
9350
- return import_node_buffer13.Buffer.from(source, "utf8");
10468
+ return import_node_buffer14.Buffer.from(source, "utf8");
9351
10469
  }
9352
10470
  if (source instanceof Uint8Array) {
9353
- return import_node_buffer13.Buffer.from(source);
10471
+ return import_node_buffer14.Buffer.from(source);
9354
10472
  }
9355
10473
  if (source && typeof source[Symbol.asyncIterator] === "function") {
9356
10474
  const chunks = [];
9357
10475
  for await (const chunk2 of source) {
9358
- chunks.push(import_node_buffer13.Buffer.isBuffer(chunk2) ? chunk2 : import_node_buffer13.Buffer.from(chunk2));
10476
+ chunks.push(import_node_buffer14.Buffer.isBuffer(chunk2) ? chunk2 : import_node_buffer14.Buffer.from(chunk2));
9359
10477
  }
9360
- return import_node_buffer13.Buffer.concat(chunks);
10478
+ return import_node_buffer14.Buffer.concat(chunks);
9361
10479
  }
9362
10480
  throw new TypeError("A message must be a Buffer, a string, a Uint8Array or a readable stream");
9363
10481
  }
@@ -9432,12 +10550,12 @@ function fromDomain(mail) {
9432
10550
  function withHeader(raw) {
9433
10551
  const first = raw.subarray(0, 1e3).toString("latin1");
9434
10552
  const headerless = raw.length > 0 && !/^(?:[!-9;-~]+[ \t]*:|From |[\r\n])/.test(first);
9435
- return headerless ? import_node_buffer13.Buffer.concat([import_node_buffer13.Buffer.from("\r\n"), raw]) : raw;
10553
+ return headerless ? import_node_buffer14.Buffer.concat([import_node_buffer14.Buffer.from("\r\n"), raw]) : raw;
9436
10554
  }
9437
- var import_node_buffer13, import_promises2, import_node_util2, debug2, DEFAULTS2, NESTED, MAX_LOOKALIKE_HOSTS, MAX_DECEPTIVE_LINKS, CLAMAV_CONCURRENCY, CLAMAV_TIMEOUT, CLAMAV_LIMITS, MAX_NSFW_IMAGES, MAX_REPUTATION_CACHES, SpamScanner, src_default;
10555
+ var import_node_buffer14, import_promises2, import_node_util2, debug2, DEFAULTS2, NESTED, MAX_LOOKALIKE_HOSTS, MAX_DECEPTIVE_LINKS, CLAMAV_CONCURRENCY, CLAMAV_TIMEOUT, CLAMAV_LIMITS, MAX_NSFW_IMAGES, MAX_REPUTATION_CACHES, SpamScanner, src_default;
9438
10556
  var init_src = __esm({
9439
10557
  "src/index.js"() {
9440
- import_node_buffer13 = require("node:buffer");
10558
+ import_node_buffer14 = require("node:buffer");
9441
10559
  import_promises2 = require("node:fs/promises");
9442
10560
  import_node_util2 = require("node:util");
9443
10561
  init_attachments();
@@ -9446,6 +10564,7 @@ var init_src = __esm({
9446
10564
  init_classifier();
9447
10565
  init_dnsbl();
9448
10566
  init_html();
10567
+ init_links();
9449
10568
  init_homograph();
9450
10569
  init_is_arbitrary();
9451
10570
  init_language();
@@ -9488,6 +10607,19 @@ var init_src = __esm({
9488
10607
  cloudflare: true,
9489
10608
  adult: true,
9490
10609
  maxHosts: 25,
10610
+ // Also read the links of the whole message and of what it carries
10611
+ // (attached messages, HTML, SVG and XML files, text files, invitations
10612
+ // and contact cards, documents in iframes and data: URLs) when link
10613
+ // hosts are looked up, for at most five seconds: off by default, as it
10614
+ // reads all of it, up to 50 MB of attachments.
10615
+ attachments: false,
10616
+ // Milliseconds the link lookups may take in all (default: timeout).
10617
+ timeout: void 0,
10618
+ // Also look up host names written in the text without a link or a path
10619
+ // ("evil.example"), which mail clients make links of, as far as there is
10620
+ // room: off by default, as a quoted reply or a signature may name any
10621
+ // site (they are checked for lookalikes either way).
10622
+ hostsInText: false,
9491
10623
  // Characters of text read for links (twice as many of HTML): more than
9492
10624
  // for the classifier (maxLength), as a link anywhere in a message may be
9493
10625
  // followed; a longer message sets results.linksTruncated.
@@ -9689,7 +10821,10 @@ var init_src = __esm({
9689
10821
  async scanFile(file, options) {
9690
10822
  return this.scan(await (0, import_promises2.readFile)(file), options);
9691
10823
  }
9692
- async checkLinks(links, config, hosts = [], from = "") {
10824
+ // (`from`: the sender's domain; `carried`: the link hosts of the whole
10825
+ // message and of what it carries, see carriedLinkHosts)
10826
+ async checkLinks(links, config, hosts = [], options = {}) {
10827
+ const { from = "", carried = null } = typeof options === "string" ? { from: options } : options;
9693
10828
  const phishing = [];
9694
10829
  const homographs = [];
9695
10830
  const seenHosts = /* @__PURE__ */ new Set();
@@ -9745,7 +10880,11 @@ var init_src = __esm({
9745
10880
  for (const host of hosts) {
9746
10881
  lookalike(host, { source: "text" });
9747
10882
  }
9748
- const ordered = [...new Set([...found.filter((link) => link.text), ...found.filter((link) => !link.text), ...bare].map((link) => lookupName(destination(link))).filter(Boolean))];
10883
+ const carriedHosts = (carried?.hosts ?? []).map((host) => lookupName(host)).filter(Boolean);
10884
+ for (const host of carriedHosts) {
10885
+ seenHosts.add(host);
10886
+ }
10887
+ const ordered = [.../* @__PURE__ */ new Set([...[...found.filter((link) => link.text), ...found.filter((link) => !link.text), ...bare].map((link) => lookupName(destination(link))).filter(Boolean), ...carriedHosts])];
9749
10888
  const firsts = /* @__PURE__ */ new Map();
9750
10889
  for (const host of ordered) {
9751
10890
  const domain = registrableDomain(host);
@@ -9757,6 +10896,7 @@ var init_src = __esm({
9757
10896
  const domains = [...new Set(checked.map((host) => registrableDomain(host)))];
9758
10897
  const blocked = [];
9759
10898
  let answered = 0;
10899
+ const linkTimeout = Number(config.phishing.timeout) > 0 ? Number(config.phishing.timeout) : config.timeout;
9760
10900
  const cloudflare = async () => {
9761
10901
  await withTimeout(Promise.all(checked.map(async (host) => {
9762
10902
  const found2 = await this.dns.checkCloudflare([host], { adult: config.phishing.adult });
@@ -9764,12 +10904,12 @@ var init_src = __esm({
9764
10904
  if (!found2.unanswered?.length) {
9765
10905
  answered++;
9766
10906
  }
9767
- })), config.timeout, null);
10907
+ })), linkTimeout, null);
9768
10908
  return { found: [...blocked], unanswered: checked.length - answered };
9769
10909
  };
9770
10910
  const [cloudflareResult, listed] = await Promise.all([
9771
10911
  config.phishing.cloudflare && checked.length > 0 ? cloudflare() : { found: [], unanswered: 0 },
9772
- config.dnsbl.domain?.length > 0 && domains.length > 0 ? withTimeout(this.dns.checkDomains(domains, config.dnsbl.domain), config.timeout, []) : []
10912
+ config.dnsbl.domain?.length > 0 && domains.length > 0 ? withTimeout(this.dns.checkDomains(domains, config.dnsbl.domain), linkTimeout, []) : []
9773
10913
  ]);
9774
10914
  for (const { host, category } of cloudflareResult.found) {
9775
10915
  phishing.push(finding(category === "malware" ? { type: "malicious_domain", domain: host, message: `Link hostname ${host} is blocked by Cloudflare's malware filtering as phishing or malware` } : { type: "adult_domain", domain: host, message: `Link hostname ${host} was detected by Cloudflare's family filtering to contain adult-related content` }));
@@ -9785,7 +10925,8 @@ var init_src = __esm({
9785
10925
  return {
9786
10926
  phishing,
9787
10927
  homographs,
9788
- uncheckedHosts: seenHosts.size - checked.length,
10928
+ // (at least one when the message has more hosts than were read)
10929
+ uncheckedHosts: Math.max(seenHosts.size - checked.length, carried?.more ? 1 : 0),
9789
10930
  timedOutHosts: cloudflareResult.unanswered
9790
10931
  };
9791
10932
  }
@@ -9957,10 +11098,17 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
9957
11098
  styled: plainObfuscation.styled || shownObfuscation.styled
9958
11099
  };
9959
11100
  const unopened = [];
9960
- const attached = await expandAttachments(mail.attachments, parseErrors, void 0, unopened);
11101
+ const opened = [];
11102
+ const attached = await expandAttachments(mail.attachments, parseErrors, void 0, { unopened, mails: opened });
11103
+ const carried = config.phishing.attachments === true && (config.phishing.cloudflare || config.dnsbl.domain?.length > 0) ? carriedLinkHosts(mail, {
11104
+ mails: opened,
11105
+ attachments: attached,
11106
+ maxHosts: config.phishing.maxHosts,
11107
+ hostsInText: config.phishing.hostsInText === true
11108
+ }) : null;
9961
11109
  const attachments = config.attachments === false ? [] : inspectAttachments(attached).filter((item) => config.macros !== false || !["macro", "pdf_active", "rtf_object"].includes(item.type)).map((item) => finding(item));
9962
11110
  const [links, authentication, checkedReputation, dnsbl, virusScan, toxicity, nsfw] = await Promise.all([
9963
- this.checkLinks(checkedLinks, config, extracted.hosts, fromDomain(mail)),
11111
+ this.checkLinks(checkedLinks, config, extracted.hosts, { from: fromDomain(mail), carried }),
9964
11112
  config.authenticationResults && typeof config.authenticationResults === "object" ? normalizeAuthOutput(config.authenticationResults) : config.authentication && session.remoteAddress ? withTimeout(authenticate(raw, {
9965
11113
  timeout: config.timeout,
9966
11114
  ...typeof config.authentication === "object" ? config.authentication : {},
@@ -10088,6 +11236,14 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
10088
11236
  // Whether the message has more text than phishing.maxLength, whose
10089
11237
  // links were not read.
10090
11238
  linksTruncated,
11239
+ // Whether a link host of the message or of what it carries was
11240
+ // never read whole (it runs past where long text is cut to be
11241
+ // read, it goes through more security gateways than are
11242
+ // unwrapped, or it is in more documents than are read), and whether
11243
+ // an attachment was left unread for time: in either case not every
11244
+ // link was checked (see phishing.attachments).
11245
+ linksTooComplex: Boolean(carried?.tooComplex),
11246
+ linksIncomplete: Boolean(carried?.incomplete),
10091
11247
  idnHomographAttack: {
10092
11248
  detected: links.homographs.length > 0,
10093
11249
  domains: links.homographs,
@@ -10099,6 +11255,9 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
10099
11255
  language: extracted.language,
10100
11256
  tokens: extracted.words,
10101
11257
  mail,
11258
+ // (the attachments of the message and of its attached messages, as
11259
+ // read, an attached message's named after it)
11260
+ attached,
10102
11261
  version: VERSION,
10103
11262
  metrics: { totalTime: time }
10104
11263
  };