1# SPDX-License-Identifier: ISC
2# Copyright (c) Justus Winter <4winter@informatik.uni-hamburg.de>
3
4import glob
5import sys
6import logging
7import argparse
8
9from afew.Database import Database
10from afew.main import main as inner_main
11from afew.FilterRegistry import all_filters
12from afew.Settings import user_config_dir, get_filter_chain, \
13    get_mail_move_rules, get_mail_move_age, get_mail_move_rename
14from afew.NotmuchSettings import read_notmuch_settings, get_notmuch_new_query
15from afew.version import version
16
17parser = argparse.ArgumentParser()
18parser.add_argument('-V', '--version', action='version', version=version)
19
20# the actions
21action_group = parser.add_argument_group(
22    'Actions',
23    'Please specify exactly one action.'
24)
25action_group.add_argument(
26    '-t', '--tag', action='store_true',
27    help='run the tag filters'
28)
29action_group.add_argument(
30    '-w', '--watch', action='store_true',
31    help='continuously monitor the mailbox for new files'
32)
33action_group.add_argument(
34    '-m', '--move-mails', action='store_true',
35    help='move mail files between maildir folders'
36)
37
38# query modifiers
39query_modifier_group = parser.add_argument_group(
40    'Query modifiers',
41    'Please specify either --all or --new or a query string.'
42)
43query_modifier_group.add_argument(
44    '-a', '--all', action='store_true',
45    help='operate on all messages'
46)
47query_modifier_group.add_argument(
48    '-n', '--new', action='store_true',
49    help='operate on all new messages'
50)
51query_modifier_group.add_argument(
52    'query', nargs='*', help='a notmuch query to find messages to work on'
53)
54
55# general options
56options_group = parser.add_argument_group('General options')
57# TODO: get config via notmuch api
58options_group.add_argument(
59    '-C', '--notmuch-config', default=None,
60    help='path to the notmuch configuration file [default: $NOTMUCH_CONFIG or'
61         ' ~/.notmuch-config]'
62)
63options_group.add_argument(
64    '-e', '--enable-filters',
65    help="filter classes to use, separated by ',' [default: filters specified"
66         " in afew's config]"
67)
68options_group.add_argument(
69    '-d', '--dry-run', default=False, action='store_true',
70    help="don't change the db [default: %(default)s]"
71)
72options_group.add_argument(
73    '-R', '--reference-set-size', type=int, default=1000,
74    help='size of the reference set [default: %(default)s]'
75)
76
77options_group.add_argument(
78    '-T', '--reference-set-timeframe', type=int, default=30, metavar='DAYS',
79    help='do not use mails older than DAYS days [default: %(default)s]'
80)
81
82options_group.add_argument(
83    '-v', '--verbose', dest='verbosity', action='count', default=0,
84    help='be more verbose, can be given multiple times'
85)
86
87options_group.add_argument(
88    '-N', '--notmuch-args', default='',
89    help='arguments for notmuch new (in move mode)'
90)
91
92
93def main():
94    if sys.version_info < (3, 6):
95        sys.exit("Python 3.6 or later is required.")
96
97    args = parser.parse_args()
98
99    no_actions = len(list(filter(None, (
100        args.tag,
101        args.watch,
102        args.move_mails
103    ))))
104    if no_actions == 0:
105        sys.exit('You need to specify an action')
106    elif no_actions > 1:
107        sys.exit('Please specify exactly one action')
108
109    no_query_modifiers = len(list(filter(None, (args.all,
110                                                args.new, args.query))))
111    if no_query_modifiers == 0 and not args.watch \
112            and not args.move_mails:
113        sys.exit('You need to specify one of --new, --all or a query string')
114    elif no_query_modifiers > 1:
115        sys.exit('Please specify either --all, --new or a query string')
116
117    read_notmuch_settings(args.notmuch_config)
118
119    if args.new:
120        query_string = get_notmuch_new_query()
121    elif args.all:
122        query_string = ''
123    else:
124        query_string = ' '.join(args.query)
125
126    loglevel = {
127        0: logging.WARNING,
128        1: logging.INFO,
129        2: logging.DEBUG,
130    }[min(2, args.verbosity)]
131    logging.basicConfig(level=loglevel)
132
133    sys.path.insert(0, user_config_dir)
134    for file_name in glob.glob1(user_config_dir, '*.py'):
135        logging.info('Importing user filter %r' % (file_name,))
136        __import__(file_name[:-3], level=0)
137
138    if args.move_mails:
139        args.mail_move_rules = get_mail_move_rules()
140        args.mail_move_age = get_mail_move_age()
141        args.mail_move_rename = get_mail_move_rename()
142
143    with Database() as database:
144        configured_filter_chain = get_filter_chain(database)
145        if args.enable_filters:
146            args.enable_filters = args.enable_filters.split(',')
147
148            all_filters_set = set(all_filters.keys())
149            enabled_filters_set = set(args.enable_filters)
150            if not all_filters_set.issuperset(enabled_filters_set):
151                sys.exit('Unknown filter(s) selected: %s' % (' '.join(
152                    enabled_filters_set.difference(all_filters_set))))
153
154            args.enable_filters = [all_filters[filter_name](database)
155                                   for filter_name
156                                   in args.enable_filters]
157        else:
158            args.enable_filters = configured_filter_chain
159
160        inner_main(args, database, query_string)
161