Example #1
0
def run_simulate_on_messages(user, email, folder_name, N=3, code=''):
    """This function is called to evaluate user's code on messages

        Args:
            user (Model.UserProfile)
            email (string): user's email address
            folder_name (string): name of a folder to extract messages 
            N (int): number of recent messages
            code (string): code to be simulated
    """
    res = {'status': False, 'imap_error': False, 'imap_log': ""}
    logger = logging.getLogger('youps')  # type: logging.Logger

    # this log is going to stdout but not going to the logging file
    # why are django settings not being picked up
    logger.info("user %s has requested simulation" % email)

    imapAccount = None
    imap = None

    try:
        imapAccount = ImapAccount.objects.get(email=email)
        auth_res = authenticate(imapAccount)
        if not auth_res['status']:
            raise ValueError(
                'Something went wrong during authentication. Refresh and try again!'
            )

        imap = auth_res['imap']  # noqa: F841 ignore unused
    except Exception, e:
        logger.exception("failed while logging into imap")
        res['code'] = "Fail to access your IMAP account"
        return
Example #2
0
def apply_button_rule(user, email, er_id, msg_schema_id, kargs):
    res = {'status': False}

    try:
        logger.info("here")
        imapAccount = ImapAccount.objects.get(email=email)
        auth_res = authenticate(imapAccount)
        if not auth_res['status']:
            raise ValueError(
                'Something went wrong during authentication. Refresh and try again!'
            )

        imap = auth_res['imap']  # noqa: F841 ignore unused

        er = EmailRule.objects.get(id=er_id)
        #  read from DB and convert to the type accordingly
        for key, value in kargs.iteritems():
            er_arg = EmailRule_Args.objects.get(rule=er, name=key)

            # parse datetime
            if er_arg.type == "datetime":
                try:
                    kargs[key] = datetime.datetime.strptime(
                        value, '%Y-%m-%dT%H:%M')
                except Exception:
                    res['code'] = key
                    raise TypeError

        mailbox = MailBox(imapAccount, imap, is_simulate=False)
        res = interpret_bypass_queue(mailbox,
                                     extra_info={
                                         "msg-id": msg_schema_id,
                                         "code": er.code,
                                         "shortcut": kargs,
                                         "rule_name": er.name
                                     })
        logger.info(kargs)
        logger.info(er.code)
        logger.info(res)
        res['status'] = True

    except ImapAccount.DoesNotExist:
        res['code'] = "Error during deleting the mode. Please refresh the page."
    except MailbotMode.DoesNotExist:
        res['code'] = "Error during deleting the mode. Please refresh the page."
    except TypeError:
        res['code'] = "Datetime %s is in wrong format!" % res['code']
    except Exception as e:
        logger.exception(e)
        res['code'] = msg_code['UNKNOWN_ERROR']
    return res
Example #3
0
    def handle(self, *args, **options):

        # iterate over all the user accounts in the database
        imapAccounts = ImapAccount.objects.filter(is_initialized=False)

        for imapAccount in imapAccounts:
            if imapAccount.is_running:
                continue
            imapAccount.is_running = True
            imapAccount.save()

            res = {'status': False, 'imap_error': False}
            logger.info("run initial sync for email: %s" % imapAccount.email)

            # authenticate with the user's imap server
            auth_res = authenticate(imapAccount)
            # if authentication failed we can't run anything
            if not auth_res['status']:
                continue

            # get an imapclient which is authenticated
            imap = auth_res['imap']

            try:
                # create the mailbox
                mailbox = MailBox(imapAccount, imap)
                # sync the mailbox with imap
                mailbox._sync()
                logger.info("Mailbox sync done")
                # after sync, logout to prevent multi-connection issue
                imap.logout()
                logger.info(
                    "Mailbox logged out to prevent multi-connection issue")
                mailbox._run_user_code()
            except Exception:
                logger.exception("mailbox task running failed %s " %
                                 imapAccount.email)
                send_email("Your YoUPS account is ready!",
                           "no-reply@" + BASE_URL, '*****@*****.**',
                           "%s register inbox failed " % imapAccount.email)

                continue

            imapAccount.is_initialized = True
            imapAccount.is_running = False
            imapAccount.save()

            res['status'] = True
Example #4
0
    def handle(self, *args, **options):
        host = 'imap.gmail.com'
        ssl = 'True'
        username = '******'
        folder = 'INBOX'

        # Setup the log handlers to stdout and file.
        log = logging.getLogger('imap_monitor')
        log.setLevel(logging.DEBUG)
        formatter = logging.Formatter(
            '%(asctime)s | %(name)s | %(levelname)s | %(message)s')
        handler_stdout = logging.StreamHandler(sys.stdout)
        handler_stdout.setLevel(logging.DEBUG)
        handler_stdout.setFormatter(formatter)
        log.addHandler(handler_stdout)
        handler_file = RotatingFileHandler('imap_monitor.log',
                                           mode='a',
                                           maxBytes=1048576,
                                           backupCount=9,
                                           encoding='UTF-8',
                                           delay=True)
        handler_file.setLevel(logging.DEBUG)
        handler_file.setFormatter(formatter)
        log.addHandler(handler_file)

        while True:
            # <--- Start of IMAP server connection loop

            # Attempt connection to IMAP server
            log.info('connecting to IMAP server - {0}'.format(host))
            try:
                imap_account = ImapAccount.objects.get(email=username)
                res = authenticate(imap_account)
                if not res['status']:
                    return

                imap = res['imap']
            except Exception:
                # If connection attempt to IMAP server fails, retry
                etype, evalue = sys.exc_info()[:2]
                estr = traceback.format_exception_only(etype, evalue)
                logstr = 'failed to connect to IMAP server - '
                for each in estr:
                    logstr += '{0}; '.format(each.strip('\n'))
                log.error(logstr)
                sleep(10)
                continue
            log.info('server connection established')

            # Select IMAP folder to monitor
            log.info('selecting IMAP folder - {0}'.format(folder))
            try:
                result = imap.select_folder(folder)
                log.info('folder selected')
            except Exception:
                # Halt script when folder selection fails
                etype, evalue = sys.exc_info()[:2]
                estr = traceback.format_exception_only(etype, evalue)
                logstr = 'failed to select IMAP folder - '
                for each in estr:
                    logstr += '{0}; '.format(each.strip('\n'))
                log.critical(logstr)
                break

            # latest_seen_UID = None
            # # Retrieve and process all unread messages. Should errors occur due
            # # to loss of connection, attempt restablishing connection
            # try:
            # 	result = imap.search('UNSEEN')
            # 	latest_seen_UID = max(result)
            # except Exception:
            # 	continue
            # log.info('{0} unread messages seen - {1}'.format(
            # 	len(result), result
            # 	))

            # for each in result:
            # try:
            # 	# result = imap.fetch(each, ['RFC822'])
            # except Exception:
            # 	log.error('failed to fetch email - {0}'.format(each))
            # 	continue
            # mail = email.message_from_string(result[each]['RFC822'])
            # try:
            # 	# process_email(mail, download, log)
            # 	log.info('processing email {0} - {1}'.format(
            # 		each, mail['subject']
            # 		))
            # except Exception:
            # 	log.error('failed to process email {0}'.format(each))
            # 	raise
            # 	continue

            while True:
                # <--- Start of mail monitoring loop

                # After all unread emails are cleared on initial login, start
                # monitoring the folder for new email arrivals and process
                # accordingly. Use the IDLE check combined with occassional NOOP
                # to refresh. Should errors occur in this loop (due to loss of
                # connection), return control to IMAP server connection loop to
                # attempt restablishing connection instead of halting script.
                imap.idle()
                result = imap.idle_check(1)
                print(result)

                # check if there is any request from users
                # if diff folder:
                #	break

                # either mark as unread/read or new message
                if result:
                    # EXISTS command mean: if the size of the mailbox changes (e.g., new messages)
                    print(result)
                    imap.idle_done()
                    result = imap.search('UID %d' % result[0][2][1])
                    log.info('{0} new unread messages - {1}'.format(
                        len(result), result))
                    for each in result:
                        _header_descriptor = 'BODY.PEEK[HEADER.FIELDS (SUBJECT)]'
                        fetch = imap.fetch(each, [_header_descriptor])
                        # mail = email.message_from_string(
                        # 	fetch[each][_header_descriptor]
                        # 	)
                        try:
                            # process_email(mail, download, log)
                            log.info('processing email {0} - {1}'.format(
                                each, fetch[each]))
                        except Exception:
                            log.error(
                                'failed to process email {0}'.format(each))
                            raise
                            continue
                else:
                    imap.idle_done()
                    imap.noop()
                    log.info('no new messages seen')
                # End of mail monitoring loop --->
                continue

            # End of IMAP server connection loop --->
            break
