コード例 #1
0
ファイル: gmailieer.py プロジェクト: yeled/gmailieer
  def push (self, args, setup = False):
    if not setup:
      self.setup (args, args.dry_run, True)

      self.force            = args.force
      self.limit            = args.limit

      self.remote.get_labels ()

    # loading local changes
    with notmuch.Database () as db:
      (rev, uuid) = db.get_revision ()

      if rev == self.local.state.lastmod:
        print ("push: everything is up-to-date.")
        return

      qry = "path:%s/** and lastmod:%d..%d" % (self.local.nm_relative, self.local.state.lastmod, rev)

      # print ("collecting changes..: %s" % qry)
      query = notmuch.Query (db, qry)
      total = query.count_messages () # might be destructive here as well
      query = notmuch.Query (db, qry)

      messages = list(query.search_messages ())
      if self.limit is not None and len(messages) > self.limit:
        messages = messages[:self.limit]

      # push changes
      bar = tqdm (leave = True, total = len(messages), desc = 'pushing, 0 changed')
      changed = 0
      for m in messages:
        r = self.remote.update (m, self.local.state.last_historyId, self.force)
        if r:
          changed += 1
          bar.set_description ('pushing, %d changed' % changed)
        bar.update (1)

      bar.close ()

    if not self.remote.all_updated:
      # will not set last_mod, this forces messages to be pushed again at next push
      print ("push: not all changes could be pushed, will re-try at next push.")
    else:
      # TODO: Once I get more confident we might set the last history Id here to
      # avoid pulling back in the changes we just pushed. Currently there's a race
      # if something is modified remotely (new email, changed tags), so this might
      # not really be possible.
      pass

    if not self.dry_run and self.remote.all_updated:
      self.local.state.set_lastmod (rev)

    print ("remote historyId: %d" % self.remote.get_current_history_id (self.local.state.last_historyId))
コード例 #2
0
ファイル: api.py プロジェクト: markthomas93/netviel
 def get(self, thread_id):
     threads = notmuch.Query(
         get_db(), "thread:{}".format(thread_id)
     ).search_threads()
     thread = next(threads)  # there can be only 1
     messages = thread.get_messages()
     return messages_to_json(messages)
コード例 #3
0
ファイル: api.py プロジェクト: vthriller/malo
 def fetch_message(message_id):
     msgs = notmuch.Query(get_db(), "mid:{}".format(message_id)).search_messages()
     try:
         msg = next(msgs)  # there can be only 1
     except StopIteration:
         return 'Not found', 404
     return message_to_json(msg)
コード例 #4
0
    def commit(self, dry_run=True):
        dirty_messages = set()
        dirty_messages.update(self._flush_tags)
        dirty_messages.update(self._add_tags.keys())
        dirty_messages.update(self._remove_tags.keys())

        if not dirty_messages:
            return

        if dry_run:
            self.log.info('I would commit changes to %i messages' %
                          len(dirty_messages))
        else:
            self.log.info('Committing changes to %i messages' %
                          len(dirty_messages))
            db = self.database.open(rw=True)

            for message_id in dirty_messages:
                messages = notmuch.Query(db, 'id:"%s"' %
                                         message_id).search_messages()

                for message in messages:
                    if message_id in self._flush_tags:
                        message.remove_all_tags()

                    for tag in self._add_tags.get(message_id, []):
                        message.add_tag(tag)

                    for tag in self._remove_tags.get(message_id, []):
                        message.remove_tag(tag)

        self.flush_changes()
コード例 #5
0
    def move(self, maildir, rules):
        '''
        Move mails in folder maildir according to the given rules.
        '''
        # identify and move messages
        logging.info("checking mails in '{}'".format(maildir))
        to_delete_fnames = []
        for query in rules.keys():
            destination = '{}/{}/cur/'.format(self.db_path, rules[query])
            main_query = self.query.format(folder=maildir, subquery=query)
            logging.debug("query: {}".format(main_query))
            messages = notmuch.Query(self.db, main_query).search_messages()

            to_delete_fnames += self.__move(messages, maildir, destination)

        # remove mail from source locations only after all copies are finished
        for fname in set(to_delete_fnames):
            os.remove(fname)

        # update notmuch database
        logging.info("updating database")
        if not self.dry_run:
            self.__update_db(maildir)
        else:
            logging.info("Would update database")
コード例 #6
0
ファイル: messages.py プロジェクト: natask/notifymuch
 def __init__(self):
     db = notmuch.Database()
     self.query = notmuch.Query(db, config.get('query'))
     if config.get('sort') == "oldest":
         self.query.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
     else:
         self.query.set_sort(notmuch.Query.SORT.NEWEST_FIRST)
コード例 #7
0
def populate_nm_patch_status(db,conn,project_name,all_my_tags):
    for t in all_my_tags:
        qstr = 'tag:pw-{} and tag:pw-{}-{}'.format(project_name,project_name,t)
        q = notmuch.Query(db, qstr)
        msgs = q.search_messages()
        for m in msgs:
            insert_nm_patch_status(conn,m.get_message_id(),project_name,t)
        conn.commit()
コード例 #8
0
ファイル: api.py プロジェクト: vthriller/malo
 def thread(query):
     query = notmuch.Query(get_db(), query)
     query.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
     thread = query.search_messages()
     messages = [message_to_json(m) for m in thread]
     if not messages:
         return 'Not found', 404
     return jsonify(messages)
コード例 #9
0
ファイル: api.py プロジェクト: vthriller/malo
 def download_message(message_id):
     msgs = notmuch.Query(get_db(), "mid:{}".format(message_id)).search_messages()
     try:
         msg = next(msgs)  # there can be only 1
     except StopIteration:
         return 'Not found', 404
     # not message/rfc822: people might want to read it in browser
     return send_file(msg.get_filename(), mimetype="text/plain")
コード例 #10
0
ファイル: api.py プロジェクト: FiloSottile/netviel
 def download_message(message_id):
     msgs = notmuch.Query(get_db(),
                          "mid:{}".format(message_id)).search_messages()
     msg = next(msgs)  # there can be only 1
     return send_file(msg.get_filename(),
                      mimetype="message/rfc822",
                      as_attachment=True,
                      attachment_filename=message_id + ".eml")
コード例 #11
0
ファイル: MailMover.py プロジェクト: neuhalje/afew
    def move(self, maildir, rules):
        '''
        Move mails in folder maildir according to the given rules.
        '''
        # identify and move messages
        logging.info("checking mails in '{}'".format(maildir))
        to_delete_fnames = []
        moved = False
        for query in rules.keys():
            destination = '{}/{}/cur/'.format(self.db_path, rules[query])
            main_query = self.query.format(folder=maildir.replace(
                "\"", "\\\""),
                                           subquery=query)
            logging.debug("query: {}".format(main_query))
            messages = notmuch.Query(self.db, main_query).search_messages()
            for message in messages:
                # a single message (identified by Message-ID) can be in several
                # places; only touch the one(s) that exists in this maildir
                all_message_fnames = message.get_filenames()
                to_move_fnames = [
                    name for name in all_message_fnames if maildir in name
                ]
                if not to_move_fnames:
                    continue
                moved = True
                self.__log_move_action(message, maildir, rules[query],
                                       self.dry_run)
                for fname in to_move_fnames:
                    if self.dry_run:
                        continue
                    try:
                        shutil.copy2(fname,
                                     self.get_new_name(fname, destination))
                        to_delete_fnames.append(fname)
                    except shutil.SameFileError:
                        logging.warn(
                            "trying to move '{}' onto itself".format(fname))
                        continue
                    except shutil.Error as e:
                        # this is ugly, but shutil does not provide more
                        # finely individuated errors
                        if str(e).endswith("already exists"):
                            continue
                        else:
                            raise

        # remove mail from source locations only after all copies are finished
        for fname in set(to_delete_fnames):
            os.remove(fname)

        # update notmuch database
        if not self.dry_run:
            if moved:
                logging.info("updating database")
                self.__update_db(maildir)
        else:
            logging.info("Would update database")
コード例 #12
0
def smaSearch(q):
    #with notmuch.Database(path = MAILDIR) as db:
    db = notmuch.Database(path=MAILDIR)
    query = notmuch.Query(db, q)
    query.set_sort(notmuch.Query.SORT.NEWEST_FIRST)
    msgs = query.search_messages()
    msglist = list(msgs)[:100]
    # db.close()
    return msglist
