Spamworldpro Mini Shell
Spamworldpro


Server : Apache/2.4.62 (Unix) OpenSSL/1.0.2k-fips
System : Linux server1.richineiserver.com 3.10.0-1160.119.1.el7.x86_64 #1 SMP Tue Jun 4 14:43:51 UTC 2024 x86_64
User : fdshops ( 1003)
PHP Version : 8.2.21
Disable Function : NONE
Directory :  /lib/python2.7/site-packages/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //lib/python2.7/site-packages/spf.pyc
�
+f�_c
@s2	ddlmZdZdZdZdZdZddlZddlZddl	Z	ddl
Z
ddlZyddlj
ZWnddlZnXddlZddlmZydd	lmZWn!ek
r�dd	lmZnXyddlZWnek
red
�nXedd�Zed
d�ZyfddlZddlZddlZeej d�r�dej _!ej j!ej j"d<neZ#Wnmddl$Z$ee$j%d�r�de$j%_!de$j%j&d<e$j'j(j)e$j'j(_*ne$j+�eZ#nXej,dej-�Z.ej,dej-�Z/dZ0ej,e0�Z1ej,d�Z2ej,d�Z3ej,d�Z4ej,d�Z5dj6dgd�Z7ej,e7d�Z8ej,de0ej-�Z9ej,didd6ej-�Z:ej,d id!e7d"6d#d$6ej-�Z;id%d&6d%d'6Z<id(d)6d*d+6d,d-6d.d/6d(d(6d*d*6d0d06d1d26d,d,6d.d.6d3d36d4d46d5d56d6d66d0d76Z=i
d8d(6d9d*6d:d06d;d16d<d.6d=d,6d>d36d?d46d@d56dAd66Z>e?Z@dBZAdCZBdDZCdDZDdDZEdDZFdZGdZHdEZIdFdGdHdIdJdKdLdMfZJidHdN6dKdO6dKdP6dLdQ6dMdR6ZKdSeLfdT��YZMdUeLfdV��YZNdWeLfdX��YZOe?e?eHePddY�ZQe?e?ePdZ�ZRd[eSfd\��YZTd]�ZUd^�ZVd_�ZWd`�ZXda�ZYdb�ZZe?dc�Z[e?dd�Z\ej]dedEkrRdf�Z^n	dg�Z^dh�Z_e`dikr.	ddlaZay/eajaejbdjdkdldmdng�\ZcZbWn=eajdk
r�Zeeefee��ee�ejgdE�nXePZheZixoecD]g\ZjZkejdodpfkr%eZhnejdqdrfkrFelek�Zinejdsdtfkreee�nq�Wemeb�dekr�ee�e_�n�emeb�djkr(yBeTdudvd'dwdxd7dye	jn��Zoeeojpebde��Wn?eNk
rZqedzeq�n eOk
r$Zqed{eq�nXnemeb�d|kreb\ZrZsZteTduerd'esdxetdye	jn�dmehdnei�ZoeojR�Zued}eueojv�euded3kr�ed~eojw�eojv�neojxo�eojxjyr�edeojxjy�neojzrxeojzD]Z{ee{�qWnnemeb�dkr!	ebdj\ZrZsZteTduerd'esdxetdye	jn�dnePdmeh�ZoeojRebde�Zued}eueojv�euded3kr�ed~eojw�eojv�neojxo�eojxjyr�edeojxjy�neojzr	xeojzD]Z{ee{�q	Wnn
ee�ndS(�i����(tprint_functions,Terence Way, Stuart Gathman, Scott Kittermanspyspf@openspf.orgs2.0.14tspfs�To check an incoming mail request:
    % python spf.py [-v] {ip} {sender} {helo}
    % python spf.py 69.55.226.139 tway@optsw.com mx1.wayforward.net

To test an SPF record:
    % python spf.py [-v] "v=spf1..." {ip} {sender} {helo}
    % python spf.py "v=spf1 +mx +ip4:10.0.0.1 -all" 10.0.0.1 tway@foo.com a    

To fetch an SPF record:
    % python spf.py {domain}
    % python spf.py wayforward.net

To test this script (and to output this usage message):
    % python spf.py
N(treduce(tMessages;ipaddr module required: http://code.google.com/p/ipaddr-py/icCs�yutj|d|d|�}|j�}|jdtkr|dkrXtd��ny1tj|d|ddd|�}|j�}Wn,tjk
r�}tdt|���nX|jd	d
kr|jd	dkrt	d|jd
dt|jd	���qng|j
D]$}|d|df|df^qg|jD]$}|d|df|df^qKSWn|tk
r�}tdt|���nTt	k
r�}tdt|���n,tjk
r�}tdt|���nXdS(NtqtypettimeoutttcisNDNS: Truncated UDP Reply, SPF records should fit in a UDP packet, retrying TCPtprotocolttcpsDNS: TCP Fallback error: trcodeiisError: tstatuss	  RCODE: tnamettypenametdatasDNS (
tDNSt
DnsRequesttreqtheadertTruetAmbiguityWarningtDNSErrort	TempErrortstrtIOErrortanswerst
additionaltAttributeError(RRtstrictRRtresptxta((s'/usr/lib/python2.7/site-packages/spf.pytDNSLookup_pydnsWs.!&2.4icCs�g}ytjj||�}x�|D]�}|dksC|dkrb|j||f|jf�q%|dkr�|j||f|j|jff�q%|dkr�|j||f|jjt	�f�q%|dks�|dkr%|j||f|j
f�q%q%WWn�tjjk
rnstjjk
r5n]tj
jk
rc}tdt|���n/tjjk
r�}tdt|���nX|S(NtAtAAAAtMXtPTRtTXTtSPFsDNS (tdnstresolvertquerytappendtaddresst
preferencetexchangettargettto_textRtstringstNoAnswertNXDOMAINt	exceptiontTimeoutRRt
NoNameservers(RRttcpfallbackRtretValRtrdataR((s'/usr/lib/python2.7/site-packages/spf.pytDNSLookup_dnspythonxs*
(('R%ics^v=spf1$|^v=spf1 s^([a-z][a-z0-9_\-\.]*)=s%(%|_|-|(\{[^\}]*\}))s(?<!%)%[^{%_-]|%$s([0-9]*)(r?)([^0-9a-zA-Z]*)s//(0|[1-9]\d*)$s/(0|[1-9]\d*)$s\.s%(?:\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])it$sA\.(?:[0-9a-z]*[a-z][0-9a-z]*|[0-9a-z]+-[0-9a-z-]*[0-9a-z])\.?$|%ss%(atext)s+([.]%(atext)s+)*$s[0-9a-z!#$%&'*+/=?^_`{}|~-]tatexts�(?:%(hex4)s:){6}%(ls32)s$|::(?:%(hex4)s:){5}%(ls32)s$|(?:%(hex4)s)?::(?:%(hex4)s:){4}%(ls32)s$|(?:(?:%(hex4)s:){0,1}%(hex4)s)?::(?:%(hex4)s:){3}%(ls32)s$|(?:(?:%(hex4)s:){0,2}%(hex4)s)?::(?:%(hex4)s:){2}%(ls32)s$|(?:(?:%(hex4)s:){0,3}%(hex4)s)?::%(hex4)s:%(ls32)s$|(?:(?:%(hex4)s:){0,4}%(hex4)s)?::%(ls32)s$|(?:(?:%(hex4)s:){0,5}%(hex4)s)?::%(hex4)s$|(?:(?:%(hex4)s:){0,6}%(hex4)s)?::$s"(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|%s)tls32s
[0-9a-f]{1,4}thex4t.tltstpasst+tfailt-tneutralt?tsoftfailt~t	permerrort	temperrorterrortnonetlocalttrustedt	ambiguoustunknownssender SPF authorizedsSPF fail - not authorizedspermanent error in processings!temporary DNS error in processings)domain owner discourages use of this hosts#access neither permitted nor deniedts!No SPF result due to local policys$No SPF check - trusted-forwarder.orgsNo error, but results may varysv=spf1 a/24 mx/24 ptrs.v=spf1 ?include:spf.trusted-forwarder.org -alli
iRtmxtptrtexiststincludetip4tip6talltprttiptipv4tipv6sall.RcBs&eZdZddd�Zd�ZRS(sSPF Warning - ambiguous resultscCs2tj|||�||_||_||_dS(N(t	Exceptiont__init__tmsgtmechtext(tselfR^R_R`((s'/usr/lib/python2.7/site-packages/spf.pyR]s		cCs$|jrd|j|jfS|jS(Ns%s: %s(R_R^(Ra((s'/usr/lib/python2.7/site-packages/spf.pyt__str__s	N(t__name__t
__module__t__doc__tNoneR]Rb(((s'/usr/lib/python2.7/site-packages/spf.pyRsRcBs&eZdZddd�Zd�ZRS(sTemporary SPF errorcCs8tj|||�t|�|_||_||_dS(N(R\R]RR^R_R`(RaR^R_R`((s'/usr/lib/python2.7/site-packages/spf.pyR]s	cCs$|jrd|j|jfS|jS(Ns%s: %s(R_R^(Ra((s'/usr/lib/python2.7/site-packages/spf.pyRbs	N(RcRdReRfR]Rb(((s'/usr/lib/python2.7/site-packages/spf.pyRst	PermErrorcBs&eZdZddd�Zd�ZRS(sPermanent SPF errorcCs2tj|||�||_||_||_dS(N(R\R]R^R_R`(RaR^R_R`((s'/usr/lib/python2.7/site-packages/spf.pyR]s		cCs$|jrd|j|jfS|jS(Ns%s: %s(R_R^(Ra((s'/usr/lib/python2.7/site-packages/spf.pyRb$s	N(RcRdReRfR]Rb(((s'/usr/lib/python2.7/site-packages/spf.pyRgscCsRtd|d|d|d|d|d|d|d|�j�\}}	}
||
fS(	s&Test an incoming MAIL FROM:<s>, from a client with ip address i.
    h is the HELO/EHLO domain name.  This is the RFC4408/7208 compliant
    pySPF2.0 interface.  The interface returns an SPF result and explanation
    only.  SMTP response codes are not returned since neither RFC 4408 nor RFC
    7208 does specify receiver policy.  Applications updated for RFC 4408 and
    RFC 7208 should use this interface.  The maximum time, in seconds, this
    function is allowed to run before a TempError is returned is controlled by
    querytime.  When set to 0 the timeout parameter (default 20 seconds)
    controls the time allowed for each DNS lookup.  When set to a non-zero
    value, it total time for all processing related to the SPF check is
    limited to querytime (default 20 seconds as recommended in RFC 7208,
    paragraph 4.6.4).

    Returns (result, explanation) where result in
    ['pass', 'permerror', 'fail', 'temperror', 'softfail', 'none', 'neutral' ].

    Example:
    #>>> check2(i='61.51.192.42', s='liukebing@bcc.com', h='bmsi.com')

    tiR?thRLtreceiverRtverboset	querytime(R(tcheck(RhR?RiRLRjRRkRltrest_texp((s'/usr/lib/python2.7/site-packages/spf.pytcheck2)s*c	
Cswtd|d|d|d|d|d|�j�\}}}|dkrQd}n|d	krj|d
kn|||fS(s?Test an incoming MAIL FROM:<s>, from a client with ip address i.
    h is the HELO/EHLO domain name.  This is the pre-RFC SPF Classic interface.
    Applications written for pySPF 1.6/1.7 can use this interface to allow
    pySPF2 to be a drop in replacement for older versions.  With the exception
    of result codes, performance in RFC 4408 compliant.

    Returns (result, code, explanation) where result in
    ['pass', 'unknown', 'fail', 'error', 'softfail', 'none', 'neutral' ].

    Example:
    #>>> check(i='61.51.192.42', s='liukebing@bcc.com', h='bmsi.com')

    RhR?RiRLRjRkRHROttempfailRJ(R(Rm(	RhR?RiRLRjRkRntcodeRp((s'/usr/lib/python2.7/site-packages/spf.pyRmBs$	
R(cBs�eZdZd'd'eeedd�Zd�Zd�Z	d�Z
d�Zd�Ze
d�Zd'd	�Zd
�Zd�Zd�Zd
�Zd�Zd�Zd�Zed�Zd�Zded�Zd�Zdd�Zd�Zd�Zid'd(6d'd)6d'd*6d'd+6d'd,6d'd-6d'd.6d'd/6Zd'ed�Zd �Z d!�Z!d"�Z"d#�Z#d'd$d'd%�Z$d&�Z%RS(0sjA query object keeps the relevant information about a single SPF
    query:

    i: ip address of SMTP client in dotted notation
    s: sender declared in MAIL FROM:<>
    l: local part of sender s
    d: current domain, initially domain part of sender s
    h: EHLO/HELO domain
    v: 'in-addr' for IPv4 clients and 'ip6' for IPv6 clients
    t: current timestamp
    p: SMTP client domain name
    o: domain part of sender s
    r: receiver
    c: pretty ip address (different from i for IPv6)

    This is also, by design, the same variables used in SPF macro
    expansion.

    Also keeps cache: DNS cache.  
    ic

Csd|||_|_|r9|r9d||_d|_n	d|_t||�\|_|_tttj���|_	|j|_
d|_|r�||_
n	d|_
i|_tt�|_tt�|_||_d|_d|_||_||_|	|_|	dkr|	|_nd|_d|_|rE|j|�nt|_||_d|_dS(Nspostmaster@thelotmailfromROi( R?Ritidenttsplit_emailR>toRtintttimetttdRftptrtcachetdicttEXPLANATIONStdefexpstexpstlibspf_localtlookupstvoid_lookupsRRRlttimertipaddrtset_ipRtdefault_modifierRktauthserv(
RaRhR?RiRLRjRRRkRl((s'/usr/lib/python2.7/site-packages/spf.pyR]ms<

															cCstd|||f�dS(Ns%s: %s "%s"(tprint(RaR_R|R((s'/usr/lib/python2.7/site-packages/spf.pytlog�scCs�t|_|j�dkr-g|_t}n"|j�dkrQg|_t}n�tjjdkr�t|t�r�|j	d�}q�ny@yt
j|�|_Wn#t
k
r�t
j|�|_nXWn%tk
r�}tt|���nX|jjdkr7|jjr.t
j|jj�|_t}q=t}nt}t|j�|_|r�d|_d|_|jr�djt|jjjd	d
�j���|_nd|_n6d|_d
|_|jr�|jj|_nd|_dS(s$Set connect ip, and ip6 or ip4 mode.tlisttlist6itasciiiR!RVR=t:RPi�R sin-addri N(tFalsetiplisttlowerRtsystversion_infotmajort
isinstanceRtdecodet	ipaddresst
ip_addressR�Rt	IPAddresst
ValueErrorRgtversiontipv4_mappedtIPv4AddresstcR tvtjoinR�texplodedtreplacetupperRhtcidrmax(RaRhRVR((s'/usr/lib/python2.7/site-packages/spf.pyR��sF					
					3			cCs;|j}|j}x"dD]}|||<|||<qWdS(NRFRBRH(RFRBs	permerror(R�R�(RaRpR�R�Rh((s'/usr/lib/python2.7/site-packages/spf.pytset_default_explanation�s
		

cCs(|j}xdD]}|||<qWdS(NRFRBRH(ssoftfailsfails	permerror(R�(RaRpR�Rh((s'/usr/lib/python2.7/site-packages/spf.pytset_explanation�s	
cCs�|js�|j�}|s'd|_q�|j|krE|j|_q�d|j}x:|D]"}|j|�rY||_PqYqYW|d|_n|jS(NROR=i(R}tvalidated_ptrsR|tendswith(RaR}tsfxR|((s'/usr/lib/python2.7/site-packages/spf.pytgetp�s	

	cCs�tj|j�drdS|j}|j|�\}}}|dkr�|jrt|jjrt|jj\}}}nd\}}||_n|||fS(	s�Return a best guess based on a default SPF record.
    >>> q = query('1.2.3.4','','SUPERVISION1',receiver='example.com')
    >>> q.best_guess()[0]
    'none'
        i����RKi�RPRHRD(RKi�RP(RDi�(t	RE_TOPLABtsplitR|t
perm_errorRmR`(RaRtpeR~R�te((s'/usr/lib/python2.7/site-packages/spf.pyt
best_guess�s	cCs�g|_d|_d|_d|_i|_y�d|_|sv|j|j�}|j	rv|j
d|j|�qvn|r�|jdd�}n|jr�|r�t
||j�}n|j||jd�}|jr�||j_|j�n|SWn�tk
rG}|j|_|jr0|jj|j�ndddt|�fStk
r�}|jsk||_n|j|_|jr�|jj|j�ndd	d
t|�fSXdS(s�

    Returns (result, mta-status-code, explanation) where result
    in ['fail', 'softfail', 'neutral' 'permerror', 'pass', 'temperror', 'none']

    Examples:
    >>> q = query(s='strong-bad@email.example.com',
    ...           h='mx.example.org', i='192.0.2.3')
    >>> q.check(spf='v=spf1 ?all')
    ('neutral', 250, 'access neither permitted nor denied')

    >>> q.check(spf='v=spf1 redirect=controlledmail.com exp=_exp.controlledmail.com')
    ('fail', 550, 'SPF fail - not authorized')
    
    >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ?all moo')
    ('permerror', 550, 'SPF Permanent Error: Unknown mechanism found: moo')

    >>> q.check(spf='v=spf1 ip4:192.0.0.n ?all')
    ('permerror', 550, 'SPF Permanent Error: Invalid IP4 address: ip4:192.0.0.n')

    >>> q.check(spf='v=spf1 ip4:192.0.2.3 ip4:192.0.0.n ?all')
    ('permerror', 550, 'SPF Permanent Error: Invalid IP4 address: ip4:192.0.0.n')

    >>> q.check(spf='v=spf1 ip6:2001:db8:ZZZZ:: ?all')
    ('permerror', 550, 'SPF Permanent Error: Invalid IP6 address: ip6:2001:db8:ZZZZ::')

    >>> q.check(spf='v=spf1 =a ?all moo')
    ('permerror', 550, 'SPF Permanent Error: Unknown qualifier, RFC 4408 para 4.6.1, found in: =a')

    >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ~all')
    ('pass', 250, 'sender SPF authorized')

    >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 -all moo=')
    ('pass', 250, 'sender SPF authorized')

    >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 -all match.sub-domains_9=yes')
    ('pass', 250, 'sender SPF authorized')

    >>> q.strict = False
    >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 -all moo')
    ('permerror', 550, 'SPF Permanent Error: Unknown mechanism found: moo')
    >>> q.perm_error.ext
    ('pass', 250, 'sender SPF authorized')

    >>> q.strict = True
    >>> q.check(spf='v=spf1 ip4:192.1.0.0/16 moo -all')
    ('permerror', 550, 'SPF Permanent Error: Unknown mechanism found: moo')

    >>> q.check(spf='v=spf1 ip4:192.1.0.0/16 ~all')
    ('softfail', 250, 'domain owner discourages use of this host')

    >>> q.check(spf='v=spf1 -ip4:192.1.0.0/6 ~all')
    ('fail', 550, 'SPF fail - not authorized')

    # Assumes DNS available
    >>> q.check()
    ('none', 250, '')

    >>> q.check(spf='v=spf1 ip4:1.2.3.4 -a:example.net -all')
    ('fail', 550, 'SPF fail - not authorized')
    >>> q.libspf_local='ip4:192.0.2.3 a:example.org'
    >>> q.check(spf='v=spf1 ip4:1.2.3.4 -a:example.net -all')
    ('pass', 250, 'sender SPF authorized')

    >>> q.check(spf='v=spf1 ip4:1.2.3.4 -all exp=_exp.controlledmail.com')
    ('fail', 550, 'Controlledmail.com does not send mail from itself.')
    
    >>> q.check(spf='v=spf1 ip4:1.2.3.4 ?all exp=_exp.controlledmail.com')
    ('neutral', 250, 'access neither permitted nor denied')
        ittops
t RIi�sSPF Temporary Error: RHi&sSPF Permanent Error: N(R_RfR�t	mechanismR�toptionsR�tdns_spfR|RkR�R�R�tinsert_libspf_local_policytcheck1R`RR^tprobR)RRg(RaRtrcR((s'/usr/lib/python2.7/site-packages/spf.pyRm�sBF											cCs�|tkr3|jr$td��ntd��ny8z'|j|}|_|j||�SWd||_XWnLtk
r�}|j|_|j	r�|j	j
|j	�nddd|fSXdS(NsToo many levels of recursionRNisSPF Ambiguity Warning: %s(t
MAX_RECURSIONRtAssertionErrorRgR|tcheck0RR^R�R_R)(RaRtdomaint	recursionttmpR((s'/usr/lib/python2.7/site-packages/spf.pyR�ls		cGsZ|jrt|��n|jsSyt|��WqStk
rO}||_qSXn|jS(N(RRgR�(RaR^R((s'/usr/lib/python2.7/site-packages/spf.pyt
note_error�s		cCs2tj|�dr%td|��n|j|�S(svalidate and expand domain-speci����sInvalid domain found (use FQDN)(R�R�Rgtexpand(Ratarg((s'/usr/lib/python2.7/site-packages/spf.pyt
expand_domain�sc
Cs:|jd�r,|jd|�|d }nt||j�\}}}}|rtj|d�}|rv|d}qd}n|tkr�|jd|�t|}n|dkr�tj|�r�|jd	|�}d
}n|d!krk|d"kr�d}n|dkrt
d
|��n|d"kr2d}n|dkrPt
d|��n|jdkr�|}q�n|d
ks�tj|�r'|d
kr�|jd|�d
|}}n|d"k	r�t
d|��n|d"kr�d}n|dkrt
d
|��ntj|�s�t
d|��q�n�|dkr�|d"k	rQt
d|��n|d"krfd}n|dkr�t
d|��ntj|�s�t
d|��q�nB|d"k	s�|d"k	r�|t
kr�t
d|��q�n|j}|d#kr�|dkr|rt
d|��n|j|�}|sBt
d|��n|dkr�||jkr�|dkr{t
d|��nt
d|��q�n|||||fS|dkr�|jd�r�|jd|�n|t
kr�|||||fS|dt
kr|jd |�}n|jd|�}|||||fS($s
Parse and validate a mechanism.
    Returns mech,m,arg,cidrlength,result

    Examples:
    >>> q = query(s='strong-bad@email.example.com.',
    ...           h='mx.example.org', i='192.0.2.3')
    >>> q.validate_mechanism('A')
    ('A', 'a', 'email.example.com', 32, 'pass')

    >>> q = query(s='strong-bad@email.example.com',
    ...           h='mx.example.org', i='192.0.2.3')
    >>> q.validate_mechanism('A//64')
    ('A//64', 'a', 'email.example.com', 32, 'pass')

    >>> q.validate_mechanism('A/24//64')
    ('A/24//64', 'a', 'email.example.com', 24, 'pass')
    
    >>> q.validate_mechanism('?mx:%{d}/27')
    ('?mx:%{d}/27', 'mx', 'email.example.com', 27, 'neutral')

    >>> try: q.validate_mechanism('ip4:1.2.3.4/247')
    ... except PermError as x: print(x)
    Invalid IP4 CIDR length: ip4:1.2.3.4/247
    
    >>> try: q.validate_mechanism('ip4:1.2.3.4/33')
    ... except PermError as x: print(x)
    Invalid IP4 CIDR length: ip4:1.2.3.4/33

    >>> try: q.validate_mechanism('a:example.com:8080')
    ... except PermError as x: print(x)
    Invalid domain found (use FQDN): example.com:8080
    
    >>> try: q.validate_mechanism('ip4:1.2.3.444/24')
    ... except PermError as x: print(x)
    Invalid IP4 address: ip4:1.2.3.444/24
    
    >>> try: q.validate_mechanism('ip4:1.2.03.4/24')
    ... except PermError as x: print(x)
    Invalid IP4 address: ip4:1.2.03.4/24
    
    >>> try: q.validate_mechanism('-all:3030')
    ... except PermError as x: print(x)
    Invalid all mechanism format - only qualifier allowed with all: -all:3030

    >>> q.validate_mechanism('-mx:%%%_/.Clara.de/27')
    ('-mx:%%%_/.Clara.de/27', 'mx', '% /.Clara.de', 27, 'fail')

    >>> q.validate_mechanism('~exists:%{i}.%{s1}.100/86400.rate.%{d}')
    ('~exists:%{i}.%{s1}.100/86400.rate.%{d}', 'exists', '192.0.2.3.com.100/86400.rate.email.example.com', 32, 'softfail')

    >>> q.validate_mechanism('a:mail.example.com.')
    ('a:mail.example.com.', 'a', 'mail.example.com', 32, 'pass')

    >>> try: q.validate_mechanism('a:mail.example.com,')
    ... except PermError as x: print(x)
    Do not separate mechnisms with commas: a:mail.example.com,

    >>> q = query(s='strong-bad@email.example.com',
    ...           h='mx.example.org', i='2001:db8:1234::face:b007')    
    >>> q.validate_mechanism('A//64')
    ('A//64', 'a', 'email.example.com', 64, 'pass')

    >>> q.validate_mechanism('A/16')
    ('A/16', 'a', 'email.example.com', 128, 'pass')

    >>> q.validate_mechanism('A/16//48')
    ('A/16//48', 'a', 'email.example.com', 48, 'pass')

    t,s%Do not separate mechnisms with commasi����iiR@sUnknown mechanism foundRs'Use the ip4 mechanism for ip4 addressesRURQi sInvalid IP4 CIDR lengthi�sInvalid IP6 CIDR lengthRVsMissing IP4sDual CIDR not allowedsInvalid IP4 addresssInvalid IP6 addresssCIDR not allowedRRRSRTsimplicit exists not alloweds
empty domain:sinclude has trivial recursions include mechanism missing domainRWR�s>Invalid all mechanism format - only qualifier allowed with alls0Unknown qualifier, RFC 4408 para 4.6.1, found in(RsmxN(Rsmxsptrsexistssinclude(R�R�tparse_mechanismR|tRESULTStgettCOMMON_MISTAKEStRE_IP4tmatchRfRgR�tRE_IP6tALL_MECHANISMSR�R�tcount(RaR_tmR�t
cidrlengthtcidr6lengthtresultR((s'/usr/lib/python2.7/site-packages/spf.pytvalidate_mechanism�s�F

	
						
cCsB|sddtdfS|jd�}|dj�dkrq|jdkr`td|j��nddtdfSg|dD]}|r||^q|}|j}d$}d}g}g}x|D]}tj|�d}	t	|	�d	kr|j
|j|��q�n|	\}
}|
|krP|
d
kr9td|��n|j
d|
|�n|j
|
�|
d
kr�|s�td|��n|j|�}|r�y0|j|�}|r�|r�|j|�nWq�q�Xq�q�|
d
kr|j�|j|�}|s�td|��q�q�|
dkrz|jdkr@td��n|jr�|jr�|j|�}tj||�}q�q�|
dkr�|s�x0|jd�D]}
|
r�t|j|
<q�q�Wq�q�|j|	d�q�Wx$|D]�\}}	}}}|	dkr�|j�|j|�}|jr7|jd||�n|j|||d�\}}}|dkriPn|dkr�|j
d||�nd}q�q�|	dkr�Pq�|	dkr�|j�y&t	|j|d��dkr�PnWqktk
r�qkXq�|	dkr9|j�|j|j||j�|�rkPqkq�|	dkrq|j�|j|j|�|�rkPqkq�|	dkr�|j dkrky|j|g|�r�PnWq�t!j"k
r�td|��q�Xqkq�|	dkr9|j dkrky|j|g|�rPnWq6t!j"k
r2td|��q6Xqkq�|	d kr�|j�t#|j$�|�rkPqkq�q�W|r�|j|�}|s�td!|��n|jr�|jd
||�n|s�t%|j&�|_i|_n|j|||�S|}d$}|s||_'n|d"kr-|d#||fS|d||fSd$S(%s�Test this query information against SPF text.

        Returns (result, mta-status-code, explanation) where
        result in ['fail', 'unknown', 'pass', 'none']
        RKi�R�isv=spf1isInvalid SPF record inRDitredirects"redirect= MUST appear at most onces%s= MUST appear at most onceRpsexp has empty domain-spec:sredirect has empty domain:tdefaults"The default= modifier is obsolete.topR=RTR@s+No valid SPF record for included domain: %sRWRSR RRQRUsin-addrssyntax errorRVRRs!redirect domain has no SPF recordRBi&N((R�R�R�RRR|R�RftRE_MODIFIERtlenR)R�RgR�R�tget_explanationR�t
check_lookupsR�R�R�R�RR�R�RkR�R�tdns_at	cidrmatchR tdns_mxR�tsocketRJtdomainmatchR�R�R�R�(RaRR�R_R�R�R�tmechst	modifiersR�tmodR�RpR�R�R�R|RnRsttxttredirect_record((s'/usr/lib/python2.7/site-packages/spf.pyR�:s�#	





	"



!

	cCs]|jd|_|jtdkr:tdtd��n|jtkrY|jd�ndS(NiisMore than %d DNS lookupssToo many DNS lookups(R�t
MAX_LOOKUPRgR�(Ra((s'/usr/lib/python2.7/site-packages/spf.pyR��s
cCs�|r�yN|j|dt�}t|�dkrSt|jt|d�dt��SWq�tk
r||jdkr}�q}q�Xn|jdkr�td��ndS(sExpand an explanation.tignore_voidiitstripdotsEmpty domain-spec on exp=N(
tdns_txtRR�RR�tto_asciiR�RgRRf(RatspecR((s'/usr/lib/python2.7/site-packages/spf.pyR��s'
cCsU|jd�dkrYt}x;|jd�D]'}|j|�r+td|��q+q+Wnd}d}xutj|�D]d}||||j�!7}||j�|j�!}|dkr�|d7}n	|dkr�|d7}n�|d	kr�|d
7}n�|dj	�}	|	dkr|j
�n$|	d
krC|rCtd|��nt||	|�}
|
r�|
|krytd|��nt|
|dd!t
j|	��}|	|dkr�tj|d�}n||7}n|j�}quW|||7}|r
|jd�r
|d }n|jd�dkrQt|�dkrQ||jd�d}qQn|S(s%Do SPF RFC macro expansion.

        Examples:
        >>> q = query(s='strong-bad@email.example.com',
        ...           h='mx.example.org', i='192.0.2.3')
        >>> q.p = 'mx.example.org'
        >>> q.r = 'example.net'

        >>> q.expand('%{d}')
        'email.example.com'

        >>> q.expand('%{d4}')
        'email.example.com'

        >>> q.expand('%{d3}')
        'email.example.com'

        >>> q.expand('%{d2}')
        'example.com'

        >>> q.expand('%{d1}')
        'com'

        >>> q.expand('%{p}')
        'mx.example.org'

        >>> q.expand('%{p2}')
        'example.org'

        >>> q.expand('%{dr}')
        'com.example.email'
    
        >>> q.expand('%{d2r}')
        'example.email'

        >>> q.expand('%{l}')
        'strong-bad'

        >>> q.expand('%{l-}')
        'strong.bad'

        >>> q.expand('%{lr}')
        'strong-bad'

        >>> q.expand('%{lr-}')
        'bad.strong'

        >>> q.expand('%{l1r-}')
        'strong'

        >>> q.expand('%{c}',stripdot=False)
        '192.0.2.3'

        >>> q.expand('%{r}',stripdot=False)
        'example.net'

        >>> q.expand('%{ir}.%{v}._spf.%{d2}')
        '3.2.0.192.in-addr._spf.example.com'

        >>> q.expand('%{lr-}.lp._spf.%{d2}')
        'bad.strong.lp._spf.example.com'

        >>> q.expand('%{lr-}.lp.%{ir}.%{v}._spf.%{d2}')
        'bad.strong.lp.3.2.0.192.in-addr._spf.example.com'

        >>> q.expand('%{ir}.%{v}.%{l1r-}.lp._spf.%{d2}')
        '3.2.0.192.in-addr.strong.lp._spf.example.com'

        >>> try: q.expand('%(ir).%{v}.%{l1r-}.lp._spf.%{d2}')
        ... except PermError as x: print(x)
        invalid-macro-char : %(ir)

        >>> q.expand('%{p2}.trusted-domains.example.net')
        'example.org.trusted-domains.example.net'

        >>> q.expand('%{p2}.trusted-domains.example.net.')
        'example.org.trusted-domains.example.net'

        >>> q = query(s='@email.example.com',
        ...           h='mx.example.org', i='192.0.2.3')
        >>> q.p = 'mx.example.org'
        >>> q.expand('%{l}')
        'postmaster'

        t%iR=sinvalid-macro-char RPs%%s%_R�s%-s%20iR}tcrts&c,r,t macros allowed in exp= text onlysUnknown Macro Encounteredii����RGi�i(tfindtRE_INVALID_MACROR�tsearchRgtRE_CHARtfinditertstarttendR�R�tgetattrt
expand_onetJOINERSR�turllibparsetquoteR�R�R�tindex(RaR?R�tregextlabelR�R�Rhtmacrotlettert	expansionR�((s'/usr/lib/python2.7/site-packages/spf.pyR��sLW



"

cCsox4|jd�D]#}|s/t|�dkrd
SqWg|j|�D]}tj|�rG|^qG}t|�dkr�|jr�td|j�nt	d��nt|�dkr�|j
dkr�t|d�S|j
dkr�y>g|j|dd	t�D]}tj|�r�|^q�}Wn7t
k
rZ}|j
dkrQt
|��ng}nXt|�dkr|t	d
��nt|�dkr�|j
dkr�t|�dkr�|d|dkr�td��nt|d�Snt|�dkrt|d�Strkg|j|dtd	t�D]}tj|�r'|^q'}t|�dkrkt|d�Snd
S(s�Get the SPF record recorded in DNS for a specific domain
        name.  Returns None if not found, or if more than one record
        is found.
        R=i?iscache=s'Two or more type TXT spf records found.iiR%R�s'Two or more type SPF spf records found.sLv=spf1 records of both type TXT and SPF (type 99) present, but not identicals._spf.N(R�R�RfR�tRE_SPFR�RkR�RRgRR�RRRtDELEGATE(RaR�R�R{RtbR((s'/usr/lib/python2.7/site-packages/spf.pyR�sD1	!
5!R$cCs�|r�y�|j||d|�}|r�g|D]#}|r.|dd j|�^q.}t|dt�rn|Sg|D]}|jd�^quSWq�tk
r�td||f��q�XngS(s,Get a list of TXT records for a domain name.R�isutf-8s.Non-ascii characters found in %s record for %s(R&R�R�tbytestencodetUnicodeErrorRg(Rat
domainnametrrR�tdns_listRR?((s'/usr/lib/python2.7/site-packages/spf.pyR��s0$
cCs�|j|d�}|jrt}t|�tkrFtdt��n|jdkr�t|�dkr|td|��q|q�n
td}|j�g|| D],}|j|d|j�D]}|^q�q�S(sSGet a list of IP addresses for all MX exchanges for a
        domain name.
        R"s More than %d MX records returnediis$No MX records found for mx mechanismi(	R&RtMAX_MXR�RgRtsortR�R (RaRtmxnamestmaxRQR((s'/usr/lib/python2.7/site-packages/spf.pyR��s	

R cCs�|s
gS|j||�}|jdkrSt|�dkrStd||��n|dkr�ttkr�g|D]}tj|�^qrS|S(s5Get a list of IP addresses for a domainname.
        iisNo %s records found forR!(R&RR�RRRR�tBytes(RaRR R~RY((s'/usr/lib/python2.7/site-packages/spf.pyR��s! cCs	|jr�t}|jdkr�yn|j|j�}t|�|krdd|}t||j��n't|�dkr�td|j��nWq�td|j��q�Xq�n
td}|j}g|j|j�| D]-}|j|j	||j
�|�r�|^q�S(s=Figure out the validated PTR domain names for the connect IP.is!More than %d PTR records returnedis&No PTR records found for ptr mechanismi(RtMAX_PTRtdns_ptrRhR�RR�R�R�R�R (RaR
tptrnamestwarningR�R}((s'/usr/lib/python2.7/site-packages/spf.pyR��s$	

	cCs#|jdt|�|jfd�S(s-Get a list of domain names for an IP address.s
%s.%s.arpaR#(R&treverse_dotsR�(RaRh((s'/usr/lib/python2.7/site-packages/spf.pyRsR"tCNAMER!R#R%cCs�|std��nt|�}|jd�r=|d }ntd�|jd�t�s_gS|j�}|jj||fg�}|r�|S|df}|jj|�}|j	o�|j
d�}|r�|d}n�tj}	|j
dkrtd��n|j
|jkr-|j
dkr-|j
}
n	|j}
tj�}x�t|||j|
�D]�\}}
|r�td	||
�n|dj�|d
f}||kr�|
}|jj||fg�}|r�Pq�n|d
dks�||d
f|	kr[|rtd||
�n|jj|g�j|
�q[q[W|jj||fg�}|j
dkr}|j
tj�||_
n|r>|r>|s�i}n%t|�tkr�tdt��n|||<|j�jd�|kr|jd
kr;td
|��q;q>|j||d|�}|r>||j||f<q>n|r�|r�|jd
7_|jtkr�tdt��q�n|S(s�DNS query.

        If the result is in cache, return that.  Otherwise pull the
        result from DNS, and cache ALL answers, so additional info
        is available for further queries later.

        CNAMEs are followed.

        If there is no data, [] is returned.

        pre: qtype in ['A', 'AAAA', 'MX', 'PTR', 'TXT', 'SPF']
        post: isinstance(__return__, types.ListType)

        Examples:
        >>> c = query(s='strong-bad@email.example.com',
        ...           h='parallel.kitterman.org',i='192.0.2.123')
        >>> "".join( chr(x) for x in bytearray(c.dns('parallel.kitterman.org', 'TXT')[0][0]) )
        'v=spf1 include:long.kitterman.org include:cname.kitterman.org -all'
        s
Invalid queryR=i����cSs$|o#dt|�ko!dkSS(Nii@(R�(Rty((s'/usr/lib/python2.7/site-packages/spf.pyt<lambda>7sRscname.is)DNS Error: exceeded max query lookup timesresult=is	addcache=s Length of CNAME chain exceeds %ds
CNAME looptcnamess Void lookup limit of %d exceeded(R\RR�RR�RR�RR�Rkt
startswithR(t
SAFE2CACHERlRRRzt	DNSLookupRR�t
setdefaultR)R�t	MAX_CNAMERgtrstripRR&R�tMAX_VOID_LOOKUPS(RaRRRR�R�tcnamektcnametdebugt
safe2cacheRttimethentkR�((s'/usr/lib/python2.7/site-packages/spf.pyR&sp

	!	%&#
	
cCs�y�ytjjdkrexJt|�D]9\}}t||t�r%||jd�||<q%q%Wnx�g|D]}tj|�^qoD]x}|j	d|�}t|j
t�r�|j|j
�rtSq�||jkr�|j
j|�q�|j
j|j�q�WWn�tk
r�x�g|D]}tj|dt�^qD]x}|j	d|�}t|j
t�r�|j|j
�r�tSq>||jkr�|j
j|�q>|j
j|j�q>WnXWn%tk
r�}tt|���nXtS(sBMatch connect IP against a CIDR network of other IP addresses.

        Examples:
        >>> c = query(s='strong-bad@email.example.com',
        ...           h='mx.example.org', i='192.0.2.3')
        >>> c.p = 'mx.example.org'
        >>> c.r = 'example.com'

        >>> c.cidrmatch(['192.0.2.3'],32)
        True
        >>> c.cidrmatch(['192.0.2.2'],32)
        False
        >>> c.cidrmatch(['192.0.2.2'],31)
        True

        >>> six = query(s='strong-bad@email.example.com',
        ...           h='mx.example.org', i='2001:0db8:0:0:0:0:0:0001')
        >>> six.p = 'mx.example.org'
        >>> six.r = 'example.com'

        >>> six.cidrmatch(['2001:0DB8::'],127)
        True
        >>> six.cidrmatch(['2001:0DB8::'],128)
        False
        >>> six.cidrmatch(['2001:0DB8:0:0:0:0:0:0001'],128)
        True
        iR�t
new_prefixR(R�R�R�t	enumerateR�RR�R�t
ip_networktsupernetR�tboolt__contains__R�RR�R)RYRt	IPNetworkR�R�Rg(RatipaddrstntidxRYtnetwrktnetworkR((s'/usr/lib/python2.7/site-packages/spf.pyR�ps4!)
/cCs�ddl}djd�|jd�D��}|jj|�}x�|jD]�}|jdkrJ|j|_|j	|_	|j
djdkr�|j
dj|_
|j
dj|_n|j
djd	kr�|j
dj|_q�qJqJWdS(
scSet SPF values from RFC 5451 Authentication Results header.
        
        Useful when SPF has already been run on a trusted gateway machine.

        Expects the entire header as an input.

        Examples:
        >>> q = query('192.0.2.3','strong-bad@email.example.com','mx.example.org')
        >>> q.mechanism = 'unknown'
        >>> p = q.parse_header_ar('''Authentication-Results: bmsi.com; spf=neutral \n     (abuse@kitterman.com: 192.0.2.3 is neither permitted nor denied by domain of email.example.com) \n     smtp.mailfrom=email.example.com \n    (sender=strong-bad@email.example.com; helo=mx.example.org; client-ip=192.0.2.3; receiver=abuse@kitterman.com; mechanism=?all)''')
        >>> q.get_header(q.result, header_type='authres', aid='bmsi.com')
        'Authentication-Results: bmsi.com; spf=neutral (unknown: 192.0.2.3 is neither permitted nor denied by domain of email.example.com) smtp.mailfrom=email.example.com (sender=email.example.com; helo=mx.example.org; client-ip=192.0.2.3; receiver=unknown; mechanism=unknown)'
        >>> p = q.parse_header_ar('''Authentication-Results: bmsi.com; spf=None (mail.bmsi.com: test; client-ip=163.247.46.150) smtp.mailfrom=admin@squiebras.cl (helo=mail.squiebras.cl; receiver=mail.bmsi.com;\n mechanism=mx/24)''')
        >>> q.get_header(q.result, header_type='authres', aid='bmsi.com')
        'Authentication-Results: bmsi.com; spf=none (unknown: 192.0.2.3 is neither permitted nor denied by domain of email.example.com) smtp.mailfrom=admin@squiebras.cl (sender=admin@squiebras.cl; helo=mx.example.org; client-ip=192.0.2.3; receiver=unknown; mechanism=unknown)'
        i����NR�css|]}|j�VqdS(N(tstrip(t.0R?((s'/usr/lib/python2.7/site-packages/spf.pys	<genexpr>�ss
RiRuRt(tauthresR�R�tAuthenticationResultsHeadertparsetresultstmethodtauthserv_idR�R�t
propertiesRtvalueR|R?Ri(RatvalR3tarobjtresobj((s'/usr/lib/python2.7/site-packages/spf.pytparse_header_ar�s"cCs�|jdd�}|dj�|_d|_t|�dkrDdS|d}|jd�r�|jd�}|dkr|jS|d|!|_||d}nt	�}|j
dd|�i}x�|jd	d�D]�\}}|d
kr�|j|�q�|dkr||_
q�|dkr.||_q�|d
krF||_q�|dkr^||_q�|dkrv||_q�|dkr�||_q�|jd�r�|||d<q�q�Wt|j
|j�\|_|_|S(s�Set SPF values from Received-SPF header.
        
        Useful when SPF has already been run on a trusted gateway machine.

        Examples:
        >>> q = query('0.0.0.0','','')
        >>> p = q.parse_header_spf('''Pass (test) client-ip=70.98.79.77;
        ... envelope-from="evelyn@subjectsthum.com"; helo=mail.subjectsthum.com;
        ... receiver=mail.bmsi.com; mechanism=a; identity=mailfrom''')
        >>> q.get_header(q.result)
        'Pass (test) client-ip=70.98.79.77; envelope-from="evelyn@subjectsthum.com"; helo=mail.subjectsthum.com; receiver=mail.bmsi.com; mechanism=a; identity=mailfrom'
        >>> o = q.parse_header_spf('''None (mail.bmsi.com: test)
        ... client-ip=163.247.46.150; envelope-from="admin@squiebras.cl";
        ... helo=mail.squiebras.cl; receiver=mail.bmsi.com; mechanism=mx/24;
        ... x-bestguess=pass; x-helo-spf=neutral; identity=mailfrom''')
        >>> q.get_header(q.result,**o)
        'None (mail.bmsi.com: test) client-ip=163.247.46.150; envelope-from="admin@squiebras.cl"; helo=mail.squiebras.cl; receiver=mail.bmsi.com; mechanism=mx/24; x-bestguess=pass; x-helo-spf=neutral; identity=mailfrom'
        >>> o['bestguess']
        'pass'
        iiiRKt(t)sReceived-SPFs; Rs	client-ips
envelope-fromRtRjtproblemR�tidentitysx-N(R�RfR�R�R�R�RR�tcommentRt
add_headert
get_paramsR�R?RiR~R_RvRwR>Rx(RaR;RtposR^R}R$R�((s'/usr/lib/python2.7/site-packages/spf.pytparse_header_spf�sD	
	!cCs-|jd�r|j|�S|j|�SdS(s�
Set SPF values from Received-SPF or RFC 5451 Authentication Results header.
        
        Useful when SPF has already been run on a trusted gateway machine. Auto
        detects the header type and parses it. Use parse_header_spf or parse_header_ar
        for each type if required.

        Examples:
        >>> q = query('0.0.0.0','','')
        >>> p = q.parse_header('''Pass (test) client-ip=70.98.79.77;
        ... envelope-from="evelyn@subjectsthum.com"; helo=mail.subjectsthum.com;
        ... receiver=mail.bmsi.com; mechanism=a; identity=mailfrom''')
        >>> q.get_header(q.result)
        'Pass (test) client-ip=70.98.79.77; envelope-from="evelyn@subjectsthum.com"; helo=mail.subjectsthum.com; receiver=mail.bmsi.com; mechanism=a; identity=mailfrom'
        >>> r = q.parse_header('''None (mail.bmsi.com: test)
        ... client-ip=163.247.46.150; envelope-from="admin@squiebras.cl";
        ... helo=mail.squiebras.cl; receiver=mail.bmsi.com; mechanism=mx/24;
        ... x-bestguess=pass; x-helo-spf=neutral; identity=mailfrom''')
        >>> q.get_header(q.result,**r)
        'None (mail.bmsi.com: test) client-ip=163.247.46.150; envelope-from="admin@squiebras.cl"; helo=mail.squiebras.cl; receiver=mail.bmsi.com; mechanism=mx/24; x-bestguess=pass; x-helo-spf=neutral; identity=mailfrom'
        >>> r['bestguess']
        'pass'
        >>> q = query('192.0.2.3','strong-bad@email.example.com','mx.example.org')
        >>> q.mechanism = 'unknown'
        >>> p = q.parse_header_ar('''Authentication-Results: bmsi.com; spf=neutral \n     (abuse@kitterman.com: 192.0.2.3 is neither permitted nor denied by domain of email.example.com) \n     smtp.mailfrom=email.example.com \n     (sender=strong-bad@email.example.com; helo=mx.example.org; client-ip=192.0.2.3; receiver=abuse@kitterman.com; mechanism=?all)''')
        >>> q.get_header(q.result, header_type='authres', aid='bmsi.com')
        'Authentication-Results: bmsi.com; spf=neutral (unknown: 192.0.2.3 is neither permitted nor denied by domain of email.example.com) smtp.mailfrom=email.example.com (sender=email.example.com; helo=mx.example.org; client-ip=192.0.2.3; receiver=unknown; mechanism=unknown)'
        >>> p = q.parse_header_ar('''Authentication-Results: bmsi.com; spf=None (mail.bmsi.com: test; client-ip=163.247.46.150) smtp.mailfrom=admin@squiebras.cl (helo=mail.squiebras.cl; receiver=mail.bmsi.com; mechanism=mx/24)''')
        >>> q.get_header(q.result, header_type='authres', aid='bmsi.com')
        'Authentication-Results: bmsi.com; spf=none (unknown: 192.0.2.3 is neither permitted nor denied by domain of email.example.com) smtp.mailfrom=admin@squiebras.cl (sender=admin@squiebras.cl; helo=mx.example.org; client-ip=192.0.2.3; receiver=unknown; mechanism=unknown)'
        sAuthentication-Results:N(RR>RG(RaR;((s'/usr/lib/python2.7/site-packages/spf.pytparse_header�s 
RcKs|dkr0|s!td��nddl}n|sB|j}n|j}t|j�}idd6dd6d	d
6dd6d
d6dd6dd6}	|j}
|
dkr�d}nt|j�}|	|}|dkr�|j	r�tdj
|j	��}
nd}
t|j�}t|d�r(|j
}nd||j|�f}d||fg}|dkr)xGd/D]?}t�|}|rg|jd|jdd �|f�qgqgWxXtt|j���D]>\}}|r�|jd!|jdd �t|�f�q�q�W|jd"d#|
f�dj
|�S|dkr�|r�t|jd$|d%|jd&|d'|d(|jd)d*j|j|j|j|j|��g��St|jd$|d%|jd&|d'|d+|jd,d-j|j|j|j|��g��Sntd.j|���dS(0sD

        Generate Received-SPF or Authentication Results header based on the
         last lookup.

        >>> q = query(s='strong-bad@email.example.com', h='mx.example.org',
        ...           i='192.0.2.3')
        >>> q.r='abuse@kitterman.com'
        >>> q.check(spf='v=spf1 ?all')
        ('neutral', 250, 'access neither permitted nor denied')
        >>> q.get_header('neutral')
        'Neutral (abuse@kitterman.com: 192.0.2.3 is neither permitted nor denied by domain of email.example.com) client-ip=192.0.2.3; envelope-from="strong-bad@email.example.com"; helo=mx.example.org; receiver=abuse@kitterman.com; mechanism=?all; identity=mailfrom'

        >>> q.check(spf='v=spf1 redirect=controlledmail.com exp=_exp.controlledmail.com')
        ('fail', 550, 'SPF fail - not authorized')
        >>> q.get_header('fail')
        'Fail (abuse@kitterman.com: domain of email.example.com does not designate 192.0.2.3 as permitted sender) client-ip=192.0.2.3; envelope-from="strong-bad@email.example.com"; helo=mx.example.org; receiver=abuse@kitterman.com; mechanism=-all; identity=mailfrom'
    
        >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ?all moo')
        ('permerror', 550, 'SPF Permanent Error: Unknown mechanism found: moo')
        >>> q.get_header('permerror')
        'PermError (abuse@kitterman.com: permanent error in processing domain of email.example.com: Unknown mechanism found) client-ip=192.0.2.3; envelope-from="strong-bad@email.example.com"; helo=mx.example.org; receiver=abuse@kitterman.com; problem=moo; identity=mailfrom'

        >>> q.check(spf='v=spf1 ip4:192.0.0.0/8 ~all')
        ('pass', 250, 'sender SPF authorized')
        >>> q.get_header('pass')
        'Pass (abuse@kitterman.com: domain of email.example.com designates 192.0.2.3 as permitted sender) client-ip=192.0.2.3; envelope-from="strong-bad@email.example.com"; helo=mx.example.org; receiver=abuse@kitterman.com; mechanism="ip4:192.0.0.0/8"; identity=mailfrom'

        >>> q.check(spf='v=spf1 ?all')
        ('neutral', 250, 'access neither permitted nor denied')
        >>> q.get_header('neutral', header_type = 'authres', aid='bmsi.com')
        'Authentication-Results: bmsi.com; spf=neutral (abuse@kitterman.com: 192.0.2.3 is neither permitted nor denied by domain of email.example.com) smtp.mailfrom=email.example.com (sender=strong-bad@email.example.com; helo=mx.example.org; client-ip=192.0.2.3; receiver=abuse@kitterman.com; mechanism=?all)'

        >>> p = query(s='strong-bad@email.example.com', h='mx.example.org',
        ...           i='192.0.2.3')
        >>> p.r='abuse@kitterman.com'
        >>> p.check(spf='v=spf1 redirect=controlledmail.com exp=_exp.controlledmail.com')
        ('fail', 550, 'SPF fail - not authorized')
        >>> p.ident = 'helo'
        >>> p.get_header('fail', header_type = 'authres', aid='bmsi.com')
        'Authentication-Results: bmsi.com; spf=fail (abuse@kitterman.com: domain of email.example.com does not designate 192.0.2.3 as permitted sender) smtp.helo=mx.example.org (sender=strong-bad@email.example.com; client-ip=192.0.2.3; receiver=abuse@kitterman.com; mechanism=-all)'

        >>> q.check(spf='v=spf1 ?all')
        ('neutral', 250, 'access neither permitted nor denied')
        >>> try: q.get_header('neutral', header_type = 'dkim')
        ... except SyntaxError as x: print(x)
        Unknown results header type: dkim
        R3sKauthserv-id missing for Authentication Results header type, see RFC5451 2.3i����NtPassR@tNeutralRDtFailRBtSoftFailRFRfRKRRIRgRHRtR�RCs%s: %ss%s (%s)Rt	client_ipt
envelope_fromRjRAR�s%s=%s;RoRCsx-%s=%s;s%s=%sRBR8R6R�tresult_commentt
smtp_mailfromtsmtp_mailfrom_comments@sender={0}; helo={1}; client-ip={2}; receiver={3}; mechanism={4}t	smtp_helotsmtp_helo_comments6sender={0}; client-ip={1}; receiver={2}; mechanism={3}s Unknown results header type: {0}(s	client_ips
envelope_fromshelosreceiversproblems	mechanism(tSyntaxErrorR3R~R�tquote_valueRiRvRfR?R_R�R�thasattrRCtget_header_commenttlocalsR)R�tsortedR�titemsRR4tSPFAuthenticationResultR|tformat(RaRnRjtheader_typetaidtkvR3RMRttresmapRBRNttagRAR�RCR$R�((s'/usr/lib/python2.7/site-packages/spf.pyt
get_header s`1			


*%0
%"cCs�|j}|dkr&d||jfS|dkrCd||jfS|dkr`d|j|fS|dkr}d|j|fS|dkr�d	||jfS|d
kr�d|S|dkr�d
||jfStd|��dS(s)Return comment for Received-SPF header.  R@s.domain of %s designates %s as permitted senderRFsDtransitioning domain of %s does not designate %s as permitted senderRDs2%s is neither permitted nor denied by domain of %sRKRHs.permanent error in processing domain of %s: %sRIs1temporary error in processing during lookup of %sRBs6domain of %s does not designate %s as permitted senders'invalid SPF result for header comment: N(RxR�R�R�(RaRntsender((s'/usr/lib/python2.7/site-packages/spf.pyRW�s,	N(sMXR (sMXsMX(sCNAMER (R R (sAAAAsAAAA(sPTRsPTR(sTXTsTXT(sSPFsSPF(&RcRdReRfRtMAX_PER_LOOKUP_TIMER�R]R�R�R�R�R�tDEFAULT_SPFR�RmR�R�R�R�R�R�R�R�R�R�R�R�R�RRR&R�R>RGRHRbRW(((s'/usr/lib/python2.7/site-packages/spf.pyR(XsP	0		+			p				�	�		�	9	
		
	Q	;	!	/	%icCsi|sd|fS|jdd�}|ddkr?d|d<nt|�dkr[t|�Sd|fSdS(stGiven a sender email s and a HELO domain h, create a valid tuple
    (l, d) local-part and domain-part.

    Examples:
    >>> split_email('', 'wayforward.net')
    ('postmaster', 'wayforward.net')

    >>> split_email('foo.com', 'wayforward.net')
    ('postmaster', 'foo.com')

    >>> split_email('terry@wayforward.net', 'optsw.com')
    ('terry', 'wayforward.net')
    t
postmastert@iiRPiN(R�R�ttuple(R?Ritparts((s'/usr/lib/python2.7/site-packages/spf.pyRw�s


cCsO|dkstj|�r|Sd|jdd�jdd�jdd�dS(sQuote the value for a key-value pair in Received-SPF header field
    if needed.  No quoting needed for a dot-atom value.

    Examples:
    >>> quote_value('foo@bar.com')
    '"foo@bar.com"'
    
    >>> quote_value('mail.example.com')
    'mail.example.com'

    >>> quote_value('A:1.2.3.4')
    '"A:1.2.3.4"'

    >>> quote_value('abc"def')
    '"abc\\"def"'

    >>> quote_value(r'abc\def')
    '"abc\\\\def"'

    >>> quote_value('abc..def')
    '"abc..def"'

    >>> quote_value('')
    '""'

    >>> quote_value(None)
    t"s\s\\s\"ts\x00N(RftRE_DOT_ATOMR�R�(R?((s'/usr/lib/python2.7/site-packages/spf.pyRU�scCs�tj|�}t|�dkr?|dt|d�}}nd}tj|�}t|�dkr�|dt|d�}}nd}|jdd�}t|�dkr�|j�}|dkr�d}n||||fS|dj�|d||fS(s�Breaks A, MX, IP4, and PTR mechanisms into a (name, domain,
    cidr,cidr6) tuple.  The domain portion defaults to d if not present,
    the cidr defaults to 32 if not present.

    Examples:
    >>> parse_mechanism('a', 'foo.com')
    ('a', 'foo.com', None, None)

    >>> parse_mechanism('exists','foo.com')
    ('exists', None, None, None)

    >>> parse_mechanism('a:bar.com', 'foo.com')
    ('a', 'bar.com', None, None)

    >>> parse_mechanism('a/24', 'foo.com')
    ('a', 'foo.com', 24, None)

    >>> parse_mechanism('A:foo:bar.com/16//48', 'foo.com')
    ('a', 'foo:bar.com', 16, 48)

    >>> parse_mechanism('-exists:%{i}.%{s1}.100/86400.rate.%{d}','foo.com')
    ('-exists', '%{i}.%{s1}.100/86400.rate.%{d}', None, None)

    >>> parse_mechanism('mx:%%%_/.Claranet.de/27','foo.com')
    ('mx', '%%%_/.Claranet.de', 27, None)

    >>> parse_mechanism('mx:%{d}//97','foo.com')
    ('mx', '%{d}', None, 97)

    >>> parse_mechanism('iP4:192.0.0.0/8','foo.com')
    ('ip4', '192.0.0.0', 8, None)
    iiiR�iRSN(tRE_DUAL_CIDRR�R�RyRftRE_CIDRR�(RR|Rtcidr6tcidr((s'/usr/lib/python2.7/site-packages/spf.pyR��s"	cCs&|jd�}|j�dj|�S(s�Reverse dotted IP addresses or domain names.

    Example:
    >>> reverse_dots('192.168.0.145')
    '145.0.168.192'

    >>> reverse_dots('email.example.com')
    'com.example.email'
    R=(R�treverseR�(RR((s'/usr/lib/python2.7/site-packages/spf.pyRs

cCsP|j�}x=|D]5}|j�}||ksD|jd|�rtSqWtS(sgrep for a given domain suffix against a list of validated PTR
    domain names.

    Examples:
    >>> domainmatch(['FOO.COM'], 'foo.com')
    1

    >>> domainmatch(['moo.foo.com'], 'FOO.COM')
    1

    >>> domainmatch(['moo.bar.com'], 'foo.com')
    0

    R=(R�R�RR�(tptrstdomainsuffixRR((s'/usr/lib/python2.7/site-packages/spf.pyR� s
cCs�|s
|Stj|�dd!\}}}|s8d}nt|||�}|r]|j�n|r|t|�dd}ndj|�S(NiiR=iRP(tRE_ARGSR�RqRyR�(RRtjoinertlnRqt
delimiters((s'/usr/lib/python2.7/site-packages/spf.pyR�7s	
cCs~gd}}x]|D]U}||kr_|j|�d}|rO|j|�qi|j|�q||7}qW|j|�|S(s�Split a string into pieces by a set of delimiter characters.  The
    resulting list is delimited by joiner, or the original delimiter if
    joiner is not specified.

    Examples:
    >>> split('192.168.0.45', '.')
    ['192', '.', '168', '.', '0', '.', '45']

    >>> split('terry@wayforward.net', '@.')
    ['terry', '@', 'wayforward', '.', 'net']

    >>> split('terry@wayforward.net', '@.', '.')
    ['terry', '.', 'wayforward', '.', 'net']
    RP(R)(RRwRuR�telementR�((s'/usr/lib/python2.7/site-packages/spf.pyR�Bs



cCs�|s
|S|j�d}|r�|j�xd|D]U}tj|d�s1|j|�}|g|||+|j�dj|�}Pq1q1W|Snd|S(s�Returns spftxt with local inserted just before last non-fail
    mechanism.  This is how the libspf{2} libraries handle "local-policy".
    
    Examples:
    >>> insert_libspf_local_policy('v=spf1 -all')
    'v=spf1 -all'
    >>> insert_libspf_local_policy('v=spf1 -all','mx')
    'v=spf1 -all'
    >>> insert_libspf_local_policy('v=spf1','a mx ptr')
    'v=spf1 a mx ptr'
    >>> insert_libspf_local_policy('v=spf1 mx -all','a ptr')
    'v=spf1 mx a ptr -all'
    >>> insert_libspf_local_policy('v=spf1 mx -include:foo.co +all','a ptr')
    'v=spf1 mx a ptr -include:foo.co +all'

    # FIXME: is this right?  If so, "last non-fail" is a bogus description.
    >>> insert_libspf_local_policy('v=spf1 mx ?include:foo.co +all','a ptr')
    'v=spf1 mx a ptr ?include:foo.co +all'
    >>> spf='v=spf1 ip4:1.2.3.4 -a:example.net -all'
    >>> local='ip4:192.0.2.3 a:example.org'
    >>> insert_libspf_local_policy(spf,local)
    'v=spf1 ip4:1.2.3.4 ip4:192.0.2.3 a:example.org -a:example.net -all'
    iiR�sv=spf1 (R�RqR�R�R�R�(tspftxtRLRR_twhere((s'/usr/lib/python2.7/site-packages/spf.pyR�_s


icCs>y|jd�SWn&tk
r9tdt|���nXdS(s*Raise PermError if arg is not 7-bit ascii.R�sNon-ascii characters foundN(RRRgtrepr(R?((s'/usr/lib/python2.7/site-packages/spf.pyR��s
cCs>y|jd�SWn&tk
r9tdt|���nXdS(s*Raise PermError if arg is not 7-bit ascii.R�sNon-ascii characters foundN(R�RRgR{(R?((s'/usr/lib/python2.7/site-packages/spf.pyR��s
cCs%ddl}ddl}|j|�S(Ni����(tdoctestRttestmod(R|R((s'/usr/lib/python2.7/site-packages/spf.pyt_test�st__main__ishvs:thelpRkRs-vs	--verboses-ss--stricts-hs--helpRhs	127.0.0.1t	localhostRiRjsTemporary DNS error: sPermError: isresult:sguessed:slax:(|t
__future__Rt
__author__t	__email__t__version__tMODULEtUSAGEtreR�R�tstructRzturllib.parseR5R�turllibt	functoolsRt
email.messageRtImportErrort
email.MessageR�R�R�RRR8R&tdns.resolvert
dns.exceptionRVt	rdatatypeR%t_by_textRRtTypettypemaptLibt
RRunpackert
getTXTdatat
getSPFdatatDiscoverNameServerstcompilet
IGNORECASERR�tPAT_CHARR�R�RtRmRnR�tPAT_IP4R�R�RlR�R�R�R�RfRRetTRUSTED_FORWARDERSR�R
RRR�RdRR�R�R\RRRgR�RqRmtobjectR(RwRUR�RR�R�R�R�R�R�R~RctgetopttargvtoptstGetoptErrorterrRtexitRkRRxRRyR�tgethostnametqR�RRhR?RiR~R�R�R�R`R�RY(((s'/usr/lib/python2.7/site-packages/spf.pyt<module>sV+

!


		

&�����Q		!	4			3		
	

*		$	

Spamworldpro Mini