Example #5
0
def register_inbox():
    """Do the initial sync on an inbox.
    """


    lockFile = 'register_inbox2.lock'
    with open(lockFile, 'w') as f:
        have_lock = get_lock(f)
        if not have_lock:
            logger.info('Lock already taken %s' % lockFile)
            return

        for imapAccount in ImapAccount.objects.filter(is_initialized=False):
            try:
                logger.info('registering inbox: %s', imapAccount.email)

                while True:
                    try:
                        # authenticate with the user's imap server
                        auth_res = authenticate(imapAccount)
                        # if authentication failed we can't run anything
                        if not auth_res['status']:
                            # Stop doing loop
                            # TODO maybe we should email the user
                            logger.critical('register authentication failed for %s', imapAccount.email)
                            continue 

                        # get an imapclient which is authenticated
                        imap = auth_res['imap']  # type: IMAPClient


                        # create the mailbox
                        mailbox = MailBox(imapAccount, imap)
                        # TODO(lukemurray): remove this
                        mailbox._log_message_ids()
                        # sync the mailbox with imap
                        done = mailbox._sync()
                        if done:
                            break

                    # if we catch an EOF error we continue
                    except imaplib.IMAP4.abort:
                        logger.exception("Caught EOF error while syncing")
                        try:
                            imap.logout()
                        except Exception:
                            logger.exception("Failure while logging out due to EOF bug")
                        continue
                    # if we catch any other type of exception we abort to avoid infinite loop
                    except Exception:
                        logger.critical("Failure while initially syncing")
                        logger.exception("Failure while initially syncing")
                        raise

                logger.info("After sync, set up an exercise folder for the new user")
                try:
                        
                    imap.create_folder("_YouPS exercise")

                    msg1 = mailbox._create_message_wrapper("Welcome to YouPS!", imapAccount.email, content="This is the test email from YouPS", content_html="This is the test email from YouPS")
                    msg1["From"] = "*****@*****.**"
                    imap.append("_YouPS exercise", str(msg1))

                    msg1 = mailbox._create_message_wrapper("[Example email] Follow up", imapAccount.email + ", [email protected]", cc="*****@*****.**", content="Hello! I just wanted to follow up regarding our last meeting! Let me know how you think!", content_html="Hello! I just wanted to follow up regarding our last meeting! Let me know how you think!")
                    msg1["From"] = "*****@*****.**"
                    imap.append("_YouPS exercise", str(msg1))

                    msg1 = mailbox._create_message_wrapper("[Example email] Blah blah", imapAccount.email + ", [email protected]", cc="*****@*****.**", content="Howdy y'all!", content_html="Howdy y'all!")
                    msg1["From"] = "*****@*****.**"
                    imap.append("_YouPS exercise", str(msg1))

                except Exception as e:
                    logger.exception(e)


                logger.info("Mailbox sync done: %s" % (imapAccount.email))

                # after sync, logout to prevent multi-connection issue
                imap.logout()

                imapAccount.is_initialized = True
                imapAccount.save()

                site = Site.objects.get_current()
                # TODO(lukemurray): bring this back
                # send_email("Your YouPS account is ready!",
                #            "no-reply@" + BASE_URL,
                #            imapAccount.email,
                #            "Start writing your automation rule here! %s://%s" % (PROTOCOL, site.domain))

                # Create a default mode & email rule to demo

                logger.info(
                    'Register done for %s', imapAccount.email)
            except ImapAccount.DoesNotExist:
                imapAccount.is_initialized = False
                imapAccount.save()
                logger.exception(
                    "syncing fails Remove periodic tasks. imap_account not exist %s" % (imapAccount.email))

            except Exception as e:
                logger.exception(
                    "User inbox syncing fails %s. Stop syncing %s" % (imapAccount.email, e))
Example #6
0
def loop_sync_user_inbox():

    lockFile = 'loop_sync_user_inbox2.lock'
    with open(lockFile, 'w') as f:
        have_lock = get_lock(f)
        if not have_lock:
            logger.info('Lock already taken %s' % lockFile)
            return

        imapAccounts = ImapAccount.objects.filter(
            is_initialized=True)  # type: t.List[ImapAccount]
        for imapAccount in imapAccounts:
            # if imapAccount.email not in ["*****@*****.**", "*****@*****.**", "*****@*****.**"]:
            #     continue
            # refresh from database
            imapAccount = ImapAccount.objects.get(id=imapAccount.id)
            if not imapAccount.is_initialized:
                continue

            imapAccount_email = imapAccount.email

            try:
                logger.info('Start syncing %s ', imapAccount_email)

                # authenticate with the user's imap server
                auth_res = authenticate(imapAccount)
                # if authentication failed we can't run anything
                if not auth_res['status']:
                    # Stop doing loop
                    # TODO maybe we should email the user
                    logger.critical('authentication failed for %s' % imapAccount.email) 
                    continue

                # get an imapclient which is authenticated
                imap = auth_res['imap']

                # create the mailbox
                try:
                    mailbox = MailBox(imapAccount, imap)
                    # TODO(lukemurray): remove this

                    mailbox._log_message_ids()
                    # sync the mailbox with imap
                    mailbox._sync()
                    logger.info(mailbox.event_data_list)
                except Exception:
                    logger.exception("Mailbox sync failed")
                    # TODO maybe we should email the user
                    continue
                logger.debug("Mailbox sync done: %s" % (imapAccount_email))

                try:
                    # get scheduled tasks
                    email_rules = EmailRule.objects.filter(mode=imapAccount.current_mode, type__startswith='new-message-')  # type: t.List[EmailRule]
                    for email_rule in email_rules:
                        # Truncate millisec since mysql doesn't suport msec. 
                        now = timezone.now().replace(microsecond=0) + datetime.timedelta(seconds=1)

                        mailbox._manage_task(email_rule, now)

                        # mark timestamp to prevent running on certain message multiple times 
                        email_rule.executed_at = now + datetime.timedelta(seconds=1)
                        email_rule.save()
                        logger.info(mailbox.event_data_list)
                except Exception:
                    logger.exception("Mailbox managing task failed")
                    # TODO maybe we should email the user
                    continue
                logger.debug("Mailbox managing task done: %s" % (imapAccount_email))

                try:
                    # get deadline tasks
                    email_rules = EmailRule.objects.filter(mode=imapAccount.current_mode, type='deadline')  # type: t.List[EmailRule]
                    for email_rule in email_rules:
                        # Truncate millisec since mysql doesn't suport msec. 
                        now = timezone.now().replace(microsecond=0) + datetime.timedelta(seconds=1)
                        mailbox._get_due_messages(email_rule, now)

                        # mark timestamp to prevent running on certain message multiple times 
                        email_rule.executed_at = now + datetime.timedelta(seconds=1)
                        email_rule.save()
                        logger.info(mailbox.event_data_list)
                except Exception:
                    logger.exception("Mailbox managing task failed")
                    # TODO maybe we should email the user
                    continue
                try:
                    res = mailbox._run_user_code()
                    dump_execution_log(imapAccount, res['imap_log'])
                except Exception():
                    logger.exception("Mailbox run user code failed")

                

                # after sync, logout to prevent multi-connection issue
                imap.logout()

                logger.info(
                    'Sync done for %s', imapAccount_email)
            except ImapAccount.DoesNotExist:
                imapAccount.is_initialized = False
                imapAccount.save()
                logger.exception(
                    "syncing fails Remove periodic tasks. imap_account not exist %s" % (imapAccount_email))

            except Exception as e:
                logger.exception(
                    "User inbox syncing fails %s. Stop syncing %s" % (imapAccount_email, e))
