Advertisement
Guest User

Untitled

a guest
May 28th, 2018
204
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.99 KB | None | 0 0
  1. import re
  2. import sys
  3. import ssl
  4. import email
  5. import base64
  6. import socket
  7.  
  8. __all__ = ['POP3Client', 'POP3ClientError']
  9.  
  10. CRLF = b'\r\n'
  11.  
  12. Commands = {'USER': ('AUTH',),
  13.             'PASS': ('AUTH',),
  14.             'QUIT': ('AUTH', 'TRANSACTION'),
  15.             'STAT': ('TRANSACTION'),
  16.             'TOP': ('TRANSACTION'),
  17.             'RETR': ('TRANSACTION'),
  18.             'LIST': ('TRANSACTION')}
  19.  
  20. class IMAP:
  21.     def __init__(self, host: str = 'pop.yandex.ru', port: int = 995):
  22.         self._host = host
  23.         self._port = port
  24.         self._sock = self._create_socket()
  25.         self._state = 'NOTAUTH'
  26.         self._create_connection()
  27.  
  28.     @staticmethod
  29.     def _create_socket():
  30.         try:
  31.             sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  32.             ssl_sock = ssl.wrap_socket(sock)
  33.             ssl_sock.settimeout(1)
  34.             return ssl_sock
  35.         except OSError as exception:
  36.             print(f'ERROR! Could not create a socket. {exception}.')
  37.             sys.exit()
  38.  
  39.     def _create_connection(self):
  40.         try:
  41.             self._sock.connect((self._host, self._port))
  42.             try:
  43.                 self._receive()
  44.                 self._state = 'AUTH'
  45.                 print(f'Successful connection to: {self._host}')
  46.             except POP3ClientError:
  47.                 print(f'Error connecting to: {self._host}')
  48.                 sys.exit()
  49.         except socket.timeout as exception:
  50.             print(f'ERROR! Could not create a connection: {exception}.')
  51.             sys.exit()
  52.  
  53.     def _close_connection(self):
  54.         self._sock.close()
  55.  
  56.     def _send_data(self, data: str):
  57.         self._sock.sendall(data.encode() + CRLF)
  58.  
  59.     def _read_data(self) -> str:
  60.         result = b''
  61.         while True:
  62.             try:
  63.                 data_part = self._sock.recv(1024)
  64.                 if data_part is None or data_part == b'':
  65.                     break
  66.                 result += data_part
  67.             except socket.timeout:
  68.                 break
  69.         return result.decode()
  70.  
  71.     def _receive(self):
  72.         response = self._read_data()
  73.         if not response.startswith('+'):
  74.             raise POP3ClientError('ERROR!' + response[4:])
  75.         return response[4:]
  76.  
  77.     def _is_valid_command(self, command: str) -> bool:
  78.         states = Commands.get(command)
  79.         if states is None or self._state not in states:
  80.             return False
  81.         return True
  82.  
  83.     def _execute(self, command: str) -> str:
  84.         if self._is_valid_command(command[0:4].strip()):
  85.             self._send_data(command)
  86.             try:
  87.                 response = self._receive()
  88.                 return response
  89.             except POP3ClientError as error:
  90.                 return f'Command Error: {error}'
  91.         else:
  92.             return 'Command Error: Wrong command or command can not be execute from this state'
  93.  
  94.     def user(self, user: str) -> str:
  95.         return self._execute(f'USER {user}')
  96.  
  97.     def password(self, password: str) -> str:
  98.         response = self._execute(f'PASS {password}')
  99.         if response.startswith('Command Error'):
  100.             return response
  101.         self._state = 'TRANSACTION'
  102.         return 'Successful authorization'
  103.  
  104.     def stat(self) -> str:
  105.         return 'Messages: ' + self._execute('STAT')
  106.  
  107.     def head(self, msg: int, type:str) -> str:
  108.         return type + ': ' + self.get_headers(self.top(msg,0))[type]
  109.  
  110.     def full(self, msg: int):
  111.         message = self.retr(msg)
  112.         if re.findall('Content-Type: multipart/mixed', message.split('\r\n\r\n')[0]):
  113.             boundary = re.findall('boundary="(.*?)"', message)[0]
  114.             content_chunks = re.split('--' + boundary, message)[1:-1]
  115.             result = ''
  116.             for chunk in content_chunks:
  117.                 header, content = chunk.split(CRLF.decode() * 2)
  118.                 if header.startswith(f'{CRLF.decode()}Content-Disposition: attachment;'):
  119.                     filename = re.findall('filename="(.*)"', header)[0]
  120.                     with open(filename, 'wb') as file:
  121.                         file.write(base64.b64decode(content.encode()))
  122.                     result += f'Attachment\r\nHeader:{header}\r\nFilename:{filename}\r\n'
  123.                 elif 'text/html' in header:
  124.                     result += f"Header:{header}\r\nContent:{re.findall('>(.*?)<',content)[0]}\r\n\r\n"
  125.                 else:
  126.                     result += f"Header:{header}\r\nContent:{content}\r\n\r\n"
  127.             return result
  128.         elif re.findall('Content-Type: text/html', message.split('\r\n\r\n')[0]):
  129.             return re.findall('>(.*?)<', message.split('\r\n\r\n')[1])[0]
  130.         else:
  131.             return message.split(('\r\n\r\n')[1])
  132.  
  133.  
  134.     def list(self, msg: int = None) -> str:
  135.         return self._execute(f'LIST {msg}') if msg else self._execute('LIST')
  136.  
  137.     def retr(self, msg: int) -> str:
  138.         return self._execute(f'RETR {msg}')
  139.  
  140.     def top(self, msg: int, num: int) -> str:
  141.         return self._execute(f'TOP {msg} {num}')
  142.  
  143.     def quit(self) -> str:
  144.         response = self._execute('QUIT')
  145.         self._close_connection()
  146.         return response
  147.  
  148.     def get_headers(self, message) -> dict:
  149.         from_reg = re.findall('(From: )=\?utf-8\?B\?(.*?)\?= (.*?)', message)
  150.         result = {}
  151.         if from_reg:
  152.             result['From'] = f'{self.get_base64_header(from_reg)} {from_reg[0][2]}'
  153.         else:
  154.             result['From'] = re.findall(f'From: (.*)\n', message)[0]
  155.         result['To'] = re.findall(r'To: (.*?)\n', message)[0]
  156.         result['Date'] = re.findall(r'Date: (.*?)\n', message)[0]
  157.         subject_reg = re.findall('(Subject: |\t)=\?utf-8\?B\?(.*?)\?=', message)
  158.         if subject_reg:
  159.             result['Subject'] = f'{self.get_base64_header(subject_reg)}'
  160.         else:
  161.             result['Subject'] = re.findall(f'Subject: (.*)\n', message)[0]
  162.         return result
  163.  
  164.     def get_base64_header(self, found) -> str:
  165.         return ''.join([base64.b64decode(x[1].encode()).decode() for x in found])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement