#!/usr/bin/env python3
# on unix-ish, can execute from the shell... ./journal_fetch_links.py

# ----
# c0de517e's email -> journal fetch script
#  Allows me to quickly post small, text-only journal entries, by sending myself an email (from any device!)
#  Appends (pre-pends, actually) to a simple text-based log file, the log file is trivial to edit, and the journal on the website will be generated from it!
#
# It took a long time just to find an email provider that still allowed access with user/pass pairs (instead of oauth etc)
# gmail remove the "app password" option, yahoo email seems to have it but didn't work (could not generate an app password)
# self-hosting seemed to be more trouble than it was worth...
#
# As for everything here - this is crappy python code and crappy data formats etc - but it's all simple enough that one could migrate in the future!
#
# From the email we parse simply the subject and the text - no tag parsing (txt2web) - no image support etc.
# ----

import os
from email.parser import BytesParser
import imaplib
import quopri
from unidecode import unidecode # this is not built-in, needs the unidecode library

os.chdir(os.path.dirname(os.path.abspath(__file__))) # Let's make sure everything from here on is relative to where this script is located

# Could/shuld simply import - but this adds directly to the global namespace so I don't need to change the code
# and it has some advantages when modifying and reloading (e.g. from an interactive debug sessions)...
with open("journal_common.py", 'r') as f:
    exec(f.read())



secret_file = "./EXTERNAL/SECRET.py"
if os.path.exists(secret_file): 
    with open(secret_file, 'r') as f:
        exec(f.read())    
    try:
        EMAIL_SITE
        EMAIL_USER
        EMAIL_PASS
        EMAIL_ALLOWLIST
    except NameError:
        print("Secret file did not define email_ variables")
else:
    print("No secret file found!")
    assert False



print("\n====================================================================================================================")
print("journal_fetch.py\n")

print("- Fetching new mails.", EMAIL_USER)
messages = journal_fetch_mails(EMAIL_SITE, EMAIL_USER, EMAIL_PASS, EMAIL_ALLOWLIST)

print("- Reading old journal log file:", JOURNAL_LOG)

journal = ""
last_postid = -1
last_splitid = -1
last_postcount = 0

if os.path.exists(JOURNAL_LOG):
    with open(JOURNAL_LOG, "r") as J:
        journal = J.read()

    # we don't need to load_and_parse_journal - the entire journal, just the last post/split...
        
    loc = journal.find(JOURNAL_MARKER_postid)
    if loc!=-1:
        endloc = journal[loc:].find("\n")+loc
        last_postid = int( journal[loc+len(JOURNAL_MARKER_postid):endloc] )

    loc = journal.find(JOURNAL_MARKER_splitid)
    if loc!=-1:
        endloc = journal[loc:].find("\n")+loc
        last_splitid = int( journal[loc+len(JOURNAL_MARKER_splitid):endloc] )

    last_postcount = journal[:loc].count(JOURNAL_MARKER_postid)

print("LAST POST, SPLIT, POSTs in split:", last_postid, last_splitid, last_postcount)

print("\n--------------------------------------------------------------------------------------------------------------------")
print("- Parsing new messages")

journal_new = []
for msg in messages:
    body = msg[4]

    # Another bad parser :) - NOT needed anymore, this was when I was storing the full message (as_string instead of get_payload)
    #header_end = body.index("\n\n")
    #if header_end!=-1:
    #    body = body[header_end+2:]

    lines = body.split("\r\n") # according to some RFC - it should be CRLF endlines for email

    newbody = "" # plain text email is split at the 80th column it seems, that's no good for (responsive) websites, so we join...
    for l in lines:
        if l.find("Sent from my iPhone")!=-1 or l.find("Sent from my iPad")!=-1:
            continue
        l = l.rstrip()
        if len(l)==0: # an empty line, preserve
            newbody+='\n'
        else:
            if l[-1]=='.': # heuristic, let's say that a line that ends with a stop deserves a \n
                newbody+=l+'\n'
            else:
                newbody+=l+' ' # join
    body = newbody.strip() + '\n' # strip extra lines at the end - but add one at the end

    # TODO - I think originally I have tested this "parser" with mails composed in gmail on the web, and from my iphone.
    # I noticed though that when sending from text editors now (simpletext on ios) I create way too many newlines. Not sure what's going
    # on so I'm adding here this ugly "heuristic" patch
    if body.count('\n\n\n') > 2:
        body = body.replace('\n\n','\n')
        print("DEBUG: Too many newlines detected and patched.")

    last_postid += 1
    last_postcount += 1
    out_str = f"{JOURNAL_MARKER_start_wdate}{msg[2]}\n{JOURNAL_MARKER_subject}{msg[3]}\n{JOURNAL_MARKER_postid}{last_postid}\n{body}"
    # print(out_str)

    if last_postcount >= JOURNAL_POSTS_PER_SPLIT:
        last_postcount = 0
        last_splitid+=1
        out_str = f"\n{JOURNAL_MARKER_splitid}{last_splitid}\n" + out_str

    journal_new.append(out_str)

print("\n--------------------------------------------------------------------------------------------------------------------")
print("- Finalizing journal")

# Write the new journal, we simply add the new text to the top...

if len(journal_new)!=0:
    print("- Old log size:",len(journal),"new posts:",len(journal_new))
    if input("CONFIRM OK TO OVERWRITE LOG - enter 'y' - ") != 'y':
        exit(0)

    with open(JOURNAL_LOG, "w") as J:
        journal_new.reverse()
        journal_new.append(journal)
        
        J.write( unidecode( (JOURNAL_MARKER_end+'\n').join(journal_new) ) ) # unidecode finds the closest ascii to unicode characters
else:
    print("- No new posts to add!")

# Finally, delete emails - only after writing to log...

if len(messages)!=0:
    if input("CONFIRM OK TO DELETE EMAILS - enter 'y' - ") != 'y':
        exit(0)

    journal_delete_mails(EMAIL_SITE, EMAIL_USER, EMAIL_PASS, messages) # needs messages as we delete by UID