Example #7
0
def run_mailbot(user,
                email,
                current_mode_id,
                modes,
                is_test,
                run_request,
                push=True):
    """This function is called everytime users hit "run", "stop" or "save" their scripts.

        Args:
            user (Model.UserProfile)
            email (string): user's email address
            current_mode_id (integer): ID of currently selected/running mode
            modes (list): a list of dicts that each element is information about each user's mode
            is_test (boolean): if is_test is True, then it just simulates the user's script and prints out log but not actually execute it.  
            run_request (boolean): if False, set the current_mode to None so the event is not fired at interpret()
    """
    res = {'status': False, 'imap_error': False, 'imap_log': ""}
    logger = logging.getLogger('youps')  # type: logging.Logger

    # this log is going to stdout but not going to the logging file
    # why are django settings not being picked up
    logger.info("user %s has run, stop, or saved" % email)

    imap = None

    try:
        imapAccount = ImapAccount.objects.get(email=email)
        auth_res = authenticate(imapAccount)
        if not auth_res['status']:
            raise ValueError(
                'Something went wrong during authentication. Refresh and try again!'
            )

        imap = auth_res['imap']  # noqa: F841 ignore unused

        imapAccount.is_test = is_test
        imapAccount.is_running = run_request

        # TODO these don't work anymore
        # uid = fetch_latest_email_id(imapAccount, imap)
        # imapAccount.newest_msg_id = uid

        # remove all user's tasks of this user to keep tasks up-to-date

        for mode_index, mode in modes.iteritems():
            mode_id = mode['id']
            mode_name = mode['name'].encode('utf-8')

            mailbotMode = MailbotMode.objects.filter(uid=mode_id,
                                                     imap_account=imapAccount)
            if not mailbotMode.exists():
                mailbotMode = MailbotMode(uid=mode_id,
                                          name=mode_name,
                                          imap_account=imapAccount)
                mailbotMode.save()

            else:
                mailbotMode = mailbotMode[0]

            # Remove old editors to re-save it
            # TODO  dont remove it
            er = EmailRule.objects.filter(mode=mailbotMode)
            logger.debug("deleting er editor run request")
            er.delete()

            for value in mode['editors']:
                uid = value['uid']
                name = value['name'].encode('utf-8')
                code = value['code'].encode('utf-8')
                folders = value['folders']
                logger.info("saving editor %s run request" % uid)
                print mode_name
                print code
                print folders

                er = EmailRule(uid=uid,
                               name=name,
                               mode=mailbotMode,
                               type=value['type'],
                               code=code)
                er.save()

                logger.info("user %s test run " % imapAccount.email)

                # res = interpret(MailBox(imapAccount, imap), None, True, {'code' : code})
                # logger.critical(res["appended_log"])

                # # Save selected folder for the mode
                for f in folders:
                    folder = FolderSchema.objects.get(imap_account=imapAccount,
                                                      name=f)
                    logger.info("saving folder to the editor %s run request" %
                                folder.name)
                    er.folders.add(folder)

                er.save()

        if run_request:
            imapAccount.current_mode = MailbotMode.objects.filter(
                uid=current_mode_id, imap_account=imapAccount)[0]

            # if the code execute well without any bug, then save the code to DB
            if not res['imap_error']:
                pass
        else:
            imapAccount.current_mode = None

        imapAccount.save()

        # res['imap_log'] = ("[TEST MODE] Your rule is successfully installed. It won't take actual action but simulate your rule. %s \n" + res['imap_log']) if is_test else ("Your rule is successfully installed. \n" + res['imap_log'])
        #         now = datetime.now()
        #         now_format = now.strftime("%m/%d/%Y %H:%M:%S") + " "
        #         res['imap_log'] = now_format + res['imap_log']
        #     else:
        #         imapAccount.is_running = False
        #         imapAccount.save()
        # else:

        #     res['imap_log'] = "Your mailbot stops running"

        res['status'] = True

    except IMAPClient.Error, e:
        logger.exception("failed while doing a user code run")
        res['code'] = e
Example #8
0
def register_inbox():
    """Do the initial sync on an inbox.
    """

    lockFile = 'register_inbox.lock'
    with open(lockFile, 'w') as f:
        have_lock = get_lock(f)
        if not have_lock:
            logger.info('Lock already taken %s' % lockFile)
            return

        for imapAccount in ImapAccount.objects.filter(is_initialized=False):
            try:
                logger.info('registering inbox: %s', imapAccount.email)

                while True:
                    try:
                        # authenticate with the user's imap server
                        auth_res = authenticate(imapAccount)
                        # if authentication failed we can't run anything
                        if not auth_res['status']:
                            # Stop doing loop
                            # TODO maybe we should email the user
                            logger.critical(
                                'register authentication failed for %s',
                                imapAccount.email)
                            continue

                        # get an imapclient which is authenticated
                        imap = auth_res['imap']  # type: IMAPClient

                        # create the mailbox
                        mailbox = MailBox(imapAccount, imap)
                        # sync the mailbox with imap
                        done = mailbox._sync()
                        if done:
                            break

                    # if we catch an EOF error we continue
                    except imaplib.IMAP4.abort:
                        logger.exception("Caught EOF error while syncing")
                        try:
                            imap.logout()
                        except Exception:
                            logger.exception(
                                "Failure while logging out due to EOF bug")
                        continue
                    # if we catch any other type of exception we abort to avoid infinite loop
                    except Exception:
                        logger.critical("Failure while initially syncing")
                        logger.exception("Failure while initially syncing")
                        raise

                logger.info("Mailbox sync done: %s" % (imapAccount.email))

                # after sync, logout to prevent multi-connection issue
                imap.logout()

                imapAccount.is_initialized = True
                imapAccount.save()

                site = Site.objects.get_current()
                send_email(
                    "Your YoUPS account is ready!", "no-reply@" + BASE_URL,
                    imapAccount.email,
                    "Start writing your automation rule here! %s://%s" %
                    (PROTOCOL, site.domain))

                logger.info('Register done for %s', imapAccount.email)
            except ImapAccount.DoesNotExist:
                imapAccount.is_initialized = False
                imapAccount.save()
                logger.exception(
                    "syncing fails Remove periodic tasks. imap_account not exist %s"
                    % (imapAccount.email))

            except Exception as e:
                logger.exception(
                    "User inbox syncing fails %s. Stop syncing %s" %
                    (imapAccount.email, e))
Example #9
0
def handle_imap_idle(user, email, folder='INBOX'):
    return
    imap_account = ImapAccount.objects.get(email=email)

    watching_folder = FolderSchema.objects.get(imap_account=imap_account,
                                               name=folder)

    bc = ButtonChannel.objects.filter(watching_folder=watching_folder)
    if bc.exists() and timezone.now() - bc.latest(
            'timestamp').timestamp < timezone.timedelta(
                seconds=3 * 60):  # there is something running so noop
        return

    while True:
        # <--- Start of IMAP server connection loop

        # Attempt connection to IMAP server
        button_logger.info('connecting to IMAP server - %s' % email)
        try:
            res = authenticate(imap_account)
            if not res['status']:
                return

            imap = res['imap']
            if "exchange" in imap_account.host or "csail" in imap_account.host:
                imap.use_uid = False
        except Exception:
            # If connection attempt to IMAP server fails, retry
            etype, evalue = sys.exc_info()[:2]
            estr = traceback.format_exception_only(etype, evalue)
            logstr = 'failed to connect to IMAP server - '
            for each in estr:
                logstr += '{0}; '.format(each.strip('\n'))
            button_logger.error(logstr)
            sleep(10)
            continue
        button_logger.info('server connection established')

        # Select IMAP folder to monitor
        button_logger.info('selecting IMAP folder - {0}'.format(folder))
        try:
            result = imap.select_folder(folder)
            button_logger.info('folder selected')
        except Exception:
            # Halt script when folder selection fails
            etype, evalue = sys.exc_info()[:2]
            estr = traceback.format_exception_only(etype, evalue)
            logstr = 'failed to select IMAP folder - '
            for each in estr:
                logstr += '{0}; '.format(each.strip('\n'))
            button_logger.critical(logstr)
            break

# latest_seen_UID = None
# # Retrieve and process all unread messages. Should errors occur due
# # to loss of connection, attempt restablishing connection
# try:
# 	result = imap.search('UNSEEN')
# 	latest_seen_UID = max(result)
# except Exception:
# 	continue
# log.info('{0} unread messages seen - {1}'.format(
# 	len(result), result
# 	))

