# This work is licensed under the Creative Commons # Attribution-NonCommercial-ShareAlike License. To view a copy of this # license, visit http://creativecommons.org/licenses/by-nc-sa/1.0/ or # send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, # California 94305, USA. # # Stuart Woodward 2003 # #!/usr/local/bin/python #TODO log with the correct time zone import sys import traceback import string import time import urllib import httplib from time import gmtime, strftime import os import errno import mimetypes import email import posix DEBUG = 1==0 # Text found in the MessageID of messages sent from your mobile phone # This is used as simple protection against some else sending a message # message to the journal MESSAGE_ID_DOMAIN = ".ezweb.ne.jp" # "From" email address that is required to be in the headers REQUIRED_FROM = '"Stuart Woodward" ' # "To" email address that is required to be in the headers REQUIRED_REPLY_TO = 'email@example.com' # Subject to be used if the mail's Subject is blank DEFAULT_SUBJECT = "Posted from my phone" # Where the attached image will be saved to imageDirRoot = "/usr/www/users/stuartcw/stuart/images/au" # Base of the url to be used in creating the posted message imageDirectoryUrlBase = "http://www.stuartwoodward.com/images/au" # livejournal logon details password="password" user="stuartcw" # files used for logging logFileName="journal2.log" debugLogFileName="debug2.log" monthDict={ 'Jan':1, 'Feb':2, 'Mar':3, 'Apr':4, 'May':5, 'Jun':6, 'Jul':7, 'Aug':8, 'Sep':9, 'Oct':10, 'Nov':11, 'Dec':12 } def log( fp, message ): if fp==None: raise "No log specified.." timeStr = strftime( "%a, %d %b %Y %H:%M:%S +0000", gmtime() ) fp.write( timeStr + " : " + message + "\n" ) def checkHeader( msg, header, expected ): # Check that the expected header is present in the msg if msg[header] != expected : # Format a Invalid Mail message in a consistant way message = "Invalid Mail: Bad '" + header + "' " message += "expected " + expected + " but got " + msg[header] raise message def isCorrectMessageIDDomain(msg): # Returns true if the msg has a Message-ID similar to # Message-ID: <20021104121742.QPRT2402@im05imap11-s0.ezweb.ne.jp> # return msg['Message-ID']!= None and (string.find( msg['Message-ID'], MESSAGE_ID_DOMAIN ) != -1) def validateMessage( logFile, msg ): # Check the message to see if it is acceptable. If not raise an exception. # This code can be modified to change the rules about what constitutes a # valid message log( logFile, "validating message" ) if DEBUG : log( logFile, "Subject:", msg['Subject'] + "\nFrom:", msg['From'] + "\nReply-To:",msg['Reply-To'] ) if not isCorrectMessageIDDomain( msg ): raise "Message is not from the correct domain." log( logFile, "Is Au" ) log( logFile, "From is " + msg['From'] ) checkHeader( msg, 'From', REQUIRED_FROM) log( logFile, "From OK" ) checkHeader( msg, 'Reply-To', REQUIRED_REPLY_TO) log( logFile, "Reply To OK" ) def createBody( body, imageFilename ): # Create the HTML body of the blog from the existing body text which may be blank # and the ImageFilename which exists in the images directory # $$ A template could be used to here to format the message # $$ we could pass in the image here and examine it to set the size return body + '' def processMail( inputStream ): # Errors opening the logs are too serious to handle logFile = open( logFileName, "a" ) debugLogFile = open( debugLogFileName, "a") try: # Log Exceptions that occur in this try block log( logFile, "------------" ) log( debugLogFile, "------------" ) # check if the images folder(imageDirRoot) exists if not os.access( imageDirRoot, os.W_OK ): raise "Can't write to " + os.path.abspath(imageDirRoot) log( logFile, "Image directory writeable" ) msg = email.message_from_file(inputStream) log( logFile, "About to validate the message" ) # throw an exception if this message does not contain the # the right information validateMessage( logFile, msg ) body = "No body" subject = msg['Subject'] #$$split out later if subject==None: subject = DEFAULT_SUBJECT imagePath = "" for part in msg.walk(): # multipart/* are just containers if part.get_main_type() == 'multipart': continue type = part.get_type() imageFilePath = "" if type == "text/plain": body = part.get_payload( decode=1 ) log( logFile, "BODY='" + body + "'" ) elif type == "image/jpeg": dir = imageDirRoot # Applications should really sanitize the given filename so that an # email message can't be used to overwrite important files filename = part.get_filename() log( logFile, "Found: " + filename + " : " + part.get_type() ) if not filename: continue imageFilePath = os.path.join(dir, filename) fp = open( imageFilePath, 'wb') fp.write(part.get_payload(decode=1)) # fp.write(part.get_payload()) fp.close() posix.chmod( imageFilePath, 0644 ) log( logFile, "Making Link: " + imageDirRoot+"/latest.jpg" ) posix.unlink( imageDirRoot+"/latest.jpg" ) posix.symlink( imageFilePath, imageDirRoot+"/latest.jpg" ) # assume that the text body comes first in the Mime attachments body = createBody( body, filename ) date = msg['Date'] postToBlog( date, subject, body, logFile ) except Exception, e: # $$ Maybe we should log the whole message here that cause the problem (type, value, tb) = sys.exc_info() if( 1 == 0): print('Exception Occurred: %s\n' % (e) ) traceback.print_exception( type, value, tb ) log( logFile,'Exception Occurred: %s\n' % (e) ) traceback.print_exception( type, value, tb, None, logFile ) debugLogFile.close() logFile.close() def postToBlog( fromDate, subject, body, logFile ): # This method posts the subject and body to a blog log( logFile, "BLOG Date: " + fromDate ) log( logFile, "BLOG SUBJECT: " + subject ) log( logFile, "BLOG BODY: " + body ) #Date: Wed, 3 Jan 2001 22:34:51 +0900 fromTime=string.strip(fromDate) # strip of whitespace fromTime=string.replace(fromTime,' ',':') # replace spaces with : timeTuple = string.split(fromTime,":") # split into tokens year=timeTuple[3] month=monthDict[timeTuple[2]] day=timeTuple[1] hour=timeTuple[4] minute=timeTuple[5] #year, month, day, hour, minute, second, weekday, day, dst = time.localtime( time.time() ) params = urllib.urlencode({'mode':'postevent','user': user,'password': password,'event':body,'subject':subject,'year':year,'mon': month,'day': day,'hour': hour,'min': minute}) # log( logFile, params ) dateTime='%s-%02d-%s %s:%s' % (year,month,day,hour,minute) h=httplib.HTTP("www.livejournal.com") # h.set_debuglevel(1==1) h.putrequest("POST","/cgi-bin/log.cgi") h.putheader("Content-length", "%d" % len(params)) h.putheader('Accept', 'text/plain') h.putheader('Host','www.livejournal.com') h.endheaders() h.send(params) errcode, errmsg, headers = h.getreply() f = h.getfile() content = f.read() log(logFile, 'Server Replied: %s %s %s\n' % (errcode, errmsg, content) ) if __name__ == "__main__": # dataFileName = "./pic.eml" # print "Reading " + dataFileName # dataFile = open( dataFileName, "r" ) # processMail( dataFile ) processMail( sys.stdin ) # dataFile.close() # print "Finished Reading " + dataFileName else: # print "Reading Stdin..." processMail( sys.stdin ) # print "Finished Reading Stdin..."