· 8 years ago · Jun 18, 2018, 09:48 PM
1from getpass import getpass
2import re
3from subprocess import Popen
4import time
5from bs4 import BeautifulSoup
6import imaplib
7import imapclient
8import pyzmail
9
10# Constants
11TORRENT = "C:\\Program Files\\qBittorrent\\qbittorrent.exe"
12
13
14def validate_email(email):
15 """
16 Validates a string for properly formatted
17 email address and returns True or False
18 """
19
20 regex = re.compile(
21 r'''[a-zA-Z0-9._%+-]+ # username
22 @
23 [a-zA-Z0-9.-]+ # domain name
24 (\.[a-zA-Z]{2,4}) # top level domain name
25 ''', re.VERBOSE
26 )
27
28 return bool(regex.search(email))
29
30
31def check_email(username, password, key, email):
32 """
33 """
34
35 # Log user in
36 imap_client = login_imap(username, password)
37
38 # Bypass size limit
39 imaplib._MAXLINE = 10000000
40
41 imap_client.select_folder("INBOX")
42
43 if username.endswith("@gmail.com"):
44 new_mail = imap_client.gmail_search(f"{key} from:{email}")
45 else:
46 new_mail = imap_client.search(["TEXT", key, "FROM", email])
47
48 if new_mail:
49 return imap_client, new_mail
50
51
52def find_imap(email):
53 """
54 Figures out and returns the IMAP client according to email address.
55 Works with Gmail, Hotmail, and Yahoo ('.com' addresses only.)
56 """
57
58 provider = email.split("@")[1]
59
60 if provider == "gmail.com":
61 return "imap.gmail.com"
62 elif provider == "hotmail.com":
63 return "imap-mail.outlook.com"
64 elif provider == "yahoo.com":
65 return "imap.mail.yahoo.com"
66
67
68def login_imap(username, pwd):
69 """
70 Logs 'username' into 'imap' client and returns IMAPClient object.
71 """
72
73 imap_client = imapclient.IMAPClient(find_imap(username), ssl=True)
74
75 try:
76 imap_client.login(username, pwd)
77 except imaplib.IMAP4.error:
78 print(f"Invalid username and/or password. Please try again.")
79 quit()
80
81 return imap_client
82
83
84def process_msgs(messages):
85 """
86 """
87
88 msgs_html = get_msgs(get_raw_msgs(messages))
89
90 commands = find_commands(msgs_html)
91
92 open_magnets(list(commands))
93
94 # TODO find and execute commands
95
96 # Delete emails after execution
97 #delete_msgs(messages)
98
99 # Log out of account
100 messages[0].logout()
101
102
103def get_raw_msgs(messages):
104 """
105 """
106
107 imap_client, UIDs = messages
108 fetched_msgs = imap_client.fetch(UIDs, ['BODY[]'])
109
110 return fetched_msgs
111
112
113def get_msgs(raw_msgs):
114 """
115 """
116
117 ready_msgs = []
118
119 for raw_msg in raw_msgs:
120 message = pyzmail.PyzMessage.factory(raw_msgs[raw_msg][b'BODY[]'])
121 message = message.html_part.get_payload().decode(
122 message.html_part.charset)
123
124 ready_msgs.append(message)
125
126 return ready_msgs
127
128
129def delete_msgs(messages):
130 """
131 """
132
133 imap_client, UIDs = messages
134
135 imap_client.delete_messages(UIDs)
136 try:
137 imapclient.expunge()
138 except AttributeError:
139 pass
140
141
142def find_commands(msgs_html):
143 """
144 """
145
146 for html in msgs_html:
147 soup = BeautifulSoup(html, "lxml")
148
149 divs = soup.select("div")
150
151 for div in divs:
152 if div.getText().startswith("magnet:"):
153 yield div.getText()
154
155
156def open_magnets(magnets):
157 """
158 """
159
160 processes = [Popen([TORRENT, magnet]) for magnet in magnets]
161
162 waiters = [process.wait() for process in processes]
163
164
165
166
167def main():
168 # Program presentation
169 print(f"\n{'Controlling Your Computer Through Email':>80}")
170 print(f"{'*********** **** ******** ******* *****':>80}\n")
171 print(
172 "Your email account (Gmail, Hotmail, or Yahoo) will be checked "
173 " every 15 minutes for commands.\nA key will be required with "
174 "every message to confirm identity.\n")
175
176 # Get user email account
177 while True:
178 username = input("Please enter the email account to be checked:\n")
179 if validate_email(username):
180 break
181
182 # Get user email account password
183 while True:
184 pwd = getpass(
185 "\nPlease enter the password for the account to be checked:\n")
186 if pwd:
187 break
188
189 # Get verification key
190 while True:
191 key = input("\nPlease enter the verification key:\n")
192 if key:
193 print(f"Key '{key}' will be used.\n")
194 break
195
196 # Get sender email account
197 while True:
198 email = input("Please enter the sender email address:\n")
199 if validate_email(email):
200 print(f"Sender '{email}' will be used.\n")
201 break
202
203 # Start program at user's command
204 print("Press ENTER to start program. Press CTRL+C to exit.")
205 input()
206 print("Program started.")
207
208 try:
209 while True:
210 new_mail = check_email(username, pwd, key, email)
211
212 if new_mail:
213 process_msgs(new_mail)
214
215 # Wait 15 minutes to check again
216 time.sleep(900)
217
218 except KeyboardInterrupt:
219 print("Program stopped. Quitting...")
220
221 quit()
222
223if __name__ == "__main__":
224 main()