# for each in result:
# try:
# 	# result = imap.fetch(each, ['RFC822'])
# except Exception:
# 	log.error('failed to fetch email - {0}'.format(each))
# 	continue
# mail = email.message_from_string(result[each]['RFC822'])
# try:
# 	# process_email(mail, download, log)
# 	log.info('processing email {0} - {1}'.format(
# 		each, mail['subject']
# 		))
# except Exception:
# 	log.error('failed to process email {0}'.format(each))
# 	raise
# 	continue

        try:
            while True:
                # <--- Start of mail monitoring loop

                # Create a new entry for watching this folder
                bc = ButtonChannel.objects.filter(
                    watching_folder=watching_folder)
                bc.delete()

                bc_folder = ButtonChannel(watching_folder=watching_folder)
                bc_folder.save()

                # After all unread emails are cleared on initial login, start
                # monitoring the folder for new email arrivals and process
                # accordingly. Use the IDLE check combined with occassional NOOP
                # to refresh. Should errors occur in this loop (due to loss of
                # connection), return control to IMAP server connection loop to
                # attempt restablishing connection instead of halting script.
                imap.idle()
                result = imap.idle_check(3 * 60)  # timeout

                # either mark as unread/read or new message
                if result:
                    # EXISTS command mean: if the size of the mailbox changes (e.g., new messages)
                    button_logger.info(result)
                    imap.idle_done()
                    try:
                        uid = -1
                        if "exchange" in imap_account.host or "csail" in imap_account.host:  # e.g., mit
                            flag = False
                            button_logger.info(result[0])
                            for r in result:
                                if r[1] == "FETCH":
                                    flag = True
                                    result = [r[0]]

                            if not flag:
                                continue
                        else:  # e.g., gmail, gsuite
                            uid = result[0][2][1]
                            result = imap.search('UID %d' % uid)

                        button_logger.info(result)
                    except Exception as e:
                        # prevent reacting to msg move/remove
                        button_logger.critical(e)
                        continue

                    button_logger.info('{0} new unread messages - {1}'.format(
                        len(result), result))
                    for each in result:
                        _header_descriptor = 'BODY.PEEK[HEADER.FIELDS (SUBJECT)]'
                        # mail = email.message_from_string(
                        # 	fetch[each][_header_descriptor]
                        # 	)
                        try:
                            fetch = imap.fetch(each,
                                               [_header_descriptor, "UID"])

                            button_logger.info(
                                'processing email {0} - {1}'.format(
                                    each, fetch[each]))
                            uid = -1
                            if "exchange" in imap_account.host or "csail" in imap_account.host:
                                uid = fetch[each]["UID"]
                            else:
                                uid = each
                            message = MessageSchema.objects.get(
                                imap_account=imap_account,
                                folder__name=folder,
                                uid=uid)
                            button_logger.info(message.base_message.subject)
                            bc = ButtonChannel(message=message,
                                               imap_account=imap_account,
                                               code=ButtonChannel.OK)
                            bc.save()

                        except MessageSchema.DoesNotExist:
                            button_logger.error(
                                "Catch new messages but can't find the message %s "
                                % fetch[each])
                            # TODO this creates a new instance of buttonchannel

                            bc = ButtonChannel(
                                imap_account=imap_account,
                                code=ButtonChannel.MSG_NOT_FOUND,
                                log=
                                "Catch new messages but can't find the message %s "
                                % fetch[each])
                            bc.save()
                        except Exception as e:
                            button_logger.error(str(e))
                            button_logger.error(
                                'failed to process email {0}'.format(each))

                            bc = ButtonChannel(imap_account=imap_account,
                                               code=ButtonChannel.UNKNOWN,
                                               log=str(e))
                            bc.save()

                else:  # After time-out && no operation
                    imap.idle_done()
                    imap.noop()
                    button_logger.info('no new messages seen')

                    return

                # End of mail monitoring loop --->
        except Exception as e:
            button_logger.exception("Error while  %s" % str(e))
        finally:
            # Remove the entry with this folder and terminate the request
            bc = ButtonChannel.objects.filter(watching_folder=watching_folder)
            bc.delete()

            imap.logout()

            return


# def fetch_flag():
#     responses = conn.select_folder(self.name)
#     highest_mod_seq = responses.get(b'HIGHESTMODSEQ') if self.c.supports_condstore() else None
#     if b'NOMODSEQ' in responses:
#         highest_mod_seq = self.highest_mod_seq = None
#     if self.uid_validity is None or self.uid_validity != uid_validity:
#         self.clear_cache()
#         self.initial_s2c_sync(conn, uid_next)
#     else:
#         self.normal_s2c_sync(conn, uid_next, highest_mod_seq)
Example #10
0
def run_simulate_on_messages(user, email, folder_names, N=3, code=''):
    """This function is called to evaluate user's code on messages

        Args:
            user (Model.UserProfile)
            email (string): user's email address
            folder_name (string): name of a folder to extract messages 
            N (int): number of recent messages
            code (string): code to be simulated
    """
    res = {'status': False, 'imap_error': False, 'imap_log': ""}
    logger = logging.getLogger('youps')  # type: logging.Logger

    # this log is going to stdout but not going to the logging file
    # why are django settings not being picked up
    logger.info("user %s has requested simulation" % email)

    imapAccount = None
    imap = None

    try:
        imapAccount = ImapAccount.objects.get(email=email)
        auth_res = authenticate(imapAccount)
        if not auth_res['status']:
            raise ValueError(
                'Something went wrong during authentication. Refresh and try again!'
            )

        imap = auth_res['imap']  # noqa: F841 ignore unused
    except Exception as e:
        logger.exception("failed while logging into imap")
        res['code'] = "Fail to access your IMAP account"
        return

    try:
        res['messages'] = {}

        for folder_name in folder_names:
            messages = MessageSchema.objects.filter(
                imap_account=imapAccount,
                folder__name=folder_name).order_by("-base_message__date")[:N]

            for message_schema in messages:
                assert isinstance(message_schema, MessageSchema)
                mailbox = MailBox(imapAccount, imap, is_simulate=True)
                imap_res = interpret_bypass_queue(mailbox,
                                                  extra_info={
                                                      'code': code,
                                                      'msg-id':
                                                      message_schema.id
                                                  })
                logger.debug(imap_res)

                message = Message(message_schema, imap)

                from_field = None
                if message.from_:
                    from_field = {
                        "name": message.from_.name,
                        "email": message.from_.email,
                        "organization": message.from_.organization,
                        "geolocation": message.from_.geolocation
                    }

                to_field = [{
                    "name": tt.name,
                    "email": tt.email,
                    "organization": tt.organization,
                    "geolocation": tt.geolocation
                } for tt in message.to]

                cc_field = [{
                    "name": tt.name,
                    "email": tt.email,
                    "organization": tt.organization,
                    "geolocation": tt.geolocation
                } for tt in message.cc]

                # TODO attach activated line
                # This is to log for users
                new_msg = {
                    "timestamp":
                    str(datetime.datetime.now().strftime("%m/%d %H:%M:%S,%f")),
                    "type":
                    "new_message",
                    "folder":
                    message.folder.name,
                    "from_":
                    from_field,
                    "subject":
                    message.subject,
                    "to":
                    to_field,
                    "cc":
                    cc_field,
                    "flags":
                    [f.encode('utf8', 'replace') for f in message.flags],
                    "date":
                    str(message.date),
                    "deadline":
                    str(message.deadline),
                    "is_read":
                    message.is_read,
                    "is_deleted":
                    message.is_deleted,
                    "is_recent":
                    message.is_recent,
                    "log":
                    imap_res['appended_log'][message_schema.id]['log'],
                    "error":
                    imap_res['appended_log'][message_schema.id]['error']
                    if 'error' in imap_res['appended_log'][message_schema.id]
                    else False
                }

                res['messages'][message_schema.id] = new_msg

        res['status'] = True
    except ImapAccount.DoesNotExist:
        logger.exception("failed while doing a user code run")
        res['code'] = "Not logged into IMAP"
    except FolderSchema.DoesNotExist:
        logger.exception("failed while doing a user code run")
        logger.debug("Folder is not found, but it should exist!")
    except Exception as e:
        logger.exception("failed while doing a user code run %s %s " %
                         (e, traceback.format_exc()))
        res['code'] = msg_code['UNKNOWN_ERROR']
    finally:
        imap.logout()

    logging.debug(res)
    return res
