]> git.notmuchmail.org Git - notmuch/blob - notmuch
notmuch: Use Query.count_messages() rather len(Query.search_messages())
[notmuch] / notmuch
1 #!/usr/bin/env python
2 """This is a notmuch implementation in python. It's goal is to allow running the test suite on the cnotmuch python bindings.
3
4 This "binary" honors the NOTMUCH_CONFIG environmen variable for reading a user's
5 notmuch configuration (e.g. the database path)
6
7 This code is licensed under the GNU GPL v3+."""
8 import sys, os, re, logging
9 from subprocess import call
10 from cnotmuch.notmuch import Database, Query
11 PREFIX=re.compile('(\w+):(.*$)')
12 #TODO Handle variable: NOTMUCH-CONFIG
13
14 #-------------------------------------------------------------------------
15 HELPTEXT="""The notmuch mail system.
16
17 Usage: notmuch <command> [args...]
18
19 Where <command> and [args...] are as follows:
20
21         setup   Interactively setup notmuch for first use.
22
23         new     [--verbose]
24
25                 Find and import new messages to the notmuch database.
26
27         search  [options...] <search-terms> [...]
28
29                 Search for messages matching the given search terms.
30
31         show    <search-terms> [...]
32
33                 Show all messages matching the search terms.
34
35         count   <search-terms> [...]
36
37                 Count messages matching the search terms.
38
39         reply   [options...] <search-terms> [...]
40
41                 Construct a reply template for a set of messages.
42
43         tag     +<tag>|-<tag> [...] [--] <search-terms> [...]
44
45                 Add/remove tags for all messages matching the search terms.
46
47         dump    [<filename>]
48
49                 Create a plain-text dump of the tags for each message.
50
51         restore <filename>
52
53                 Restore the tags from the given dump file (see 'dump').
54
55         search-tags     [<search-terms> [...] ]
56
57                 List all tags found in the database or matching messages.
58
59         help    [<command>]
60
61                 This message, or more detailed help for the named command.
62
63 Use "notmuch help <command>" for more details on each command.
64 And "notmuch help search-terms" for the common search-terms syntax.
65 """
66 #-------------------------------------------------------------------------
67 #TODO: replace the dynamic pieces
68 USAGE="""Notmuch is configured and appears to have a database. Excellent!
69
70 At this point you can start exploring the functionality of notmuch by
71 using commands such as:
72
73         notmuch search tag:inbox
74
75         notmuch search to:"Sebastian Spaeth"
76
77         notmuch search from:"Sebastian@SSpaeth.de"
78
79         notmuch search subject:"my favorite things"
80
81 See "notmuch help search" for more details.
82
83 You can also use "notmuch show" with any of the thread IDs resulting
84 from a search. Finally, you may want to explore using a more sophisticated
85 interface to notmuch such as the emacs interface implemented in notmuch.el
86 or any other interface described at http://notmuchmail.org
87
88 And don't forget to run "notmuch new" whenever new mail arrives.
89
90 Have fun, and may your inbox never have much mail.
91 """
92 #-------------------------------------------------------------------------
93 def quote_query_line(argv):
94    #mangle arguments wrapping terms with spaces in quotes
95    for i in xrange(0,len(argv)):
96       if argv[i].find(' ') >= 0:
97          #if we use prefix:termWithSpaces, put quotes around term
98          m = PREFIX.match(argv[i])
99          if m:
100             argv[i] = '%s:"%s"' % (m.group(1), m.group(2))
101          else:
102             argv[i] = '"'+argv[i]+'"'
103    return ' '.join(argv)
104
105 if __name__ == '__main__':
106
107    # Handle command line options
108    # No option 
109    #-------------------------------------
110    if len(sys.argv) == 1:
111       print USAGE
112    #-------------------------------------
113    elif sys.argv[1] == 'setup':
114        """ Interactively setup notmuch for first use. """
115        print "Not implemented."
116    #-------------------------------------
117    elif sys.argv[1] == 'new':
118        """ Interactively setup notmuch for first use. """
119        #print "Not implemented. We cheat by calling the proper notmuch"
120        call(['notmuch new'],shell=True)
121    #-------------------------------------
122    elif sys.argv[1] == 'help':
123        if len(sys.argv) == 2: print HELPTEXT
124        else: print "Not implemented"
125    #-------------------------------------
126    elif sys.argv[1] == 'show':
127       db = Database()
128       if len(sys.argv) == 2:
129          #no further search term
130          querystr=''
131       else:
132          #mangle arguments wrapping terms with spaces in quotes
133          querystr = quote_query_line(sys.argv[2:])
134       logging.debug("show "+querystr)
135       m = Query(db,querystr).search_messages()
136       for msg in m:
137          print(msg.format_as_text())
138    #-------------------------------------
139    elif sys.argv[1] == 'new':
140        #TODO: handle --verbose
141        print "Not implemented."
142    #-------------------------------------
143    elif sys.argv[1] == 'count':
144       db = Database()
145       if len(sys.argv) == 2:
146          #no further search term
147          querystr=''
148       else:
149          #mangle arguments wrapping terms with spaces in quotes
150          querystr = quote_query_line(sys.argv[2:])
151       logging.debug("count "+querystr)
152       print(Query(db,querystr).count_messages())
153       
154    #-------------------------------------
155    elif sys.argv[1] == 'tag':
156       #build lists of tags to be added and removed
157       add, remove = [], []
158       while not sys.argv[2]=='--' and \
159             (sys.argv[2].startswith('+') or sys.argv[2].startswith('-')):
160          if sys.argv[2].startswith('+'):
161             #append to add list without initial +
162             add.append(sys.argv.pop(2)[1:])
163          else:
164             #append to remove list without initial -
165             remove.append(sys.argv.pop(2)[1:])
166       #skip eventual '--'
167       if sys.argv[2]=='--': sys.argv.pop(2)
168       #the rest is search terms
169       querystr = quote_query_line(sys.argv[2:])
170       logging.warning("tag search-term "+querystr)
171       db = Database(mode=Database.MODE.READ_WRITE)
172       m  = Query(db,querystr).search_messages()
173       for msg in m:
174          #actually add and remove all tags
175          map(msg.add_tag, add)
176          map(msg.remove_tag, remove)
177    #-------------------------------------
178    elif sys.argv[1] == 'search-tags':
179       if len(sys.argv) == 2:
180          #no further search term
181          print("\n".join(Database().get_all_tags()))
182       else:
183          #mangle arguments wrapping terms with spaces in quotes
184          querystr = quote_query_line(sys.argv[2:])
185          logging.debug("search-term "+querystr)
186          db = Database()
187          m  = Query(db,querystr).search_messages()
188          print("\n".join([t for t in m.collect_tags()]))
189    #-------------------------------------
190    elif sys.argv[1] == 'dump':
191       #TODO: implement "dump <filename>"
192       if len(sys.argv) == 2:
193          f = sys.stdout
194       else:
195          f = open(sys.argv[2],"w")
196       db = Database()
197       q = Query(db,'')
198       q.set_sort(Query.SORT.MESSAGE_ID)
199       m = q.search_messages()
200       for msg in m:
201          f.write("%s (%s)\n" % (msg.get_message_id(), msg.get_tags()))
202    #-------------------------------------
203    else:
204        # unknown command
205        print "Error: Unknown command '%s' (see \"notmuch help\")" % sys.argv[1]
206
207
208    #TODO: implement
209    """
210 setup
211 new
212 search  [options...] <search-terms> [...]
213 show    <search-terms> [...]
214 reply   [options...] <search-terms> [...]
215 restore <filename>
216    """