spamscanner 7.0.10 → 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
  });
@@ -4423,7 +4611,8 @@ async function parseWithin(raw, parse = parseMessage, deadline = Date.now() + PA
4423
4611
  }
4424
4612
  }
4425
4613
  }
4426
- 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;
4427
4616
  const all = [];
4428
4617
  const deadline = Date.now() + PARSE_TIMEOUT;
4429
4618
  let budget = MAX_NESTED_BYTES;
@@ -4472,6 +4661,7 @@ async function expandAttachments(attachments = [], errors = [], parse = parseMes
4472
4661
  if (inner.error) {
4473
4662
  errors.push(inner.error);
4474
4663
  }
4664
+ mails.push(inner.mail);
4475
4665
  await visit(inner.mail.attachments, prefix ? `${prefix}/${name}` : name || "attached message", depth + 1);
4476
4666
  }
4477
4667
  }
@@ -6015,6 +6205,924 @@ var init_classifier = __esm({
6015
6205
  }
6016
6206
  });
6017
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
+
6018
7126
  // src/is-arbitrary.js
6019
7127
  function unquoted(text) {
6020
7128
  let start = 0;
@@ -6079,13 +7187,13 @@ function joinsDisplay(brand, display, name) {
6079
7187
  return false;
6080
7188
  }
6081
7189
  function isOfficial({ brand, official }, domain, display, shared = true) {
6082
- const parsed = (0, import_tldts4.parse)(domain);
7190
+ const parsed = (0, import_tldts5.parse)(domain);
6083
7191
  const name = parsed.domainWithoutSuffix ?? "";
6084
7192
  const compact = brand.replaceAll(" ", "");
6085
7193
  if (parsed.publicSuffix === compact || compact.length >= 5 && joinsDisplay(brand, display, name) && !JOINED_WORDS.some((word) => name.slice(compact.length).includes(word))) {
6086
7194
  return true;
6087
7195
  }
6088
- 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);
6089
7197
  }
6090
7198
  function headerString(mail, name) {
6091
7199
  const value = mail.headers?.get?.(name);
@@ -6187,7 +7295,7 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
6187
7295
  }
6188
7296
  } else if (claimed && isWholeName(name, claimed)) {
6189
7297
  const domain = claimed[1];
6190
- 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, ""));
6191
7299
  if (brand) {
6192
7300
  hit("FROM_NAME_BRAND", 2, `Display name is an address of "${brand.brand}" but the message is from ${fromRoot}`, "PHISHING");
6193
7301
  }
@@ -6220,10 +7328,10 @@ ${withoutHelp(markup)}`) || isInjection(readable) || attributeText(markup).some(
6220
7328
  category
6221
7329
  };
6222
7330
  }
6223
- 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;
6224
7332
  var init_is_arbitrary = __esm({
6225
7333
  "src/is-arbitrary.js"() {
6226
- import_tldts4 = require("tldts");
7334
+ import_tldts5 = require("tldts");
6227
7335
  init_homograph();
6228
7336
  init_html();
6229
7337
  init_linear();
@@ -6474,7 +7582,7 @@ function authHeaders(config) {
6474
7582
  case "basic": {
6475
7583
  const user = config.username ?? "";
6476
7584
  const pass = config.password ?? config.apiKey ?? "";
6477
- 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")}`;
6478
7586
  break;
6479
7587
  }
6480
7588
  case "x-api-key": {
@@ -6921,10 +8029,10 @@ function replyText(api, reply2) {
6921
8029
  }
6922
8030
  return reply2?.choices?.[0]?.message?.content || null;
6923
8031
  }
