Advertisement
Guest User

Untitled

a guest
May 24th, 2015
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.54 KB | None | 0 0
  1. #!/usr/bin/python3
  2.  
  3. import argparse
  4. import ssl
  5. import sys
  6. import socket
  7. #import os
  8. import re
  9. from base64 import b64encode, b64decode
  10. from getpass import getpass
  11. import time
  12. import quopri
  13. from random import randint
  14.  
  15. SSL_PORT = 995
  16. PORT = 995
  17. ALT_PORT = 110
  18. BUF_SIZE = 2048
  19.  
  20. pattern = re.compile(r"^(\d+)( (\d+))*?$")
  21. header_pattern = re.compile(r"([A-Z][A-Za-z\-]+):(.*)", re.DOTALL)
  22. headers = {"From", "To", "Subject", "Date"}
  23. end_file_pattern = re.compile(r"--.*?--")
  24. type_header = {"Content-Disposition"}
  25. attachment_pattern = re.compile(r"(attachment)(.*)")
  26. filename_pattern = re.compile(r"(filename)(.*)")
  27. filename_pattern2 = re.compile(r"(=)(.*)")
  28. coded_line_begin = re.compile(r"=(.*?)\?(.*?)\?(B|Q|b|q)\?(.*)")
  29. coded_line_end = re.compile(r"(.*?)\?=(.*)")
  30. #Content-Disposition:attachment;filename="test.png"
  31.     #To: КН-201 <e@mail>
  32.     #Subject: тема
  33.     #Date: Fri, 5 Apr 2012 09:00:00 GMT+5
  34.  
  35.  
  36.  
  37. def parse(choose_of_user, minv, maxv):
  38.     #print(minv, maxv)
  39.     result = pattern.search(choose_of_user)
  40.     if result:
  41.         begin = int(result.group(1))
  42.         if result.group(2):
  43.             end = int(result.group(3))
  44.         else:
  45.             end = int(result.group(1)) + 1
  46.         #print(minv <= begin and begin <= end and end <= maxv + 1)
  47.         if (minv <= begin and begin <= end and end <= maxv + 1):
  48.             return range(begin, end)
  49.     else:
  50.         return None
  51.  
  52.  
  53. class MessageParser:
  54.     def __init__(self):
  55.         pass
  56.  
  57.     def parse_message(self, msg):
  58.         lines = msg.split(b"\r\n")
  59.         size = 0
  60.         attachment_count = 0
  61.         msg = {"filename":[]}
  62.         current_header = ""
  63.         read_token = False
  64.         attach_read = False
  65.         for line_bytes in lines:
  66.             #print(line)
  67.             try:
  68.                 line = line_bytes.decode()
  69.             except UnicodeDecodeError:
  70.                 #print("unicode")
  71.                 continue
  72.             size += len(line)
  73.             res = header_pattern.search(line)
  74.             if res:
  75.                 name_header = res.group(1)
  76.                 if name_header in headers:
  77.                     #print("header" + name_header)
  78.                     current_header = name_header
  79.                     read_token = True
  80.                     #print(res.group(1))
  81.                     msg[current_header] = res.group(2) + "\r\n"
  82.                 elif name_header in type_header:
  83.                     #print(line)
  84.                     res = attachment_pattern.search(res.group(2))
  85.                     if res:
  86.                         res = filename_pattern.search(res.group(2))
  87.                         if res:
  88.                             res = filename_pattern2.search(res.group(2))
  89.                             if res:
  90.                                 attachment_count += 1
  91.                                 msg["filename"].append(res.group(2))
  92.                                 read_token = True
  93.                                 msg[res.group(2)] = 0
  94.                                 current_header = res.group(2)
  95.                                 attach_read = True
  96.                 elif attach_read:
  97.                     pass
  98.                     #print(line)
  99.                     #print("true")
  100.                     #msg[current_header] += line + "\r\n"    
  101.                 else:
  102.                     #print(line)
  103.                     #print("false")
  104.                     read_token = False
  105.                     attach_read = False
  106.             elif read_token and not attach_read:
  107.                 #print(line)
  108.                 #print("true")
  109.                 msg[current_header] += line + "\r\n"
  110.             elif attach_read and read_token:
  111.                     #print(line, len(line))
  112.                 #print("true")
  113.                 read_token = False
  114.             elif attach_read:
  115.                 if (end_file_pattern.search(line)):
  116.                     #print("end", line)
  117.                     attach_read = False
  118.                 else:
  119.                     msg[current_header] += len(line)
  120.             else:
  121.                 read_token = False
  122.                 attach_read = False
  123.        
  124.         msg["From"] = self.decode_header(msg.get("From"))
  125.         msg["Subject"] = self.decode_header(msg.get("Subject"))
  126.         msg["To"] = self.decode_header(msg.get("To"))
  127.         msg["Date"] = msg.get("Date", "").strip()
  128.         for key in headers:
  129.             try:
  130.                 print("{}: {}".format(key, msg.get(key)))
  131.             except UnicodeEncodeError:
  132.                 print("Header has a proplem with unicode {}".format(key))
  133.                 print("{} in bytes".format(msg.get(key).encode()))
  134.         print("Amount attaches = {}".format(attachment_count))
  135.         for filename in msg["filename"]:
  136.             print("Filename: {}, size of file: {}".format(filename, msg.get(filename)))
  137.            
  138.     def decode_header(self, header):
  139.         result = ""
  140.         data = ""
  141.         end = ""
  142.         #print("header")
  143.         #print(header)
  144.         #print()
  145.         if header:
  146.             tokens = coded_line_begin.search(header)
  147.             if tokens:
  148.                 while tokens:
  149.                     notcode = tokens.group(1)
  150.                     coding = tokens.group(2)
  151.                     alg = tokens.group(3)
  152.                     data = tokens.group(4)
  153.                     result += notcode
  154.                     #print(notcode, coding, alg, data)
  155.                     res = coded_line_end.search(data)
  156.                     result += self.get_original_string(coding, alg, res)
  157.                     if res:
  158.                         tokens = coded_line_begin.search(res.group(1))
  159.                         end = res.group(2)
  160.                 return result + end
  161.             else:
  162.                 return header
  163.  
  164.     def get_original_string(self, coding, alg, res):
  165.         if res:
  166.             #print(res.group(1))
  167.             coded_data = res.group(1)
  168.             try:
  169.                 if alg == "Q" or alg == "q":
  170.                     string = quopri.decodestring(coded_data).decode(coding)
  171.                 else:
  172.                     string = b64decode(coded_data).decode(coding)
  173.             except UnicodeEncodeError:
  174.                 return "unicode_troubles"
  175.             return string
  176.         return ""
  177.  
  178.  
  179.  
  180. class POP3:
  181.     def __init__(self, server_hostname, debug):
  182.         self.server_hostname = server_hostname
  183.         self.debug = debug
  184.         self.timeout = 2
  185.         self.parser = MessageParser()
  186.  
  187.     def _get_socket(self, host, port, timeout):
  188.         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  189.         sock.settimeout(timeout)
  190.         if port == SSL_PORT:
  191.             sock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_SSLv23)
  192.         sock.connect((host, port))
  193.         greeting = sock.recv(1024)
  194.         if self.debug:
  195.             print(greeting, file=sys.stderr)
  196.         return sock
  197.  
  198.     def connect(self, host, port):
  199.         self.sock = self._get_socket(host, port, self.timeout)
  200.    
  201.     def send(self, msg):
  202.         if (self.debug):
  203.             print(msg, file=sys.stderr)
  204.         self.sock.send(msg.encode() + b"\r\n")
  205.  
  206.     def recieve(self):
  207.         result = b""
  208.         data = b""
  209.         try:
  210.             data = self.sock.recv(BUF_SIZE)
  211.             while data:
  212.                 result += data
  213.                 data = self.sock.recv(BUF_SIZE)
  214.         except socket.timeout:
  215.             # print("timeout")
  216.             if result[:1] == b"-":
  217.                 print("Oparation failed")
  218.                 sys.exit(1)
  219.             return result
  220.         if result[:1] == b"-":
  221.             print("Oparation failed")
  222.             sys.exit(1)
  223.         return result
  224.  
  225.     def authentication(self):
  226.         mail = input("Enter your mail ")
  227.         password = getpass("Enter your password ")
  228.         self.send("USER {}".format(mail))
  229.         ans = self.recieve()
  230.         if (self.debug):
  231.             print(ans, file=sys.stderr)
  232.         self.send("PASS {}".format(password))
  233.         ans = self.recieve()
  234.         if (self.debug):
  235.             print(ans, file=sys.stderr)
  236.  
  237.     def list_command(self):
  238.         self.send("LIST")
  239.         data = self.recieve()
  240.         if (self.debug):
  241.             print(data, file=sys.stderr)
  242.         list_msgs = data.split(b"\r\n")[1:-2]
  243.         #for letter_id in list_msgs[:-2]:
  244.         #    print(letter_id.decode())
  245.         first = int(list_msgs[0].decode().split(" ")[0])
  246.         last =  int(list_msgs[-1].decode().split(" ")[0])
  247.         print("First_number {}, last number - {}".format(first, last))
  248.         res = None
  249.         while not res:
  250.             choose_of_user = input("сhoose one or range ")
  251.             if (self.debug):
  252.                 print(choose_of_user, file=sys.stderr)
  253.             res = parse(choose_of_user, first, last)
  254.             #print(res)
  255.         for i in res:
  256.             msg_id = list_msgs[i - 1].decode().split(" ")[0]
  257.             size_msg = list_msgs[i - 1].decode().split(" ")[1]
  258.             print("ID {}".format(msg_id))
  259.             try:
  260.                 self.retr_command("{}".format(list_msgs[i - 1].decode().split(" ")[0]))
  261.             except UnicodeDecodeError as e:
  262.                 pass
  263.                 #print(e)
  264.             print("Size message {} in octets".format(size_msg))
  265.  
  266.                
  267.     def retr_command(self, msg_id):
  268.         self.send("RETR {}".format(msg_id))
  269.         ans = self.recieve()
  270.         while ans[-5:] != b"\r\n.\r\n":
  271.             #print(ans[-5:])
  272.             ans += self.recieve()
  273.         self.parser.parse_message(ans)
  274.         if (self.debug):
  275.             with open("retr.eml", "w") as f:
  276.                 print(ans, file=f)        
  277.  
  278.     def top_command(self, msg_id):
  279.         self.send("TOP {}".format(msg_id))
  280.         ans = self.recieve()
  281.         self.parser.parse_message(ans)
  282.         if (self.debug):
  283.             with open("top.eml", "w") as f:
  284.                 print(ans, file=f)
  285.  
  286.     def capa_command(self):
  287.         self.send("CAPA")
  288.         data = self.recieve().decode()
  289.         if (self.debug):
  290.             print(data, file=sys.stderr)
  291.  
  292.     def quit_command(self):
  293.         self.send("QUIT")
  294.         data = self.recieve()
  295.         if (self.debug):
  296.             print(data, file=sys.stderr)
  297.  
  298. def is_valid_ip4_address(addr):
  299.     parts = addr.split(".")
  300.     if not len(parts) == 4:
  301.         return False
  302.     for part in parts:
  303.         try:
  304.             number = int(part)  
  305.         except ValueError:
  306.             return False
  307.         if number > 255:
  308.             return False
  309.     return True
  310.  
  311. def to_ip(addr):
  312.     if is_valid_ip4_address(addr):
  313.         return addr
  314.     return socket.gethostbyname(addr)
  315.  
  316. def new_session(server, debug):
  317.     connection = POP3(server, debug)
  318.     ssl_connection = True
  319.     try:
  320.         connection.connect(server, PORT)
  321.         if (debug):
  322.             print("PORT = {}".format(PORT))
  323.     except OSError as e:
  324.         try:
  325.             connection.connect(server, ALT_PORT)
  326.             if (debug):
  327.                 ssl_connection = False
  328.                 print("PORT = {}".format(ALT_PORT))
  329.         except OSError as e:
  330.             print(e)
  331.             sys.exit(1)
  332.     connection.capa_command()
  333.     connection.authentication()
  334.     connection.list_command()
  335.  
  336.     connection.quit_command()
  337.  
  338.  
  339. def main():
  340.     parser = argparse.ArgumentParser(description="POP3")
  341.     parser.add_argument("server_pop3", help="Server POP3")
  342.     parser.add_argument("-d", "--debug", action='store_true', help="debug_mode")
  343.     args = parser.parse_args()
  344.     try:
  345.         new_session(args.server_pop3, args.debug)
  346.     except Exception as e:
  347.         print(e)
  348.  
  349.    
  350.  
  351. if __name__ == "__main__":
  352.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement