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

Last change on this file since 129 was 129, checked in by bas, 16 years ago

EmailtoTracScript?:

email2trac.py.in:

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