Example #11
0
def run_mailbot(user,
                email,
                current_mode_id,
                modes,
                is_test,
                run_request,
                push=True):
    """This function is called everytime users hit "run", "stop" or "save" their scripts.

        Args:
            user (Model.UserProfile)
            email (string): user's email address
            current_mode_id (integer): ID of currently selected/running mode
            modes (list): a list of dicts that each element is information about each user's mode
            is_test (boolean): if is_test is True, then it just simulates the user's script and prints out log but not actually execute it.  
            run_request (boolean): if False, set the current_mode to None so the event is not fired at interpret()
    """
    res = {'status': False, 'imap_error': False, 'imap_log': ""}
    logger = logging.getLogger('youps')  # type: logging.Logger

    # this log is going to stdout but not going to the logging file
    # why are django settings not being picked up
    logger.info("user %s has run, stop, or saved" % email)

    imap = None

    try:
        imapAccount = ImapAccount.objects.get(email=email)
        auth_res = authenticate(imapAccount)
        if not auth_res['status']:
            raise ValueError(
                'Something went wrong during authentication. Refresh and try again!'
            )

        imap = auth_res['imap']  # noqa: F841 ignore unused

        imapAccount.is_test = is_test
        turn_on_youps(imapAccount, run_request, "By user's request")

        # TODO these don't work anymore
        # uid = fetch_latest_email_id(imapAccount, imap)'
        # imapAccount.newest_msg_id = uid

        # remove all user's tasks of this user to keep tasks up-to-date
        # old_mailbotMode = MailbotMode.objects.filter(imap_account=imapAccount)
        # old_mailbotMode.delete()

        for mode_index, mode in modes.iteritems():
            mode_name = mode['name'].encode('utf-8')
            mode_name = mode_name.split("<br>")[0] if mode_name else "mode"
            logger.info(mode_name)

            mailbotMode = MailbotMode.objects.filter(id=mode['id'],
                                                     imap_account=imapAccount)
            if mailbotMode.exists():
                mailbotMode = mailbotMode[0]
                mailbotMode.name = mode_name
                mailbotMode.save()
            else:
                mailbotMode = MailbotMode(name=mode_name,
                                          imap_account=imapAccount)
                mailbotMode.save()

            # Remove old editors to re-save it
            # TODO  dont remove it
            er = EmailRule.objects.filter(mode=mailbotMode)
            logger.debug("deleting er editor run request")
            args = EmailRule_Args.objects.filter(rule=er)
            args.delete()
            er.delete()

            for value in mode['editors']:
                name = value['name'].encode('utf-8')
                code = value['code'].encode('utf-8')
                folders = value['folders']
                logger.info(value)

                er = EmailRule(name=name,
                               mode=mailbotMode,
                               type=value['type'],
                               code=code)
                er.save()

                # Save selected folder for the mode
                for f in folders:
                    folder = FolderSchema.objects.get(imap_account=imapAccount,
                                                      name=f)
                    logger.info("saving folder to the editor %s run request" %
                                folder.name)
                    er.folders.add(folder)

                er.save()

                # Save shortcut email args
                if value['type'] == "shortcut":
                    for arg in value['args']:
                        logger.info(arg)

                        new_arg = EmailRule_Args(type=arg['type'], rule=er)
                        if arg['name']:
                            new_arg.name = arg['name']
                        new_arg.save()

            logger.info(
                EmailRule.objects.filter(mode=mailbotMode).values(
                    'name', 'id'))

        if run_request:
            imapAccount.current_mode = MailbotMode.objects.get(
                id=current_mode_id, imap_account=imapAccount)

            # if the code execute well without any bug, then save the code to DB
            if not res['imap_error']:
                pass
        else:
            imapAccount.current_mode = None

        imapAccount.save()

        # res['imap_log'] = ("[TEST MODE] Your rule is successfully installed. It won't take actual action but simulate your rule. %s \n" + res['imap_log']) if is_test else ("Your rule is successfully installed. \n" + res['imap_log'])
        #         now = datetime.now()
        #         now_format = now.strftime("%m/%d/%Y %H:%M:%S") + " "
        #         res['imap_log'] = now_format + res['imap_log']
        #     else:
        #         imapAccount.is_running = False
        #         imapAccount.save()
        # else:

        #     res['imap_log'] = "Your mailbot stops running"

        res['status'] = True

    except IMAPClient.Error as e:
        logger.exception("failed while doing a user code run")
        res['code'] = e
    except ImapAccount.DoesNotExist:
        logger.exception("failed while doing a user code run")
        res['code'] = "Not logged into IMAP"
    except FolderSchema.DoesNotExist:
        logger.exception("failed while doing a user code run")
        logger.debug("Folder is not found, but it should exist!")
    except MailbotMode.DoesNotExist:
        logger.exception("No current mode exist")
        res['code'] = "Currently no mode is selected. Select one of your mode to execute your YouPS."
    except Exception as e:
        # TODO add exception
        logger.exception("failed while doing a user code run")
        print(traceback.format_exc())
        res['code'] = msg_code['UNKNOWN_ERROR']
    finally:
        imap.logout()

    logging.debug(res)
    return res