コード例 #13
0
ファイル: sort_mail.py プロジェクト: pazz/scripts
def tag_search(db, search, *tags):
    q = notmuch.Query(db, search)
    count = 0
    for msg in q.search_messages():
        count += 1
        tag_message(msg, *tags)
    if count > 0:
        logging.debug('Tagging %d messages with (%s)' %
                      (count, ' '.join(tags)))
コード例 #14
0
ファイル: api.py プロジェクト: vthriller/malo
    def remove_tag(message_id, tag):
        msgs = notmuch.Query(get_db(), "mid:{}".format(message_id)).search_messages()
        try:
            msg = next(msgs)  # there can be only 1
        except StopIteration:
            return 'Not found', 404

        msg.remove_tag(tag, sync_maildir_flags=True)

        return jsonify(list(msg.get_tags()))
コード例 #15
0
    def state_color(self):
        # Check for query hits in the list.
        for query_tuple in self.color_query_tuples:
            query = self.unread_query + ' and (' + query_tuple[0] + ')'
            count = notmuch.Query(self.database, query).count_messages()

            # Stop here of any hit and return the queries color.
            if count > 0:
                return query_tuple[1]

        return ''
コード例 #16
0
ファイル: repository.py プロジェクト: neuhalje/notmuch-task
    def do_query(self, query):
        """
        Executes a notmuch query.

        :param query: the query to execute
        :type  query: str
        :returns: the query result
        :rtype:   :class:`notmuch.Query`
        """
        logging.debug('Executing query %r' % query)
        return notmuch.Query(self.open(), query)
コード例 #17
0
ファイル: api.py プロジェクト: markthomas93/netviel
 def download_attachment(message_id, num):
     msgs = notmuch.Query(get_db(), "mid:{}".format(message_id)).search_messages()
     msg = next(msgs)  # there can be only 1
     d = message_attachment(msg, num)
     if not d:
         return None
     if isinstance(d["content"], str):
         f = io.StringIO(d["content"])
     else:
         f = io.BytesIO(d["content"])
     return send_file(f, mimetype=d["content_type"], as_attachment=True,
         attachment_filename=d["filename"])
コード例 #18
0
    def differing_address_count(self):
        messages = notmuch.Query(self.database,
                                 self.unread_query).search_messages()
        address_list = dict()

        # Count uniquely addresses by add them as keys to a mapping.
        for message in messages:
            name, address = parseaddr(message.get_header('To'))
            address_list[address] = None

        # The number of keys are the amount of individual addresses.
        return len(address_list)
コード例 #19
0
def get_oldest_nm_message(db, project_list):
    pw_list = 'to:{}'.format(project_list)
    qstr = pw_list
    #qstr = qstr + ' and not (tag:{}'.format(all_my_tags[0])
    #for t in all_my_tags[1:]:
    #    qstr = qstr + ' or tag:{}'.format(t)
    #qstr = qstr + ')'
    q = notmuch.Query(db, qstr)

    #q.exclude_tag('pwsync')
    q.set_sort(notmuch.Query.SORT.OLDEST_FIRST)
    #q.set_sort(notmuch.Query.SORT.NEWEST_FIRST)
    msgs = q.search_messages()
    since =  datetime.datetime.fromtimestamp(next(msgs).get_date())
    return since
コード例 #20
0
ファイル: api.py プロジェクト: vthriller/malo
 def download_attachment(message_id, num, filename):
     # filename is unused, only added to url to name saved files appropriately
     msgs = notmuch.Query(get_db(), "mid:{}".format(message_id)).search_messages()
     try:
         msg = next(msgs)  # there can be only 1
     except StopIteration:
         return 'Not found', 404
     d = message_attachment(msg, num)
     if not d:
         return None
     if isinstance(d["content"], str):
         f = io.BytesIO(d["content"].encode())
     else:
         f = io.BytesIO(d["content"])
     f.seek(0)
     return send_file(f, mimetype=d["content_type"])