6924
- 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;
6925
8033
  var init_llm = __esm({
6926
8034
  "src/llm.js"() {
6927
- import_node_buffer7 = require("node:buffer");
8035
+ import_node_buffer8 = require("node:buffer");
6928
8036
  import_node_crypto2 = require("node:crypto");
6929
8037
  import_node_os = __toESM(require("node:os"), 1);
6930
8038
  import_node_process = __toESM(require("node:process"), 1);
@@ -7676,7 +8784,7 @@ var init_package = __esm({
7676
8784
  package_default = {
7677
8785
  name: "spamscanner",
7678
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.",
7679
- version: "7.0.10",
8787
+ version: "7.0.11",
7680
8788
  author: "Forward Email (https://forwardemail.net)",
7681
8789
  bin: {
7682
8790
  spamscanner: "./dist/esm/cli.js"
@@ -7865,10 +8973,10 @@ function splitMessage(raw) {
7865
8973
  const match = /^\r?\n|\r?\n\r?\n/.exec(text);
7866
8974
  if (!match) {
7867
8975
  const newline2 = text.includes("\n") && !text.includes("\r\n") ? "\n" : "\r\n";
7868
- 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 };
7869
8977
  }
7870
8978
  const newline = match[0].startsWith("\r") ? "\r\n" : "\n";
7871
- 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 };
7872
8980
  }
7873
8981
  function subjectTagText(tag, spaceAfter = false) {
7874
8982
  const line = String(tag).replaceAll(new RegExp("\\p{Cc}+", "gu"), " ").trim();
@@ -7878,14 +8986,14 @@ function subjectTagText(tag, spaceAfter = false) {
7878
8986
  const words2 = [];
7879
8987
  let chunk2 = "";
7880
8988
  for (const character of spaceAfter ? `${line} ` : line) {
7881
- if (import_node_buffer8.Buffer.byteLength(chunk2 + character, "utf8") > ENCODED_BYTES) {
8989
+ if (import_node_buffer9.Buffer.byteLength(chunk2 + character, "utf8") > ENCODED_BYTES) {
7882
8990
  words2.push(chunk2);
7883
8991
  chunk2 = "";
7884
8992
  }
7885
8993
  chunk2 += character;
7886
8994
  }
7887
8995
  words2.push(chunk2);
7888
- 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(" ");
7889
8997
  }
7890
8998
  function taggedSubject(tag, current, newline = "\r\n") {
7891
8999
  const unfolded = current.replaceAll(/\r?\n/g, "");
@@ -7916,7 +9024,7 @@ function taggedSubject(tag, current, newline = "\r\n") {
7916
9024
  return lines2.join(newline).slice("Subject: ".length);
7917
9025
  }
7918
9026
  function rewriteMessage(source, headers = [], options = {}) {
7919
- 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");
7920
9028
  const { header, body, newline } = splitMessage(raw);
7921
9029
  const remove = options.remove ?? /^x-spam-/i;
7922
9030
  const lines2 = header === "" ? [] : header.split(/\r?\n/);
@@ -7941,15 +9049,15 @@ function rewriteMessage(source, headers = [], options = {}) {
7941
9049
  }
7942
9050
  }
7943
9051
  }
7944
- 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));
7945
9053
  const mbox = kept.length > 0 && kept[0][0].startsWith("From ") ? kept.shift() : [];
7946
9054
  const head = [...mbox, ...added, ...kept.map((field) => field.join(newline))].join(newline);
7947
- 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]);
7948
9056
  }
7949
- 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;
7950
9058
  var init_headers = __esm({
7951
9059
  "src/headers.js"() {
7952
- import_node_buffer8 = require("node:buffer");
9060
+ import_node_buffer9 = require("node:buffer");
7953
9061
  ENCODED_BYTES = 39;
7954
9062
  PLAIN_WORD = 64;
7955
9063
  ENCODED_LINE = 76;
@@ -8125,7 +9233,7 @@ async function* readJsonl(file, options = {}) {
8125
9233
  }
8126
9234
  async function* walk(directory) {
8127
9235
  const entries = await import_promises.default.readdir(directory, { withFileTypes: true });
8128
- 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)));
8129
9237
  for (const entry of entries) {
8130
9238
  if (SKIP.has(entry.name) || entry.name.startsWith(".")) {
8131
9239
  continue;
@@ -8150,7 +9258,7 @@ async function* readMessages(source) {
8150
9258
  const handle = await import_promises.default.open(file);
8151
9259
  let head;
8152
9260
  try {
8153
- 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);
8154
9262
  head = buffer.subarray(0, bytesRead).toString("latin1");
8155
9263
  } finally {
8156
9264
  await handle.close();
@@ -8162,10 +9270,10 @@ async function* readMessages(source) {
8162
9270
  }
8163
9271
  }
8164
9272
  }
8165
- 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;
8166
9274
  var init_sources = __esm({
8167
9275
  "src/sources.js"() {
8168
- import_node_buffer9 = require("node:buffer");
9276
+ import_node_buffer10 = require("node:buffer");
8169
9277
  import_node_fs3 = require("node:fs");
8170
9278
  import_promises = __toESM(require("node:fs/promises"), 1);
8171
9279
  import_node_path2 = __toESM(require("node:path"), 1);
@@ -8339,8 +9447,8 @@ function sessionFromQuery(query) {
8339
9447
  return session;
8340
9448
  }
8341
9449
  function sameToken(given, expected) {
8342
- const a = import_node_buffer10.Buffer.from(String(given));
8343
- 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));
8344
9452
  return a.length === b.length && (0, import_node_crypto5.timingSafeEqual)(a, b);
8345
9453
  }
8346
9454
  function readBody(request, limit) {
@@ -8360,7 +9468,7 @@ function readBody(request, limit) {
8360
9468
  reject(error);
8361
9469
  return;
8362
9470
  }
8363
- resolve(import_node_buffer10.Buffer.concat(chunks));
9471
+ resolve(import_node_buffer11.Buffer.concat(chunks));
8364
9472
  });
8365
9473
  request.on("error", reject);
8366
9474
  });
@@ -8375,7 +9483,7 @@ function createHttpServer(scanner, options = {}) {
8375
9483
  let active = 0;
8376
9484
  const server = import_node_http2.default.createServer(async (request, response) => {
8377
9485
  const send = (status, body, headers = {}) => {
8378
- const isBuffer = import_node_buffer10.Buffer.isBuffer(body);
9486
+ const isBuffer = import_node_buffer11.Buffer.isBuffer(body);
8379
9487
  response.writeHead(status, { "content-type": isBuffer ? "message/rfc822" : "application/json; charset=utf-8", "cache-control": "no-store", ...headers });
8380
9488
  response.end(isBuffer ? body : `${JSON.stringify(body)}
8381
9489
  `);
@@ -8448,14 +9556,14 @@ function createTcpServer(scanner, options = {}) {
8448
9556
  timeout = 6e4,
8449
9557
  maxConnections = MAX_CONNECTIONS
8450
9558
  } = options;
8451
- const server = import_node_net4.default.createServer({ allowHalfOpen: true }, (socket) => {
9559
+ const server = import_node_net5.default.createServer({ allowHalfOpen: true }, (socket) => {
8452
9560
  const chunks = [];
8453
9561
  let size = 0;
8454
9562
  socket.setTimeout(timeout, () => socket.destroy());
8455
9563
  const onEnd = async () => {
8456
9564
  socket.setTimeout(0);
8457
9565
  try {
8458
- const result = await scanner.scan(import_node_buffer10.Buffer.concat(chunks));
9566
+ const result = await scanner.scan(import_node_buffer11.Buffer.concat(chunks));
8459
9567
  socket.end(json ? `${JSON.stringify(serializeResult(result))}
8460
9568
  ` : `${result.isSpam ? "SPAM" : "HAM"} ${result.score.toFixed(1)}/${result.threshold.toFixed(1)} ${result.tests.map((test) => test.name).join(",")}
8461
9569
  `);
@@ -8484,13 +9592,13 @@ function createTcpServer(scanner, options = {}) {
8484
9592
  server.maxConnections = maxConnections;
8485
9593
  return server;
8486
9594
  }
8487
- 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;
8488
9596
  var init_server = __esm({
8489
9597
  "src/server.js"() {
8490
- import_node_buffer10 = require("node:buffer");
9598
+ import_node_buffer11 = require("node:buffer");
8491
9599
  import_node_crypto5 = require("node:crypto");
8492
9600
  import_node_http2 = __toESM(require("node:http"), 1);
8493
- import_node_net4 = __toESM(require("node:net"), 1);
9601
+ import_node_net5 = __toESM(require("node:net"), 1);
8494
9602
  init_headers();
8495
9603
  init_version();
8496
9604
  MAX_MESSAGE_SIZE = 25 * 1024 * 1024;
@@ -8499,12 +9607,12 @@ var init_server = __esm({
8499
9607
  });
8500
9608
 
8501
9609
  // src/milter.js
8502
- function packet(command, data2 = import_node_buffer11.Buffer.alloc(0)) {
8503
- const payload = import_node_buffer11.Buffer.isBuffer(data2) ? data2 : import_node_buffer11.Buffer.from(data2, "latin1");
8504
- 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);
8505
9613
  header.writeUInt32BE(payload.length + 1);
8506
9614
  header.write(command, 4, "latin1");
8507
- return import_node_buffer11.Buffer.concat([header, payload]);
9615
+ return import_node_buffer12.Buffer.concat([header, payload]);
8508
9616
  }
8509
9617
  function cstrings(data2) {
8510
9618
  const parts = data2.toString("latin1").split("\0");
@@ -8514,19 +9622,19 @@ function cstrings(data2) {
8514
9622
  return parts;
8515
9623
  }
8516
9624
  function cstring(value) {
8517
- return import_node_buffer11.Buffer.from(`${value}\0`, "latin1");
9625
+ return import_node_buffer12.Buffer.from(`${value}\0`, "latin1");
8518
9626
  }
8519
9627
  function address(value) {
8520
9628
  const text = String(value ?? "").trim();
8521
9629
  const match = /^<?([^<>]*)>?$/.exec(text);
8522
9630
  return match ? match[1] : text;
8523
9631
  }
8524
- 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;
8525
9633
  var init_milter = __esm({
8526
9634
  "src/milter.js"() {
8527
- import_node_buffer11 = require("node:buffer");
9635
+ import_node_buffer12 = require("node:buffer");
8528
9636
  import_node_events = require("node:events");
8529
- import_node_net5 = __toESM(require("node:net"), 1);
9637
+ import_node_net6 = __toESM(require("node:net"), 1);
8530
9638
  init_headers();
8531
9639
  init_auth();
8532
9640
  init_server();
@@ -8644,7 +9752,7 @@ var init_milter = __esm({
8644
9752
  if (this.buffered < this.needed) {
8645
9753
  return;
8646
9754
  }
8647
- 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);
8648
9756
  this.needed = 4;
8649
9757
  while (buffer.length >= 4) {
8650
9758
  const length = buffer.readUInt32BE(0);
@@ -8689,7 +9797,7 @@ var init_milter = __esm({
8689
9797
  const protocol = data2.readUInt32BE(8);
8690
9798
  const wanted = ACTIONS.ADDHDRS | ACTIONS.CHGHDRS | ACTIONS.QUARANTINE;
8691
9799
  this.leadingSpace = Boolean(protocol & PROTOCOL.HDR_LEADSPC);
8692
- const reply2 = import_node_buffer11.Buffer.alloc(12);
9800
+ const reply2 = import_node_buffer12.Buffer.alloc(12);
8693
9801
  reply2.writeUInt32BE(Math.min(version, 6), 0);
8694
9802
  reply2.writeUInt32BE(actions & wanted, 4);
8695
9803
  reply2.writeUInt32BE(protocol & (PROTOCOL.HDR_LEADSPC | PROTOCOL.NOUNKNOWN), 8);
@@ -8754,7 +9862,7 @@ var init_milter = __esm({
8754
9862
  if (this.truncated || this.size + data2.length > options.maxSize) {
8755
9863
  this.truncated = true;
8756
9864
  } else {
8757
- this.body.push(import_node_buffer11.Buffer.from(data2));
9865
+ this.body.push(import_node_buffer12.Buffer.from(data2));
8758
9866
  this.size += data2.length;
8759
9867
  }
8760
9868
  this.send(RESPONSES.CONTINUE);
@@ -8789,7 +9897,7 @@ var init_milter = __esm({
8789
9897
  /** @returns {Buffer} */
8790
9898
  rawMessage() {
8791
9899
  const head = this.headers.map(([name, value]) => `${name}:${this.leadingSpace || value.startsWith(" ") || value.startsWith(" ") ? "" : " "}${value}`).join("\r\n");
8792
- 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
8793
9901
  \r
8794
9902
  ` : "\r\n", "latin1"), ...this.body]);
8795
9903
  }
@@ -8800,9 +9908,9 @@ var init_milter = __esm({
8800
9908
  const key = name.toLowerCase();
8801
9909
  counts.set(key, (counts.get(key) || 0) + 1);
8802
9910
  if (key.startsWith("x-spam-")) {
8803
- const index = import_node_buffer11.Buffer.alloc(4);
9911
+ const index = import_node_buffer12.Buffer.alloc(4);
8804
9912
  index.writeUInt32BE(counts.get(key));
8805
- 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("")]));
8806
9914
  }
8807
9915
  }
8808
9916
  }
@@ -8825,7 +9933,7 @@ var init_milter = __esm({
8825
9933
  }
8826
9934
  this.server.report(error);
8827
9935
  this.removeForgedHeaders();
8828
- 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`)]));
8829
9937
  this.send(RESPONSES.CONTINUE);
8830
9938
  this.resetMessage();
8831
9939
  return;
@@ -8846,15 +9954,15 @@ var init_milter = __esm({
8846
9954
  headers.unshift(["Authentication-Results", formatAuthResultsHeader(result.results.authentication, options.hostname)]);
8847
9955
  }
8848
9956
  for (const [name, value] of headers) {
8849
- 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"))]));
8850
9958
  }
8851
9959
  if (result.isSpam && options.subjectTag) {
8852
9960
  const subject = this.headers.find(([name]) => name.toLowerCase() === "subject");
8853
9961
  const value = taggedSubject(options.subjectTag, subject ? subject[1].trim() : "", "\n");
8854
9962
  if (value !== null) {
8855
- const index = import_node_buffer11.Buffer.alloc(4);
9963
+ const index = import_node_buffer12.Buffer.alloc(4);
8856
9964
  index.writeUInt32BE(1);
8857
- 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"))]));
8858
9966
  }
8859
9967
  }
8860
9968
  if (result.action === "reject" && options.reject) {
@@ -8905,7 +10013,7 @@ var init_milter = __esm({
8905
10013
  throw new RangeError(`rejectCode must be a 4xx or 5xx SMTP code, not ${this.options.rejectCode}`);
8906
10014
  }
8907
10015
  this.sockets = /* @__PURE__ */ new Set();
8908
- this.server = import_node_net5.default.createServer((socket) => {
10016
+ this.server = import_node_net6.default.createServer((socket) => {
8909
10017
  this.sockets.add(socket);
8910
10018
  socket.on("close", () => this.sockets.delete(socket));
8911
10019
  return new MilterSession(socket, this);
@@ -8981,7 +10089,7 @@ function reply(code, text, headers = [], body = null) {
8981
10089
  lines2.push(`Content-length: ${body.length}`);
8982
10090
  }
8983
10091
  lines2.push(...headers.map(([name, value]) => `${name}: ${value}`), "", "");
8984
- 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]);
8985
10093
  }
8986
10094
  function report(result) {
8987
10095
  const lines2 = [
@@ -9026,11 +10134,11 @@ async function answer(scanner, request, message, options) {
9026
10134
  return reply(EX_OK, "EX_OK", [verdict]);
9027
10135
  }
9028
10136
  case "SYMBOLS": {
9029
- 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(",")));
9030
10138
  }
9031
10139
  case "REPORT":
9032
10140
  case "REPORT_IFSPAM": {
9033
- 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));
9034
10142
  }
9035
10143
  default: {
9036
10144
  const rewritten = rewriteMessage(message, spamHeaders(result, { version: VERSION }), { subjectTag: result.isSpam ? options.subjectTag : null });
@@ -9038,7 +10146,7 @@ async function answer(scanner, request, message, options) {
9038
10146
  return reply(EX_OK, "EX_OK", [verdict], rewritten);
9039
10147
  }
9040
10148
  const { header, newline } = splitMessage(rewritten);
9041
- 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"));
9042
10150
  }
9043
10151
  }
9044
10152
  }
@@ -9052,8 +10160,8 @@ function createSpamdServer(scanner, options = {}) {
9052
10160
  maxConnections: MAX_CONNECTIONS,
9053
10161
  ...options
9054
10162
  };
9055
- const server = import_node_net6.default.createServer({ allowHalfOpen: true }, (socket) => {
9056
- 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);
9057
10165
  const chunks = [];
9058
10166
  let size = 0;
9059
10167
  let request = null;
@@ -9079,7 +10187,7 @@ function createSpamdServer(scanner, options = {}) {
9079
10187
  return;
9080
10188
  }
9081
10189
  if (!request) {
9082
- head = import_node_buffer12.Buffer.concat([head, chunk2]);
10190
+ head = import_node_buffer13.Buffer.concat([head, chunk2]);
9083
10191
  const end = head.indexOf("\r\n\r\n");
9084
10192
  if (end === -1) {
9085
10193
  if (head.length > 64 * 1024) {
@@ -9114,7 +10222,7 @@ function createSpamdServer(scanner, options = {}) {
9114
10222
  chunks.push(chunk2);
9115
10223
  size += chunk2.length;
9116
10224
  if (request.length === null ? ["PING", "SKIP"].includes(request.command) : size >= request.length) {
9117
- 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));
9118
10226
  } else if (size > settings.maxSize) {
9119
10227
  fail(EX_DATAERR, `Message larger than ${settings.maxSize} bytes`);
9120
10228
  }
@@ -9126,7 +10234,7 @@ function createSpamdServer(scanner, options = {}) {
9126
10234
  if (!request) {
9127
10235
  fail(EX_PROTOCOL, "Incomplete request");
9128
10236
  } else if (request.length === null) {
9129
- finish(import_node_buffer12.Buffer.concat(chunks));
10237
+ finish(import_node_buffer13.Buffer.concat(chunks));
9130
10238
  } else {
9131
10239
  fail(EX_PROTOCOL, `Message shorter than its Content-length of ${request.length} bytes`);
9132
10240
  }
@@ -9137,11 +10245,11 @@ function createSpamdServer(scanner, options = {}) {
9137
10245
  server.maxConnections = settings.maxConnections;
9138
10246
  return server;
9139
10247
  }
9140
- 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;
9141
10249
  var init_spamd = __esm({
9142
10250
  "src/spamd.js"() {
9143
- import_node_buffer12 = require("node:buffer");
9144
- import_node_net6 = __toESM(require("node:net"), 1);
10251
+ import_node_buffer13 = require("node:buffer");
10252
+ import_node_net7 = __toESM(require("node:net"), 1);
9145
10253
  init_headers();
9146
10254
  init_server();
9147
10255
  init_version();
@@ -9353,21 +10461,21 @@ async function withTimeout(promise, ms, fallback) {
9353
10461
  }
9354
10462
  }
9355
10463
  async function toBuffer(source) {
9356
- if (import_node_buffer13.Buffer.isBuffer(source)) {
10464
+ if (import_node_buffer14.Buffer.isBuffer(source)) {
9357
10465
  return source;
9358
10466
  }
9359
10467
  if (typeof source === "string") {
9360
- return import_node_buffer13.Buffer.from(source, "utf8");
10468
+ return import_node_buffer14.Buffer.from(source, "utf8");
9361
10469
  }
9362
10470
  if (source instanceof Uint8Array) {
9363
- return import_node_buffer13.Buffer.from(source);
10471
+ return import_node_buffer14.Buffer.from(source);
9364
10472
  }
9365
10473
  if (source && typeof source[Symbol.asyncIterator] === "function") {
9366
10474
  const chunks = [];
9367
10475
  for await (const chunk2 of source) {
9368
- 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));
9369
10477
  }
9370
- return import_node_buffer13.Buffer.concat(chunks);
10478
+ return import_node_buffer14.Buffer.concat(chunks);
9371
10479
  }
9372
10480
  throw new TypeError("A message must be a Buffer, a string, a Uint8Array or a readable stream");
9373
10481
  }
@@ -9442,12 +10550,12 @@ function fromDomain(mail) {
9442
10550
  function withHeader(raw) {
9443
10551
  const first = raw.subarray(0, 1e3).toString("latin1");
9444
10552
  const headerless = raw.length > 0 && !/^(?:[!-9;-~]+[ \t]*:|From |[\r\n])/.test(first);
9445
- 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;
9446
10554
  }
9447
- 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;
9448
10556
  var init_src = __esm({
9449
10557
  "src/index.js"() {
9450
- import_node_buffer13 = require("node:buffer");
10558
+ import_node_buffer14 = require("node:buffer");
9451
10559
  import_promises2 = require("node:fs/promises");
9452
10560
  import_node_util2 = require("node:util");
9453
10561
  init_attachments();
@@ -9456,6 +10564,7 @@ var init_src = __esm({
9456
10564
  init_classifier();
9457
10565
  init_dnsbl();
9458
10566
  init_html();
10567
+ init_links();
9459
10568
  init_homograph();
9460
10569
  init_is_arbitrary();
9461
10570
  init_language();
@@ -9498,6 +10607,19 @@ var init_src = __esm({
9498
10607
  cloudflare: true,
9499
10608
  adult: true,
9500
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,
9501
10623
  // Characters of text read for links (twice as many of HTML): more than
9502
10624
  // for the classifier (maxLength), as a link anywhere in a message may be
9503
10625
  // followed; a longer message sets results.linksTruncated.
@@ -9699,7 +10821,10 @@ var init_src = __esm({
9699
10821
  async scanFile(file, options) {
9700
10822
  return this.scan(await (0, import_promises2.readFile)(file), options);
9701
10823
  }
9702
- 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;
9703
10828
  const phishing = [];
9704
10829
  const homographs = [];
9705
10830
  const seenHosts = /* @__PURE__ */ new Set();
@@ -9755,7 +10880,11 @@ var init_src = __esm({
9755
10880
  for (const host of hosts) {
9756
10881
  lookalike(host, { source: "text" });
9757
10882
  }
9758
- 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])];
9759
10888
  const firsts = /* @__PURE__ */ new Map();
9760
10889
  for (const host of ordered) {
9761
10890
  const domain = registrableDomain(host);
@@ -9767,6 +10896,7 @@ var init_src = __esm({
9767
10896
  const domains = [...new Set(checked.map((host) => registrableDomain(host)))];
9768
10897
  const blocked = [];
9769
10898
  let answered = 0;
10899
+ const linkTimeout = Number(config.phishing.timeout) > 0 ? Number(config.phishing.timeout) : config.timeout;
9770
10900
  const cloudflare = async () => {
9771
10901
  await withTimeout(Promise.all(checked.map(async (host) => {
9772
10902
  const found2 = await this.dns.checkCloudflare([host], { adult: config.phishing.adult });
@@ -9774,12 +10904,12 @@ var init_src = __esm({
9774
10904
  if (!found2.unanswered?.length) {
9775
10905
  answered++;
9776
10906
  }
9777
- })), config.timeout, null);
10907
+ })), linkTimeout, null);
9778
10908
  return { found: [...blocked], unanswered: checked.length - answered };
9779
10909
  };
9780
10910
  const [cloudflareResult, listed] = await Promise.all([
9781
10911
  config.phishing.cloudflare && checked.length > 0 ? cloudflare() : { found: [], unanswered: 0 },
9782
- 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, []) : []
9783
10913
  ]);
9784
10914
  for (const { host, category } of cloudflareResult.found) {
9785
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` }));
@@ -9795,7 +10925,8 @@ var init_src = __esm({
9795
10925
  return {
9796
10926
  phishing,
9797
10927
  homographs,
9798
- 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),
9799
10930
  timedOutHosts: cloudflareResult.unanswered
9800
10931
  };
9801
10932
  }
@@ -9967,10 +11098,17 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
9967
11098
  styled: plainObfuscation.styled || shownObfuscation.styled
9968
11099
  };
9969
11100
  const unopened = [];
9970
- 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;
9971
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));
9972
11110
  const [links, authentication, checkedReputation, dnsbl, virusScan, toxicity, nsfw] = await Promise.all([
9973
- this.checkLinks(checkedLinks, config, extracted.hosts, fromDomain(mail)),
11111
+ this.checkLinks(checkedLinks, config, extracted.hosts, { from: fromDomain(mail), carried }),
9974
11112
  config.authenticationResults && typeof config.authenticationResults === "object" ? normalizeAuthOutput(config.authenticationResults) : config.authentication && session.remoteAddress ? withTimeout(authenticate(raw, {
9975
11113
  timeout: config.timeout,
9976
11114
  ...typeof config.authentication === "object" ? config.authentication : {},
@@ -10098,6 +11236,14 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
10098
11236
  // Whether the message has more text than phishing.maxLength, whose
10099
11237
  // links were not read.
10100
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),
10101
11247
  idnHomographAttack: {
10102
11248
  detected: links.homographs.length > 0,
10103
11249
  domains: links.homographs,
@@ -10109,6 +11255,9 @@ ${visibleText(html2.slice(0, config.maxLength * 2)).text}`, { maxLength: config.
10109
11255
  language: extracted.language,
10110
11256
  tokens: extracted.words,
10111
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,
10112
11261
  version: VERSION,
10113
11262
  metrics: { totalTime: time }
10114
11263
  };