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

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

EmailtoTracScript?:

email2trac.py.in:

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