コード例 #21
0
def add_tags(notmuch_db, add_gmail=False):
    """loop through all the messages and tags from X-Keywords header to
    notmuch. This obviously might take a while

    @param notmuch_db: notmuch db instance
    @param add_gmail: wether to add tags like Sent, Important, etc"""
    all_messages = notmuch.Query(notmuch_db, '').search_messages()
    for message in all_messages:
        message_tags = message.get_header('X-Keywords')
        if message_tags:
            for tag in message_tags.split(','):
                if tag.startswith('\\'):
                    if add_gmail:
                        message.add_tag(tag)
                else:
                    logging.debug('Adding tag %s to msg <%s>', tag, message.get_message_id())
                    message.add_tag(tag)
コード例 #22
0
def iter_email_paths(args: typing.List[str]) -> typing.Iterator[str]:
    """Iterate over paths of matching emails."""
    if len(args) > 0:
        yield from args
        return
    if notmuch is None:
        print(
            f"E: No files specified on command-line and could not import notmuch: {_nm_exc}",
            file=sys.stderr,
        )
        sys.exit(1)
    database = notmuch.Database()
    query = notmuch.Query(
        database, "from:mintos subject:tägliche subject:Zusammenfassung")
    query.set_sort(notmuch.Query.SORT.OLDEST_FIRST)  # pylint: disable=no-member
    msgs = query.search_messages()
    for msg in msgs:
        yield msg.get_filename()
コード例 #23
0
ファイル: database.py プロジェクト: askurihin/not-much-fire
    def filtered_messages(self) -> List[Message]:
        """Filter unread messages which have not been notified already.

        Queries Notmuch for unread messages and compare their timestamp
        against the last time notifying messages by the caches state.
        Messages which arrived before this timestamp are considered as
        already notified and therefore part of the returned list.
        """

        unfiltered_messages = notmuch.Query(
            self.database, self.notmuch_query).search_messages()
        messages = []

        for message in unfiltered_messages:
            if self._get_message_date(message) > self.cache.last_update:
                messages.append(message)

        return messages
コード例 #24
0
ファイル: list.py プロジェクト: alistair23/misc-files
def dump_notmuch_query(patches, args):
    import notmuch

    sub_series = find_subseries(patches, args)
    if not sub_series:
        return

    def fn(series):
        return 'id:"%s"' % series['messages'][0]['message-id']

    query_str = ' or '.join(map(fn, sub_series))

    db = notmuch.Database(config.get_notmuch_dir())
    q = notmuch.Query(db, query_str)

    tids = []
    for thread in q.search_threads():
        tids.append('thread:%s' % thread.get_thread_id())

    print(' or '.join(tids))
コード例 #25
0
def _main():
    logging.basicConfig(level=logging.INFO,
                        format="%(levelname)s: %(message)s")

    # If called without any argument, this is supposed to be a first run: index everything
    if len(sys.argv) == 1:
        if os.path.exists(os.path.expanduser(_DBPATH)):
            print("%s already exists.\n"
                  "Please delete it if you want to recreate the database." %
                  _DBPATH)
            sys.exit(1)

        book = AddrBook(True)
        nmdb = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
        query = notmuch.Query(nmdb, "tag:sent or tag:replied")
        book.index(query.search_messages())

    # If called with arguments, search for that.
    else:
        needle = " ".join(sys.argv[1:])
        AddrBook().find(needle)
コード例 #26
0
def run(db):
    query = notmuch.Query(db, "")
    cnt = 0
    for msg in query.search_messages():
        fns = [fn for fn in msg.get_filenames()]
        if len(fns) < 2:
            continue

        dirnames = [os.path.dirname(os.path.dirname(fn)) for fn in fns]
        same_dir = True
        for dirname in dirnames:
            if dirname != dirnames[0]:
                same_dir = False
                break
        if not same_dir:
            continue

        fns.sort(key=os.path.getmtime)
        for fn in fns[1:]:
            cnt += 1
            os.unlink(fn)

    print cnt
