I made a few more edits to FTPoverEmail. I got the SSH functionality working and fixed a couple of bugs for this next version. I’ve started studying for CCDP so my work on it has tailed off a fair amount. Here’s the next version with the bug fixes and SSH functionality. I called this one a beta in that at least it runs fully and that at least it works most of the time now :-D.
import smtplib
import email
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import mimetypes
import os
import imaplib
import time
import sys
import subprocess
import signal
import urllib3
from_name = ''
to_name = ''
subject = ''
log_file = None
user = "your_email_here@gmail.com"
password = "your_password_here"
def sendresponse(response):
global log_file
response_email = MIMEText(response)
response_email['Subject'] = subject
response_email['From'] = to_name
response_email['To'] = from_name
try:
smtp = smtplib.SMTP('smtp.gmail.com')
smtp.starttls()
smtp.login(user, password)
smtp.sendmail(to_name, from_name, response_email.as_string())
smtp.close()
except smtplib.SMTPResponseException:
print(
"Server encountered the following error while attempting to
connect to SMTP server: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
log_file.write(time.strftime("%c") + " --------> " +
"Server encountered the following error while attempting to
connect to SMTP server: \nType: {0}\nValue: {1}\nTraceback: {2} \r\n".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
def sendfile(file_name, optional_text=None):
global log_file
response = MIMEMultipart()
response['Subject'] = subject
response['From'] = to_name
response['To'] = from_name
if bool(optional_text):
response.attach(MIMEText(optional_text))
else:
response.attach(MIMEText("Grabbed file " + file_name + ". See attachment."))
file_type = mimetypes.guess_type(file_name, strict=False)
main_type = None
if file_type is None:
attachment = MIMEBase('application', 'octet-stream')
else:
main_type = file_type[0].split('/')[0]
sub_type = file_type[0].split('/')[1]
attachment = MIMEBase(main_type, sub_type)
try:
f = open(file_name, "rb")
attachment.set_payload(f.read())
f.close()
except OSError:
print(
"Server encountered the following error while attempting to open
the file you asked for: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
log_file.write(time.strftime("%c") + " --------> " +
"Server encountered the following error while attempting to open the file
you asked for: \nType: {0}\nValue: {1}\nTraceback: {2}\r\n".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
sendresponse(
"Server encountered the following error while attempting to
open the file you asked for: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
if main_type == 'application' or main_type == 'audio' or main_type == 'image':
encoders.encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment;
file_name="%s"' % os.path.basename(file_name))
response.attach(attachment)
try:
smtp = smtplib.SMTP('smtp.gmail.com')
smtp.starttls()
smtp.login(user, password)
smtp.sendmail(to_name, from_name, response.as_string())
smtp.close()
except smtplib.SMTPResponseException:
print(
"Server encountered the following error while attempting to connect to
SMTP server: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
log_file.write(time.strftime("%c") + " --------> " +
"Server encountered the following error while attempting to connect to
SMTP server: \nType: {0}\nValue: {1}\nTraceback: {2} \r\n".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
def getemail():
global from_name
global to_name
global subject
global log_file
try:
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login(user, password)
mail.list()
mail.select("inbox")
result, data = mail.search(None, "UNSEEN")
if not data[0].split():
return None
id_list = data[0].split()
latest_email_id = id_list[-1]
result, data = mail.fetch(latest_email_id, "(RFC822)")
raw_email = data[0][1]
email_message = email.message_from_bytes(raw_email)
log_file.write(time.strftime("%c") + " --------> " + "-----Receiving E-mail-----\r\n")
print("-----Receiving E-mail-----\r\n")
if email_message['To'] is not None:
print(email_message['To'] + "\r\n")
log_file.write(time.strftime("%c") + " --------> " + email_message['To'] + "\r\n")
to_name = email_message['To']
else:
print("Received email with an empty To address. Ignoring the message.\r\n")
log_file.write(time.strftime("%c") + " --------> " +
"Received email with an empty To address. Ignoring the message.\r\n")
return
if email_message['Return-Path'] is not None:
print(email_message['Return-Path'])
log_file.write(time.strftime("%c") + " --------> " +
email_message['Return-Path'] + "\r\n")
from_name = email_message['Return-Path']
else:
log_file.write(time.strftime("%c") + " --------> " +
"Received email with an empty Return-Path. Ignoring the message.\r\n")
print("Received email with an empty Return-Path. Ignoring the message.")
return
if email_message['Subject'] is not None:
if email_message['Subject'].find("Re:") == -1:
subject = "Re: " + email_message['Subject']
else:
subject = email_message['Subject']
else:
subject = ''
print(subject + "\r\n")
log_file.write(time.strftime("%c") + " --------> " + subject + "\r\n")
if email_message.get_content_maintype() == 'multipart':
found_command = False
for index, part in enumerate(email_message.walk()):
if part.get_content_maintype() is 'multipart':
continue
if part.get_content_type() == 'text/plain':
found_command = True
message = part.get_payload()
proccommand(message.splitlines(), index, email_message)
break
if found_command:
return
else:
sendresponse("Error: No command was found in multipart email. Was it there?")
print("Error: Server encountered a multipart email that did not appear
to have a command in it")
elif email_message.get_content_maintype() == 'text':
print(email_message.get_payload())
proccommand(email_message.get_payload().splitlines())
else:
print("Error processing email in getemail. Encountered unrecognized content type.")
log_file.write(time.strftime("%c") + " --------> " +
"Error processing email in getemail. Encountered unrecognized content type.\r\n")
sendresponse("Error processing email in getemail. Encountered unrecognized content type.")
return
log_file.write(time.strftime("%c") + " --------> " +
"-----End Message Receive-----\r\n\r\n")
except imaplib.IMAP4.error:
print(
"Unable to pull e-mail via IMAP. An error occured: \nType:
{0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
log_file.write(time.strftime("%c") + " --------> " +
"Unable to pull e-mail via IMAP. An error occured: \nType:
{0}\nValue: {1}\nTraceback: {2}\r\n".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
def proccommand(message, index=None, email_message=None):
global log_file
command = message[0].split(' ')
message = message[0]
log_file.write(time.strftime("%c") + " --------> " + "Message: " + message + "\r\n")
errors_occurred = False
if "FTP" == command[0].upper():
if command[1].lower() == "cd":
if len(command) != 3:
sendresponse("Error: Incorrect number of arguments for cd")
errors_occurred = True
elif not os.path.exists(command[2]):
sendresponse("Error: The path: \"" + command[2] + "\" does not exist")
errors_occurred = True
else:
os.chdir(command[2])
sendresponse("CD completed successfully. Directory is now: " + os.getcwd())
elif command[1].lower() == "dir":
if len(command) < 2 or len(command) > 3:
sendresponse("Error: Incorrect number of arguments for dir")
errors_occurred = True
else:
if len(command) == 2:
response = ""
for file in os.listdir(os.getcwd()):
response = response + file + "\n"
sendresponse(response)
else:
if not os.path.exists(command[2]):
sendresponse("Error: The path: \"" + command[2] + "\" does not exist")
errors_occurred = True
else:
response = ""
for file in os.listdir(command[2]):
response = response + file + "\n"
sendresponse(response)
elif command[1].lower() == "pwd":
if len(command) != 2:
sendresponse("Error: Incorrect number of arguments for pwd")
errors_occurred = True
else:
sendresponse(os.getcwd())
elif command[1].lower() == "get":
if len(command) < 3:
sendresponse("Error: Incorrect number of arguments for get")
errors_occurred = True
else:
if not os.path.exists(" ".join(command[2:])):
sendresponse("Error: The path: \"" + " ".join(command[2:]) + "\" does not exist")
errors_occurred = True
else:
sendfile(" ".join(command[2:]))
elif command[1].lower() == "put":
if len(command) < 3:
sendresponse("Error: Incorrect number of arguments for put")
errors_occurred = True
else:
valid_path = True
if bool(os.path.split(" ".join(command[2:]))[0]):
if not os.path.exists(os.path.split(" ".join(command[2:]))[0]):
valid_path = False
sendresponse(
"Error: The path: \"" + os.path.split(" ".join(command[2:]))[0] +
"\" does not exist")
errors_occurred = True
if valid_path:
for part in list(email_message.walk())[index:]:
if part.get_content_maintype() is 'multipart':
continue
file_name = part.get_filename()
if bool(file_name):
try:
file_descriptor = open(" ".join(command[2:]), 'wb')
file_descriptor.write(part.get_payload(decode=True))
file_descriptor.close()
sendresponse("Successfully processed the put command: " + message)
except OSError:
errors_occurred = True
print(
"Server encountered the following error while attempting to write
the file you uploaded: \nType: {0}\nValue: {1}\nTraceback:
{2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]),
str(sys.exc_info()[2])))
log_file.write(time.strftime("%c") + " --------> " +
"Server encountered the following error while attempting
to write the file you uploaded: \nType: {0}\nValue:
{1}\nTraceback: {2}\r\n".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]),
str(sys.exc_info()[2])))
sendresponse(
"Server encountered the following error while attempting to
write the file you uploaded: \nType: {0}\nValue:
{1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]),
str(sys.exc_info()[2])))
break
elif command[1].lower() == "del":
if len(command) == 3:
try:
os.remove(command[2])
sendresponse("Successfully deleted file: " + command[2])
except OSError:
print(
"Server encountered the following error while attempting to
delete the file: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
log_file.write(time.strftime("%c") + " --------> " +
"Server encountered the following error while attempting to
delete the file: \nType: {0}\nValue: {1}\nTraceback: {2}\r\n".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
sendresponse(
"Server encountered the following error while attempting to
delete the file: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
else:
sendresponse(
'Error: Incorrect number of arguments sent to the "del" command.
Syntax is "FTP del <filename"')
elif command[1].lower() == "kill":
log_file.close()
sys.exit(0)
else:
errors_occurred = True
sendresponse("Error: That command did not match an FTP command.")
print("Error: That command did not match an FTP command.")
log_file.write(time.strftime("%c") + " --------> " +
"Error: That command did not match an FTP command.")
elif command[0].upper() == "SSH":
if len(command) < 2:
errors_occurred = True
sendresponse("Error: It does not appeared you supplied an argument for your SSH command.")
print("Error: It does not appear the user supplied an argument with an SSH command.\r\n")
log_file.write(time.strftime("%c") + " --------> " +
"Error: It does not appear the user supplied an argument with an SSH command.")
elif command[1].upper() == "BINARY":
if len(command) > 2:
try:
command_output = subprocess.check_output(command[2], shell=True)
try:
file_descriptor = open("output.bin", 'wb')
file_descriptor.write(command_output)
file_descriptor.close()
sendfile("output.bin", "The output of your command \"" + command[2] +
"\" is attached.")
os.remove("output.bin")
except OSError:
errors_occurred = True
print(
"Server encountered the following error while attempting to write
the output to a file: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
log_file.write(time.strftime("%c") + " --------> " +
"Server encountered the following error while attempting to write
the output to a file: \nType: {0}\nValue: {1}\nTraceback: {2}\r\n".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
sendresponse(
"Server encountered the following error while attempting to write
the output to a file: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
except subprocess.CalledProcessError:
sendresponse(
"Server encountered the following error while attempting to process
the command {3}: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]),
str(sys.exc_info()[2]), str(command[1])))
print(
"Server encountered the following error while attempting to process
the command {3}: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2]),
str(command[1])))
log_file.write(time.strftime("%c") + " --------> " +
"Server encountered the following error while attempting to process
the command {3}: \nType: {0}\nValue: {1}\nTraceback: {2}\r\n".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]),
str(sys.exc_info()[2]), str(command[1])))
else:
command_output = subprocess.Popen(" ".join(command[1:]),
shell=True,
stdin=subprocess.PIPE,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
output = ""
for line in command_output.stderr:
output = output + str(line.rstrip())[2:-1] + '\n'
command_output.stdout.flush()
output += '\n\n'
for line in command_output.stdout:
output = output + str(line.rstrip())[2:-1] + '\n'
command_output.stdout.flush()
sendresponse("Successfully processed command: " +
message + "\r\n\r\n" + output)
else:
sendresponse("Error: Bad or nonexistent command: " + message)
print("Server received an email which matched no commands.")
log_file.write(time.strftime("%c") + " --------> " +
"Server received an email which matched no commands.\r\n")
if errors_occurred:
print("Failed to process command \"" + message + "\"")
log_file.write(time.strftime("%c") + " --------> " +
"Failed to process command \"" + message + "\"\r\n")
else:
print("Successfully processed command: " + message)
log_file.write(time.strftime("%c") + " --------> " +
"Successfully processed command: " + message + "\r\n")
def signal_handler(signal, frame):
print("Server exiting...")
log_file.write(time.strftime("%c") + " -------->
" + "Server shutting down...\r\n")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
try:
log_file = open("log_file", 'a')
except OSError:
print(
"Server encountered the following error while attempting to open the
log file: \nType: {0}\nValue: {1}\nTraceback: {2}".format(
str(sys.exc_info()[0]), str(sys.exc_info()[1]), str(sys.exc_info()[2])))
sys.exit(1)
while 1:
getemail()
time.sleep(5)
log_file.close()