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

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

EmailtoTracScript?:

email2trac.py.in, email2trac.conf:

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