コード例 #27
0
    def push(self, args, setup=False):
        if not setup:
            self.setup(args, args.dry_run, True)

            self.force = args.force
            self.limit = args.limit

            self.remote.get_labels()

        # loading local changes
        with notmuch.Database() as db:
            (rev, uuid) = db.get_revision()

            if rev == self.local.state.lastmod:
                self.vprint("push: everything is up-to-date.")
                return

            qry = "path:%s/** and lastmod:%d..%d" % (
                self.local.nm_relative, self.local.state.lastmod, rev)

            query = notmuch.Query(db, qry)
            total = query.count_messages()  # probably destructive here as well
            query = notmuch.Query(db, qry)

            messages = list(query.search_messages())
            if self.limit is not None and len(messages) > self.limit:
                messages = messages[:self.limit]

            # get gids and filter out messages outside this repository
            messages, gids = self.local.messages_to_gids(messages)

            # get meta-data on changed messages from remote
            remote_messages = []
            self.bar_create(leave=True,
                            total=len(gids),
                            desc='receiving metadata')

            def _got_msgs(ms):
                for m in ms:
                    self.bar_update(1)
                    remote_messages.append(m)

            self.remote.get_messages(gids, _got_msgs, 'minimal')
            self.bar_close()

            # resolve changes
            self.bar_create(leave=True,
                            total=len(gids),
                            desc='resolving changes')
            actions = []
            for rm, nm in zip(remote_messages, messages):
                actions.append(
                    self.remote.update(rm, nm, self.local.state.last_historyId,
                                       self.force))
                self.bar_update(1)

            self.bar_close()

            # remove no-ops
            actions = [a for a in actions if a]

            # limit
            if self.limit is not None and len(actions) >= self.limit:
                actions = actions[:self.limit]

            # push changes
            if len(actions) > 0:
                self.bar_create(leave=True,
                                total=len(actions),
                                desc='pushing, 0 changed')
                changed = 0

                def cb(resp):
                    nonlocal changed
                    self.bar_update(1)
                    changed += 1
                    if not self.args.quiet and self.bar:
                        self.bar.set_description('pushing, %d changed' %
                                                 changed)

                self.remote.push_changes(actions, cb)

                self.bar_close()
            else:
                self.vprint('push: nothing to push')

        if not self.remote.all_updated:
            # will not set last_mod, this forces messages to be pushed again at next push
            print(
                "push: not all changes could be pushed, will re-try at next push."
            )
        else:
            # TODO: Once we get more confident we might set the last history Id here to
            # avoid pulling back in the changes we just pushed. Currently there's a race
            # if something is modified remotely (new email, changed tags), so this might
            # not really be possible.
            pass

        if not self.dry_run and self.remote.all_updated:
            self.local.state.set_lastmod(rev)

        self.vprint("remote historyId: %d" %
                    self.remote.get_current_history_id(
                        self.local.state.last_historyId))
コード例 #28
0
markup_cnt = '[<span foreground="#93e0e3">{0}</span>]'
markup_from = '<span foreground="#ffeece">{0}</span>'
markup_subj = '<b>{0}</b>'
markup_tags = '<i>(<span foreground="#9fc59f">{0}</span>)</i>'

MAX_FROM_LEN = 35
MAX_SUBJ_LEN = 70
MAX_THREADS = 15

config = configparser.ConfigParser()
with open(os.path.expanduser("~/.notmuch-config")) as ini:
    config.read_file(ini)
exc_tags = config["search"].get("exclude_tags", "").split(";")

db = notmuch.Database(mode=notmuch.Database.MODE.READ_ONLY)
q = notmuch.Query(db, "tag:unread or tag:todo")
q.set_sort(notmuch.Query.SORT.NEWEST_FIRST)
for tag in exc_tags:
    q.exclude_tag(tag.strip())

# Read data about the new messages
tab = []
msgs, threads_total, threads_unread = 0, 0, 0
mlc, mlf, mls = 0, 0, 0
for thr in q.search_threads():
    threads_total += 1
    tags = list(thr.get_tags())
    if "unread" not in tags:
        continue
    threads_unread += 1
コード例 #29
0
ファイル: api.py プロジェクト: bigeagle/netviel
 def get(self, query_string):
     threads = notmuch.Query(get_db(), query_string).search_threads()
     return threads_to_json(threads, number=None)
コード例 #30
0
ファイル: notmuch_abook.py プロジェクト: rubdos/notmuch-abook
 def _get_all_messages(self):
     notmuch_db = notmuch.Database(self.db_path)
     query = notmuch.Query(notmuch_db, self.query)
     return query.search_messages()