Example #12
0
def fetch_watch_message(user, email, watched_message):
    res = {'status': False, 'log': "", 'messages': {}}

    try:
        imapAccount = ImapAccount.objects.get(email=email)
        res['watch_status'] = True
    except ImapAccount.DoesNotExist:
        res['code'] = "Error during authentication. Please refresh"
        return

    try:
        imap = None

        auth_res = authenticate(imapAccount)
        if not auth_res['status']:
            raise ValueError(
                'Something went wrong during authentication. Refresh and try again!'
            )

        imap = auth_res['imap']  # noqa: F841 ignore unused
    except Exception as e:
        logger.exception("failed while logging into imap")
        res['code'] = "Fail to access your IMAP account"
        return

    try:
        if res['watch_status']:
            imapAccount.sync_paused = True
            mailbox = MailBox(imapAccount, imap, is_simulate=False)
            msgs = None
            cnt = 0
            while True:
                for folder in mailbox._list_selectable_folders():
                    response = imap.select_folder(folder.name)

                    highest_mod_seq = response.get('HIGHESTMODSEQ')
                    logger.debug(highest_mod_seq)

                    # this mailbox is using highest mod_seq and there is no update
                    if highest_mod_seq is not None and folder._highest_mod_seq <= 0:
                        continue

                    logger.info("refresh flags")

                    msgs = folder._refresh_flag_changes(highest_mod_seq)

                    if msgs:
                        for r in msgs:

                            # if this message is already caught, skip to next to find another new msgs
                            logger.debug(r.id)
                            logger.debug(watched_message)
                            if str(r.id) in watched_message:
                                continue
                            logger.info(r.base_message.subject)
                            message = Message(
                                r, imap_client=""
                            )  # since we are only extracting metadata, no need to use imap_client
                            res['message_schemaid'] = r.id
                            res['message'] = message._get_meta_data_friendly()
                            res['sender'] = message._get_from_friendly()

                            try:
                                message_arrival_time = dateutil.parser.parse(
                                    res["message"]["date"])
                                # if the message arrives today, send only hour and minute
                                if message_arrival_time.date(
                                ) == datetime.datetime.today().date():
                                    res["message"]["date"] = "%d:%02d" % (
                                        message_arrival_time.hour,
                                        message_arrival_time.minute)
                            except:
                                logger.exception(
                                    "parsing arrival date fail; skipping parsing"
                                )

                            res['context'] = {
                                'sender': res['sender']["name"],
                                "subject": res['message']['subject'],
                                "date": res["message"]["date"],
                                "message_id": res['message_schemaid']
                            }

                            # if there is update, send it to the client immediatly
                            if 'message' in res:
                                res['status'] = True
                                return res

                # r=requests.get(url, headers=headers)

                # if r.json()['deltas']:
                #     break
                # # logger.info("finding delta..")
                if cnt == 10:
                    break
                cnt = cnt + 1
                sleep(0.01)

            # for d in r.json()['deltas']:
            #     if d['object'] == "message" or d['object'] == "thread":
            #         logger.info(d['attributes']['subject'])
            #         res["log"] = d['attributes']['subject']

            # if bc and bc.code == ButtonChannel.OK:
            #     res['folder'] = bc.message.folder.name
            #     res['uid'] = bc.message.id

            #     message = Message(bc.message, imap_client="")   # since we are only extracting metadata, no need to use imap_client
            #     res['message'] = message._get_meta_data_friendly()
            #     res['sender'] = message._get_from_friendly()
            # else:
            #     # if something went wrong only return the log
            #     logger.info(bc.code)
            #     res["log"] = "%s - %s" % (bc.get_code_display(), bc.log)

        res['status'] = True

    except ButtonChannel.DoesNotExist:
        res['uid'] = 0
    except Exception as e:
        logger.exception(e)
        res['code'] = msg_code['UNKNOWN_ERROR']
    finally:
        logger.info("Finish watching cycle")
        imapAccount.sync_paused = False
        imap.logout()

    return res