o
    b]                     @   sJ  d Z ddlZddlZddlmZ ddlmZmZmZ ddl	m
Z
 ddlmZ ddlmZmZ dd	 Zd d
dZG dd dZeeG dd deZee
jG dd dZeeG dd deZG dd deZee
jG dd dZG dd dejZeeG dd deZee
jG dd dZeeG dd deZdS )!zD
Support for aliases(5) configuration files.

@author: Jp Calderone
    N)implementer)deferprotocolreactor)smtp)IAlias)failurelogc           	      C   sp   dd | ddD }t|dkr d}||f}t||  dS |\}}| | g ttj| d dS )	a  
    Parse a line from an aliases file.

    @type result: L{dict} mapping L{bytes} to L{list} of L{bytes}
    @param result: A dictionary mapping username to aliases to which
        the results of parsing the line are added.

    @type line: L{bytes}
    @param line: A line from an aliases file.

    @type filename: L{bytes}
    @param filename: The full or relative path to the aliases file.

    @type lineNo: L{int}
    @param lineNo: The position of the line within the aliases file.
    c                 S      g | ]}|  qS  strip).0pr   r   4/usr/lib/python3/dist-packages/twisted/mail/alias.py
<listcomp>)       zhandle.<locals>.<listcomp>:      z+Invalid format on line %d of alias file %s.,N)	splitlenr	   err
setdefaultr   extendmapstr)	resultlinefilenamelineNopartsfmtarguseraliasr   r   r   handle   s   (r'   c           
      C   s   i }d}|du rt |}d}nt|dd}d}d}z7|D ],}|d7 }| }| d	r.q|d
s8|dr=|| }q|rFt|||| |}qW |rP|  n|rX|  w w |rbt|||| | D ]\}}	t|	| |||< qf|S )a  
    Load a file containing email aliases.

    Lines in the file should be formatted like so::

         username: alias1, alias2, ..., aliasN

    Aliases beginning with a C{|} will be treated as programs, will be run, and
    the message will be written to their stdin.

    Aliases beginning with a C{:} will be treated as a file containing
    additional aliases for the username.

    Aliases beginning with a C{/} will be treated as the full pathname to a file
    to which the message will be appended.

    Aliases without a host part will be assumed to be addresses on localhost.

    If a username is specified multiple times, the aliases for each are joined
    together as if they had all been on one line.

    Lines beginning with a space or a tab are continuations of the previous
    line.

    Lines beginning with a C{#} are comments.

    @type domains: L{dict} mapping L{bytes} to L{IDomain} provider
    @param domains: A mapping of domain name to domain object.

    @type filename: L{bytes} or L{None}
    @param filename: The full or relative path to a file from which to load
        aliases. If omitted, the C{fp} parameter must be specified.

    @type fp: file-like object or L{None}
    @param fp: The file from which to load aliases. If specified,
        the C{filename} parameter is ignored.

    @rtype: L{dict} mapping L{bytes} to L{AliasGroup}
    @return: A mapping from username to group of aliases.
    FNTnamez	<unknown>r    r   # 	)	opengetattrrstriplstrip
startswithr'   closeitems
AliasGroup)
domainsr    fpr   r2   iprevr   uar   r   r   loadAliasFile3   s>   )

r;   c                   @   s*   e Zd ZdZdd Zdd Zd	ddZdS )
	AliasBasez
    The default base class for aliases.

    @ivar domains: See L{__init__}.

    @type original: L{Address}
    @ivar original: The original address being aliased.
    c                 C   s   || _ t|| _dS )z
        @type domains: L{dict} mapping L{bytes} to L{IDomain} provider
        @param domains: A mapping of domain name to domain object.

        @type original: L{bytes}
        @param original: The original address being aliased.
        N)r5   r   Addressoriginal)selfr5   r>   r   r   r   __init__   s   zAliasBase.__init__c                 C   s   | j | jj S )z
        Return the domain associated with original address.

        @rtype: L{IDomain} provider
        @return: The domain for the original address.
        )r5   r>   domainr?   r   r   r   rA         zAliasBase.domainNc                 C   s0   |du ri }t | |v rdS d|t | < |  S aY  
        Map this alias to its ultimate destination.

        @type aliasmap: L{dict} mapping L{bytes} to L{AliasBase}
        @param aliasmap: A mapping of username to alias or group of aliases.

        @type memo: L{None} or L{dict} of L{AliasBase}
        @param memo: A record of the aliases already considered in the
            resolution process.  If provided, C{memo} is modified to include
            this alias.

        @rtype: L{IMessage <smtp.IMessage>} or L{None}
        @return: A message receiver for the ultimate destination or None for
            an invalid destination.
        N)r   createMessageReceiverr?   aliasmapmemor   r   r   resolve   s   zAliasBase.resolveN)__name__
__module____qualname____doc__r@   rA   rI   r   r   r   r   r<   {   s
    		r<   c                   @   s8   e Zd ZdZdd ZdefddZdd Zdd
dZd	S )AddressAliasz
    An alias which translates one email address into another.

    @type alias : L{Address}
    @ivar alias: The destination address.
    c                 G   s"   t j| g|R   t|| _dS )aQ  
        @type alias: L{Address}, L{User}, L{bytes} or object which can be
            converted into L{bytes}
        @param alias: The destination address.

        @type args: 2-L{tuple} of (0) L{dict} mapping L{bytes} to L{IDomain}
            provider, (1) L{bytes}
        @param args: Arguments for L{AliasBase.__init__}.
        N)r<   r@   r   r=   r&   )r?   r&   argsr   r   r   r@      s   
zAddressAlias.__init__returnc                 C      d| j  dS )z
        Build a string representation of this L{AddressAlias} instance.

        @rtype: L{bytes}
        @return: A string containing the destination address.
        z	<Address >)r&   rB   r   r   r   __str__   rC   zAddressAlias.__str__c                 C   s   |   t| jS )z
        Create a message receiver which delivers a message to
        the destination address.

        @rtype: L{IMessage <smtp.IMessage>} provider
        @return: A message receiver.
        )rA   existsr   r&   rB   r   r   r   rE      s   z"AddressAlias.createMessageReceiverNc                 C   s   |du ri }t | |v rdS d|t | < z|  t| jddd| W S  tjy/   Y nw | jj|v r@|| jj ||S dS rD   )	r   rA   rU   r   Userr&   SMTPBadRcptlocalrI   rF   r   r   r   rI      s   "zAddressAlias.resolverJ   )	rK   rL   rM   rN   r@   r   rT   rE   rI   r   r   r   r   rO      s    	
rO   c                   @   >   e Zd ZdZdd Zdd Zdd Zdd	 Zd
efddZ	dS )FileWrappera  
    A message receiver which delivers a message to a file.

    @type fp: file-like object
    @ivar fp: A file used for temporary storage of the message.

    @type finalname: L{bytes}
    @ivar finalname: The name of the file in which the message should be
        stored.
    c                 C   s   t  | _|| _dS )z
        @type filename: L{bytes}
        @param filename: The name of the file in which the message should be
            stored.
        N)tempfileTemporaryFiler6   	finalname)r?   r    r   r   r   r@     s   

zFileWrapper.__init__c                 C   s   | j |d  dS )z
        Write a received line to the temporary file.

        @type line: L{bytes}
        @param line: A received line of the message.
        
N)r6   writer?   r   r   r   r   lineReceived     zFileWrapper.lineReceivedc                 C   s   | j dd zt| jd}W n ty   tt  Y S w | |	| j 
  | j   W d   n1 s:w   Y  t| jS )ac  
        Handle end of message by writing the message to the file.

        @rtype: L{Deferred <defer.Deferred>} which successfully results in
            L{bytes}
        @return: A deferred which succeeds with the name of the file to which
            the message has been stored or fails if the message cannot be
            saved to the file.
        r   r:   N)r6   seekr-   r]   BaseExceptionr   failr   Failurer_   readr2   succeed)r?   fr   r   r   eomReceived  s   
