diff --git a/README.md b/README.md index 6255482..17c026b 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ olk | olkp | olknew | olkc ``` ---------------------------------------- -## Command olk - search email +## Command olk - Search email This workflow supports searching: - Mail Subject - Mail Sender - Mail Preview Content -By default, it will search all three above togther, you can figure out which single item you want to search with below format: +By default, it will search all three above together, you can figure out which single item you want to search with below format: olk from:{keyword} @@ -28,11 +28,23 @@ Supports multiple keywords search: olk title:{keyword1} {keyword2} {keyword3} +It also support get last {n} unread mail quickly: + + olk recent:10 + +or just get today's unread mail: + + olk recent:today + +You can also apply some simple keywords filter on it: + + olk recent:30 {keyword1} {keyword2} + ### This workflow search result supports Powerful Pagination: > * 'Next Page' if there's more pages available. > * If you are using **Alfred V3**, Press 'CTRL' on 'Next Page' item as modifier, then it behave as 'Previous Page' -## Command olkc - configuration +## Command olkc - Configuration You can use olkc to set some configurations for search: diff --git a/event.py b/event.py new file mode 100644 index 0000000..bf5641a --- /dev/null +++ b/event.py @@ -0,0 +1,160 @@ +# encoding:utf-8 +from __future__ import print_function, unicode_literals + +import sys +import os +import sqlite3 +import random +import unicodedata as ud + +import workflow +from workflow import Workflow +from workflow import Workflow3 +from consts import * +from util import Util + +GITHUB_SLUG = 'xeric/alfred-outlook' +UPDATE_FREQUENCY = 7 + +log = None + +APPLE_SCRIPT = """ + +set theStartDate to current date +set hours of theStartDate to 0 +set minutes of theStartDate to 0 +set seconds of theStartDate to 0 +set theEndDate to theStartDate + (2 * days) - 1 + +tell application "Microsoft Outlook" + set allEvents to every calendar event where its start time is greater than or equal to theStartDate and end time is less than or equal to theEndDate + + repeat with aEvent in allEvents + set eventProps to properties of aEvent + log eventProps + end repeat + +end tell + +""" + +SELECT_STR = """Select PathToDataFile, Contact_DisplayName, Record_ExchangeOrEasId + from Contacts + where Record_ExchangeOrEasId in (%s) + """ + + +def main(wf): + query = wf.decode(sys.argv[1]) + + handle(wf, query) + + log.info('searching contact with keyword') + + +def handle(wf, query): + if len(query) < 1 or (not str(ud.name(query[0])).startswith("CJK UNIFIED") and len(query) < 2): + wf.add_item(title='Type more characters to search...', + subtitle='too less characters will lead huge irrelevant results', + arg='', + uid=str(random.random()), + valid=False + ) + else: + # run a script to get exchange id + exchangeIdAndEmail = workflow.util.run_applescript(APPLE_SCRIPT % (query, query,)) + log.info(exchangeIdAndEmail) + idEmnailList = exchangeIdAndEmail.split(",") + + contacts = None + + log.info("found contact total number: " + str(len(idEmnailList) / 2)) + + homePath = os.environ['HOME'] + + profile = wf.stored_data(KEY_PROFILE) or OUTLOOK_DEFAULT_PROFILE + + # outlookData = homePath + '/outlook/' + outlookData = homePath + OUTLOOK_DATA_PARENT + profile + OUTLOOK_DATA_FOLDER + log.info(outlookData) + + if not Util.validateProfile(outlookData): + wf.add_item(title='Profile: ' + profile + ' is not valid...', + subtitle='please use olkc profile to switch profile', + arg='olkc profile ', + uid='err' + str(random.random()), + valid=False) + + elif len(contacts) == 0: + wf.add_item(title='No matched contact found...', + subtitle='please check the keyword and try again', + uid='err' + str(random.random()), + valid=False) + else: + con = sqlite3.connect(outlookData + OUTLOOK_SQLITE_FILE) + cur = con.cursor() + + dynamicVarsQM = "" + dynamicVars = [] + for x in contacts: + if x[0]: + dynamicVarsQM = dynamicVarsQM + "?," + dynamicVars.append(x[0]) + dynamicVarsQM = dynamicVarsQM[:-1] + + res = cur.execute(SELECT_STR % dynamicVarsQM, tuple(dynamicVars)) + + resultCount = cur.rowcount + log.info("got " + str(resultCount) + " results found") + + if resultCount: + for row in cur: + relativePath = row[0] + dispName = row[1] + excid = row[2] or "" + fillContacts(contacts, relativePath, dispName, excid) + + cur.close() + + # id, email, name, relative path + for i, contact in enumerate(contacts): + if i >= 20: + break + + log.info(contact) + path = outlookData + contact[3] if contact[3] else None + + email = contact[1] + it = wf.add_item(title=wf.decode(contact[2] or ""), + subtitle=(email if email and email.strip() else "No Email Found"), + valid=True, + uid=str(contact[0]), + arg=path or email, + type='file' if path else "") + if not Util.isAlfredV2(wf): + mod = it.add_modifier(key='ctrl', + subtitle="Compose a mail to " + email, + arg=email, + valid=True) + + wf.send_feedback() + + +if __name__ == '__main__': + wf = Workflow(update_settings={ + 'github_slug': GITHUB_SLUG, + 'frequency': UPDATE_FREQUENCY + }) + + if not Util.isAlfredV2(wf): + wf = Workflow3(update_settings={ + 'github_slug': GITHUB_SLUG, + 'frequency': UPDATE_FREQUENCY + }) + + log = wf.logger + + if wf.update_available: + wf.start_update() + + sys.exit(wf.run(main)) diff --git a/main.py b/main.py index 404c776..55b00be 100644 --- a/main.py +++ b/main.py @@ -7,6 +7,7 @@ import re import random import unicodedata as ud +from datetime import date, timedelta from workflow import Workflow from workflow import Workflow3 @@ -84,12 +85,16 @@ def handle(wf, query): searchType = 'All' + originalQuery = query if query.startswith('from:'): searchType = 'From' query = query.replace('from:', '') elif query.startswith('title:'): searchType = 'Title' query = query.replace('title:', '') + elif query.startswith('recent:'): + searchType = 'Recent' + query = query.replace('recent:', '') if query is None or query == '': wf.add_item(title='Type keywords to search mail ' + searchType + '...', @@ -121,7 +126,7 @@ def handle(wf, query): for row in cur: count += 1 - if calculatedPageSize > count: + if calculatedPageSize + 1 > count: log.info(row[0]) path = outlookData + row[3] if row[2]: @@ -137,7 +142,7 @@ def handle(wf, query): type='file') page += 1 if count > calculatedPageSize: - queryByVersion = query if not Util.isAlfredV2(wf) else query + '|' + str(page) + queryByVersion = originalQuery if not Util.isAlfredV2(wf) else originalQuery + '|' + str(page) it = wf.add_item(title='More Results Available...', subtitle='click to retrieve next ' + str(calculatedPageSize) + ' results', arg=queryByVersion, @@ -156,7 +161,7 @@ def handle(wf, query): else: if page > 1: previousPage = 0 if page - 2 < 0 else page - 2 - queryByVersion = query if not Util.isAlfredV2(wf) else query + '|' + str(previousPage) + queryByVersion = originalQuery if not Util.isAlfredV2(wf) else originalQuery + '|' + str(previousPage) it = wf.add_item(title='No More Results', subtitle='click to retrieve previous ' + str(calculatedPageSize) + ' results', arg=queryByVersion, @@ -229,8 +234,19 @@ def queryTitle(cur, keywords, offset, pageSize, folder): res = cur.execute(SELECT_STR % (titleConditions), variables + (pageSize, offset,)) -def queryAll(cur, keywords, offset, pageSize, folder): - if len(keywords) is None: +def queryRecent(cur, keywords, offset, pageSize, folder): + top = 10 + + if len(keywords) is not None: + if (keywords[0].isnumeric()): + top = int(keywords[0]) + elif (keywords[0] == 'today'): + top = -1000 + + queryAll(cur, keywords[1:], offset, pageSize, folder, top) + +def queryAll(cur, keywords, offset, pageSize, folder, top = -1): + if len(keywords) == 0 and top == -1: return log.info("query by subject, content and sender") log.info(keywords) @@ -241,6 +257,7 @@ def queryAll(cur, keywords, offset, pageSize, folder): titleVars = [] senderVars = [] contentVars = [] + conditions = None for kw in keywords: titleVars.append('%' + kw + '%') @@ -259,17 +276,40 @@ def queryAll(cur, keywords, offset, pageSize, folder): else: contentConditions += 'AND Message_Preview LIKE ? ' - titleConditions += ') ' - senderConditions += ') ' - contentConditions += ') ' + if keywords: + titleConditions += ') ' + senderConditions += ') ' + contentConditions += ') ' - conditions = titleConditions + senderConditions + contentConditions + conditions = titleConditions + senderConditions + contentConditions variables = tuple(titleVars) + tuple(senderVars) + tuple(contentVars) if folder > 0: conditions = '(' + conditions + ')' + FOLDER_COND variables += (folder,) + # calculate offset by top value + # log.info("top: %d, pageSize: %d, offset: %d" % (top, pageSize, offset)) + if top > 0: + if top > (pageSize - 1): + if top < (pageSize - 1) + offset: + pageSize = top - offset + else: + pageSize = top + + #append read flag + if conditions is None: + conditions = "Message_ReadFlag = 0 " + else: + conditions += " AND Message_ReadFlag = 0 " + elif top == -1000: + variables += (int(date.today().strftime('%s')),) + if conditions is None: + conditions = "Message_TimeReceived > ? AND Message_ReadFlag = 0 " + else: + conditions += " AND Message_TimeReceived > ? AND Message_ReadFlag = 0 " + + log.info(SELECT_STR % (conditions)) log.info(variables + (pageSize, offset,))