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

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

EmailtoTracScript?:

email2trac.py.in:

  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 20.5 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 89 2006-06-26 08:01:47Z 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')
[22]499
[89]500                                try:
501                                        temp = unicode(body_text, charset)
502                                except (UnicodeError,LookupError):
503                                        temp = unicode(body_text, 'iso-8859-15')
504
505                                #ubody_text = unicode(body_text, charset).encode('utf-8')
506                                ubody_text = temp.encode('utf-8')
507
[22]508                        elif part.get_content_type() == 'text/html':
[72]509                                ubody_text = '\n\n(see attachment for HTML mail message)\n'
[22]510
511                        else:
[72]512                                ubody_text = '\n\n(see attachment for message)\n'
[22]513
514                        has_description = 1
515                        break           # we have the description, so break
516
517                if not has_description:
[72]518                        ubody_text = '\n\n(see attachment for message)\n'
[22]519
[72]520                return ubody_text
[22]521
[77]522        def notify(self, tkt , new=True, modtime=0):
[79]523                """
524                A wrapper for the TRAC notify function. So we can use templates
525                """
[41]526                try:
527                        # create false {abs_}href properties, to trick Notify()
528                        #
529                        self.env.abs_href = Href(self.get_config('project', 'url'))
530                        self.env.href = Href(self.get_config('project', 'url'))
[22]531
[41]532                        tn = TicketNotifyEmail(self.env)
[42]533                        if self.notify_template:
534                                tn.template_name = self.notify_template;
535
[77]536                        tn.notify(tkt, new, modtime)
[41]537
538                except Exception, e:
[79]539                        print 'TD: Failure sending notification on creation of ticket #%s: %s' %(tkt['id'], e)
[41]540
[22]541        def mail_line(self, str):
542                return '%s %s' % (self.comment, str)
543
544
[72]545        def html_mailto_link(self, subject, id, body):
546                if not self.author:
[88]547                        author = self.email_addr
[22]548                else:   
[72]549                        author = self.to_unicode(self.author)
[22]550
551                # Must find a fix
552                #
553                #arr = string.split(body, '\n')
554                #arr = map(self.mail_line, arr)
555                #body = string.join(arr, '\n')
556                #body = '%s wrote:\n%s' %(author, body)
557
558                # Temporary fix
[74]559                str = 'mailto:%s?Subject=%s&Cc=%s' %(
560                       urllib.quote(self.email_addr),
561                           urllib.quote('Re: #%s: %s' %(id, subject)),
562                           urllib.quote(self.MAILTO_CC)
563                           )
564
[22]565                str = '\n{{{\n#!html\n<a href="%s">Reply to: %s</a>\n}}}\n' %(str, author)
566
567                return str
568
[72]569        def attachments(self, message, ticket):
[79]570                '''
571                save any attachments as files in the ticket's directory
572                '''
[22]573                count = 0
[77]574                first = 0
575                number = 0
[22]576                for part in message.walk():
577                        if part.get_content_maintype() == 'multipart':          # multipart/* is just a container
578                                continue
579
580                        if not first:                                                                           # first content is the message
581                                first = 1
582                                if part.get_content_type() == 'text/plain':             # if first is text, is was already put in the description
583                                        continue
584
585                        filename = part.get_filename()
[77]586                        count = count + 1
[22]587                        if not filename:
[77]588                                number = number + 1
589                                filename = 'part%04d' % number
[22]590
[72]591                                ext = mimetypes.guess_extension(part.get_content_type())
[22]592                                if not ext:
593                                        ext = '.bin'
594
595                                filename = '%s%s' % (filename, ext)
596                        else:
597                                filename = self.to_unicode(filename)
598
[48]599                        # From the trac code
600                        #
601                        filename = filename.replace('\\', '/').replace(':', '/')
602                        filename = os.path.basename(filename)
[22]603
[48]604                        # We try to normalize the filename to utf-8 NFC if we can.
605                        # Files uploaded from OS X might be in NFD.
606                        #
607                        if sys.version_info[0] > 2 or (sys.version_info[0] == 2 and sys.version_info[1] >= 3):
608                                filename = unicodedata.normalize('NFC', unicode(filename, 'utf-8')).encode('utf-8') 
609
[22]610                        url_filename = urllib.quote(filename)
[68]611                        if self.VERSION == 0.8:
[22]612                                dir = os.path.join(self.env.get_attachments_dir(), 'ticket',
613                                                        urllib.quote(str(ticket['id'])))
614                                if not os.path.exists(dir):
615                                        mkdir_p(dir, 0755)
[68]616                        else:
617                                dir = '/tmp'
[22]618
[48]619                        path, fd =  util.create_unique_file(os.path.join(dir, url_filename))
[22]620                        text = part.get_payload(decode=1)
621                        if not text:
622                                text = '(None)'
[48]623                        fd.write(text)
624                        fd.close()
[22]625
626                        # get the filesize
627                        #
[48]628                        stats = os.lstat(path)
[22]629                        filesize = stats[stat.ST_SIZE]
630
631                        # Insert the attachment it differs for the different TRAC versions
[73]632                        #
[68]633                        if self.VERSION == 0.8:
[22]634                                cursor = self.db.cursor()
[73]635                                try:
636                                        cursor.execute('INSERT INTO attachment VALUES("%s","%s","%s",%d,%d,"%s","%s","%s")'
637                                                %('ticket', urllib.quote(str(ticket['id'])), filename + '?format=raw', filesize,
638                                                int(time.time()),'', self.author, 'e-mail') )
639
640                                # Attachment is already known
641                                #
642                                except sqlite.IntegrityError:   
[84]643                                        #self.db.close()
644                                        return count
[73]645
[22]646                                self.db.commit()
[73]647
[68]648                        else:
649                                fd = open(path)
650                                att = attachment.Attachment(self.env, 'ticket', ticket['id'])
651                                att.insert(url_filename, fd, filesize)
652                                fd.close()
[22]653
[77]654                # Return how many attachments
655                #
656                return count
[22]657
[77]658
[22]659def mkdir_p(dir, mode):
660        '''do a mkdir -p'''
661
662        arr = string.split(dir, '/')
663        path = ''
664        for part in arr:
665                path = '%s/%s' % (path, part)
666                try:
667                        stats = os.stat(path)
668                except OSError:
669                        os.mkdir(path, mode)
670
671
672def ReadConfig(file, name):
673        """
674        Parse the config file
675        """
676
677        if not os.path.isfile(file):
[79]678                print 'File %s does not exist' %file
[22]679                sys.exit(1)
680
681        config = ConfigParser.ConfigParser()
682        try:
683                config.read(file)
684        except ConfigParser.MissingSectionHeaderError,detail:
685                print detail
686                sys.exit(1)
687
688
689        # Use given project name else use defaults
690        #
691        if name:
692                if not config.has_section(name):
[79]693                        print "Not a valid project name: %s" %name
[22]694                        print "Valid names: %s" %config.sections()
695                        sys.exit(1)
696
697                project =  dict()
698                for option in  config.options(name):
699                        project[option] = config.get(name, option)
700
701        else:
702                project = config.defaults()
703
704        return project
705
[87]706
[22]707if __name__ == '__main__':
708        # Default config file
709        #
[24]710        configfile = '@email2trac_conf@'
[22]711        project = ''
712        component = ''
[87]713        ENABLE_SYSLOG = 0
714               
[22]715        try:
716                opts, args = getopt.getopt(sys.argv[1:], 'chf:p:', ['component=','help', 'file=', 'project='])
717        except getopt.error,detail:
718                print __doc__
719                print detail
720                sys.exit(1)
[87]721       
[22]722        project_name = None
723        for opt,value in opts:
724                if opt in [ '-h', '--help']:
725                        print __doc__
726                        sys.exit(0)
727                elif opt in ['-c', '--component']:
728                        component = value
729                elif opt in ['-f', '--file']:
730                        configfile = value
731                elif opt in ['-p', '--project']:
732                        project_name = value
[87]733       
[22]734        settings = ReadConfig(configfile, project_name)
735        if not settings.has_key('project'):
736                print __doc__
[79]737                print 'No Trac project is defined in the email2trac config file.'
[22]738                sys.exit(1)
[87]739       
[22]740        if component:
741                settings['component'] = component
[87]742       
[22]743        if settings.has_key('trac_version'):
744                version = float(settings['trac_version'])
745        else:
746                version = trac_default_version
747
[87]748        if settings.has_key('enable_syslog'):
749                ENABLE_SYSLOG =  float(settings['enable_syslog'])
750                       
[22]751        #debug HvB
752        #print settings
[87]753       
754        try:
755                if version == 0.8:
756                        from trac.Environment import Environment
757                        from trac.Ticket import Ticket
758                        from trac.Notify import TicketNotifyEmail
759                        from trac.Href import Href
760                        from trac import util
761                        import sqlite
762                elif version == 0.9:
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                        from trac.Notify import TicketNotifyEmail
769                elif version == 0.10:
770                        from trac import attachment
771                        from trac.env import Environment
772                        from trac.ticket import Ticket
773                        from trac.web.href import Href
774                        from trac import util
775                        # see http://projects.edgewall.com/trac/changeset/2799
776                        from trac.ticket.notification import TicketNotifyEmail
777       
778                env = Environment(settings['project'], create=0)
779                tktparser = TicketEmailParser(env, settings, version)
780                tktparser.parse(sys.stdin)
[22]781
[87]782        # Catch all errors ans log to SYSLOG if we have enabled this
783        # else stdout
784        #
785        except Exception, error:
786                import syslog, traceback
[41]787
[87]788                if ENABLE_SYSLOG:
789                        syslog.openlog('email2trac', syslog.LOG_NOWAIT)
790                        etype, evalue, etb = sys.exc_info()
791                        for e in traceback.format_exception(etype, evalue, etb):
792                                syslog.syslog(e)
793                        syslog.closelog()
794                else:
795                        traceback.print_exc()
[22]796
797# EOB
Note: See TracBrowser for help on using the repository browser.