zFileWrapper.eomReceivedc                 C   s   | j   d| _ dS )zG
        Close the temporary file when the connection is lost.
        N)r6   r2   rB   r   r   r   connectionLost-  s   

zFileWrapper.connectionLostrQ   c                 C   rR   )z
        Build a string representation of this L{FileWrapper} instance.

        @rtype: L{bytes}
        @return: A string containing the file name of the message.
        z<FileWrapper rS   )r]   rB   r   r   r   rT   4  rC   zFileWrapper.__str__N
rK   rL   rM   rN   r@   ra   rj   rk   r   rT   r   r   r   r   rZ      s    		rZ   c                   @   s.   e Zd ZdZdd ZdefddZdd Zd	S )
	FileAliasz_
    An alias which translates an address to a file.

    @ivar filename: See L{__init__}.
    c                 G   s   t j| g|R   || _dS )a"  
        @type filename: L{bytes}
        @param filename: The name of the file in which to store the message.

        @type args: 2-L{tuple} of (0) L{dict} mapping L{bytes} to L{IDomain}
            provider, (1) L{bytes}
        @param args: Arguments for L{AliasBase.__init__}.
        N)r<   r@   r    )r?   r    rP   r   r   r   r@   F  s   	
zFileAlias.__init__rQ   c                 C   rR   )z
        Build a string representation of this L{FileAlias} instance.

        @rtype: L{bytes}
        @return: A string containing the name of the file.
        z<File rS   )r    rB   r   r   r   rT   R  rC   zFileAlias.__str__c                 C   
   t | jS )z
        Create a message receiver which delivers a message to the file.

        @rtype: L{FileWrapper}
        @return: A message receiver which writes a message to the file.
        )rZ   r    rB   r   r   r   rE   [     
zFileAlias.createMessageReceiverN)rK   rL   rM   rN   r@   r   rT   rE   r   r   r   r   rm   >  s
    	rm   c                   @   s   e Zd ZdZdS )ProcessAliasTimeoutzb
    An error indicating that a timeout occurred while waiting for a process
    to complete.
    N)rK   rL   rM   rN   r   r   r   r   rp   e  s    rp   c                   @   s`   e Zd ZdZdZdZdZeZdddZdd Z	d	d
 Z
dd Zdd Zdd ZdefddZdS )MessageWrapperaF  
    A message receiver which delivers a message to a child process.

    @type completionTimeout: L{int} or L{float}
    @ivar completionTimeout: The number of seconds to wait for the child
        process to exit before reporting the delivery as a failure.

    @type _timeoutCallID: L{None} or
        L{IDelayedCall <twisted.internet.interfaces.IDelayedCall>} provider
    @ivar _timeoutCallID: The call used to time out delivery, started when the
        connection to the child process is closed.

    @type done: L{bool}
    @ivar done: A flag indicating whether the child process has exited
        (C{True}) or not (C{False}).

    @type reactor: L{IReactorTime <twisted.internet.interfaces.IReactorTime>}
        provider
    @ivar reactor: A reactor which will be used to schedule timeouts.

    @ivar protocol: See L{__init__}.

    @type processName: L{bytes} or L{None}
    @ivar processName: The process name.

    @type completion: L{Deferred <defer.Deferred>}
    @ivar completion: The deferred which will be triggered by the protocol
        when the child process exits.
    F<   Nc                 C   sD   || _ || _t | _| j| j_| j| j |dur || _dS dS )a  
        @type protocol: L{ProcessAliasProtocol}
        @param protocol: The protocol associated with the child process.

        @type process: L{bytes} or L{None}
        @param process: The process name.

        @type reactor: L{None} or L{IReactorTime
            <twisted.internet.interfaces.IReactorTime>} provider
        @param reactor: A reactor which will be used to schedule timeouts.
        N)	processNamer   r   Deferred
completiononEndaddBoth_processEndedr   )r?   r   processr   r   r   r   r@     s   


zMessageWrapper.__init__c                 C   s(   d| _ | jdur| j  d| _dS |S )a  
        Record process termination and cancel the timeout call if it is active.

        @type result: L{Failure <failure.Failure>}
        @param result: The reason the child process terminated.

        @rtype: L{None} or L{Failure <failure.Failure>}
        @return: None, if the process end is expected, or the reason the child
            process terminated, if the process end is unexpected.
        TN)done_timeoutCallIDcancel)r?   r   r   r   r   rx     s
   


zMessageWrapper._processEndedc                 C   s    | j rdS | jj|d  dS )z
        Write a received line to the child process.

        @type line: L{bytes}
        @param line: A received line of the message.
        Nr^   )rz   r   	transportr_   r`   r   r   r   ra     s   zMessageWrapper.lineReceivedc                 C   s,   | j s| jj  | j| j| j| _| j	S )z
        Disconnect from the child process and set up a timeout to wait for it
        to exit.

        @rtype: L{Deferred <defer.Deferred>}
        @return: A deferred which will be called back when the child process
            exits.
        )
