def __init__(self, config): self.config = config if self.config.useMail: self.mailer = Mailer(config) self.assertDetector = AssertionDetector(self.config.knownPath) self.crashDetector = CrashDetector(self.config.knownPath) self.androidLogLinefilter = lambda x: re.sub('^[^:]+: ', '', x)
class Watcher: def __init__(self, readserver, readlogin, readport, sendserver, sendfrom, sendto, sendlogin, prefix): self.reader = Reader(readlogin, readserver, readport) self.sender = Mailer(sendlogin, sendfrom, sendserver) self.sendto = sendto self.prefix = prefix def action(self): unreaded =self.reader.get_unread() for ur in unreaded: self.sender.send(self.sendto, self.prefix + ur.headers.Subject, ur.string) print "Sending " + ur.headers.Subject
def onSend(self, event): self.mailer = Mailer(self.settings.getEmail(), self.settings.getPassword()) toaddr = self.settings.getEmailTo() subject = self.txtTask.GetValue() self.onMinimize(None) self.txtTask.SetValue("") self.mailer.sendMail(toaddr, subject, "") # Send at the end to close faster the window
def __init__(self, config=None): """ Initialisation de la configuration de l'alerting""" self.__config = config if self.__config is None: with open('config.json') as json_data_file: data = json.load(json_data_file) self.__config = data['site'] self.mailer = Mailer() self.number_try = 0 self.number_alert = 0
def __init__(self): """ Initialize mail setup """ self.mailer = Mailer() self.attacks = {} self.counts = {} self.send_daily = "SEND_DAILY_REPORT" in os.environ and os.environ.get( "SEND_DAILY_REPORT") == "true" self.send_emerg = "SEND_EMERGENCY" in os.environ and os.environ.get( "SEND_EMERGENCY") == "true" self.last_attackmail = 0 self.last_reportmail = int(time.time())
class Alerting: def __init__(self, config=None): """ Initialisation de la configuration de l'alerting""" self.__config = config if self.__config is None: with open('config.json') as json_data_file: data = json.load(json_data_file) self.__config = data['site'] self.mailer = Mailer() self.number_try = 0 self.number_alert = 0 def do_post(self): try: self.number_try += 1 r = requests.post(self.__config['url'], headers=self.__config['headers'], data=self.__config['nextButton']) s = self.__config['regex'] result = re.search(s, r.content.decode('utf-8')) # On a trouver le message indiquant qu'il n'existe aucun rendez-vous disponible if result is not None: print(result.group(0)) print("########### UN RENDEZ-VOUS DISPONIBLE ###########") return True else: print("########### AUCUN RENDEZ-VOUS DISPONIBLE ###########") return False except: print("ERREUR LORS DE L'ACCESS AU SITE DE LA PREFECTURE") time.sleep(300) def alerting(self): sleepTime = 60 while True: if self.do_post(): self.mailer.send_mail() self.add_number_alert() sleepTime = self.__config['time'] + random.randrange(30, 60) print("########### TENTATIVE NUMERO %s ###########" % self.number_try) print("########### NOUVELLE TENTATIVE DANS %s SECONDES ###########" % sleepTime) time.sleep(sleepTime) def add_number_alert(self): self.number_alert += 1 if self.number_alert > self.__config['max_alert'] - 1: exit(0)
def onSend(self, event): self.mailer = Mailer(self.settings.getEmail(), self.settings.getPassword()) toaddr = self.settings.getEmailTo() subject = self.txtTask.GetValue() self.onMinimize(None) self.txtTask.SetValue("") self.mailer.sendMail(toaddr, subject, "") # Send at the end to close faster the window
def __init__(self, config): self.config = config if self.config.useMail: self.mailer = Mailer(config) self.assertDetector = AssertionDetector(self.config.knownPath) self.crashDetector = CrashDetector(self.config.knownPath) self.androidLogLinefilter = lambda x: re.sub('^[^:]+: ', '', x)
def dbpickup(choice, obj): try: mydb = mysql.connector.connect(host="localhost", user="******", passwd="", database="crm") mycursor = mydb.cursor(buffered=True) if choice == 1: mycursor.execute("select email_id from customer_master") result = mycursor.fetchall() for x in result: print("mailing") Mailer.send(x[0], obj.subject, obj.mailcontent) print("Mailed to " + str(x[0])) elif choice == 2: myd = datetime.strptime(obj.dateEdit_2.text(), '%m/%d/%Y').date() myd2 = datetime.strptime(obj.dateEdit_3.text(), '%m/%d/%Y').date() mycursor.execute( "select email_id from customer_master where visiting_date >= %s AND visiting_date <= " "%s", ( unicode(myd).__str__(), unicode(myd2).__str__(), )) result = mycursor.fetchall() for x in result: Mailer.send(x[0], obj.subject, obj.mailcontent) print("Mailed to " + str(x[0])) return 1 except Error as e: print("There is a problem with MySQL", e) return 0 finally: mycursor.close() mydb.close() print("Advertised Successfully...")
class MainFrame(wx.Frame): def __init__(self): super(MainFrame, self).__init__(None, title="New Task", style=wx.SYSTEM_MENU | wx.CAPTION | wx.MINIMIZE_BOX | wx.CLOSE_BOX) self.file = 'settings.cfg' self.settings = Settings(self.file) # Icon icon = wx.Icon("images/task.ico", wx.BITMAP_TYPE_ICO) self.SetIcon(icon) # self.createControls() self.bindEvents() self.doLayout() self.SetSizeWH(400, 100) self.Centre() self.Show(True) # ============================================================================================== # ====================================== UI # ============================================================================================== def createControls(self): self.panel = wx.Panel(self) self.txtTask = wx.TextCtrl(self.panel, 0, 'New Task', style=wx.TE_PROCESS_ENTER) bmp = wx.Bitmap("images/settings.png", wx.BITMAP_TYPE_ANY) self.btnSettings = wx.BitmapButton(self.panel, id=wx.ID_ANY, bitmap=bmp, size=(bmp.GetWidth() + 10, bmp.GetHeight() + 10)) self.lblDummy = wx.StaticText(self.panel, size=(170, 300)) self.btnCancel = wx.Button(self.panel, label='Cancel [esc]', size=(90, 26)) self.btnSend = wx.Button(self.panel, label='Send [enter]', size=(90, 26)) def doLayout(self): vbox = wx.BoxSizer(wx.VERTICAL) # Line 1 vbox.Add(self.txtTask, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border=10) # Line 2 hbox2 = wx.BoxSizer(wx.HORIZONTAL) hbox2.Add(self.btnSettings) hbox2.Add(self.lblDummy) hbox2.Add(self.btnCancel) hbox2.Add(self.btnSend) vbox.Add(hbox2, flag=wx.LEFT | wx.RIGHT | wx.TOP, border=10) # Main self.panel.SetSizer(vbox) # ============================================================================================== # ====================================== EVENTS # ============================================================================================== def bindEvents(self): self.txtTask.Bind(wx.EVT_KEY_UP, self.OnKeyUP) self.txtTask.Bind(wx.EVT_TEXT_ENTER, self.onSend) self.btnSettings.Bind(wx.EVT_BUTTON, self.onOpenSettings) self.btnSend.Bind(wx.EVT_BUTTON, self.onSend) self.btnCancel.Bind(wx.EVT_BUTTON, self.onCancel) wx.EVT_CLOSE(self, self.onClose) # triggered when the app is closed self.registerHotkey() self.registerMinimizeToTray() def onSend(self, event): self.mailer = Mailer(self.settings.getEmail(), self.settings.getPassword()) toaddr = self.settings.getEmailTo() subject = self.txtTask.GetValue() self.onMinimize(None) self.txtTask.SetValue("") self.mailer.sendMail(toaddr, subject, "") # Send at the end to close faster the window def onCancel(self, event): self.txtTask.SetValue("") self.onMinimize(None) def onOpenSettings(self, event): SettingsForm(self, self.file) def onClose(self, event): self.tbIcon.RemoveIcon( ) # remove the systemtray icon when the program closes os._exit(1) def OnKeyUP(self, event): keyCode = event.GetKeyCode() if keyCode == wx.WXK_ESCAPE: self.ToggleShow(None) # ============================================================================================== # ====================================== HOTKEYS # ============================================================================================== def registerHotkey(self): self.hotKeyId = wx.NewId() print self.RegisterHotKey( self.hotKeyId, # a unique ID for this hotkey win32con.MOD_WIN, # the modifier key win32con.VK_DELETE) # the key to watch for self.Bind(wx.EVT_HOTKEY, self.handleHotKey, id=self.hotKeyId) def handleHotKey(self, evt): self.ToggleShow(None) # ============================================================================================== # ====================================== MINIMIZE TO TRAY # ============================================================================================== def registerMinimizeToTray(self): self.tbIcon = wx.TaskBarIcon() icon = wx.Icon("images/task.ico", wx.BITMAP_TYPE_ICO) self.tbIcon.SetIcon(icon, "Tasks") wx.EVT_TASKBAR_LEFT_DCLICK(self.tbIcon, self.ToggleShow) # left click wx.EVT_TASKBAR_LEFT_UP(self.tbIcon, self.ToggleShow) # double left click wx.EVT_TASKBAR_RIGHT_UP(self.tbIcon, self.ToggleShow) # single left click self.Bind(wx.EVT_ICONIZE, self.onMinimize) # binding for minimizing def onMinimize(self, event): self.Hide( ) # this removes it from the taskbar so it only appears in the system tray def ToggleShow(self, event): if self.IsShown(): self.Hide() else: self.Show() self.txtTask.SetFocus() self.Restore( ) # take it out of the taskbar (otherwise it'll be shown but still minimized, which is awkward)
# モジュールのロード exec("from {} import {}".format(key, schema)) # クラスのインスタンス化 ins = eval( "{}(bq_client, st_client, dataset, config.get('base','bucket'), table_date)" .format(schema)) exists_table = ins.get_table() in table_ids # データロード処理 result = ins.load_data(exists_table) if not result: logger.warning( '{} : cloud storage にインポート対象のファイルがありません'.format(key)) else: result.result() if result.state == 'DONE': logger.info('{} インポート完了'.format(key)) except Exception as e: # キャッチして例外をログに logger.exception(e) logger.info('exit') mail = Mailer( '[bq-uploader]エラー発生', 'CSVインポートでエラーが発生しました\n' + e.message + '\n\n処理結果ログ\n\n' + log_message.getvalue()) mail.send_message() sys.exit(1) logger.info('exit') mail = Mailer('[bq-uploader]処理完了', 'CSVインポートが完了しました。\n\n処理結果ログ\n\n' + log_message.getvalue()) mail.send_message()
#!/usr/bin/python from ifgovdb import IfGovDb from mail import Mailer import logging from datetime import datetime logging.basicConfig(filename='/home/bitnami/ifsubthenemail/ifgov.log', level=logging.INFO) logging.info("Started at " + str(datetime.now())) mailer = Mailer() db = IfGovDb() for s in db.getNewSubscriptions(): if s.notificationsettings != None: address = s.notificationsettings message = "You have registered a new notification with ifGov. If at (" + str(s.lon) + "," + str(s.lat) + ") when " + s.source + " is changed then email me." logging.info("Emailing " + address + ": " + message) mailer.sendMail([address],"*****@*****.**","New Subscription",message); db.setWelcomed(s) else: logging.warn("No email address for " + s.name) for s in db.getChangedSubscriptions(): if s.notificationsettings != None: address = s.notificationsettings message = s.source + " was " + s.lastvalue + " and is now " + s.currentvalue + "." logging.info("Emailing " + address + ": " + message) mailer.sendMail([address],"*****@*****.**","Changed value",message); db.setNotified(s) else:
import requests from bs4 import BeautifulSoup import codecs import os import multiprocessing from multiprocessing.pool import ThreadPool import config from mail import Mailer from logger import Logger SMTP_EMAIL = getattr(config, 'SMTP_EMAIL') SMTP_PASS = getattr(config, 'SMTP_PASS') MAIL_TEMPLATES = getattr(config, 'MAIL_TEMPLATES') MAILER = Mailer(SMTP_EMAIL, SMTP_PASS) LOGGER = logger = Logger(__name__).get() BASE_URL = getattr(config, 'BASE_URL') NUM_PAGES = int(getattr(config, 'NUM_PAGES')) POOL_SIZE = multiprocessing.cpu_count() DAYS_POSTED = int(getattr(config, 'DAYS_POSTED')) def get_links(base_url, num_pages, search_terms): """ Method to get all variations of links to scrape based on query params search terms Args: base_url: the base url for which to query params num_pages: the number of pages via pagination to search (size) search_terms: the list of keywords to scrape for """ links = []
class Triager: def __init__(self, config): self.config = config if self.config.useMail: self.mailer = Mailer(config) self.assertDetector = AssertionDetector(self.config.knownPath) self.crashDetector = CrashDetector(self.config.knownPath) self.androidLogLinefilter = lambda x: re.sub('^[^:]+: ', '', x) def process(self, issueUUID, miniDump, systemLog, websockLog): print "Triaging crash..." # Read Android system log systemLogFile = open(systemLog) # Check if we got aborted or crashed aborted = self.assertDetector.hasFatalAssertion( systemLogFile, verbose=True, lineFilter=self.androidLogLinefilter) # Reopen file systemLogFile.close() systemLogFile = open(systemLog) # Check if the syslog file contains an interesting assertion. # The lambda removes the Android syslog tags before matching assertions = self.assertDetector.scanFileAssertions( systemLogFile, verbose=True, ignoreKnownAssertions=True, lineFilter=self.androidLogLinefilter) hasNewAssertion = len(assertions) > 0 systemLogFile.close() if miniDump == None and not hasNewAssertion: print "Error: No minidump available but also no assertions detected!" return isNewCrash = (miniDump != None) crashFunction = "Unknown" issueDesc = "Unknown" if miniDump != None: # Obtain symbolized crash trace to check crash signature trace = miniDump.getSymbolizedCrashTrace() if (len(trace) > 0): crashFunction = trace[0][1] issueDesc = "Crashed at " + crashFunction isNewCrash = not self.crashDetector.isKnownCrashSignature( crashFunction) # Also check first frame (some functions are blacklisted here) if (isNewCrash and len(trace) > 1): isNewCrash = not self.crashDetector.isKnownCrashSignature( trace[1][1]) # Use the last assertion as issue description if hasNewAssertion: issueDesc = assertions[len(assertions) - 1] print issueDesc if hasNewAssertion or (not aborted and isNewCrash): print "Found new issue, check " + websockLog + " to reproduce" if self.config.useMail: self.mailer.notify(issueUUID, issueDesc, miniDump) else: # Delete files if not in debug mode if not self.config.debug: if miniDump != None: miniDump.cleanup() os.remove(systemLog) os.remove(websockLog) return def checkLine(self, line): return self.assertDetector.scanLineAssertions( self.androidLogLinefilter(line))
from argparse import ArgumentParser from datetime import datetime from logging import DEBUG, INFO, WARNING, basicConfig, getLogger from mail import MailConfiguration, Mailer from traceback import print_exc from rest import Client #from ux import TerminalInterface if __name__ == '__main__': parser = ArgumentParser(description='capture and email image') args = parser.parse_args() basicConfig( filename=datetime.now().strftime('demo_%Y-%m-%dT%H.%M.%S%z.log'), level=DEBUG, format='%(asctime)-15s %(message)s') logger = getLogger('demo') client = Client(port=10082) cfg = MailConfiguration('config/mail.yaml', 'gmail') mailer = Mailer(cfg.address, cfg.username, cfg.password, cfg.host, cfg.port) sid = client.capture_snapshot(count=1)[0] filepath = client.get_snapshot(sid) mailer.send([cfg.address], 'camera activity', datetime.now().strftime('date: %FT%T'), [filepath]) mailer.close()
def main(): mailer = Mailer() data = {"my_string": "Wheee!", "my_list": [0, 1, 2, 3]} rendered = mailer.render_template('templates/demo.html', data) mailer.send_mail('*****@*****.**', 'test', rendered) print("Email Sent")
class Notifications(): """ Class to send notification about attacks to theadmin """ # the system can not keep all events in the memory, therefore it # cleans up the memory from time to time, the following values # allow to influence the cleaning. # values kept on cleanup (keeping n newest) CONNECTION_IDS_KEEP_ON_CLEANUP = 100 # starts a cleanup when this limit is reached MAX_CONNECTION_IDS = 200 # number of request logged by connection (id)/ user MAX_REQUESTS_PER_ID = 10 @staticmethod def is_active(): """ Check if MAIL_TO is set in the environment variables, it this is the case, we assume that the users wants to get notifications. """ return "MAIL_TO" in os.environ and len(os.environ.get("MAIL_TO")) > 0 def __init__(self): """ Initialize mail setup """ self.mailer = Mailer() self.attacks = {} self.counts = {} self.send_daily = "SEND_DAILY_REPORT" in os.environ and os.environ.get( "SEND_DAILY_REPORT") == "true" self.send_emerg = "SEND_EMERGENCY" in os.environ and os.environ.get( "SEND_EMERGENCY") == "true" self.last_attackmail = 0 self.last_reportmail = int(time.time()) def log_attack(self, connection_id, lda_is_attack, nn_is_attack, lda_types, nn_types=[]): """ Logs a detected attack Args: connection_id (int): the connection id of the user lda_is_attack (bool): answer by lda to "is attack?" nn_is_attack (bool): answer by nn to "is attack?" lda_types (array): most probable attack types by lda; [['type', distance], ...], e.g. [['rfi', 0.2], ['lfi', 0.3], ...]] nn_types (array): most probable attack types by nn; [['type', distance], ...] """ # create a new dict entry for a new suspicious connection id if connection_id not in self.attacks: self.attacks[connection_id] = [] # we only save up to a certain amount of request per id if len(self.attacks[connection_id] ) >= Notifications.MAX_REQUESTS_PER_ID: self.attacks[connection_id].pop(0) # specify a suspicious entry for a request self.attacks[connection_id].append({ 'is_attack': { 'lda': lda_is_attack, 'nn': nn_is_attack }, 'types': { 'lda': self.format_types(lda_types), 'nn': self.format_types(nn_types) if nn_types != [] else 'not calculated' }, 'time': int(time.time()) }) # track how many attacks are launched within a day today = int(date.today().strftime("%s")) if today not in self.counts: self.counts[today] = 0 self.counts[today] += 1 # if attack is detected, send an emergency mail(1h interval) self.send_emergency() # free dict entries, only save up to a certain amount of connection ids self.keep_memory_free() def format_types(self, types): """ Formats the assumed attack types and their distances for email dispatch. Args: types (list): List of lists containing the attack type and its distance for the most probable attack types: [['type', distance], ...]. """ s = [] for t, p in types: s.append(t + ' (' + ("%.3f" % p) + ')') return ', '.join(s) def keep_memory_free(self): """ Makes sure that the dictionary of connection ids does not get too big by deleting the oldest entries when the maximum size has been reached. """ if len(self.attacks) > Notifications.MAX_CONNECTION_IDS: for cid, _ in sorted( self.attacks.items(), key=lambda l: l['time'], reverse=True )[Notifications.CONNECTION_IDS_KEEP_ON_CLEANUP:]: del self.attacks[cid] def send_emergency(self): """ Sends an emergency mail to the admin. In order to avoid spam, emergency emails are sent at most once per hour. The mail contains information about the attackers and the assumed attack types. """ current_time = int(time.time()) if self.send_emerg and current_time - self.last_attackmail > 3600: self.last_attackmail = current_time time_range = current_time - 3600 # setup mail content: Table containing user ID and potential attacks text = '<html><style>table,th,tr,td { border:solid 1px black; border-collapse: collapse; padding: 2px; }</style><table>' text += '<tr><th align="left">User ID</th><th align="left">Is Attack?</th><th align="left">Types (distance)</th></tr>' count = 0 for cid, attacks in self.attacks.items(): for data in attacks: if data['time'] > time_range: count += 1 text += '<tr><td align="right">' + str(cid) + '</td>' text += '<td align="left">LDA: ' + ( '✓' if data['is_attack']['lda'] else '✗') + '<br/> NN: ' + ( '✓' if data['is_attack']['nn'] else '✗') + '</td>' text += '<td align="left">LDA: ' + data['types'][ 'lda'] + '<br/> NN: ' + data['types'][ 'nn'] + '</td></tr>' text += '</table></html>' self.mailer.send( text, "Emergency – " + str(count) + " attacks in the last hour") def send_daily_report(self): """ Sends a daily report to the admin, containing information about the number of attack attempts per day. """ current_time = int(time.time()) if self.send_daily and current_time - self.last_reportmail > 86400: self.last_reportmail = current_time # setup mail content: Table containing user ID and potential attacks text = '<html><style>table,th,tr,td { border:solid 1px black; border-collapse: collapse; padding: 2px; }</style><table>' text += '<tr><th align="left">Day</th><th align="left">Number of attacks</th></tr>' dellist = [] for day, count in self.counts.items(): text += '<tr><td>' + date.fromtimestamp(day).strftime( "%Y-%m-%d") + '</td><td align="right">' + str( count) + '</td></tr>' if current_time - day > 86400 * 21: # only keep last 21 days dellist.append(day) text += '</table></html>' if len(dellist) > 0: for day in dellist: del self.counts[day] self.mailer.send(text, "Daily Report")
def __init__(self, readserver, readlogin, readport, sendserver, sendfrom, sendto, sendlogin, prefix): self.reader = Reader(readlogin, readserver, readport) self.sender = Mailer(sendlogin, sendfrom, sendserver) self.sendto = sendto self.prefix = prefix
class Triager: def __init__(self, config): self.config = config if self.config.useMail: self.mailer = Mailer(config) self.assertDetector = AssertionDetector(self.config.knownPath) self.crashDetector = CrashDetector(self.config.knownPath) self.androidLogLinefilter = lambda x: re.sub('^[^:]+: ', '', x) def process(self, issueUUID, miniDump, systemLog, websockLog): print "Triaging crash..." # Read Android system log systemLogFile = open(systemLog) # Check if we got aborted or crashed aborted = self.assertDetector.hasFatalAssertion( systemLogFile, verbose=True, lineFilter=self.androidLogLinefilter ) # Reopen file systemLogFile.close() systemLogFile = open(systemLog) # Check if the syslog file contains an interesting assertion. # The lambda removes the Android syslog tags before matching assertions = self.assertDetector.scanFileAssertions( systemLogFile, verbose=True, ignoreKnownAssertions=True, lineFilter=self.androidLogLinefilter ) hasNewAssertion = len(assertions) > 0 systemLogFile.close() if miniDump == None and not hasNewAssertion: print "Error: No minidump available but also no assertions detected!" return isNewCrash = (miniDump != None) crashFunction = "Unknown" issueDesc = "Unknown" if miniDump != None: # Obtain symbolized crash trace to check crash signature trace = miniDump.getSymbolizedCrashTrace() if (len(trace) > 0): crashFunction = trace[0][1] issueDesc = "Crashed at " + crashFunction isNewCrash = not self.crashDetector.isKnownCrashSignature(crashFunction) # Also check first frame (some functions are blacklisted here) if (isNewCrash and len(trace) > 1): isNewCrash = not self.crashDetector.isKnownCrashSignature(trace[1][1]) # Use the last assertion as issue description if hasNewAssertion: issueDesc = assertions[len(assertions)-1] print issueDesc if hasNewAssertion or (not aborted and isNewCrash): print "Found new issue, check " + websockLog + " to reproduce" if self.config.useMail: self.mailer.notify(issueUUID, issueDesc, miniDump) else: # Delete files if not in debug mode if not self.config.debug: if miniDump != None: miniDump.cleanup() os.remove(systemLog) os.remove(websockLog) return def checkLine(self, line): return self.assertDetector.scanLineAssertions(self.androidLogLinefilter(line))
class MainFrame(wx.Frame): def __init__(self): super(MainFrame, self).__init__(None, title="New Task", style=wx.SYSTEM_MENU | wx.CAPTION | wx.MINIMIZE_BOX | wx.CLOSE_BOX) self.file = 'settings.cfg' self.settings = Settings(self.file) # Icon icon = wx.Icon("images/task.ico", wx.BITMAP_TYPE_ICO) self.SetIcon(icon) # self.createControls() self.bindEvents() self.doLayout() self.SetSizeWH(400, 100) self.Centre() self.Show(True) # ============================================================================================== # ====================================== UI # ============================================================================================== def createControls(self): self.panel = wx.Panel(self) self.txtTask = wx.TextCtrl(self.panel, 0, 'New Task', style=wx.TE_PROCESS_ENTER) bmp = wx.Bitmap("images/settings.png", wx.BITMAP_TYPE_ANY) self.btnSettings = wx.BitmapButton(self.panel, id=wx.ID_ANY, bitmap=bmp, size=(bmp.GetWidth() + 10, bmp.GetHeight() + 10)) self.lblDummy = wx.StaticText(self.panel, size=(170, 300)) self.btnCancel = wx.Button(self.panel, label='Cancel [esc]', size=(90, 26)) self.btnSend = wx.Button(self.panel, label='Send [enter]', size=(90, 26)) def doLayout(self): vbox = wx.BoxSizer(wx.VERTICAL) # Line 1 vbox.Add(self.txtTask, flag=wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border=10) # Line 2 hbox2 = wx.BoxSizer(wx.HORIZONTAL) hbox2.Add(self.btnSettings) hbox2.Add(self.lblDummy) hbox2.Add(self.btnCancel) hbox2.Add(self.btnSend) vbox.Add(hbox2, flag=wx.LEFT | wx.RIGHT | wx.TOP, border=10) # Main self.panel.SetSizer(vbox) # ============================================================================================== # ====================================== EVENTS # ============================================================================================== def bindEvents(self): self.txtTask.Bind(wx.EVT_KEY_UP, self.OnKeyUP) self.txtTask.Bind(wx.EVT_TEXT_ENTER, self.onSend) self.btnSettings.Bind(wx.EVT_BUTTON, self.onOpenSettings) self.btnSend.Bind(wx.EVT_BUTTON, self.onSend) self.btnCancel.Bind(wx.EVT_BUTTON, self.onCancel) wx.EVT_CLOSE(self, self.onClose) # triggered when the app is closed self.registerHotkey() self.registerMinimizeToTray() def onSend(self, event): self.mailer = Mailer(self.settings.getEmail(), self.settings.getPassword()) toaddr = self.settings.getEmailTo() subject = self.txtTask.GetValue() self.onMinimize(None) self.txtTask.SetValue("") self.mailer.sendMail(toaddr, subject, "") # Send at the end to close faster the window def onCancel(self, event): self.txtTask.SetValue("") self.onMinimize(None) def onOpenSettings(self, event): SettingsForm(self, self.file) def onClose(self, event): self.tbIcon.RemoveIcon() # remove the systemtray icon when the program closes os._exit(1) def OnKeyUP(self, event): keyCode = event.GetKeyCode() if keyCode == wx.WXK_ESCAPE: self.ToggleShow(None) # ============================================================================================== # ====================================== HOTKEYS # ============================================================================================== def registerHotkey(self): self.hotKeyId = wx.NewId() print self.RegisterHotKey( self.hotKeyId, # a unique ID for this hotkey win32con.MOD_WIN, # the modifier key win32con.VK_DELETE) # the key to watch for self.Bind(wx.EVT_HOTKEY, self.handleHotKey, id=self.hotKeyId) def handleHotKey(self, evt): self.ToggleShow(None) # ============================================================================================== # ====================================== MINIMIZE TO TRAY # ============================================================================================== def registerMinimizeToTray(self): self.tbIcon = wx.TaskBarIcon() icon = wx.Icon("images/task.ico", wx.BITMAP_TYPE_ICO) self.tbIcon.SetIcon(icon, "Tasks") wx.EVT_TASKBAR_LEFT_DCLICK(self.tbIcon, self.ToggleShow) # left click wx.EVT_TASKBAR_LEFT_UP(self.tbIcon, self.ToggleShow) # double left click wx.EVT_TASKBAR_RIGHT_UP(self.tbIcon, self.ToggleShow) # single left click self.Bind(wx.EVT_ICONIZE, self.onMinimize) # binding for minimizing def onMinimize(self, event): self.Hide() # this removes it from the taskbar so it only appears in the system tray def ToggleShow(self, event): if self.IsShown(): self.Hide() else: self.Show() self.txtTask.SetFocus() self.Restore() # take it out of the taskbar (otherwise it'll be shown but still minimized, which is awkward)