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

Last change on this file since 126 was 126, checked in by bas, 18 years ago

EmailtoTracScript?:

email2trac.py.in:

  • Fixed a bug in Ticket Update, when ticket does not exists threat is as a new ticket


  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 21.4 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 126 2006-10-18 07:33:34Z 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                self.attachments(m, tkt)
383
384                if self.notification:
385                        self.notify(tkt, False, when)
386
387                return True
388
389        def new_ticket(self, msg):
390                """
391                Create a new ticket
392                """
393                tkt = Ticket(self.env)
394                tkt['status'] = 'new'
395
396                # Some defaults
397                #
398                tkt['milestone'] = self.get_config('ticket', 'default_milestone')
399                tkt['priority'] = self.get_config('ticket', 'default_priority')
400                tkt['severity'] = self.get_config('ticket', 'default_severity')
401                tkt['version'] = self.get_config('ticket', 'default_version')
402
403                if not msg['Subject']:
404                        tkt['summary'] = u'(geen subject)'
405                else:
406                        tkt['summary'] = self.to_unicode(msg['Subject'])
407
408
409                if settings.has_key('component'):
410                        tkt['component'] = settings['component']
411                else:
412                        tkt['component'] = self.spam(msg)
413
414                # Discard SPAM messages.
415                #
416                if self.DROP_SPAM and (tkt['component'] == 'Spam'):
417                        # print 'This message is a SPAM. Automatic ticket insertion refused (SPAM level > %d' % self.SPAM_LEVEL
418                        return False   
419
420                # Set default owner for component
421                #
422                self.set_owner(tkt)
423                self.set_reply_fields(tkt, msg)
424
425                # produce e-mail like header
426                #
427                head = ''
428                if self.EMAIL_HEADER > 0:
429                        head = self.email_header_txt(msg)
430                       
431
432                body_text = self.get_body_text(msg)
433
434                tkt['description'] = 'email2trac:%s\r\n%s' \
435                        %(head, body_text)
436
437                when = int(time.time())
438                if self.VERSION == 0.8:
439                        ticket_id = tkt.insert(self.db)
440                else:
441                        ticket_id = tkt.insert()
442                        tkt['id'] = ticket_id
443
444                changed = False
445                comment = ''
446
447                # Rewrite the description if we have mailto enabled
448                #
449                if self.MAILTO:
450                        changed = True
451                        comment = '\nadded mailto line\n'
452                        mailto = self.html_mailto_link(self.to_unicode(msg['subject']), ticket_id, body_text)
453                        #tkt['description'] = 'email2trac:%s%s\r\n{{{\r\n%s\r\n}}}' %(head, mailto, body_text)
454                        tkt['description'] = 'email2trac:%s%s\r\n%s' %(head, mailto, body_text)
455
456                n =  self.attachments(msg, tkt)
457                if n:
458                        changed = True
459                        comment = '%s\nThis message has %d attachment(s)\n' %(comment, n)
460
461                if changed:
462                        if self.VERSION  == 0.8:
463                                tkt.save_changes(self.db, self.author, comment)
464                        else:
465                                tkt.save_changes(self.author, comment)
466
467                #print tkt.get_changelog(self.db, when)
468
469                if self.notification:
470                        self.notify(tkt, True)
471                        #self.notify(tkt, False)
472
473        def parse(self, fp):
474                global m
475
476                m = email.message_from_file(fp)
477                if not m:
478                        return
479
480                if self.DEBUG > 1:        # save the entire e-mail message text
481                        self.save_email_for_debug(m)
482                        self.debug_attachments(m)
483
484                self.db = self.env.get_db_cnx()
485                self.get_author_emailaddrs(m)
486
487                if self.get_config('notification', 'smtp_enabled') in ['true']:
488                        self.notification = 1
489                else:
490                        self.notification = 0
491
492                # Must we update existing tickets
493                #
494                if self.TICKET_UPDATE > 0:
495                        if self.ticket_update(m):
496                                return True
497
498                self.new_ticket(m)
499
500        def get_body_text(self, msg):
501                """
502                put the message text in the ticket description or in the changes field.
503                message text can be plain text or html or something else
504                """
505                has_description = 0
506                encoding = True
507                ubody_text = u'No plain text message'
508                for part in msg.walk():
509
510                        # 'multipart/*' is a container for multipart messages
511                        #
512                        if part.get_content_maintype() == 'multipart':
513                                continue
514
515                        if part.get_content_type() == 'text/plain':
516                                # Try to decode, if fails then do not decode
517                                #
518                                body_text = part.get_payload(decode=1)
519                                if not body_text:                       
520                                        body_text = part.get_payload(decode=0)
521
522                                # Get contents charset (iso-8859-15 if not defined in mail headers)
523                                #
524                                charset = part.get_content_charset()
525                                if not charset:
526                                        charset = 'iso-8859-15'
527
528                                try:
529                                        ubody_text = unicode(body_text, charset)
530
531                                except UnicodeError, detail:
532                                        ubody_text = unicode(body_text, 'iso-8859-15')
533
534                                except LookupError, detail:
535                                        ubody_text = body_text
536                                        encoding = False
537
538                        elif part.get_content_type() == 'text/html':
539                                ubody_text = '(see attachment for HTML mail message)'
540
541                        else:
542                                ubody_text = '(see attachment for message)'
543
544                        has_description = 1
545                        break           # we have the description, so break
546
547                if not has_description:
548                        ubody_text = '(see attachment for message)'
549
550                # A patch so that the web-interface will not update the description
551                # field of a ticket
552                #
553                ubody_text = ('\r\n'.join(ubody_text.splitlines()))
554
555                #  If we can unicode it try to encode it for trac
556                #  else we a lot of garbage
557                #
558                if encoding:
559                        ubody_text = ubody_text.encode('utf-8')
560
561                ubody_text = '{{{\r\n%s\r\n}}}' %ubody_text
562                return ubody_text
563
564        def notify(self, tkt , new=True, modtime=0):
565                """
566                A wrapper for the TRAC notify function. So we can use templates
567                """
568                if tkt['component'] == 'Spam':
569                        return 
570
571                try:
572                        # create false {abs_}href properties, to trick Notify()
573                        #
574                        self.env.abs_href = Href(self.get_config('project', 'url'))
575                        self.env.href = Href(self.get_config('project', 'url'))
576
577                        tn = TicketNotifyEmail(self.env)
578                        if self.notify_template:
579                                tn.template_name = self.notify_template;
580
581                        tn.notify(tkt, new, modtime)
582
583                except Exception, e:
584                        print 'TD: Failure sending notification on creation of ticket #%s: %s' %(tkt['id'], e)
585
586        def mail_line(self, str):
587                return '%s %s' % (self.comment, str)
588
589
590        def html_mailto_link(self, subject, id, body):
591                if not self.author:
592                        author = self.email_addr
593                else:   
594                        author = self.to_unicode(self.author)
595
596                # Must find a fix
597                #
598                #arr = string.split(body, '\n')
599                #arr = map(self.mail_line, arr)
600                #body = string.join(arr, '\n')
601                #body = '%s wrote:\n%s' %(author, body)
602
603                # Temporary fix
604                str = 'mailto:%s?Subject=%s&Cc=%s' %(
605                       urllib.quote(self.email_addr),
606                           urllib.quote('Re: #%s: %s' %(id, subject)),
607                           urllib.quote(self.MAILTO_CC)
608                           )
609
610                str = '\r\n{{{\r\n#!html\r\n<a href="%s">Reply to: %s</a>\r\n}}}\r\n' %(str, author)
611
612                return str
613
614        def attachments(self, message, ticket):
615                '''
616                save any attachments as files in the ticket's directory
617                '''
618                count = 0
619                first = 0
620                number = 0
621                for part in message.walk():
622                        if part.get_content_maintype() == 'multipart':          # multipart/* is just a container
623                                continue
624
625                        if not first:                                                                           # first content is the message
626                                first = 1
627                                if part.get_content_type() == 'text/plain':             # if first is text, is was already put in the description
628                                        continue
629
630                        filename = part.get_filename()
631                        count = count + 1
632                        if not filename:
633                                number = number + 1
634                                filename = 'part%04d' % number
635
636                                ext = mimetypes.guess_extension(part.get_content_type())
637                                if not ext:
638                                        ext = '.bin'
639
640                                filename = '%s%s' % (filename, ext)
641                        else:
642                                filename = self.to_unicode(filename)
643
644                        # From the trac code
645                        #
646                        filename = filename.replace('\\', '/').replace(':', '/')
647                        filename = os.path.basename(filename)
648
649                        # We try to normalize the filename to utf-8 NFC if we can.
650                        # Files uploaded from OS X might be in NFD.
651                        # Check python version and then try it
652                        #
653                        if sys.version_info[0] > 2 or (sys.version_info[0] == 2 and sys.version_info[1] >= 3):
654                                try:
655                                        filename = unicodedata.normalize('NFC', unicode(filename, 'utf-8')).encode('utf-8') 
656                                except TypeError:
657                                        pass
658
659                        url_filename = urllib.quote(filename)
660                        if self.VERSION == 0.8:
661                                dir = os.path.join(self.env.get_attachments_dir(), 'ticket',
662                                                        urllib.quote(str(ticket['id'])))
663                                if not os.path.exists(dir):
664                                        mkdir_p(dir, 0755)
665                        else:
666                                dir = '/tmp'
667
668                        path, fd =  util.create_unique_file(os.path.join(dir, url_filename))
669                        text = part.get_payload(decode=1)
670                        if not text:
671                                text = '(None)'
672                        fd.write(text)
673                        fd.close()
674
675                        # get the filesize
676                        #
677                        stats = os.lstat(path)
678                        filesize = stats[stat.ST_SIZE]
679
680                        # Insert the attachment it differs for the different TRAC versions
681                        #
682                        if self.VERSION == 0.8:
683                                cursor = self.db.cursor()
684                                try:
685                                        cursor.execute('INSERT INTO attachment VALUES("%s","%s","%s",%d,%d,"%s","%s","%s")'
686                                                %('ticket', urllib.quote(str(ticket['id'])), filename + '?format=raw', filesize,
687                                                int(time.time()),'', self.author, 'e-mail') )
688
689                                # Attachment is already known
690                                #
691                                except sqlite.IntegrityError:   
692                                        #self.db.close()
693                                        return count
694
695                                self.db.commit()
696
697                        else:
698                                fd = open(path)
699                                att = attachment.Attachment(self.env, 'ticket', ticket['id'])
700                                att.author = self.author
701                                att.description = 'Added by email2trac'
702                                att.insert(url_filename, fd, filesize)
703                                fd.close()
704
705                        # Remove the created temporary filename
706                        #
707                        os.unlink(path)
708
709                # Return how many attachments
710                #
711                return count
712
713
714def mkdir_p(dir, mode):
715        '''do a mkdir -p'''
716
717        arr = string.split(dir, '/')
718        path = ''
719        for part in arr:
720                path = '%s/%s' % (path, part)
721                try:
722                        stats = os.stat(path)
723                except OSError:
724                        os.mkdir(path, mode)
725
726
727def ReadConfig(file, name):
728        """
729        Parse the config file
730        """
731
732        if not os.path.isfile(file):
733                print 'File %s does not exist' %file
734                sys.exit(1)
735
736        config = ConfigParser.ConfigParser()
737        try:
738                config.read(file)
739        except ConfigParser.MissingSectionHeaderError,detail:
740                print detail
741                sys.exit(1)
742
743
744        # Use given project name else use defaults
745        #
746        if name:
747                if not config.has_section(name):
748                        print "Not a valid project name: %s" %name
749                        print "Valid names: %s" %config.sections()
750                        sys.exit(1)
751
752                project =  dict()
753                for option in  config.options(name):
754                        project[option] = config.get(name, option)
755
756        else:
757                project = config.defaults()
758
759        return project
760
761
762if __name__ == '__main__':
763        # Default config file
764        #
765        configfile = '@email2trac_conf@'
766        project = ''
767        component = ''
768        ENABLE_SYSLOG = 0
769               
770        try:
771                opts, args = getopt.getopt(sys.argv[1:], 'chf:p:', ['component=','help', 'file=', 'project='])
772        except getopt.error,detail:
773                print __doc__
774                print detail
775                sys.exit(1)
776       
777        project_name = None
778        for opt,value in opts:
779                if opt in [ '-h', '--help']:
780                        print __doc__
781                        sys.exit(0)
782                elif opt in ['-c', '--component']:
783                        component = value
784                elif opt in ['-f', '--file']:
785                        configfile = value
786                elif opt in ['-p', '--project']:
787                        project_name = value
788       
789        settings = ReadConfig(configfile, project_name)
790        if not settings.has_key('project'):
791                print __doc__
792                print 'No Trac project is defined in the email2trac config file.'
793                sys.exit(1)
794       
795        if component:
796                settings['component'] = component
797       
798        if settings.has_key('trac_version'):
799                version = float(settings['trac_version'])
800        else:
801                version = trac_default_version
802
803        if settings.has_key('enable_syslog'):
804                ENABLE_SYSLOG =  float(settings['enable_syslog'])
805                       
806        #debug HvB
807        #print settings
808       
809        try:
810                if version == 0.8:
811                        from trac.Environment import Environment
812                        from trac.Ticket import Ticket
813                        from trac.Notify import TicketNotifyEmail
814                        from trac.Href import Href
815                        from trac import util
816                        import sqlite
817                elif version == 0.9:
818                        from trac import attachment
819                        from trac.env import Environment
820                        from trac.ticket import Ticket
821                        from trac.web.href import Href
822                        from trac import util
823                        from trac.Notify import TicketNotifyEmail
824                elif version == 0.10:
825                        from trac import attachment
826                        from trac.env import Environment
827                        from trac.ticket import Ticket
828                        from trac.web.href import Href
829                        from trac import util
830                        # see http://projects.edgewall.com/trac/changeset/2799
831                        from trac.ticket.notification import TicketNotifyEmail
832       
833                env = Environment(settings['project'], create=0)
834                tktparser = TicketEmailParser(env, settings, version)
835                tktparser.parse(sys.stdin)
836
837        # Catch all errors ans log to SYSLOG if we have enabled this
838        # else stdout
839        #
840        except Exception, error:
841                if ENABLE_SYSLOG:
842                        syslog.openlog('email2trac', syslog.LOG_NOWAIT)
843                        etype, evalue, etb = sys.exc_info()
844                        for e in traceback.format_exception(etype, evalue, etb):
845                                syslog.syslog(e)
846                        syslog.closelog()
847                else:
848                        traceback.print_exc()
849
850                if m:
851                        tktparser.save_email_for_debug(m, True)
852
853# EOB
Note: See TracBrowser for help on using the repository browser.