rz   r   r}   loseConnectionr   	callLatercompletionTimeout_completionCancelr{   ru   rB   r   r   r   rj     s   	zMessageWrapper.eomReceivedc                 C   sD   d| _ | jjd td| j d}d| j_| jt	
| dS )z
        Handle the expiration of the timeout for the child process to exit by
        terminating the child process forcefully and issuing a failure to the
        L{completion} deferred.
        NKILLzNo answer after z seconds)r{   r   r}   signalProcessrp   r   rv   ru   errbackr   rf   )r?   excr   r   r   r     s
   z MessageWrapper._completionCancelc                 C   s   dS )z9
        Ignore notification of lost connection.
        Nr   rB   r   r   r   rk     s    zMessageWrapper.connectionLostrQ   c                 C   rR   )z
        Build a string representation of this L{MessageWrapper} instance.

        @rtype: L{bytes}
        @return: A string containing the name of the process.
        z<ProcessWrapper rS   )rs   rB   r   r   r   rT     rC   zMessageWrapper.__str__NN)rK   rL   rM   rN   rz   r   r{   r   r@   rx   ra   rj   r   rk   r   rT   r   r   r   r   rq   l  s    
rq   c                   @   s   e Zd ZdZdZdd ZdS )ProcessAliasProtocolz
    A process protocol which errbacks a deferred when the associated
    process ends.

    @type onEnd: L{None} or L{Deferred <defer.Deferred>}
    @ivar onEnd: If set, a deferred on which to errback when the process ends.
    Nc                 C   s   | j dur| j | dS dS )z
        Call an errback.

        @type reason: L{Failure <failure.Failure>}
        @param reason: The reason the child process terminated.
        N)rv   r   )r?   reasonr   r   r   processEnded  s   
z!ProcessAliasProtocol.processEnded)rK   rL   rM   rN   rv   r   r   r   r   r   r     s    r   c                   @   s:   e Zd ZdZeZdd ZdefddZdd Zd	d
 Z	dS )ProcessAliasa6  
    An alias which is handled by the execution of a program.

    @type path: L{list} of L{bytes}
    @ivar path: The arguments to pass to the process. The first string is
        the executable's name.

    @type program: L{bytes}
    @ivar program: The path of the program to be executed.

    @type reactor: L{IReactorTime <twisted.internet.interfaces.IReactorTime>}
        and L{IReactorProcess <twisted.internet.interfaces.IReactorProcess>}
        provider
    @ivar reactor: A reactor which will be used to create and timeout the
        child process.
    c                 G   s,   t j| g|R   | | _| jd | _dS )aX  
        @type path: L{bytes}
        @param path: The command to invoke the program consisting of the path
            to the executable followed by any arguments.

        @type args: 2-L{tuple} of (0) L{dict} mapping L{bytes} to L{IDomain}
            provider, (1) L{bytes}
        @param args: Arguments for L{AliasBase.__init__}.
        r   N)r<   r@   r   pathprogram)r?   r   rP   r   r   r   r@     s   
