]> git.phdru.name Git - mimedecode.git/blob - mimedecode/__main__.py
Feat: Move main() to __main__.py
[mimedecode.git] / mimedecode / __main__.py
1 import os
2 import sys
3 from . import mimedecode
4
5
6 def version(exit=1):
7     sys.stdout.write("""\
8 Broytman mimedecode.py version %s, %s
9 """ % (mimedecode.__version__, mimedecode.__copyright__))
10     if exit:
11         sys.exit(0)
12
13
14 def usage(code=0, errormsg=''):
15     version(0)
16     sys.stdout.write("""\
17 Usage: %s [-h|--help] [-V|--version] [-cCDP] [-H|--host=hostname] [-f charset] [-d header1[,h2,...]|*[,-h1,...]] [-p header1[,h2,h3,...]:param1[,p2,p3,...]] [-r header1[,h2,...]|*[,-h1,...]] [-R header1[,h2,h3,...]:param1[,p2,p3,...]] [--set-header header:value] [--set-param header:param=value] [-Bbeit mask] [--save-headers|body|message mask] [-O dest_dir] [-o output_file] [input_file [output_file]]
18 """ % mimedecode.me)
19     if errormsg:
20         sys.stderr.write(errormsg + os.linesep)
21     sys.exit(code)
22
23
24 class GlobalOptions:
25     from m_lib.defenc import default_encoding
26     recode_charset = 1  # recode charset of message body
27
28     host_name = None
29
30     # A list of headers to decode
31     decode_headers = ["From", "To", "Cc", "Reply-To", "Mail-Followup-To",
32                       "Subject"]
33
34     # A list of headers parameters to decode
35     decode_header_params = [
36         ("Content-Type", "name"),
37         ("Content-Disposition", "filename"),
38     ]
39
40     # A list of headers to remove
41     remove_headers = []
42     # A list of headers parameters to remove
43     remove_headers_params = []
44
45     # A list of header/value pairs to set
46     set_header_value = []
47     # A list of header/parameter/value triples to set
48     set_header_param = []
49
50     totext_mask = []  # A list of content-types to decode
51     binary_mask = []  # A list of content-types to pass through
52     # A list of content-types to pass through (content-transfer-decoded).
53     decoded_binary_mask = []
54     # Ignore (do not decode and do not include into output)
55     # but output a warning instead of the body.
56     ignore_mask = []
57     # Completely ignore - no headers, no body, no warning.
58     fully_ignore_mask = []
59     error_mask = []  # Raise error if encounter one of these
60
61     save_counter = 0
62     save_headers_mask = []
63     save_body_mask = []
64     save_message_mask = []
65
66     input_filename = None
67     output_filename = None
68     destination_dir = os.curdir
69
70
71 g = mimedecode.g = GlobalOptions
72
73
74 def get_opts():
75     from getopt import getopt, GetoptError
76
77     try:
78         options, arguments = getopt(
79             sys.argv[1:],
80             'hVcCDPH:f:d:p:r:R:b:B:e:I:i:t:O:o:',
81             ['help', 'version', 'host=',
82              'save-headers=', 'save-body=', 'save-message=',
83              'set-header=', 'set-param='])
84     except GetoptError:
85         usage(1)
86
87     for option, value in options:
88         if option in ('-h', '--help'):
89             usage()
90         elif option in ('-V', '--version'):
91             version()
92         elif option == '-c':
93             g.recode_charset = 1
94         elif option == '-C':
95             g.recode_charset = 0
96         elif option in ('-H', '--host'):
97             g.host_name = value
98         elif option == '-f':
99             g.default_encoding = value
100         elif option == '-d':
101             if value.startswith('*'):
102                 g.decode_headers = []
103             g.decode_headers.append(value)
104         elif option == '-D':
105             g.decode_headers = []
106         elif option == '-p':
107             g.decode_header_params.append(value.split(':', 1))
108         elif option == '-P':
109             g.decode_header_params = []
110         elif option == '-r':
111             g.remove_headers.append(value)
112         elif option == '-R':
113             g.remove_headers_params.append(value.split(':', 1))
114         elif option == '--set-header':
115             g.set_header_value.append(value.split(':', 1))
116         elif option == '--set-param':
117             header, value = value.split(':', 1)
118             if '=' in value:
119                 param, value = value.split('=', 1)
120             else:
121                 param, value = value.split(':', 1)
122             g.set_header_param.append((header, param, value))
123         elif option == '-t':
124             g.totext_mask.append(value)
125         elif option == '-B':
126             g.binary_mask.append(value)
127         elif option == '-b':
128             g.decoded_binary_mask.append(value)
129         elif option == '-I':
130             g.fully_ignore_mask.append(value)
131         elif option == '-i':
132             g.ignore_mask.append(value)
133         elif option == '-e':
134             g.error_mask.append(value)
135         elif option == '--save-headers':
136             g.save_headers_mask.append(value)
137         elif option == '--save-body':
138             g.save_body_mask.append(value)
139         elif option == '--save-message':
140             g.save_message_mask.append(value)
141         elif option == '-O':
142             g.destination_dir = value
143         elif option == '-o':
144             g.output_filename = value
145         else:
146             usage(1)
147
148     return arguments
149
150
151 def main():
152     arguments = get_opts()
153
154     la = len(arguments)
155     if la == 0:
156         g.input_filename = '-'
157         infile = sys.stdin
158         if g.output_filename:
159             outfile = open_output_file(g.output_filename)
160         else:
161             g.output_filename = '-'
162             outfile = sys.stdout
163     elif la in (1, 2):
164         if (arguments[0] == '-'):
165             g.input_filename = '-'
166             infile = sys.stdin
167         else:
168             g.input_filename = arguments[0]
169             infile = open(arguments[0], 'r')
170         if la == 1:
171             if g.output_filename:
172                 outfile = open_output_file(g.output_filename)
173             else:
174                 g.output_filename = '-'
175                 outfile = sys.stdout
176         elif la == 2:
177             if g.output_filename:
178                 usage(1, 'Too many output filenames')
179             if (arguments[1] == '-'):
180                 g.output_filename = '-'
181                 outfile = sys.stdout
182             else:
183                 g.output_filename = arguments[1]
184                 outfile = open_output_file(g.output_filename)
185     else:
186         usage(1, 'Too many arguments')
187
188     if (infile is sys.stdin) and sys.stdin.isatty():
189         if (outfile is sys.stdout) and sys.stdout.isatty():
190             usage()
191         usage(1, 'Filtering from console is forbidden')
192
193     if not g.host_name:
194         import socket
195         g.host_name = socket.gethostname()
196
197     g.outfile = outfile
198     if hasattr(outfile, 'buffer'):
199         def output_bytes(s):
200             if not isinstance(s, bytes):
201                 s = s.encode(g.default_encoding, "replace")
202             outfile.buffer.write(s)
203         output = output_bytes
204     else:
205         output = outfile.write
206     mimedecode.output = output
207
208     import email
209     msg = email.message_from_file(infile)
210
211     for header, value in g.set_header_value:
212         mimedecode.set_header(msg, header, value)
213
214     for header, param, value in g.set_header_param:
215         if header in msg:
216             msg.set_param(param, value, header)
217
218     try:
219         mimedecode.decode_message(msg)
220     finally:
221         infile.close()
222         outfile.close()
223
224
225 if __name__ == "__main__":
226     main()