source: emailtotracscript/trunk/email2trac.py.in @ 136

Last change on this file since 136 was 136, checked in by bas, 17 years ago

EmailtoTracScript?:

email2trac.py.in,email2trac.conf:

  • Added strip_signature option, inspired by Mailman software
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 22.3 KB
Line 
1#!@PYTHON@
2# Copyright (C) 2002
3#
4# This file is part of the email2trac utils
5#
6# This program is free software; you can redistribute it and/or modify it
7# under the terms of the GNU General Public License as published by the
8# Free Software Foundation; either version 2, or (at your option) any
9# later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19#
20# For vi/emacs or other use tabstop=4 (vi: set ts=4)
21#
22"""
23email2trac.py -- Email tickets to Trac.
24
25A simple MTA filter to create Trac tickets from inbound emails.
26
27Copyright 2005, Daniel Lundin <daniel@edgewall.com>
28Copyright 2005, Edgewall Software
29
30Changed By: Bas van der Vlies <basv@sara.nl>
31Date      : 13 September 2005
32Descr.    : Added config file and command line options, spam level
33            detection, reply address and mailto option. Unicode support
34
35Changed By: Walter de Jong <walter@sara.nl>
36Descr.    : multipart-message code and trac attachments
37
38
39The scripts reads emails from stdin and inserts directly into a Trac database.
40MIME headers are mapped as follows:
41
42        * From:      => Reporter
43                     => CC (Optional via reply_address option)
44        * Subject:   => Summary
45        * Body       => Description
46        * Component  => Can be set to SPAM via spam_level option
47
48How to use
49----------
50 * Create an config file:
51        [DEFAULT]                      # REQUIRED
52        project      : /data/trac/test # REQUIRED
53        debug        : 1               # OPTIONAL, if set print some DEBUG info
54        spam_level   : 4               # OPTIONAL, if set check for SPAM mail
55        reply_address: 1               # OPTIONAL, if set then fill in ticket CC field
56        umask        : 022             # OPTIONAL, if set then use this umask for creation of the attachments
57        mailto_link  : 1               # OPTIONAL, if set then [mailto:<>] in description
58        mailto_cc    : basv@sara.nl    # OPTIONAL, use this address as CC in mailto line
59        ticket_update: 1               # OPTIONAL, if set then check if this is an update for a ticket
60        trac_version : 0.8             # OPTIONAL, default is 0.9
61
62        [jouvin]                         # OPTIONAL project declaration, if set both fields necessary
63        project      : /data/trac/jouvin # use -p|--project jouvin. 
64       
65 * default config file is : /etc/email2trac.conf
66
67 * Commandline opions:
68                -h | --help
69                -c <value> | --component=<value>
70                -f <config file> | --file=<config file>
71                -p <project name> | --project=<project name>
72
73SVN Info:
74        $Id: email2trac.py.in 136 2006-11-27 15:29:32Z bas $
75"""
76import os
77import sys
78import string
79import getopt
80import stat
81import time
82import email
83import email.Iterators
84import email.Header
85import re
86import urllib
87import unicodedata
88import ConfigParser
89from stat import *
90import mimetypes
91import syslog
92import traceback
93
94
95# Some global variables
96#
97trac_default_version = 0.9
98m = None
99
100
101class TicketEmailParser(object):
102        env = None
103        comment = '> '
104   
105        def __init__(self, env, parameters, version):
106                self.env = env
107
108                # Database connection
109                #
110                self.db = None
111
112                # Some useful mail constants
113                #
114                self.author = None
115                self.email_addr = None
116                self.email_field = None
117
118                self.VERSION = version
119                if self.VERSION == 0.8:
120                        self.get_config = self.env.get_config
121                else:
122                        self.get_config = self.env.config.get
123
124                if parameters.has_key('umask'):
125                        os.umask(int(parameters['umask'], 8))
126
127                if parameters.has_key('debug'):
128                        self.DEBUG = int(parameters['debug'])
129                else:
130                        self.DEBUG = 0
131
132                if parameters.has_key('mailto_link'):
133                        self.MAILTO = int(parameters['mailto_link'])
134                        if parameters.has_key('mailto_cc'):
135                                self.MAILTO_CC = parameters['mailto_cc']
136                        else:
137                                self.MAILTO_CC = ''
138                else:
139                        self.MAILTO = 0
140
141                if parameters.has_key('spam_level'):
142                        self.SPAM_LEVEL = int(parameters['spam_level'])
143                else:
144                        self.SPAM_LEVEL = 0
145
146                if parameters.has_key('email_comment'):
147                        self.comment = str(parameters['email_comment'])
148
149                if parameters.has_key('email_header'):
150                        self.EMAIL_HEADER = int(parameters['email_header'])
151                else:
152                        self.EMAIL_HEADER = 0
153
154                if parameters.has_key('alternate_notify_template'):
155                        self.notify_template = str(parameters['alternate_notify_template'])
156                else:
157                        self.notify_template = None
158
159                if parameters.has_key('reply_all'):
160                        self.REPLY_ALL = int(parameters['reply_all'])
161                else:
162                        self.REPLY_ALL = 0
163
164                if parameters.has_key('ticket_update'):
165                        self.TICKET_UPDATE = int(parameters['ticket_update'])
166                else:
167                        self.TICKET_UPDATE = 0
168
169                if parameters.has_key('drop_spam'):
170                        self.DROP_SPAM = int(parameters['drop_spam'])
171                else:
172                        self.DROP_SPAM = 0
173
174                if parameters.has_key('verbatim_format'):
175                        self.VERBATIM_FORMAT = int(parameters['verbatim_format'])
176                else:
177                        self.VERBATIM_FORMAT = 1
178
179                if parameters.has_key('strip_signature'):
180                        self.STRIP_SIGNATURE = int(parameters['strip_signature'])
181                else:
182                        self.STRIP_SIGNATURE = 0
183
184
185        # X-Spam-Score: *** (3.255) BAYES_50,DNS_FROM_AHBL_RHSBL,HTML_
186        # Note if Spam_level then '*' are included
187        def spam(self, message):
188                if message.has_key('X-Spam-Score'):
189                        spam_l = string.split(message['X-Spam-Score'])
190                        number = spam_l[0].count('*')
191
192                        if number >= self.SPAM_LEVEL:
193                                return 'Spam'
194
195                elif message.has_key('X-Virus-found'):                  # treat virus mails as spam
196                        return 'Spam'
197
198                return self.get_config('ticket', 'default_component')
199
200        def to_unicode(self, str):
201                """
202                Email has 7 bit ASCII code, convert it to unicode with the charset
203        that is encoded in 7-bit ASCII code and encode it as utf-8 so Trac
204                understands it.
205                """
206                results =  email.Header.decode_header(str)
207                str = None
208                for text,format in results:
209                        if format:
210                                try:
211                                        temp = unicode(text, format)
212                                except (UnicodeError,LookupError):
213                                        # This always works
214                                        #
215                                        temp = unicode(text, 'iso-8859-15')
216                        else:
217                                temp = string.strip(text)
218                                temp = unicode(text, 'iso-8859-15')
219
220                        if str:
221                                str = '%s %s' %(str, temp)
222                        else:
223                                str = '%s' %temp
224
225                str = str.encode('utf-8')
226                return str
227
228        def debug_attachments(self, message):
229                n = 0
230                for part in message.walk():
231                        if part.get_content_maintype() == 'multipart':      # multipart/* is just a container
232                                print 'TD: multipart container'
233                                continue
234
235                        n = n + 1
236                        print 'TD: part%d: Content-Type: %s' % (n, part.get_content_type())
237                        print 'TD: part%d: filename: %s' % (n, part.get_filename())
238
239                        if part.is_multipart():
240                                print 'TD: this part is multipart'
241                                payload = part.get_payload(decode=1)
242                                print 'TD: payload:', payload
243                        else:
244                                print 'TD: this part is not multipart'
245
246                        part_file = '/var/tmp/part%d' % n
247                        print 'TD: writing part%d (%s)' % (n,part_file)
248                        fx = open(part_file, 'wb')
249                        text = part.get_payload(decode=1)
250                        if not text:
251                                text = '(None)'
252                        fx.write(text)
253                        fx.close()
254                        try:
255                                os.chmod(part_file,S_IRWXU|S_IRWXG|S_IRWXO)
256                        except OSError:
257                                pass
258
259        def email_header_txt(self, m):
260                """
261                Display To and CC addresses in description field
262                """
263                str = ''
264                if m['To'] and len(m['To']) > 0 and m['To'] != 'hic@sara.nl':
265                        str = "'''To:''' %s [[BR]]" %(m['To'])
266                if m['Cc'] and len(m['Cc']) > 0:
267                        str = "%s'''Cc:''' %s [[BR]]" % (str, m['Cc'])
268
269                return  self.to_unicode(str)
270
271        def set_owner(self, ticket):
272                """
273                Select default owner for ticket component
274                """
275                cursor = self.db.cursor()
276                sql = "SELECT owner FROM component WHERE name='%s'" % ticket['component']
277                cursor.execute(sql)
278                try:
279                        ticket['owner'] = cursor.fetchone()[0]
280                except TypeError, detail:
281                        ticket['owner'] = "UNKNOWN"
282
283        def get_author_emailaddrs(self, message):
284                """
285                Get the default author name and email address from the message
286                """
287                self.author, self.email_addr  = email.Utils.parseaddr(message['from'])
288
289                # Look for email address in registered trac users
290                #
291                if self.VERSION == 0.8:
292                        users = []
293                else:
294                        users = [ u for (u, n, e) in self.env.get_known_users(self.db)
295                                if e == self.email_addr ]
296
297                if len(users) == 1:
298                        self.email_field = users[0]
299                else:
300                        self.email_field =  self.to_unicode(message['from'])
301
302        def set_reply_fields(self, ticket, message):
303                """
304                Set all the right fields for a new ticket
305                """
306                ticket['reporter'] = self.email_field
307
308                # Put all CC-addresses in ticket CC field
309                #
310                if self.REPLY_ALL:
311                        #tos = message.get_all('to', [])
312                        ccs = message.get_all('cc', [])
313
314                        addrs = email.Utils.getaddresses(ccs)
315                        if not addrs:
316                                return
317
318                        # Remove reporter email address if notification is
319                        # on
320                        #
321                        if self.notification:
322                                try:
323                                        addrs.remove((self.author, self.email_addr))
324                                except ValueError, detail:
325                                        pass
326
327                        for name,mail in addrs:
328                                try:
329                                        mail_list = '%s, %s' %(mail_list, mail)
330                                except:
331                                        mail_list = mail
332
333                        if mail_list:
334                                ticket['cc'] = self.to_unicode(mail_list)
335
336        def save_email_for_debug(self, message, tempfile=False):
337                if tempfile:
338                        import tempfile
339                        msg_file = tempfile.mktemp('.email2trac')
340                else:
341                        msg_file = '/var/tmp/msg.txt'
342                print 'TD: saving email to %s' % msg_file
343                fx = open(msg_file, 'wb')
344                fx.write('%s' % message)
345                fx.close()
346                try:
347                        os.chmod(msg_file,S_IRWXU|S_IRWXG|S_IRWXO)
348                except OSError:
349                        pass
350
351        def ticket_update(self, m):
352                """
353                If the current email is a reply to an existing ticket, this function
354                will append the contents of this email to that ticket, instead of
355                creating a new one.
356                """
357                if not m['Subject']:
358                        return False
359                else:
360                        subject  = self.to_unicode(m['Subject'])
361
362                TICKET_RE = re.compile(r"""
363                                        (?P<ticketnr>[#][0-9]+:)
364                                        """, re.VERBOSE)
365
366                result =  TICKET_RE.search(subject)
367                if not result:
368                        return False
369
370                body_text = self.get_body_text(m)
371
372                # Strip '#' and ':' from ticket_id
373                #
374                ticket_id = result.group('ticketnr')
375                ticket_id = int(ticket_id[1:-1])
376
377                # Get current time
378                #
379                when = int(time.time())
380
381                if self.VERSION  == 0.8:
382                        tkt = Ticket(self.db, ticket_id)
383                        tkt.save_changes(self.db, self.author, body_text, when)
384                else:
385                        try:
386                                tkt = Ticket(self.env, ticket_id, self.db)
387                        except util.TracError, detail:
388                                return False
389
390                        tkt.save_changes(self.author, body_text, when)
391                        tkt['id'] = ticket_id
392
393                if self.VERSION  == 0.9:
394                        self.attachments(m, tkt, True)
395                else:
396                        self.attachments(m, tkt)
397
398                if self.notification:
399                        self.notify(tkt, False, when)
400
401                return True
402
403        def new_ticket(self, msg):
404                """
405                Create a new ticket
406                """
407                tkt = Ticket(self.env)
408                tkt['status'] = 'new'
409
410                # Some defaults
411                #
412                tkt['milestone'] = self.get_config('ticket', 'default_milestone')
413                tkt['priority'] = self.get_config('ticket', 'default_priority')
414                tkt['severity'] = self.get_config('ticket', 'default_severity')
415                tkt['version'] = self.get_config('ticket', 'default_version')
416
417                if not msg['Subject']:
418                        tkt['summary'] = u'(geen subject)'
419                else:
420                        tkt['summary'] = self.to_unicode(msg['Subject'])
421
422
423                if settings.has_key('component'):
424                        tkt['component'] = settings['component']
425                else:
426                        tkt['component'] = self.spam(msg)
427
428                # Discard SPAM messages.
429                #
430                if self.DROP_SPAM and (tkt['component'] == 'Spam'):
431                        # print 'This message is a SPAM. Automatic ticket insertion refused (SPAM level > %d' % self.SPAM_LEVEL
432                        return False   
433
434                # Set default owner for component
435                #
436                self.set_owner(tkt)
437                self.set_reply_fields(tkt, msg)
438
439                # produce e-mail like header
440                #
441                head = ''
442                if self.EMAIL_HEADER > 0:
443                        head = self.email_header_txt(msg)
444                       
445
446                body_text = self.get_body_text(msg)
447
448                tkt['description'] = 'email2trac:%s\r\n%s' \
449                        %(head, body_text)
450
451                when = int(time.time())
452                if self.VERSION == 0.8:
453                        ticket_id = tkt.insert(self.db)
454                else:
455                        ticket_id = tkt.insert()
456                        tkt['id'] = ticket_id
457
458                changed = False
459                comment = ''
460
461                # Rewrite the description if we have mailto enabled
462                #
463                if self.MAILTO:
464                        changed = True
465                        comment = '\nadded mailto line\n'
466                        mailto = self.html_mailto_link(self.to_unicode(msg['subject']), ticket_id, body_text)
467                        #tkt['description'] = 'email2trac:%s%s\r\n{{{\r\n%s\r\n}}}' %(head, mailto, body_text)
468                        tkt['description'] = 'email2trac:%s%s\r\n%s' %(head, mailto, body_text)
469
470                n =  self.attachments(msg, tkt)
471                if n:
472                        changed = True
473                        comment = '%s\nThis message has %d attachment(s)\n' %(comment, n)
474
475                if changed:
476                        if self.VERSION  == 0.8:
477                                tkt.save_changes(self.db, self.author, comment)
478                        else:
479                                tkt.save_changes(self.author, comment)
480
481                #print tkt.get_changelog(self.db, when)
482
483                if self.notification:
484                        self.notify(tkt, True)
485                        #self.notify(tkt, False)
486
487        def parse(self, fp):
488                global m
489
490                m = email.message_from_file(fp)
491                if not m:
492                        return
493
494                if self.DEBUG > 1:        # save the entire e-mail message text
495                        self.save_email_for_debug(m)
496                        self.debug_attachments(m)
497
498                self.db = self.env.get_db_cnx()
499                self.get_author_emailaddrs(m)
500
501                if self.get_config('notification', 'smtp_enabled') in ['true']:
502                        self.notification = 1
503                else:
504                        self.notification = 0
505
506                # Must we update existing tickets
507                #
508                if self.TICKET_UPDATE > 0:
509                        if self.ticket_update(m):
510                                return True
511
512                self.new_ticket(m)
513
514        def strip_signature(self, text):
515                """
516                Strip signature from message, inspired by Mailman software
517                """
518                body = []
519                for line in text.splitlines():
520                        if line == '-- ':
521                                break
522                        body.append(line)
523
524                return ('\n'.join(body))
525
526        def get_body_text(self, msg):
527                """
528                put the message text in the ticket description or in the changes field.
529                message text can be plain text or html or something else
530                """
531                has_description = 0
532                encoding = True
533                ubody_text = u'No plain text message'
534                for part in msg.walk():
535
536                        # 'multipart/*' is a container for multipart messages
537                        #
538                        if part.get_content_maintype() == 'multipart':
539                                continue
540
541                        if part.get_content_type() == 'text/plain':
542                                # Try to decode, if fails then do not decode
543                                #
544                                body_text = part.get_payload(decode=1)
545                                if not body_text:                       
546                                        body_text = part.get_payload(decode=0)
547               
548                                if self.STRIP_SIGNATURE:
549                                        body_text = self.strip_signature(body_text)
550
551                                # Get contents charset (iso-8859-15 if not defined in mail headers)
552                                #
553                                charset = part.get_content_charset()
554                                if not charset:
555                                        charset = 'iso-8859-15'
556
557                                try:
558                                        ubody_text = unicode(body_text, charset)
559
560                                except UnicodeError, detail:
561                                        ubody_text = unicode(body_text, 'iso-8859-15')
562
563                                except LookupError, detail:
564                                        ubody_text = body_text
565                                        encoding = False
566
567                        elif part.get_content_type() == 'text/html':
568                                ubody_text = '(see attachment for HTML mail message)'
569
570                        else:
571                                ubody_text = '(see attachment for message)'
572
573                        has_description = 1
574                        break           # we have the description, so break
575
576                if not has_description:
577                        ubody_text = '(see attachment for message)'
578
579                # A patch so that the web-interface will not update the description
580                # field of a ticket
581                #
582                ubody_text = ('\r\n'.join(ubody_text.splitlines()))
583
584                #  If we can unicode it try to encode it for trac
585                #  else we a lot of garbage
586                #
587                if encoding:
588                        ubody_text = ubody_text.encode('utf-8')
589
590                if self.VERBATIM_FORMAT:
591                        ubody_text = '{{{\r\n%s\r\n}}}' %ubody_text
592                else:
593                        ubody_text = '%s' %ubody_text
594
595                return ubody_text
596
597        def notify(self, tkt , new=True, modtime=0):
598                """
599                A wrapper for the TRAC notify function. So we can use templates
600                """
601                if tkt['component'] == 'Spam':
602                        return 
603
604                try:
605                        # create false {abs_}href properties, to trick Notify()
606                        #
607                        self.env.abs_href = Href(self.get_config('project', 'url'))
608                        self.env.href = Href(self.get_config('project', 'url'))
609
610                        tn = TicketNotifyEmail(self.env)
611                        if self.notify_template:
612                                tn.template_name = self.notify_template;
613
614                        tn.notify(tkt, new, modtime)
615
616                except Exception, e:
617                        print 'TD: Failure sending notification on creation of ticket #%s: %s' %(tkt['id'], e)
618
619        def mail_line(self, str):
620                return '%s %s' % (self.comment, str)
621
622
623        def html_mailto_link(self, subject, id, body):
624                if not self.author:
625                        author = self.email_addr
626                else:   
627                        author = self.to_unicode(self.author)
628
629                # Must find a fix
630                #
631                #arr = string.split(body, '\n')
632                #arr = map(self.mail_line, arr)
633                #body = string.join(arr, '\n')
634                #body = '%s wrote:\n%s' %(author, body)
635
636                # Temporary fix
637                str = 'mailto:%s?Subject=%s&Cc=%s' %(
638                       urllib.quote(self.email_addr),
639                           urllib.quote('Re: #%s: %s' %(id, subject)),
640                           urllib.quote(self.MAILTO_CC)
641                           )
642
643                str = '\r\n{{{\r\n#!html\r\n<a href="%s">Reply to: %s</a>\r\n}}}\r\n' %(str, author)
644
645                return str
646
647        def attachments(self, message, ticket, update=False):
648                '''
649                save any attachments as files in the ticket's directory
650                '''
651                count = 0
652                first = 0
653                number = 0
654                for part in message.walk():
655                        if part.get_content_maintype() == 'multipart':          # multipart/* is just a container
656                                continue
657
658                        if not first:                                                                           # first content is the message
659                                first = 1
660                                if part.get_content_type() == 'text/plain':             # if first is text, is was already put in the description
661                                        continue
662
663                        filename = part.get_filename()
664                        count = count + 1
665                        if not filename:
666                                number = number + 1
667                                filename = 'part%04d' % number
668
669                                ext = mimetypes.guess_extension(part.get_content_type())
670                                if not ext:
671                                        ext = '.bin'
672
673                                filename = '%s%s' % (filename, ext)
674                        else:
675                                filename = self.to_unicode(filename)
676
677                        # From the trac code
678                        #
679                        filename = filename.replace('\\', '/').replace(':', '/')
680                        filename = os.path.basename(filename)
681
682                        # We try to normalize the filename to utf-8 NFC if we can.
683                        # Files uploaded from OS X might be in NFD.
684                        # Check python version and then try it
685                        #
686                        if sys.version_info[0] > 2 or (sys.version_info[0] == 2 and sys.version_info[1] >= 3):
687                                try:
688                                        filename = unicodedata.normalize('NFC', unicode(filename, 'utf-8')).encode('utf-8') 
689                                except TypeError:
690                                        pass
691
692                        url_filename = urllib.quote(filename)
693                        if self.VERSION == 0.8:
694                                dir = os.path.join(self.env.get_attachments_dir(), 'ticket',
695                                                        urllib.quote(str(ticket['id'])))
696                                if not os.path.exists(dir):
697                                        mkdir_p(dir, 0755)
698                        else:
699                                dir = '/tmp'
700
701                        path, fd =  util.create_unique_file(os.path.join(dir, url_filename))
702                        text = part.get_payload(decode=1)
703                        if not text:
704                                text = '(None)'
705                        fd.write(text)
706                        fd.close()
707
708                        # get the filesize
709                        #
710                        stats = os.lstat(path)
711                        filesize = stats[stat.ST_SIZE]
712
713                        # Insert the attachment it differs for the different TRAC versions
714                        #
715                        if self.VERSION == 0.8:
716                                cursor = self.db.cursor()
717                                try:
718                                        cursor.execute('INSERT INTO attachment VALUES("%s","%s","%s",%d,%d,"%s","%s","%s")'
719                                                %('ticket', urllib.quote(str(ticket['id'])), filename + '?format=raw', filesize,
720                                                int(time.time()),'', self.author, 'e-mail') )
721
722                                # Attachment is already known
723                                #
724                                except sqlite.IntegrityError:   
725                                        #self.db.close()
726                                        return count
727
728                                self.db.commit()
729
730                        else:
731                                fd = open(path)
732                                att = attachment.Attachment(self.env, 'ticket', ticket['id'])
733
734                                # This will break the ticket_update system, the body_text is vaporized
735                                # ;-(
736                                #
737                                if not update:
738                                        att.author = self.author
739                                        att.description = self.to_unicode('Added by email2trac')
740
741                                att.insert(url_filename, fd, filesize)
742                                fd.close()
743
744                        # Remove the created temporary filename
745                        #
746                        os.unlink(path)
747
748                # Return how many attachments
749                #
750                return count
751
752
753def mkdir_p(dir, mode):
754        '''do a mkdir -p'''
755
756        arr = string.split(dir, '/')
757        path = ''
758        for part in arr:
759                path = '%s/%s' % (path, part)
760                try:
761                        stats = os.stat(path)
762                except OSError:
763                        os.mkdir(path, mode)
764
765
766def ReadConfig(file, name):
767        """
768        Parse the config file
769        """
770
771        if not os.path.isfile(file):
772                print 'File %s does not exist' %file
773                sys.exit(1)
774
775        config = ConfigParser.ConfigParser()
776        try:
777                config.read(file)
778        except ConfigParser.MissingSectionHeaderError,detail:
779                print detail
780                sys.exit(1)
781
782
783        # Use given project name else use defaults
784        #
785        if name:
786                if not config.has_section(name):
787                        print "Not a valid project name: %s" %name
788                        print "Valid names: %s" %config.sections()
789                        sys.exit(1)
790
791                project =  dict()
792                for option in  config.options(name):
793                        project[option] = config.get(name, option)
794
795        else:
796                project = config.defaults()
797
798        return project
799
800
801if __name__ == '__main__':
802        # Default config file
803        #
804        configfile = '@email2trac_conf@'
805        project = ''
806        component = ''
807        ENABLE_SYSLOG = 0
808               
809        try:
810                opts, args = getopt.getopt(sys.argv[1:], 'chf:p:', ['component=','help', 'file=', 'project='])
811        except getopt.error,detail:
812                print __doc__
813                print detail
814                sys.exit(1)
815       
816        project_name = None
817        for opt,value in opts:
818                if opt in [ '-h', '--help']:
819                        print __doc__
820                        sys.exit(0)
821                elif opt in ['-c', '--component']:
822                        component = value
823                elif opt in ['-f', '--file']:
824                        configfile = value
825                elif opt in ['-p', '--project']:
826                        project_name = value
827       
828        settings = ReadConfig(configfile, project_name)
829        if not settings.has_key('project'):
830                print __doc__
831                print 'No Trac project is defined in the email2trac config file.'
832                sys.exit(1)
833       
834        if component:
835                settings['component'] = component
836       
837        if settings.has_key('trac_version'):
838                version = float(settings['trac_version'])
839        else:
840                version = trac_default_version
841
842        if settings.has_key('enable_syslog'):
843                ENABLE_SYSLOG =  float(settings['enable_syslog'])
844                       
845        #debug HvB
846        #print settings
847       
848        try:
849                if version == 0.8:
850                        from trac.Environment import Environment
851                        from trac.Ticket import Ticket
852                        from trac.Notify import TicketNotifyEmail
853                        from trac.Href import Href
854                        from trac import util
855                        import sqlite
856                elif version == 0.9:
857                        from trac import attachment
858                        from trac.env import Environment
859                        from trac.ticket import Ticket
860                        from trac.web.href import Href
861                        from trac import util
862                        from trac.Notify import TicketNotifyEmail
863                elif version == 0.10:
864                        from trac import attachment
865                        from trac.env import Environment
866                        from trac.ticket import Ticket
867                        from trac.web.href import Href
868                        from trac import util
869                        # see http://projects.edgewall.com/trac/changeset/2799
870                        from trac.ticket.notification import TicketNotifyEmail
871       
872                env = Environment(settings['project'], create=0)
873                tktparser = TicketEmailParser(env, settings, version)
874                tktparser.parse(sys.stdin)
875
876        # Catch all errors ans log to SYSLOG if we have enabled this
877        # else stdout
878        #
879        except Exception, error:
880                if ENABLE_SYSLOG:
881                        syslog.openlog('email2trac', syslog.LOG_NOWAIT)
882                        etype, evalue, etb = sys.exc_info()
883                        for e in traceback.format_exception(etype, evalue, etb):
884                                syslog.syslog(e)
885                        syslog.closelog()
886                else:
887                        traceback.print_exc()
888
889                if m:
890                        tktparser.save_email_for_debug(m, True)
891
892# EOB
Note: See TracBrowser for help on using the repository browser.