zProcessAlias.__init__rQ   c                 C   rR   )z
        Build a string representation of this L{ProcessAlias} instance.

        @rtype: L{bytes}
        @return: A string containing the command used to invoke the process.
        z	<Process rS   )r   rB   r   r   r   rT   .  rC   zProcessAlias.__str__c                 C   s   | j |||S )aP  
        Spawn a process.

        This wraps the L{spawnProcess
        <twisted.internet.interfaces.IReactorProcess.spawnProcess>} method on
        L{reactor} so that it can be customized for test purposes.

        @type proto: L{IProcessProtocol
            <twisted.internet.interfaces.IProcessProtocol>} provider
        @param proto: An object which will be notified of all events related to
            the created process.

        @type program: L{bytes}
        @param program: The full path name of the file to execute.

        @type path: L{list} of L{bytes}
        @param path: The arguments to pass to the process. The first string
            should be the executable's name.

        @rtype: L{IProcessTransport
            <twisted.internet.interfaces.IProcessTransport>} provider
        @return: A process transport.
        )r   spawnProcess)r?   protor   r   r   r   r   r   7  s   zProcessAlias.spawnProcessc                 C   s,   t  }t|| j| j}| || j| j |S )z
        Launch a process and create a message receiver to pass a message
        to the process.

        @rtype: L{MessageWrapper}
        @return: A message receiver which delivers a message to the process.
        )r   rq   r   r   r   r   )r?   r   mr   r   r   rE   Q  s   z"ProcessAlias.createMessageReceiverN)
rK   rL   rM   rN   r   r@   r   rT   r   rE   r   r   r   r   r   
  s    	r   c                   @   rY   )MultiWrapperz
    A message receiver which delivers a single message to multiple other
    message receivers.

    @ivar objs: See L{__init__}.
    c                 C   s
   || _ dS )z
        @type objs: L{list} of L{IMessage <smtp.IMessage>} provider
        @param objs: Message receivers to which the incoming message should be
            directed.
        N)objs)r?   r   r   r   r   r@   h  s   
zMultiWrapper.__init__c                 C   s   | j D ]}|| qdS )z
        Pass a received line to the message receivers.

        @type line: L{bytes}
        @param line: A line of the message.
        N)r   ra   )r?   r   or   r   r   ra   p  s   
zMultiWrapper.lineReceivedc                 C   s   t dd | jD S )aG  
        Pass the end of message along to the message receivers.

        @rtype: L{DeferredList <defer.DeferredList>} whose successful results
            are L{bytes} or L{None}
        @return: A deferred list which triggers when all of the message
            receivers have finished handling their end of message.
        c                 S   r
   r   )rj   )r   r   r   r   r   r     r   z,MultiWrapper.eomReceived.<locals>.<listcomp>)r   DeferredListr   rB   r   r   r   rj   z  s   	zMultiWrapper.eomReceivedc                 C   s   | j D ]}|  qdS )zQ
        Inform the message receivers that the connection has been lost.
        N)r   rk   )r?   r   r   r   r   rk     s   

zMultiWrapper.connectionLostrQ   c                 C   s   dt t| jdS )z
        Build a string representation of this L{MultiWrapper} instance.

        @rtype: L{bytes}
        @return: A string containing a list of the message receivers.
        z<GroupWrapper rS   )r   r   r   rB   r   r   r   rT     rb   zMultiWrapper.__str__Nrl   r   r   r   r   r   _  s    
r   c                   @   sD   e Zd ZdZeZdd Zdd ZdefddZ	d	d
 Z
dddZdS )r4   aL  
    An alias which points to multiple destination aliases.

    @type processAliasFactory: no-argument callable which returns
        L{ProcessAlias}
    @ivar processAliasFactory: A factory for process aliases.

    @type aliases: L{list} of L{AliasBase} which implements L{IAlias}
    @ivar aliases: The destination aliases.
    c              	   G   sJ  t j| g|R   g | _|r|  }|dr^z
t|dd }W n ty8   t	d|dd  Y ngw | d
dd |D }W d   n1 sPw   Y  ||d nA|d	ru| j| j|dd g|R   n*|d
rtj|rt	d n| jt|g|R   n| jt|g|R   |sdS dS )a  
        Create a group of aliases.

        Parse a list of alias strings and, for each, create an appropriate
        alias object.

        @type items: L{list} of L{bytes}
        @param items: Aliases.

        @type args: n-L{tuple} of (0) L{dict} mapping L{bytes} to L{IDomain}
            provider, (1) L{bytes}
        @param args: Arguments for L{AliasBase.__init__}.
        r   r   NzInvalid filename in alias file r+   c                 S   r
   r   r   )r   lr   r   r   r     r   z'AliasGroup.__init__.<locals>.<listcomp>r   |/z Directory delivery not supported)r<   r@   aliasespopr   r1   r-   rd   r	   r   joinr   r   appendprocessAliasFactoryosr   isdirrm   rO   )r?   r3   rP   addrri   r   r   r   r@     s,   

$
zAliasGroup.__init__c                 C   rn   )z
        Return the number of aliases in the group.

        @rtype: L{int}
        @return: The number of aliases in the group.
        )r   r   rB   r   r   r   __len__  ro   zAliasGroup.__len__rQ   c                 C   s   dd tt| j S )z
        Build a string representation of this L{AliasGroup} instance.

        @rtype: L{bytes}
        @return: A string containing the aliases in the group.
        z<AliasGroup [%s]>z, )r   r   r   r   rB   r   r   r   rT     s   zAliasGroup.__str__c                 C   s   t dd | jD S )a,  
        Create a message receiver for each alias and return a message receiver
        which will pass on a message to each of those.

        @rtype: L{MultiWrapper}
        @return: A message receiver which passes a message on to message
            receivers for each alias in the group.
        c                 S   r
   r   )rE   )r   r:   r   r   r   r     r   z4AliasGroup.createMessageReceiver.<locals>.<listcomp>)r   r   rB   r   r   r   rE     s   	z AliasGroup.createMessageReceiverNc                 C   s<   |du ri }g }| j D ]}|||| qttd|S )a  
        Map each of the aliases in the group to its ultimate destination.

        @type aliasmap: L{dict} mapping L{bytes} to L{AliasBase}
        @param aliasmap: A mapping of username to alias or group of aliases.

        @type memo: L{None} or L{dict} of L{AliasBase}
        @param memo: A record of the aliases already considered in the
            resolution process.  If provided, C{memo} is modified to include
            this alias.

        @rtype: L{MultiWrapper}
        @return: A message receiver which passes the message on to message
            receivers for the ultimate destination of each alias in the group.
        N)r   r   rI   r   filter)r?   rG   rH   rr:   r   r   r   rI     s   
zAliasGroup.resolverJ   )rK   rL   rM   rN   r   r   r@   r   r   rT   rE   rI   r   r   r   r   r4     s    &		r4   r   )rN   r   r[   zope.interfacer   twisted.internetr   r   r   twisted.mailr   twisted.mail.interfacesr   twisted.pythonr   r	   r'   r;   r<   rO   IMessagerZ   rm   	Exceptionrp   rq   ProcessProtocolr   r   r   r4   r   r   r   r   <module>   s8   
H6FE& T6